diff --git a/Dockerfile b/Dockerfile index a28b231eab..ec3694c7e8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM tgstation/byond:512.1467 as base +FROM tgstation/byond:512.1488 as base FROM base as build_base diff --git a/README.md b/README.md index 3e123280a2..ed82fb08e6 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Based and maintained from /tg/station.
**Forums:** http://citadel-station.net/forum/
**Ban Appeals:** http://citadel-station.net/forum/forumdisplay.php?fid=8
**Code:** https://github.com/Citadel-Station-13/Citadel-Station-13
-**Discord:** [Here](https://discord.gg/3gJ9pnM).
+**Discord:** [Here](https://discord.gg/E6SQuhz).
## DOWNLOADING diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm index 738148c948..ed5b07168f 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm @@ -508,7 +508,9 @@ /obj/structure/stone_tile/cracked{ dir = 4 }, -/obj/item/construction/rcd/loaded, +/obj/item/construction/rcd/loaded/upgraded{ + + }, /turf/open/indestructible/boss, /area/ruin/unpowered/ash_walkers) "bn" = ( diff --git a/_maps/RandomRuins/SpaceRuins/advancedlab.dmm b/_maps/RandomRuins/SpaceRuins/advancedlab.dmm new file mode 100644 index 0000000000..39e29018ea --- /dev/null +++ b/_maps/RandomRuins/SpaceRuins/advancedlab.dmm @@ -0,0 +1,582 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"a" = ( +/turf/template_noop, +/area/template_noop) +"b" = ( +/turf/closed/wall, +/area/ruin/space/has_grav/powered/advancedlab) +"c" = ( +/obj/structure/fans/tiny, +/obj/machinery/door/airlock/external, +/turf/open/floor/plasteel, +/area/ruin/space/has_grav/powered/advancedlab) +"d" = ( +/obj/machinery/vending/assist, +/turf/open/floor/plasteel, +/area/ruin/space/has_grav/powered/advancedlab) +"e" = ( +/obj/machinery/vending/snack/random, +/turf/open/floor/plasteel, +/area/ruin/space/has_grav/powered/advancedlab) +"f" = ( +/turf/open/floor/plasteel, +/area/ruin/space/has_grav/powered/advancedlab) +"g" = ( +/obj/machinery/light{ + dir = 1 + }, +/turf/open/floor/plasteel, +/area/ruin/space/has_grav/powered/advancedlab) +"h" = ( +/obj/structure/table/glass, +/obj/item/crowbar/advanced, +/obj/item/multitool/advanced{ + pixel_x = 4; + pixel_y = -1 + }, +/turf/open/floor/plasteel, +/area/ruin/space/has_grav/powered/advancedlab) +"i" = ( +/obj/machinery/computer/rdconsole, +/turf/open/floor/plasteel, +/area/ruin/space/has_grav/powered/advancedlab) +"j" = ( +/obj/structure/chair/comfy/beige, +/turf/open/floor/plasteel, +/area/ruin/space/has_grav/powered/advancedlab) +"k" = ( +/obj/structure/table/glass, +/obj/item/screwdriver/advanced{ + pixel_y = 8 + }, +/turf/open/floor/plasteel, +/area/ruin/space/has_grav/powered/advancedlab) +"l" = ( +/obj/structure/table/glass, +/turf/open/floor/plasteel, +/area/ruin/space/has_grav/powered/advancedlab) +"m" = ( +/obj/structure/table/glass, +/obj/item/gps{ + gpstag = "Abductor Replication Lab"; + pixel_x = -2; + pixel_y = 3 + }, +/turf/open/floor/plasteel, +/area/ruin/space/has_grav/powered/advancedlab) +"n" = ( +/obj/structure/chair/comfy/beige{ + icon_state = "comfychair"; + dir = 8 + }, +/turf/open/floor/plasteel, +/area/ruin/space/has_grav/powered/advancedlab) +"o" = ( +/obj/structure/table/glass, +/obj/item/weldingtool/advanced{ + pixel_x = 4; + pixel_y = 4 + }, +/turf/open/floor/plasteel, +/area/ruin/space/has_grav/powered/advancedlab) +"p" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/structure/table/glass, +/obj/item/paper{ + name = "Note to finder"; + pixel_x = -1; + pixel_y = 3; + info = "As of yet, our experiments have seen a fair bit of success. Unfortunately, our business partners have stopped funding us as they realised they utterly hate each other. To whoever finds this place, they are yours. Use them how you will. I leave you with the next generation of greytiding." + }, +/turf/open/floor/plasteel, +/area/ruin/space/has_grav/powered/advancedlab) +"q" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/structure/table/glass, +/turf/open/floor/plasteel, +/area/ruin/space/has_grav/powered/advancedlab) +"r" = ( +/obj/structure/table/glass, +/obj/item/wirecutters/advanced{ + pixel_y = 7 + }, +/obj/item/wrench/advanced{ + pixel_x = -1; + pixel_y = 3 + }, +/turf/open/floor/plasteel, +/area/ruin/space/has_grav/powered/advancedlab) +"s" = ( +/obj/structure/chair/comfy/beige{ + icon_state = "comfychair"; + dir = 1 + }, +/turf/open/floor/plasteel, +/area/ruin/space/has_grav/powered/advancedlab) +"t" = ( +/obj/machinery/light/small, +/turf/open/floor/plasteel, +/area/ruin/space/has_grav/powered/advancedlab) +"u" = ( +/obj/machinery/light/small{ + icon_state = "bulb"; + dir = 4 + }, +/obj/structure/closet, +/obj/item/clothing/suit/hooded/wintercoat/miner, +/obj/item/clothing/shoes/sneakers/brown, +/obj/item/clothing/under/pants/classicjeans, +/obj/item/clothing/neck/scarf, +/obj/item/clothing/neck/stripedgreenscarf, +/obj/item/toy/tennis/rainbow, +/obj/item/toy/tennis, +/obj/item/clothing/suit/hooded/wintercoat/miner, +/obj/item/clothing/shoes/sneakers/brown, +/obj/item/clothing/under/pants/classicjeans, +/turf/open/floor/plasteel, +/area/ruin/space/has_grav/powered/advancedlab) +"v" = ( +/obj/machinery/vending/boozeomat{ + req_access = null; + shut_up = 1 + }, +/turf/closed/wall, +/area/ruin/space/has_grav/powered/advancedlab) +"w" = ( +/obj/machinery/door/airlock/command{ + name = "Dorms" + }, +/turf/open/floor/plasteel, +/area/ruin/space/has_grav/powered/advancedlab) +"x" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/structure/table/glass, +/turf/open/floor/plasteel, +/area/ruin/space/has_grav/powered/advancedlab) +"y" = ( +/obj/machinery/light/small{ + icon_state = "bulb"; + dir = 1 + }, +/turf/open/floor/wood, +/area/ruin/space/has_grav/powered/advancedlab) +"z" = ( +/obj/machinery/door/airlock/security{ + name = "Visiting Business Partners" + }, +/turf/open/floor/wood, +/area/ruin/space/has_grav/powered/advancedlab) +"A" = ( +/turf/open/floor/wood, +/area/ruin/space/has_grav/powered/advancedlab) +"B" = ( +/obj/structure/bed, +/obj/item/bedsheet/syndie, +/turf/open/floor/wood, +/area/ruin/space/has_grav/powered/advancedlab) +"C" = ( +/obj/structure/closet{ + name = "Clothes" + }, +/obj/item/clothing/head/chameleon, +/obj/item/clothing/gloves/combat, +/obj/item/clothing/suit/chameleon, +/obj/item/clothing/under/chameleon, +/obj/item/clothing/shoes/chameleon, +/turf/open/floor/wood, +/area/ruin/space/has_grav/powered/advancedlab) +"D" = ( +/obj/machinery/light/small, +/turf/open/floor/wood, +/area/ruin/space/has_grav/powered/advancedlab) +"E" = ( +/obj/structure/table/wood, +/obj/item/radio/headset/chameleon, +/turf/open/floor/wood, +/area/ruin/space/has_grav/powered/advancedlab) +"F" = ( +/obj/structure/falsewall, +/turf/open/floor/wood, +/area/ruin/space/has_grav/powered/advancedlab) +"G" = ( +/obj/structure/table/wood, +/turf/open/floor/wood, +/area/ruin/space/has_grav/powered/advancedlab) +"H" = ( +/obj/structure/table/wood, +/obj/item/radio/headset/headset_cent/alt{ + keyslot2 = null + }, +/turf/open/floor/wood, +/area/ruin/space/has_grav/powered/advancedlab) +"I" = ( +/obj/structure/closet{ + name = "Official Clothing" + }, +/obj/item/clothing/under/rank/centcom_commander, +/obj/item/clothing/head/centhat, +/obj/item/clothing/gloves/combat, +/obj/item/clothing/suit/armor/vest, +/obj/item/clothing/shoes/sneakers/brown, +/turf/open/floor/wood, +/area/ruin/space/has_grav/powered/advancedlab) +"J" = ( +/obj/machinery/door/airlock/command{ + name = "Dorms" + }, +/turf/open/floor/wood, +/area/ruin/space/has_grav/powered/advancedlab) +"K" = ( +/obj/machinery/door/airlock/command{ + name = "Visiting Officials" + }, +/turf/open/floor/wood, +/area/ruin/space/has_grav/powered/advancedlab) +"L" = ( +/obj/structure/bed, +/obj/item/bedsheet/centcom, +/turf/open/floor/wood, +/area/ruin/space/has_grav/powered/advancedlab) +"M" = ( +/obj/structure/lattice, +/obj/effect/spawner/structure/window/reinforced, +/turf/open/space/basic, +/area/ruin/space/has_grav/powered/advancedlab) +"N" = ( +/obj/structure/extinguisher_cabinet, +/turf/closed/wall, +/area/ruin/space/has_grav/powered/advancedlab) +"O" = ( +/obj/structure/reagent_dispensers/water_cooler, +/turf/open/floor/plasteel, +/area/ruin/space/has_grav/powered/advancedlab) +"P" = ( +/obj/structure/lattice, +/turf/template_noop, +/area/space/nearstation) +"Q" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/turf/open/floor/plasteel, +/area/ruin/space/has_grav/powered/advancedlab) +"R" = ( +/obj/machinery/light/small{ + icon_state = "bulb"; + dir = 1 + }, +/turf/open/floor/plasteel, +/area/ruin/space/has_grav/powered/advancedlab) +"T" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/turf/open/floor/wood, +/area/ruin/space/has_grav/powered/advancedlab) + +(1,1,1) = {" +a +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +a +a +"} +(2,1,1) = {" +a +b +d +j +l +q +s +O +b +a +a +a +a +a +a +a +a +a +"} +(3,1,1) = {" +a +b +e +j +m +l +s +f +b +a +a +a +a +a +a +a +a +a +"} +(4,1,1) = {" +a +c +f +j +l +l +s +f +M +M +M +M +M +M +a +a +a +a +"} +(5,1,1) = {" +a +b +f +f +n +n +f +f +w +f +Q +f +f +M +a +a +a +a +"} +(6,1,1) = {" +a +b +f +f +f +f +f +f +M +M +M +M +f +M +a +a +a +a +"} +(7,1,1) = {" +a +b +g +f +f +f +f +f +b +P +P +M +R +M +a +a +a +a +"} +(8,1,1) = {" +a +N +f +f +f +f +f +u +b +P +P +M +f +M +a +a +a +a +"} +(9,1,1) = {" +a +b +f +f +f +f +f +b +b +b +b +M +J +M +b +a +a +a +"} +(10,1,1) = {" +a +b +h +k +o +r +f +b +y +A +A +F +T +A +b +a +a +a +"} +(11,1,1) = {" +a +b +i +f +f +f +t +b +z +v +b +b +b +K +b +a +a +a +"} +(12,1,1) = {" +a +b +p +f +f +f +f +b +A +C +b +G +A +A +b +a +a +a +"} +(13,1,1) = {" +a +b +l +l +x +l +f +b +A +D +b +H +A +D +b +a +a +a +"} +(14,1,1) = {" +a +b +b +b +b +b +b +b +B +E +b +I +A +L +b +a +a +a +"} +(15,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +a +a +a +"} diff --git a/_maps/RandomRuins/SpaceRuins/gasthelizards.dmm b/_maps/RandomRuins/SpaceRuins/gasthelizards.dmm index 8956267108..e21c3a92f7 100644 --- a/_maps/RandomRuins/SpaceRuins/gasthelizards.dmm +++ b/_maps/RandomRuins/SpaceRuins/gasthelizards.dmm @@ -103,7 +103,7 @@ /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/lizard, /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/lizard, /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/lizard, -/turf/open/floor/plasteel/airless/dark, +/turf/open/floor/plasteel/freezer, /area/ruin/space/has_grav/gasthelizard) "n" = ( /obj/structure/closet/crate/freezer, @@ -117,7 +117,7 @@ }, /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/lizard, /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/lizard, -/turf/open/floor/plasteel/airless/dark, +/turf/open/floor/plasteel/freezer, /area/ruin/space/has_grav/gasthelizard) "o" = ( /obj/structure/closet/crate/freezer, @@ -129,7 +129,7 @@ /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/lizard, /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/lizard, /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/lizard, -/turf/open/floor/plasteel/airless/dark, +/turf/open/floor/plasteel/freezer, /area/ruin/space/has_grav/gasthelizard) "p" = ( /obj/structure/window/reinforced{ @@ -158,7 +158,7 @@ /turf/open/floor/plasteel, /area/ruin/space/has_grav/gasthelizard) "r" = ( -/turf/open/floor/plasteel/airless/dark, +/turf/open/floor/plasteel/dark, /area/ruin/space/has_grav/gasthelizard) "s" = ( /obj/machinery/atmospherics/components/unary/portables_connector/visible{ @@ -203,14 +203,14 @@ /area/ruin/space/has_grav/gasthelizard) "x" = ( /obj/structure/kitchenspike, -/turf/open/floor/plasteel/airless/dark, +/turf/open/floor/plasteel/dark, /area/ruin/space/has_grav/gasthelizard) "y" = ( /obj/structure/table/reinforced, /obj/item/kitchen/knife/butcher, /obj/item/restraints/handcuffs, /obj/item/reagent_containers/spray/pepper, -/turf/open/floor/plasteel/airless/dark, +/turf/open/floor/plasteel/dark, /area/ruin/space/has_grav/gasthelizard) "z" = ( /obj/machinery/atmospherics/components/unary/portables_connector/visible{ @@ -230,14 +230,14 @@ /area/ruin/space/has_grav/gasthelizard) "C" = ( /obj/machinery/gibber, -/turf/open/floor/plasteel/airless/dark, +/turf/open/floor/plasteel/dark, /area/ruin/space/has_grav/gasthelizard) "D" = ( /obj/structure/table/reinforced, /obj/item/clothing/suit/straight_jacket, /obj/item/reagent_containers/syringe/lethal, /obj/item/reagent_containers/syringe/lethal/choral, -/turf/open/floor/plasteel/airless/dark, +/turf/open/floor/plasteel/dark, /area/ruin/space/has_grav/gasthelizard) "E" = ( /obj/machinery/atmospherics/components/unary/portables_connector/visible{ @@ -258,7 +258,7 @@ /area/ruin/space/has_grav/gasthelizard) "H" = ( /obj/machinery/door/airlock/security, -/turf/open/floor/plasteel/airless/dark, +/turf/open/floor/plasteel/dark, /area/ruin/space/has_grav/gasthelizard) "I" = ( /obj/item/reagent_containers/glass/bottle/morphine{ @@ -282,7 +282,7 @@ pixel_y = 6 }, /obj/structure/table/reinforced, -/turf/open/floor/plasteel/airless/dark, +/turf/open/floor/plasteel/dark, /area/ruin/space/has_grav/gasthelizard) "J" = ( /obj/structure/rack, @@ -328,12 +328,12 @@ /obj/item/cautery, /obj/item/circular_saw, /obj/machinery/light, -/turf/open/floor/plasteel/airless/dark, +/turf/open/floor/plasteel/dark, /area/ruin/space/has_grav/gasthelizard) "Q" = ( /obj/structure/table/optable, /obj/effect/decal/cleanable/blood/old, -/turf/open/floor/plasteel/airless/dark, +/turf/open/floor/plasteel/dark, /area/ruin/space/has_grav/gasthelizard) "R" = ( /obj/structure/table/reinforced, @@ -342,7 +342,7 @@ /obj/item/reagent_containers/glass/bottle/mutagen, /obj/item/reagent_containers/glass/bottle/mutagen, /obj/item/razor, -/turf/open/floor/plasteel/airless/dark, +/turf/open/floor/plasteel/dark, /area/ruin/space/has_grav/gasthelizard) "S" = ( /obj/machinery/suit_storage_unit/security, diff --git a/_maps/map_files/BoxStation/BoxStation.dmm b/_maps/map_files/BoxStation/BoxStation.dmm index 980e23188a..9c944ee1b7 100644 --- a/_maps/map_files/BoxStation/BoxStation.dmm +++ b/_maps/map_files/BoxStation/BoxStation.dmm @@ -41,6 +41,21 @@ }, /turf/open/floor/plasteel, /area/crew_quarters/bar) +"aad" = ( +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden, +/obj/effect/turf_decal/tile/red{ + dir = 1 + }, +/obj/effect/turf_decal/tile/red{ + dir = 8 + }, +/obj/structure/table, +/obj/item/restraints/handcuffs, +/turf/open/floor/plasteel, +/area/security/prison) "aae" = ( /obj/effect/landmark/carpspawn, /turf/open/space, @@ -577,6 +592,22 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/closed/wall/r_wall, /area/security/execution/transfer) +"abz" = ( +/obj/machinery/atmospherics/pipe/manifold/supply/hidden, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/turf_decal/tile/red{ + dir = 1 + }, +/obj/effect/turf_decal/tile/red{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/open/floor/plasteel, +/area/security/prison) "abA" = ( /obj/machinery/light, /obj/machinery/atmospherics/components/unary/vent_scrubber/on{ @@ -1849,16 +1880,16 @@ /turf/open/floor/plasteel/dark, /area/security/execution/transfer) "aef" = ( -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/supply/hidden, /obj/effect/turf_decal/tile/red{ dir = 1 }, +/obj/effect/turf_decal/tile/red, /obj/effect/turf_decal/tile/red{ dir = 8 }, +/obj/structure/cable{ + icon_state = "1-2" + }, /turf/open/floor/plasteel, /area/security/prison) "aeg" = ( @@ -2118,6 +2149,31 @@ }, /turf/open/floor/plating, /area/maintenance/fore/secondary) +"aeD" = ( +/obj/machinery/door/airlock/security{ + name = "Firing Range"; + req_access_txt = "2" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/open/floor/plasteel, +/area/security/prison) +"aeE" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 9 + }, +/obj/machinery/light/small{ + dir = 8 + }, +/turf/open/floor/plating, +/area/security/prison) +"aeF" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/turf/open/floor/plating, +/area/security/prison) "aeG" = ( /obj/structure/cable, /obj/machinery/power/solar{ @@ -2193,17 +2249,13 @@ /turf/open/floor/plasteel/dark, /area/security/execution/transfer) "aeM" = ( -/obj/machinery/atmospherics/pipe/manifold/supply/hidden, -/obj/structure/cable{ - icon_state = "4-8" +/obj/effect/turf_decal/stripes/line{ + dir = 5 }, -/obj/effect/turf_decal/tile/red{ - dir = 1 +/obj/structure/window/reinforced{ + dir = 4 }, -/obj/effect/turf_decal/tile/red{ - dir = 8 - }, -/turf/open/floor/plasteel, +/turf/open/floor/plating, /area/security/prison) "aeN" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden{ @@ -2494,6 +2546,10 @@ }, /turf/open/floor/plasteel, /area/security/main) +"afn" = ( +/obj/structure/table, +/turf/open/floor/plasteel/showroomfloor, +/area/security/warden) "afo" = ( /obj/machinery/door/airlock/external{ name = "Escape Pod Three" @@ -2514,6 +2570,20 @@ }, /turf/open/space/basic, /area/space) +"afq" = ( +/obj/machinery/atmospherics/components/unary/vent_scrubber/on, +/turf/open/floor/plasteel, +/area/security/prison) +"afr" = ( +/obj/effect/spawner/structure/window/reinforced, +/turf/open/floor/plating, +/area/security/prison) +"afs" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/turf/open/floor/plating, +/area/security/prison) "aft" = ( /obj/machinery/atmospherics/pipe/simple/general/visible{ dir = 5 @@ -2570,16 +2640,16 @@ /turf/open/floor/plasteel/dark, /area/security/execution/transfer) "afz" = ( -/obj/structure/table, -/obj/item/restraints/handcuffs, -/obj/effect/turf_decal/tile/red{ - dir = 1 +/obj/effect/turf_decal/stripes/line{ + dir = 4 }, -/obj/effect/turf_decal/tile/red, -/obj/effect/turf_decal/tile/red{ - dir = 8 +/obj/machinery/door/window/westleft{ + base_state = "right"; + dir = 4; + icon_state = "right"; + name = "Shooting Range" }, -/turf/open/floor/plasteel, +/turf/open/floor/plating, /area/security/prison) "afA" = ( /turf/closed/wall/r_wall, @@ -2823,6 +2893,16 @@ /obj/machinery/atmospherics/pipe/manifold4w/general/visible, /turf/open/floor/plasteel, /area/engine/atmos) +"age" = ( +/obj/machinery/door/window/southleft{ + name = "Target Storage" + }, +/obj/item/target/clown, +/obj/item/target/clown, +/obj/item/target, +/obj/item/target, +/turf/open/floor/plating, +/area/security/prison) "agf" = ( /obj/structure/table, /obj/item/stack/sheet/metal, @@ -2924,7 +3004,7 @@ /turf/open/floor/plasteel/showroomfloor, /area/security/warden) "agp" = ( -/obj/machinery/computer/prisoner, +/obj/machinery/computer/prisoner/management, /turf/open/floor/plasteel/showroomfloor, /area/security/warden) "agq" = ( @@ -2976,6 +3056,16 @@ }, /turf/open/floor/plasteel/showroomfloor, /area/security/warden) +"agv" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, +/turf/open/floor/plasteel, +/area/security/prison) "agw" = ( /obj/structure/table, /obj/machinery/syndicatebomb/training, @@ -3100,10 +3190,13 @@ /turf/open/floor/plasteel, /area/security/main) "agH" = ( -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 4 +/obj/machinery/door/window/southright{ + name = "Target Storage" }, -/turf/open/floor/plasteel/dark, +/obj/item/target/alien, +/obj/item/target/alien, +/obj/item/target/syndicate, +/turf/open/floor/plating, /area/security/prison) "agI" = ( /obj/machinery/airalarm{ @@ -3474,6 +3567,15 @@ }, /turf/open/floor/plasteel/showroomfloor, /area/security/warden) +"ahw" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 10 + }, +/obj/machinery/light/small{ + dir = 8 + }, +/turf/open/floor/plating, +/area/security/prison) "ahx" = ( /obj/structure/cable{ icon_state = "4-8" @@ -4489,7 +4591,7 @@ /turf/open/space, /area/solar/port/fore) "ajr" = ( -/obj/machinery/computer/gulag_teleporter_computer, +/obj/machinery/computer/prisoner/gulag_teleporter_computer, /turf/open/floor/plasteel, /area/security/processing) "ajs" = ( @@ -4497,26 +4599,18 @@ /turf/open/floor/plasteel, /area/security/processing) "ajt" = ( -/obj/structure/sign/warning/securearea{ - pixel_x = 32 - }, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ - dir = 4 - }, -/obj/structure/table, -/obj/item/storage/box/prisoner, -/obj/machinery/camera{ - c_tag = "Labor Shuttle Dock North" - }, -/turf/open/floor/plasteel, -/area/security/processing) +/obj/effect/turf_decal/stripes/line, +/turf/open/floor/plating, +/area/security/prison) "aju" = ( -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ +/obj/effect/turf_decal/stripes/line{ dir = 6 }, -/obj/machinery/computer/security/labor, -/turf/open/floor/plasteel, -/area/security/processing) +/obj/structure/window/reinforced{ + dir = 4 + }, +/turf/open/floor/plating, +/area/security/prison) "ajv" = ( /obj/machinery/light{ dir = 8 @@ -4830,6 +4924,29 @@ /obj/effect/mapping_helpers/airlock/cyclelink_helper, /turf/open/floor/plating, /area/maintenance/solars/port/fore) +"ajX" = ( +/obj/structure/table, +/obj/structure/cable{ + icon_state = "0-2" + }, +/obj/effect/turf_decal/tile/red{ + dir = 1 + }, +/obj/effect/turf_decal/tile/red{ + dir = 8 + }, +/obj/machinery/recharger, +/obj/item/gun/energy/laser/practice, +/obj/item/gun/energy/laser/practice, +/turf/open/floor/plasteel, +/area/security/prison) +"ajY" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, +/turf/open/floor/plasteel, +/area/security/prison) "ajZ" = ( /obj/effect/spawner/structure/window/reinforced, /obj/structure/sign/warning/vacuum/external{ @@ -4854,20 +4971,18 @@ /area/security/processing) "akc" = ( /obj/structure/cable{ - icon_state = "4-8" + icon_state = "1-2" }, -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 6 +/obj/machinery/airalarm{ + dir = 8; + pixel_x = 24 }, /turf/open/floor/plasteel, -/area/security/processing) +/area/security/prison) "akd" = ( -/obj/structure/cable{ - icon_state = "2-4" - }, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, -/turf/open/floor/plasteel, -/area/security/processing) +/obj/structure/lattice, +/turf/closed/wall, +/area/security/prison) "ake" = ( /obj/structure/cable{ icon_state = "4-8" @@ -5136,6 +5251,44 @@ }, /turf/open/floor/plating, /area/maintenance/solars/port/fore) +"akC" = ( +/obj/machinery/door/airlock/security{ + name = "Labor Shuttle"; + req_access_txt = "2" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, +/turf/open/floor/plasteel, +/area/security/processing) +"akD" = ( +/obj/effect/spawner/structure/window/reinforced, +/obj/machinery/atmospherics/pipe/simple/supply/hidden, +/turf/open/floor/plating, +/area/security/prison) +"akE" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{ + dir = 8 + }, +/turf/open/floor/plasteel, +/area/security/processing) +"akF" = ( +/obj/structure/sign/warning/securearea{ + pixel_x = 32 + }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 + }, +/obj/machinery/camera{ + c_tag = "Labor Shuttle Dock North" + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden, +/turf/open/floor/plasteel, +/area/security/processing) "akG" = ( /obj/structure/sign/warning/vacuum/external{ pixel_y = 32 @@ -5156,11 +5309,12 @@ /turf/open/floor/plasteel, /area/security/processing) "akJ" = ( -/obj/machinery/light_switch{ - pixel_x = 27 +/obj/structure/cable{ + icon_state = "2-4" }, -/obj/machinery/atmospherics/pipe/manifold/supply/hidden{ - dir = 4 +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, +/obj/structure/cable{ + icon_state = "1-2" }, /turf/open/floor/plasteel, /area/security/processing) @@ -5445,12 +5599,42 @@ /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/maintenance/port/fore) +"alj" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/supply/hidden{ + dir = 8 + }, +/turf/open/floor/plasteel, +/area/security/processing) "alk" = ( /obj/machinery/atmospherics/pipe/manifold/scrubbers/visible{ dir = 1 }, /turf/open/floor/plasteel, /area/engine/atmos) +"all" = ( +/obj/machinery/light_switch{ + pixel_x = 27 + }, +/obj/machinery/atmospherics/pipe/manifold/supply/hidden{ + dir = 4 + }, +/obj/machinery/computer/security/labor, +/turf/open/floor/plasteel, +/area/security/processing) +"alm" = ( +/obj/machinery/airalarm{ + dir = 8; + pixel_x = 24 + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden, +/obj/structure/chair{ + dir = 1 + }, +/turf/open/floor/plasteel, +/area/security/processing) "aln" = ( /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 4 @@ -5462,6 +5646,12 @@ }, /turf/open/floor/plating, /area/security/processing) +"alo" = ( +/obj/machinery/atmospherics/pipe/simple/supply/hidden, +/obj/structure/table, +/obj/item/storage/box/prisoner, +/turf/open/floor/plasteel, +/area/security/processing) "alp" = ( /turf/open/floor/plating, /area/security/processing) @@ -5469,13 +5659,10 @@ /turf/open/floor/plasteel, /area/security/processing) "alr" = ( -/obj/machinery/airalarm{ - dir = 8; - pixel_x = 24 - }, -/obj/machinery/atmospherics/pipe/simple/supply/hidden, -/turf/open/floor/plasteel, -/area/security/processing) +/obj/structure/target_stake, +/obj/item/target/syndicate, +/turf/open/floor/plating, +/area/security/prison) "als" = ( /obj/structure/cable{ icon_state = "1-2" @@ -5527,6 +5714,18 @@ }, /turf/open/floor/plasteel, /area/security/brig) +"alx" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/effect/turf_decal/tile/red{ + dir = 1 + }, +/obj/effect/turf_decal/tile/red{ + dir = 8 + }, +/turf/open/floor/plasteel, +/area/security/prison) "aly" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on{ dir = 1 @@ -5681,6 +5880,33 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/open/floor/plating, /area/maintenance/fore/secondary) +"alM" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/power/apc{ + areastring = "/area/security/main"; + dir = 4; + name = "Firing Range APC"; + pixel_x = 24 + }, +/turf/open/floor/plasteel, +/area/security/prison) +"alN" = ( +/obj/machinery/camera{ + c_tag = "Dormitory Toilets"; + dir = 1 + }, +/obj/structure/table, +/obj/structure/bedsheetbin/towel, +/turf/open/floor/plasteel/freezer, +/area/crew_quarters/toilet) "alO" = ( /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, @@ -5736,6 +5962,44 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/visible, /turf/open/floor/plasteel, /area/engine/atmos) +"alY" = ( +/obj/effect/turf_decal/tile/red{ + dir = 1 + }, +/obj/effect/turf_decal/tile/red{ + dir = 8 + }, +/obj/machinery/camera{ + c_tag = "Firing Range"; + dir = 1 + }, +/turf/open/floor/plasteel, +/area/security/prison) +"alZ" = ( +/obj/structure/table, +/obj/machinery/atmospherics/components/unary/vent_pump/on, +/obj/item/clothing/glasses/sunglasses{ + pixel_x = 3; + pixel_y = 3 + }, +/obj/item/clothing/glasses/sunglasses{ + pixel_x = 3; + pixel_y = 3 + }, +/obj/item/clothing/ears/earmuffs{ + pixel_x = -3; + pixel_y = -2 + }, +/obj/item/clothing/ears/earmuffs{ + pixel_x = -3; + pixel_y = -2 + }, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/turf/open/floor/plasteel, +/area/security/prison) "ama" = ( /mob/living/simple_animal/sloth/paperwork, /turf/open/floor/plasteel, @@ -5755,10 +6019,6 @@ }, /turf/open/floor/plasteel, /area/security/processing) -"amd" = ( -/obj/machinery/atmospherics/pipe/simple/supply/hidden, -/turf/open/floor/plasteel, -/area/security/processing) "ame" = ( /obj/structure/cable{ icon_state = "1-2" @@ -6031,26 +6291,6 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/open/floor/plasteel, /area/security/processing) -"amN" = ( -/obj/structure/table, -/obj/item/clothing/glasses/sunglasses{ - pixel_x = 3; - pixel_y = 3 - }, -/obj/item/clothing/glasses/sunglasses{ - pixel_x = 3; - pixel_y = 3 - }, -/obj/item/clothing/ears/earmuffs{ - pixel_x = -3; - pixel_y = -2 - }, -/obj/item/clothing/ears/earmuffs{ - pixel_x = -3; - pixel_y = -2 - }, -/turf/open/floor/plasteel/showroomfloor, -/area/security/warden) "amQ" = ( /obj/structure/cable{ icon_state = "0-4" @@ -9240,7 +9480,7 @@ }, /obj/machinery/atmospherics/pipe/simple/supply/hidden, /turf/open/floor/plating, -/area/lawoffice) +/area/maintenance/fore) "avj" = ( /obj/machinery/firealarm{ dir = 8; @@ -15437,13 +15677,6 @@ }, /turf/open/floor/plasteel, /area/hallway/primary/central) -"aJz" = ( -/obj/machinery/camera{ - c_tag = "Dormitory Toilets"; - dir = 1 - }, -/turf/open/floor/plasteel/freezer, -/area/crew_quarters/toilet) "aJA" = ( /obj/machinery/door/airlock/maintenance{ name = "Kitchen Maintenance"; @@ -17686,6 +17919,9 @@ /obj/effect/turf_decal/stripes/line{ dir = 9 }, +/obj/item/twohanded/required/kirbyplants{ + icon_state = "plant-20" + }, /turf/open/floor/plasteel, /area/hallway/secondary/entry) "aPu" = ( @@ -19371,7 +19607,7 @@ /turf/closed/wall, /area/bridge) "aTR" = ( -/obj/machinery/computer/prisoner, +/obj/machinery/computer/prisoner/management, /obj/effect/turf_decal/tile/red{ dir = 1 }, @@ -20964,6 +21200,11 @@ /obj/effect/turf_decal/stripes/corner{ dir = 2 }, +/obj/item/twohanded/required/kirbyplants{ + icon_state = "plant-21"; + pixel_x = -3; + pixel_y = 3 + }, /turf/open/floor/plasteel, /area/crew_quarters/locker) "aXu" = ( @@ -21064,6 +21305,9 @@ /obj/effect/turf_decal/stripes/line{ dir = 4 }, +/obj/item/twohanded/required/kirbyplants{ + icon_state = "plant-05" + }, /turf/open/floor/plasteel, /area/hallway/secondary/exit) "aXI" = ( @@ -21702,6 +21946,9 @@ dir = 1; pixel_y = -24 }, +/obj/item/twohanded/required/kirbyplants{ + icon_state = "plant-08" + }, /turf/open/floor/wood, /area/library) "aZe" = ( @@ -24326,6 +24573,9 @@ /obj/effect/turf_decal/tile/purple{ dir = 8 }, +/obj/item/twohanded/required/kirbyplants{ + icon_state = "plant-13" + }, /turf/open/floor/plasteel, /area/hallway/primary/starboard) "bfX" = ( @@ -24372,6 +24622,9 @@ /obj/effect/turf_decal/tile/purple{ dir = 8 }, +/obj/item/twohanded/required/kirbyplants{ + icon_state = "plant-10" + }, /turf/open/floor/plasteel, /area/hallway/primary/starboard) "bgc" = ( @@ -27040,11 +27293,6 @@ }, /turf/open/floor/plasteel, /area/quartermaster/sorting) -"bml" = ( -/obj/effect/spawner/structure/window/reinforced, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/plasteel, -/area/quartermaster/office) "bmm" = ( /obj/structure/cable{ icon_state = "1-2" @@ -27874,6 +28122,7 @@ /obj/effect/turf_decal/tile/blue{ dir = 4 }, +/obj/effect/mapping_helpers/airlock/unres, /turf/open/floor/plasteel/white, /area/medical/medbay/central) "bof" = ( @@ -27897,6 +28146,7 @@ /obj/effect/turf_decal/tile/blue{ dir = 4 }, +/obj/effect/mapping_helpers/airlock/unres, /turf/open/floor/plasteel/white, /area/medical/medbay/central) "boi" = ( @@ -29805,6 +30055,7 @@ name = "Genetics"; req_access_txt = "5; 68" }, +/obj/effect/mapping_helpers/airlock/unres, /turf/open/floor/plasteel/white, /area/medical/genetics) "bsv" = ( @@ -30089,6 +30340,9 @@ /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 4 }, +/obj/item/twohanded/required/kirbyplants{ + icon_state = "plant-16" + }, /turf/open/floor/plasteel/white, /area/science/research) "bti" = ( @@ -32307,19 +32561,16 @@ /turf/open/floor/plasteel/cafeteria, /area/crew_quarters/heads/hor) "byc" = ( -/obj/structure/table, -/obj/item/paper_bin{ - pixel_x = -3; - pixel_y = 7 - }, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 4 }, -/obj/item/stamp/qm, /obj/effect/turf_decal/tile/brown, /obj/effect/turf_decal/tile/brown{ dir = 8 }, +/obj/machinery/computer/card/minor/qm{ + dir = 1 + }, /turf/open/floor/plasteel, /area/quartermaster/qm) "byd" = ( @@ -32359,6 +32610,11 @@ /obj/effect/turf_decal/tile/brown{ dir = 8 }, +/obj/item/stamp/qm, +/obj/item/paper_bin{ + pixel_x = -3; + pixel_y = 7 + }, /turf/open/floor/plasteel, /area/quartermaster/qm) "byh" = ( @@ -39479,6 +39735,7 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 4 }, +/obj/item/twohanded/required/kirbyplants, /turf/open/floor/plasteel/white/side{ dir = 1 }, @@ -56869,6 +57126,18 @@ }, /turf/open/floor/plating, /area/maintenance/port) +"hwu" = ( +/obj/item/twohanded/required/kirbyplants{ + icon_state = "plant-24" + }, +/turf/open/floor/plasteel, +/area/security/prison) +"hEm" = ( +/obj/item/twohanded/required/kirbyplants{ + icon_state = "plant-22" + }, +/turf/open/floor/plasteel/white, +/area/medical/medbay/central) "hRa" = ( /obj/structure/table/reinforced, /obj/machinery/light{ @@ -57155,6 +57424,10 @@ /obj/machinery/vending/wardrobe/bar_wardrobe, /turf/open/floor/wood, /area/crew_quarters/bar) +"moD" = ( +/obj/effect/landmark/barthpot, +/turf/open/floor/wood, +/area/library) "mpI" = ( /obj/structure/table/wood, /turf/open/floor/wood{ @@ -57328,6 +57601,15 @@ }, /turf/open/floor/plasteel, /area/science/circuit) +"qoW" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 10 + }, +/obj/item/twohanded/required/kirbyplants{ + icon_state = "plant-18" + }, +/turf/open/floor/plasteel, +/area/hallway/secondary/entry) "quT" = ( /obj/structure/lattice, /obj/structure/grille/broken, @@ -57339,6 +57621,12 @@ }, /turf/open/floor/carpet, /area/crew_quarters/cryopod) +"qQP" = ( +/obj/item/twohanded/required/kirbyplants{ + icon_state = "plant-14" + }, +/turf/open/floor/plasteel, +/area/hallway/primary/port) "rcD" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 4 @@ -57349,6 +57637,15 @@ /obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden, /turf/open/floor/plasteel, /area/maintenance/disposal/incinerator) +"rjA" = ( +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 + }, +/obj/item/twohanded/required/kirbyplants{ + icon_state = "plant-04" + }, +/turf/open/floor/plasteel/white, +/area/medical/medbay/central) "rmX" = ( /obj/structure/table, /obj/item/reagent_containers/food/drinks/beer, @@ -57492,6 +57789,12 @@ icon_state = "wood-broken5" }, /area/maintenance/bar) +"tlO" = ( +/obj/item/twohanded/required/kirbyplants{ + icon_state = "applebush" + }, +/turf/open/floor/plasteel, +/area/hallway/primary/port) "tqg" = ( /obj/machinery/cryopod{ dir = 4 @@ -57648,6 +57951,20 @@ }, /turf/open/floor/plating, /area/maintenance/starboard/aft) +"uZN" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/effect/turf_decal/tile/blue{ + dir = 4 + }, +/obj/item/twohanded/required/kirbyplants{ + icon_state = "plant-03" + }, +/turf/open/floor/plasteel/white/corner{ + dir = 1 + }, +/area/hallway/secondary/entry) "vbD" = ( /obj/machinery/door/firedoor, /obj/machinery/door/airlock/command/glass{ @@ -57822,6 +58139,20 @@ }, /turf/closed/wall/r_wall, /area/maintenance/disposal/incinerator) +"xFY" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/effect/turf_decal/tile/blue{ + dir = 4 + }, +/obj/item/twohanded/required/kirbyplants{ + icon_state = "plant-06" + }, +/turf/open/floor/plasteel/white/corner{ + dir = 1 + }, +/area/hallway/secondary/entry) "xIa" = ( /obj/structure/table, /obj/effect/spawner/lootdrop/grille_or_trash, @@ -67194,7 +67525,7 @@ apN apN apN apJ -awY +xFY ayk awW aAD @@ -67218,7 +67549,7 @@ aaa aaa aaa arB -awY +uZN ayk awW aAD @@ -69790,7 +70121,7 @@ awW arB awZ aym -azB +qoW awW aaf aaa @@ -79544,7 +79875,7 @@ aKt aLN aMS aOi -aLE +tlO aPK aSl aTH @@ -80535,12 +80866,12 @@ adB aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa +acd +acd +acd +afr +acd +acd aaa aaa aaa @@ -80793,11 +81124,11 @@ abc abc afu abc -aaa -aaa -aaa -aaa -aaa +age +aeE +afs +ahw +acd aaa aaa aaa @@ -80852,7 +81183,7 @@ boS bfm bNK bkN -bml +bfm bwe bwe bwd @@ -81050,11 +81381,11 @@ aea aeH aft abc -aaa -aaa -aaa -aaa -aaa +agH +aeF +alr +ajt +afr aaa aaa aiU @@ -81308,10 +81639,10 @@ aeJ afw abc abc -aaf -aaa -aaf -aaf +aeF +aay +ajt +akd aaf aaf aiU @@ -81565,9 +81896,9 @@ aeI afv agf abc -aaf -aaa -aaa +aeF +aay +ajt aiT aiT aiV @@ -81600,7 +81931,7 @@ aKA aLN aMS aOz -aLE +qQP aPQ aSa aSr @@ -81822,9 +82153,9 @@ aeL afy agh abc -aaf -aaa -aaf +aeM +afz +aju aiT ajs akb @@ -82079,9 +82410,9 @@ aeK afx agg abc -aaf -aaa -aaa +ajX +alx +alY aiU ajr aka @@ -82335,13 +82666,13 @@ aeg aeN afA afA -afA -aaf -aaa -aaa -aiU -aju -akd +abc +afq +agv +ajY +akC +akE +akJ akK als ame @@ -82588,20 +82919,20 @@ acd acC ada adF +aad +abz aef -aeM -afz -aai -aai -aai -aai -aai -aai -ajt +aeD +aav akc -akJ -alr -amd +alM +alZ +akD +akF +alj +all +alm +alo amL anu alq @@ -82848,11 +83179,11 @@ adH aei aeO afJ -acd -agL -agK -agK -aiB +aai +aai +aai +aai +aai aai ajw akf @@ -83106,10 +83437,10 @@ aeh aeO afI agl -agH +agL ags ags -aho +aiB acd ajv ake @@ -85152,7 +85483,7 @@ aaG aaK aaP aaX -aat +hwu aat acd acD @@ -87731,7 +88062,7 @@ bkA acF aes avB -amN +afn agt awN aHp @@ -89819,7 +90150,7 @@ aDL aFf aGk aHU -aJz +alN aAh aLQ aJq @@ -94720,7 +95051,7 @@ aYV aYV bet bfH -bhh +hEm bhh bhg bln @@ -97056,7 +97387,7 @@ bCR bqQ bGX bCR -bqQ +rjA bRN bIK bPq @@ -102164,7 +102495,7 @@ aQq aRP aIt aIt -aIt +moD aWd aXV aIt diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index fd7c0a3c00..b0f513e41d 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -124,6 +124,36 @@ }, /turf/open/floor/plating, /area/crew_quarters/abandoned_gambling_den) +"aaq" = ( +/obj/effect/decal/cleanable/dirt, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 + }, +/obj/machinery/airalarm{ + dir = 1; + pixel_y = -22 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/structure/table, +/obj/structure/bedsheetbin/towel, +/turf/open/floor/plasteel, +/area/crew_quarters/toilet/restrooms) +"aar" = ( +/obj/structure/table, +/obj/machinery/light{ + dir = 8 + }, +/obj/effect/turf_decal/tile/blue{ + dir = 8 + }, +/obj/structure/bedsheetbin/color, +/turf/open/floor/plasteel/white/corner{ + dir = 1 + }, +/area/crew_quarters/dorms) "aas" = ( /obj/docking_port/stationary/random{ id = "pod_lavaland1"; @@ -1010,10 +1040,6 @@ }, /turf/open/floor/plasteel, /area/hallway/secondary/entry) -"aez" = ( -/obj/machinery/keycard_auth, -/turf/closed/wall, -/area/quartermaster/qm) "aeB" = ( /obj/machinery/status_display, /turf/closed/wall, @@ -1075,6 +1101,10 @@ "aeF" = ( /turf/open/floor/plating, /area/construction/mining/aux_base) +"aeH" = ( +/obj/structure/lattice, +/turf/open/space/basic, +/area/space/nearstation) "aeR" = ( /obj/structure/closet/emcloset, /obj/effect/decal/cleanable/dirt, @@ -4503,7 +4533,7 @@ /turf/open/floor/plasteel, /area/security/checkpoint) "anx" = ( -/obj/machinery/computer/prisoner{ +/obj/machinery/computer/prisoner/management{ dir = 8 }, /obj/machinery/status_display{ @@ -9270,7 +9300,6 @@ /obj/item/restraints/legcuffs/beartrap, /obj/item/restraints/legcuffs/beartrap, /obj/item/restraints/legcuffs/beartrap, -/obj/effect/decal/cleanable/cobweb, /obj/effect/turf_decal/bot, /obj/effect/turf_decal/tile/neutral{ dir = 1 @@ -9288,7 +9317,6 @@ /obj/machinery/status_display{ pixel_y = 32 }, -/obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/bot, /obj/machinery/vending/wardrobe/jani_wardrobe, /obj/effect/turf_decal/tile/neutral{ @@ -9336,7 +9364,6 @@ name = "Custodial RC"; pixel_y = 32 }, -/obj/effect/decal/cleanable/dirt, /obj/machinery/camera{ c_tag = "Custodial Closet"; dir = 2; @@ -9855,22 +9882,35 @@ /turf/open/floor/plasteel, /area/janitor) "awC" = ( -/obj/effect/decal/cleanable/dirt, /obj/effect/landmark/start/janitor, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 4 }, -/turf/open/floor/plating, +/obj/effect/turf_decal/tile/purple{ + dir = 4 + }, +/obj/effect/turf_decal/tile/purple{ + dir = 8 + }, +/obj/effect/turf_decal/tile/purple{ + dir = 1 + }, +/turf/open/floor/plasteel/white, /area/janitor) "awD" = ( -/obj/effect/decal/cleanable/dirt, /obj/structure/cable/white{ icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 4 }, -/turf/open/floor/plating, +/obj/effect/turf_decal/tile/green{ + dir = 4 + }, +/obj/effect/turf_decal/tile/green{ + dir = 1 + }, +/turf/open/floor/plasteel/white, /area/janitor) "awE" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ @@ -9885,7 +9925,6 @@ /turf/open/floor/plasteel/white, /area/janitor) "awF" = ( -/obj/effect/decal/cleanable/dirt, /obj/effect/landmark/start/janitor, /obj/machinery/atmospherics/components/unary/vent_scrubber/on{ dir = 8 @@ -9905,7 +9944,6 @@ pixel_x = 32 }, /obj/item/reagent_containers/glass/bucket, -/obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/bot, /obj/effect/turf_decal/tile/neutral{ dir = 1 @@ -10567,8 +10605,6 @@ }, /obj/item/storage/box/lights/mixed, /obj/item/lightreplacer, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /obj/effect/turf_decal/tile/neutral{ dir = 1 @@ -10611,7 +10647,6 @@ /turf/open/floor/plasteel, /area/janitor) "axX" = ( -/obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/bot, /obj/effect/landmark/event_spawn, /obj/effect/turf_decal/tile/neutral{ @@ -10639,11 +10674,21 @@ /area/janitor) "axZ" = ( /obj/structure/janitorialcart, -/obj/effect/decal/cleanable/dirt, /obj/structure/sign/poster/official/work_for_a_future{ pixel_x = 32 }, -/turf/open/floor/plating, +/obj/effect/turf_decal/bot, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/turf/open/floor/plasteel, /area/janitor) "aya" = ( /obj/effect/decal/cleanable/dirt, @@ -11231,7 +11276,6 @@ }, /obj/item/reagent_containers/glass/bucket, /obj/item/reagent_containers/glass/bucket, -/obj/effect/decal/cleanable/dirt, /obj/item/mop, /obj/item/mop, /obj/item/radio/intercom{ @@ -11274,15 +11318,12 @@ /obj/machinery/light_switch{ pixel_y = -26 }, -/obj/effect/decal/cleanable/dirt, /obj/structure/cable/white{ icon_state = "1-8" }, +/obj/effect/turf_decal/tile/green, /obj/effect/turf_decal/tile/green{ - dir = 1 - }, -/obj/effect/turf_decal/tile/green{ - dir = 4 + dir = 8 }, /turf/open/floor/plasteel/white, /area/janitor) @@ -11301,7 +11342,6 @@ /turf/open/floor/plasteel, /area/janitor) "aze" = ( -/obj/effect/decal/cleanable/dirt, /obj/structure/disposalpipe/segment{ dir = 6 }, @@ -11323,7 +11363,6 @@ /obj/structure/extinguisher_cabinet{ pixel_x = 26 }, -/obj/effect/decal/cleanable/dirt, /obj/machinery/light/small, /obj/structure/disposalpipe/trunk{ dir = 8 @@ -11774,11 +11813,15 @@ /area/engine/atmospherics_engine) "aAb" = ( /turf/closed/wall, -/area/hydroponics/garden/abandoned) +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) "aAc" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/closed/wall, -/area/hydroponics/garden/abandoned) +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) "aAd" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/tile/neutral{ @@ -11824,7 +11867,6 @@ /turf/closed/wall, /area/janitor) "aAi" = ( -/obj/effect/decal/cleanable/dirt, /obj/machinery/door/airlock{ name = "Custodial Closet"; req_access_txt = "26" @@ -11881,6 +11923,7 @@ /obj/effect/turf_decal/tile/neutral{ dir = 8 }, +/obj/effect/decal/cleanable/dirt, /turf/open/floor/plasteel, /area/maintenance/port/fore) "aAm" = ( @@ -12358,7 +12401,9 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/delivery, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned) +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) "aBh" = ( /obj/item/twohanded/required/kirbyplants/random, /obj/machinery/light/small{ @@ -12367,27 +12412,27 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/delivery, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned) +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) "aBi" = ( /obj/structure/table, /obj/item/clothing/suit/apron/overalls, /obj/item/cultivator, /obj/effect/turf_decal/bot, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned) +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) "aBj" = ( /obj/machinery/biogenerator, /obj/effect/turf_decal/delivery, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned) +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) "aBk" = ( /obj/structure/table, -/obj/item/seeds/poppy/lily{ - pixel_x = 4; - pixel_y = 4 - }, -/obj/item/seeds/poppy/geranium, -/obj/effect/decal/cleanable/dirt, /obj/item/reagent_containers/food/snacks/grown/wheat, /obj/item/reagent_containers/food/snacks/grown/corn, /obj/item/reagent_containers/food/snacks/grown/apple, @@ -12395,15 +12440,23 @@ /obj/machinery/airalarm{ pixel_y = 23 }, +/obj/item/seeds/poppy/lily{ + pixel_x = 4; + pixel_y = 4 + }, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned) +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) "aBl" = ( /obj/machinery/hydroponics/soil, /obj/item/seeds/tea, /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/delivery, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned) +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) "aBm" = ( /obj/item/twohanded/required/kirbyplants/random, /obj/machinery/status_display{ @@ -12411,18 +12464,21 @@ }, /obj/effect/turf_decal/delivery, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned) +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) "aBn" = ( /obj/structure/table, /obj/item/stack/packageWrap, -/obj/effect/decal/cleanable/dirt, /obj/item/hand_labeler, /obj/item/reagent_containers/food/snacks/grown/tea, /obj/item/reagent_containers/food/snacks/grown/grapes, /obj/item/reagent_containers/food/snacks/grown/cherries, /obj/effect/turf_decal/bot, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned) +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) "aBo" = ( /obj/item/twohanded/required/kirbyplants/random, /obj/machinery/light/small{ @@ -12432,14 +12488,18 @@ /obj/effect/turf_decal/delivery, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned) +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) "aBp" = ( /obj/machinery/hydroponics/soil, /obj/item/seeds/poppy, /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/delivery, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned) +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) "aBq" = ( /obj/structure/cable/white{ icon_state = "2-4" @@ -12537,7 +12597,6 @@ /turf/open/floor/plating, /area/maintenance/port/fore) "aBx" = ( -/obj/effect/decal/cleanable/dirt, /obj/structure/cable/white{ icon_state = "4-8" }, @@ -12557,7 +12616,6 @@ /turf/open/floor/plasteel, /area/maintenance/port/fore) "aBy" = ( -/obj/effect/decal/cleanable/dirt, /obj/structure/cable/white{ icon_state = "1-8" }, @@ -12602,7 +12660,6 @@ /turf/open/floor/plasteel, /area/maintenance/port/fore) "aBB" = ( -/obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 4 }, @@ -12624,16 +12681,6 @@ /obj/structure/disposalpipe/segment{ dir = 4 }, -/turf/open/floor/plating, -/area/maintenance/port/fore) -"aBD" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ - dir = 4 - }, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, /obj/effect/turf_decal/tile/neutral{ dir = 1 }, @@ -13032,26 +13079,34 @@ /turf/closed/wall/r_wall, /area/engine/atmospherics_engine) "aCv" = ( -/obj/effect/decal/cleanable/dirt, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned) +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) "aCw" = ( +/obj/effect/turf_decal/delivery, +/obj/machinery/hydroponics/soil, +/obj/item/seeds/watermelon, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned) +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) "aCx" = ( -/obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/components/unary/vent_scrubber/on{ dir = 4 }, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned) +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) "aCy" = ( -/obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{ dir = 4 }, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned) +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) "aCz" = ( /obj/structure/cable/white{ icon_state = "1-2" @@ -13080,13 +13135,19 @@ /turf/closed/wall, /area/maintenance/port/fore) "aCD" = ( -/obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 4 }, /obj/structure/disposalpipe/segment, -/turf/open/floor/plating, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/turf/open/floor/plasteel, /area/maintenance/port/fore) "aCE" = ( /obj/structure/cable/white{ @@ -13101,7 +13162,6 @@ /turf/open/floor/plasteel, /area/maintenance/port/fore) "aCF" = ( -/obj/effect/decal/cleanable/dirt, /obj/structure/cable/white{ icon_state = "4-8" }, @@ -13134,10 +13194,16 @@ icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/manifold/supply/hidden, -/turf/open/floor/plating, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral, +/turf/open/floor/plasteel, /area/maintenance/port/fore) "aCI" = ( -/obj/effect/decal/cleanable/dirt, /obj/structure/cable/white{ icon_state = "4-8" }, @@ -13658,15 +13724,21 @@ }, /obj/effect/turf_decal/bot, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned) +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) "aDy" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned) +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) "aDz" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned) +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) "aDA" = ( /obj/structure/sink{ dir = 4; @@ -13677,7 +13749,9 @@ }, /obj/effect/turf_decal/bot, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned) +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) "aDB" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, @@ -14188,37 +14262,38 @@ /turf/open/space, /area/space/nearstation) "aEB" = ( -/obj/effect/decal/cleanable/dirt, /obj/structure/cable/white{ icon_state = "2-4" }, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned) +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) "aEC" = ( /obj/structure/cable/white{ icon_state = "4-8" }, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned) +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) "aED" = ( -/obj/effect/decal/cleanable/dirt, /obj/structure/cable/white{ icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/supply/hidden, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned) +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) "aEE" = ( /obj/structure/cable/white{ icon_state = "2-8" }, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned) -"aEF" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, -/turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned) +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) "aEG" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/cable/white{ @@ -14854,14 +14929,18 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/delivery, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned) +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) "aFK" = ( /obj/machinery/hydroponics/soil, /obj/item/seeds/harebell, /obj/machinery/light/small, /obj/effect/turf_decal/delivery, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned) +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) "aFL" = ( /obj/structure/table, /obj/item/shovel/spade, @@ -14872,47 +14951,54 @@ pixel_x = -5 }, /obj/item/reagent_containers/syringe, -/obj/effect/decal/cleanable/dirt, /obj/structure/cable/white, /obj/machinery/power/apc{ - dir = 2; - name = "Abandoned Garden APC"; areastring = "/area/hydroponics/garden/abandoned"; + dir = 2; + name = "Maintenance Garden APC"; pixel_y = -26 }, /obj/effect/turf_decal/bot, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned) +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) "aFM" = ( -/obj/machinery/seed_extractor, /obj/machinery/status_display{ pixel_y = -32 }, -/obj/item/reagent_containers/glass/bucket, /obj/effect/turf_decal/delivery, +/obj/machinery/hydroponics/soil, +/obj/item/seeds/poppy/geranium, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned) +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) "aFN" = ( /obj/structure/table, /obj/item/plant_analyzer, /obj/item/hatchet, -/obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/bot, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned) +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) "aFO" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden, /obj/effect/turf_decal/delivery, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned) +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) "aFP" = ( -/obj/effect/decal/cleanable/dirt, /obj/structure/cable/white{ icon_state = "1-2" }, /obj/effect/turf_decal/delivery, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned) +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) "aFQ" = ( /obj/structure/table, /obj/item/crowbar, @@ -14920,7 +15006,9 @@ /obj/item/reagent_containers/glass/bucket, /obj/effect/turf_decal/bot, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned) +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) "aFR" = ( /obj/machinery/hydroponics/soil, /obj/item/seeds/tower, @@ -14929,7 +15017,9 @@ /obj/effect/turf_decal/delivery, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned) +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) "aFS" = ( /obj/structure/cable/white{ icon_state = "1-2" @@ -15021,6 +15111,9 @@ location = "Bar" }, /obj/effect/turf_decal/delivery, +/obj/machinery/door/window/eastleft{ + req_access_txt = "25" + }, /turf/open/floor/plasteel, /area/crew_quarters/bar) "aGc" = ( @@ -15922,18 +16015,16 @@ /area/engine/atmospherics_engine) "aHl" = ( /obj/effect/spawner/structure/window/reinforced, -/obj/structure/barricade/wooden, /turf/open/floor/plating, -/area/hydroponics/garden/abandoned) +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) "aHm" = ( /obj/machinery/door/airlock/maintenance_hatch{ name = "Maintenance Hatch"; req_access_txt = "12" }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/pipe/simple/supply/hidden, -/obj/structure/barricade/wooden, /obj/effect/turf_decal/stripes/line{ dir = 2 }, @@ -15941,17 +16032,17 @@ dir = 1 }, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned) +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) "aHn" = ( /obj/machinery/door/airlock/maintenance_hatch{ name = "Maintenance Hatch"; req_access_txt = "12" }, -/obj/effect/decal/cleanable/dirt, /obj/structure/cable/white{ icon_state = "1-2" }, -/obj/structure/barricade/wooden, /obj/effect/turf_decal/stripes/line{ dir = 2 }, @@ -15959,13 +16050,16 @@ dir = 1 }, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned) +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) "aHo" = ( /obj/effect/spawner/structure/window/reinforced, -/obj/structure/barricade/wooden, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/open/floor/plating, -/area/hydroponics/garden/abandoned) +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) "aHp" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/cable/white{ @@ -16794,7 +16888,6 @@ /turf/open/floor/plasteel, /area/maintenance/port/fore) "aII" = ( -/obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 5 }, @@ -16808,7 +16901,8 @@ /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 4 }, -/turf/open/floor/plating, +/obj/effect/turf_decal/delivery, +/turf/open/floor/plasteel, /area/maintenance/port/fore) "aIK" = ( /obj/structure/cable/white{ @@ -16818,10 +16912,18 @@ dir = 4 }, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, -/turf/open/floor/plating, +/obj/machinery/light/small{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/turf/open/floor/plasteel, /area/maintenance/port/fore) "aIL" = ( -/obj/effect/decal/cleanable/dirt, /obj/structure/cable/white{ icon_state = "4-8" }, @@ -17687,10 +17789,16 @@ /area/engine/atmospherics_engine) "aKg" = ( /obj/structure/closet/emcloset, -/turf/open/floor/plating, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral, +/turf/open/floor/plasteel, /area/maintenance/port/fore) "aKh" = ( -/obj/effect/decal/cleanable/dirt, /obj/structure/rack, /obj/effect/spawner/lootdrop/maintenance{ lootcount = 2; @@ -17704,7 +17812,11 @@ /area/maintenance/port/fore) "aKi" = ( /obj/structure/closet, -/turf/open/floor/plating, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral, +/turf/open/floor/plasteel, /area/maintenance/port/fore) "aKj" = ( /obj/effect/decal/cleanable/dirt, @@ -17715,16 +17827,20 @@ /turf/open/floor/plasteel, /area/maintenance/port/fore) "aKk" = ( -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /obj/effect/turf_decal/tile/neutral, /obj/effect/turf_decal/tile/neutral{ dir = 8 }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/open/floor/plasteel, /area/maintenance/port/fore) "aKl" = ( /obj/effect/landmark/event_spawn, /obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral, /obj/effect/turf_decal/tile/neutral{ dir = 8 }, @@ -21299,6 +21415,9 @@ location = "Theatre" }, /obj/effect/turf_decal/delivery, +/obj/machinery/door/window/westleft{ + req_access_txt = "46" + }, /turf/open/floor/plasteel, /area/crew_quarters/theatre) "aQj" = ( @@ -26153,6 +26272,9 @@ dir = 4 }, /obj/effect/turf_decal/delivery, +/obj/machinery/door/window/eastright{ + req_one_access_txt = "48,50" + }, /turf/open/floor/plasteel, /area/quartermaster/office) "aXg" = ( @@ -27548,7 +27670,6 @@ /turf/open/floor/plasteel, /area/quartermaster/qm) "aZh" = ( -/obj/structure/table/reinforced, /obj/machinery/light{ dir = 4 }, @@ -27559,6 +27680,9 @@ /obj/effect/turf_decal/tile/brown{ dir = 8 }, +/obj/machinery/computer/card/minor/qm{ + dir = 8 + }, /turf/open/floor/plasteel, /area/quartermaster/qm) "aZi" = ( @@ -29213,6 +29337,9 @@ location = "Kitchen" }, /obj/effect/turf_decal/delivery, +/obj/machinery/door/window/eastleft{ + req_access_txt = "28" + }, /turf/open/floor/plasteel, /area/crew_quarters/kitchen) "bcd" = ( @@ -30865,6 +30992,9 @@ location = "Hydroponics" }, /obj/effect/turf_decal/delivery, +/obj/machinery/door/window/westleft{ + req_access_txt = "35" + }, /turf/open/floor/plasteel, /area/hallway/secondary/service) "beW" = ( @@ -36055,6 +36185,9 @@ /obj/structure/plasticflaps/opaque, /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/delivery, +/obj/machinery/door/window/northright{ + req_access_txt = "48" + }, /turf/open/floor/plasteel, /area/maintenance/starboard/fore) "bnB" = ( @@ -36400,7 +36533,7 @@ /turf/open/floor/plasteel/grimy, /area/crew_quarters/heads/hos) "boc" = ( -/obj/machinery/computer/prisoner{ +/obj/machinery/computer/prisoner/management{ dir = 8 }, /turf/open/floor/plasteel/grimy, @@ -38706,7 +38839,7 @@ /turf/open/floor/plasteel/grimy, /area/crew_quarters/heads/hos) "brE" = ( -/obj/machinery/computer/prisoner{ +/obj/machinery/computer/prisoner/management{ dir = 8 }, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ @@ -39195,13 +39328,6 @@ name = "Hydroponics Desk"; req_access_txt = "35" }, -/obj/item/seeds/lime{ - pixel_x = 6 - }, -/obj/item/seeds/watermelon, -/obj/item/seeds/grape{ - pixel_x = -6 - }, /obj/item/reagent_containers/food/snacks/grown/wheat, /obj/item/reagent_containers/food/snacks/grown/watermelon, /obj/item/reagent_containers/food/snacks/grown/banana, @@ -39610,7 +39736,7 @@ /turf/open/floor/plasteel/dark, /area/security/execution/transfer) "bth" = ( -/obj/machinery/computer/gulag_teleporter_computer{ +/obj/machinery/computer/prisoner/gulag_teleporter_computer{ dir = 1 }, /obj/structure/disposalpipe/segment{ @@ -41789,6 +41915,9 @@ location = "Atmospherics" }, /obj/effect/turf_decal/delivery, +/obj/machinery/door/window/westleft{ + req_access_txt = "24" + }, /turf/open/floor/plasteel, /area/engine/atmos) "bwH" = ( @@ -42723,7 +42852,7 @@ /turf/open/floor/plasteel/dark, /area/bridge) "byk" = ( -/obj/machinery/computer/prisoner, +/obj/machinery/computer/prisoner/management, /obj/effect/turf_decal/tile/red{ dir = 1 }, @@ -56938,7 +57067,7 @@ /turf/open/floor/plasteel, /area/security/warden) "bTh" = ( -/obj/machinery/computer/prisoner{ +/obj/machinery/computer/prisoner/management{ dir = 8 }, /obj/structure/cable/white{ @@ -71753,6 +71882,9 @@ location = "Security" }, /obj/effect/turf_decal/delivery, +/obj/machinery/door/window/northleft{ + req_access_txt = "63" + }, /turf/open/floor/plasteel, /area/security/range) "cqh" = ( @@ -80743,21 +80875,6 @@ }, /turf/open/floor/plating, /area/crew_quarters/toilet/restrooms) -"cFc" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ - dir = 4 - }, -/obj/machinery/airalarm{ - dir = 1; - pixel_y = -22 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/plasteel, -/area/crew_quarters/toilet/restrooms) "cFd" = ( /obj/machinery/shower{ dir = 8; @@ -82547,6 +82664,9 @@ location = "Engineering" }, /obj/effect/turf_decal/delivery, +/obj/machinery/door/window/northright{ + req_access_txt = "10" + }, /turf/open/floor/plasteel, /area/engine/engineering) "cIr" = ( @@ -84247,19 +84367,6 @@ /obj/item/reagent_containers/dropper, /turf/open/floor/plating, /area/maintenance/starboard/aft) -"cKT" = ( -/obj/structure/table, -/obj/structure/bedsheetbin, -/obj/machinery/light{ - dir = 8 - }, -/obj/effect/turf_decal/tile/blue{ - dir = 8 - }, -/turf/open/floor/plasteel/white/corner{ - dir = 1 - }, -/area/crew_quarters/dorms) "cKU" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /obj/effect/turf_decal/tile/neutral{ @@ -87734,6 +87841,9 @@ location = "Medbay" }, /obj/effect/turf_decal/delivery, +/obj/machinery/door/window/westleft{ + req_access_txt = "5" + }, /turf/open/floor/plasteel, /area/medical/storage) "cRl" = ( @@ -88597,6 +88707,9 @@ /obj/effect/turf_decal/stripes/line{ dir = 4 }, +/obj/effect/mapping_helpers/airlock/unres{ + dir = 4 + }, /turf/open/floor/plasteel, /area/medical/medbay/central) "cSK" = ( @@ -89771,6 +89884,9 @@ /obj/effect/turf_decal/stripes/line{ dir = 4 }, +/obj/effect/mapping_helpers/airlock/unres{ + dir = 4 + }, /turf/open/floor/plasteel, /area/medical/medbay/central) "cUD" = ( @@ -114081,6 +114197,9 @@ location = "Robotics" }, /obj/effect/turf_decal/delivery, +/obj/machinery/door/window/northright{ + req_access_txt = "47" + }, /turf/open/floor/plasteel, /area/science/robotics/lab) "dKl" = ( @@ -114276,11 +114395,6 @@ /obj/structure/cable/white{ icon_state = "1-2" }, -/obj/machinery/door/airlock/maintenance_hatch{ - name = "Maintenance Hatch"; - req_access_txt = "12" - }, -/obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/pipe/simple/supply/hidden, /obj/effect/turf_decal/stripes/line{ dir = 2 @@ -114288,6 +114402,10 @@ /obj/effect/turf_decal/stripes/line{ dir = 1 }, +/obj/machinery/door/airlock/maintenance_hatch{ + name = "Chapel Maintenance"; + req_access_txt = "27" + }, /turf/open/floor/plasteel, /area/maintenance/port/aft) "dKE" = ( @@ -118987,7 +119105,6 @@ /obj/structure/cable/white{ icon_state = "1-2" }, -/obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/pipe/manifold4w/supply/hidden, /obj/effect/turf_decal/delivery, /turf/open/floor/plasteel, @@ -119332,7 +119449,6 @@ /turf/closed/wall, /area/chapel/office) "dTx" = ( -/obj/structure/bodycontainer/morgue, /obj/effect/turf_decal/tile/neutral{ dir = 1 }, @@ -119343,6 +119459,7 @@ /obj/effect/turf_decal/tile/neutral{ dir = 8 }, +/obj/structure/closet/crate/coffin, /turf/open/floor/plasteel/dark, /area/chapel/office) "dTy" = ( @@ -120414,7 +120531,6 @@ name = "Station Intercom"; pixel_x = -26 }, -/obj/item/clothing/under/burial, /obj/effect/turf_decal/tile/neutral{ dir = 1 }, @@ -121768,7 +121884,6 @@ /turf/open/floor/plating, /area/maintenance/port/aft) "dYv" = ( -/obj/structure/bodycontainer/morgue, /obj/structure/sign/poster/official/ian{ pixel_y = -32 }, @@ -121782,6 +121897,7 @@ /obj/effect/turf_decal/tile/neutral{ dir = 8 }, +/obj/structure/closet/crate/coffin, /turf/open/floor/plasteel/dark, /area/chapel/office) "dYw" = ( @@ -122478,14 +122594,19 @@ /turf/open/floor/plating, /area/maintenance/port/aft) "dZM" = ( -/obj/effect/decal/cleanable/dirt, /obj/structure/cable/white{ icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 9 }, -/turf/open/floor/plating, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/turf/open/floor/plasteel, /area/maintenance/port/aft) "dZN" = ( /turf/closed/wall/r_wall, @@ -122824,7 +122945,6 @@ /turf/open/floor/plasteel, /area/maintenance/port/aft) "eat" = ( -/obj/effect/decal/cleanable/dirt, /obj/structure/cable/white{ icon_state = "1-8" }, @@ -122838,11 +122958,6 @@ /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 5 }, -/obj/machinery/button/crematorium{ - id = "cremawheat"; - pixel_x = -26; - req_access_txt = "27" - }, /obj/effect/turf_decal/tile/neutral{ dir = 1 }, @@ -123163,24 +123278,6 @@ /obj/structure/sign/nanotrasen, /turf/closed/wall/r_wall, /area/maintenance/port/aft) -"ebd" = ( -/obj/structure/bodycontainer/morgue, -/obj/machinery/airalarm{ - dir = 4; - pixel_x = -22 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/plasteel/dark, -/area/chapel/office) "ebe" = ( /obj/machinery/light{ dir = 4 @@ -123539,12 +123636,6 @@ /turf/open/floor/plasteel, /area/maintenance/port/aft) "ebS" = ( -/obj/structure/table, -/obj/item/storage/box/gloves{ - pixel_x = 3; - pixel_y = 3 - }, -/obj/item/storage/box/bodybags, /obj/effect/turf_decal/tile/neutral{ dir = 1 }, @@ -123555,15 +123646,15 @@ /obj/effect/turf_decal/tile/neutral{ dir = 8 }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 + }, /turf/open/floor/plasteel/dark, /area/chapel/office) "ebT" = ( /obj/structure/cable/white{ icon_state = "1-2" }, -/obj/machinery/atmospherics/components/unary/vent_scrubber/on{ - dir = 1 - }, /obj/effect/turf_decal/tile/neutral{ dir = 1 }, @@ -123574,6 +123665,9 @@ /obj/effect/turf_decal/tile/neutral{ dir = 8 }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 9 + }, /turf/open/floor/plasteel/dark, /area/chapel/office) "ebU" = ( @@ -123816,7 +123910,6 @@ /turf/open/floor/plasteel, /area/maintenance/port/aft) "ecw" = ( -/obj/structure/bodycontainer/morgue, /obj/machinery/firealarm{ dir = 1; pixel_y = -24 @@ -123831,6 +123924,7 @@ /obj/effect/turf_decal/tile/neutral{ dir = 8 }, +/obj/structure/closet/crate/coffin, /turf/open/floor/plasteel/dark, /area/chapel/office) "ecx" = ( @@ -125921,7 +126015,7 @@ /turf/open/floor/plasteel, /area/security/checkpoint/escape) "egj" = ( -/obj/machinery/computer/prisoner{ +/obj/machinery/computer/prisoner/management{ dir = 1 }, /obj/structure/cable/white{ @@ -126280,6 +126374,20 @@ }, /turf/open/floor/plasteel/dark, /area/library) +"enO" = ( +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/structure/bodycontainer/morgue, +/turf/open/floor/plasteel/dark, +/area/chapel/office) "exE" = ( /obj/machinery/air_sensor/atmos/toxins_mixing_tank, /turf/open/floor/engine/vacuum, @@ -126430,6 +126538,10 @@ /obj/machinery/atmospherics/pipe/simple/supply/hidden, /turf/closed/wall/r_wall, /area/science/circuit) +"fHS" = ( +/obj/structure/sign/warning/vacuum, +/turf/closed/wall/r_wall, +/area/chapel/office) "fLR" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 6 @@ -126462,6 +126574,20 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/closed/wall/r_wall, /area/science/circuit) +"gFk" = ( +/obj/structure/grille, +/turf/open/space, +/area/space/nearstation) +"gJj" = ( +/obj/machinery/door/window/northleft{ + name = "Mass Driver" + }, +/obj/machinery/mass_driver{ + id = "chapelgun"; + name = "Holy Driver" + }, +/turf/open/floor/plating, +/area/chapel/office) "gKr" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on{ dir = 1 @@ -126479,6 +126605,26 @@ }, /turf/open/floor/plasteel/white, /area/science/misc_lab) +"gNJ" = ( +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/machinery/airalarm{ + dir = 2; + pixel_y = 22 + }, +/turf/open/floor/plasteel/dark, +/area/chapel/office) "gNS" = ( /obj/effect/turf_decal/stripes/line, /obj/effect/turf_decal/tile/neutral{ @@ -126503,6 +126649,20 @@ /obj/effect/turf_decal/tile/purple, /turf/open/floor/plasteel/white, /area/science/research) +"gQw" = ( +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/turf/open/floor/plasteel{ + heat_capacity = 1e+006 + }, +/area/maintenance/port/aft) "gQS" = ( /turf/open/floor/plasteel/white/side{ dir = 9 @@ -126543,6 +126703,10 @@ }, /turf/open/floor/plating, /area/quartermaster/storage) +"hei" = ( +/obj/effect/decal/cleanable/dirt, +/turf/closed/wall/r_wall, +/area/chapel/office) "hic" = ( /obj/structure/table/reinforced, /obj/item/integrated_electronics/analyzer, @@ -126604,6 +126768,22 @@ }, /turf/open/floor/plasteel, /area/security/prison) +"hLO" = ( +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/delivery, +/obj/structure/closet, +/obj/effect/spawner/lootdrop/maintenance{ + lootcount = 3; + name = "3maintenance loot spawner" + }, +/turf/open/floor/plasteel, +/area/maintenance/port/aft) "hNZ" = ( /obj/structure/chair/office/light{ dir = 8 @@ -126627,11 +126807,50 @@ /obj/effect/turf_decal/bot, /turf/open/floor/plasteel, /area/science/research) +"ibC" = ( +/obj/effect/turf_decal/delivery, +/obj/machinery/hydroponics/soil, +/obj/item/seeds/lime{ + pixel_x = 6 + }, +/turf/open/floor/plasteel, +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) +"iiH" = ( +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/turf/open/floor/plasteel, +/area/maintenance/port/fore) +"ijd" = ( +/obj/machinery/atmospherics/pipe/simple/supply/hidden, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/turf/open/floor/plasteel/dark, +/area/chapel/office) "ijB" = ( /obj/structure/reagent_dispensers/keg/aphro/strong, /obj/item/reagent_containers/glass/beaker, /turf/open/floor/plating, /area/crew_quarters/abandoned_gambling_den) +"ivF" = ( +/obj/machinery/door/poddoor{ + id = "chapelgun"; + name = "Chapel Launcher Door" + }, +/obj/structure/fans/tiny, +/turf/open/floor/plating, +/area/chapel/office) "iwL" = ( /obj/machinery/status_display{ pixel_x = 32 @@ -126650,6 +126869,9 @@ }, /turf/open/floor/engine/vacuum, /area/science/mixing) +"iyd" = ( +/turf/open/space, +/area/space) "iQh" = ( /obj/structure/bodycontainer/morgue{ dir = 1 @@ -126714,6 +126936,21 @@ }, /turf/open/floor/plasteel, /area/science/research/abandoned) +"jhK" = ( +/obj/structure/rack, +/obj/effect/spawner/lootdrop/maintenance{ + lootcount = 2; + name = "2maintenance loot spawner" + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/turf/open/floor/plasteel, +/area/maintenance/port/aft) "jjN" = ( /obj/structure/table/reinforced, /obj/machinery/camera{ @@ -126811,6 +127048,19 @@ /obj/machinery/chem_master, /turf/open/floor/plasteel/dark, /area/medical/medbay/central) +"jPA" = ( +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/turf/open/floor/plasteel/dark, +/area/chapel/office) "jRy" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 4 @@ -126864,6 +127114,31 @@ }, /turf/open/floor/plasteel, /area/maintenance/port) +"kzw" = ( +/obj/machinery/button/crematorium{ + id = "cremawheat"; + pixel_x = -26; + req_access_txt = "27" + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/structure/table, +/obj/item/clothing/under/burial, +/obj/item/clothing/under/burial, +/obj/item/clothing/under/burial, +/obj/item/clothing/under/burial, +/obj/item/clothing/under/burial, +/obj/item/clothing/under/burial, +/turf/open/floor/plasteel/dark, +/area/chapel/office) "kLu" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 4 @@ -126879,6 +127154,10 @@ }, /turf/open/floor/plasteel/white, /area/science/mixing) +"kZu" = ( +/obj/effect/landmark/barthpot, +/turf/open/floor/wood, +/area/library) "lak" = ( /turf/open/floor/plasteel/white/side{ dir = 10 @@ -127028,6 +127307,14 @@ dir = 1 }, /area/science/circuit) +"mdk" = ( +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/machinery/light/small, +/turf/open/floor/plasteel, +/area/maintenance/port/fore) "mkm" = ( /obj/machinery/atmospherics/components/binary/valve, /obj/machinery/embedded_controller/radio/airlock_controller/incinerator_toxmix{ @@ -127095,14 +127382,118 @@ }, /turf/open/floor/engine, /area/science/mixing) +"mXJ" = ( +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral, +/turf/open/floor/plasteel/dark, +/area/chapel/office) "nyN" = ( /obj/machinery/vending/kink, /turf/open/floor/plating, /area/crew_quarters/abandoned_gambling_den) +"nOV" = ( +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/machinery/light{ + dir = 8 + }, +/turf/open/floor/plasteel/dark, +/area/chapel/office) "nSh" = ( /obj/machinery/atmospherics/pipe/simple/general/hidden, /turf/closed/wall/r_wall, /area/maintenance/disposal/incinerator) +"oaP" = ( +/obj/machinery/seed_extractor, +/obj/item/reagent_containers/glass/bucket, +/obj/effect/turf_decal/delivery, +/turf/open/floor/plasteel, +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) +"obe" = ( +/obj/structure/cable/white{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden, +/obj/structure/disposalpipe/segment, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral, +/turf/open/floor/plasteel, +/area/maintenance/port/fore) +"ost" = ( +/obj/structure/filingcabinet/chestdrawer, +/obj/effect/turf_decal/tile/brown{ + dir = 1 + }, +/obj/effect/turf_decal/tile/brown{ + dir = 4 + }, +/obj/effect/turf_decal/tile/brown{ + dir = 8 + }, +/obj/machinery/keycard_auth{ + pixel_x = -25 + }, +/turf/open/floor/plasteel, +/area/quartermaster/qm) +"owr" = ( +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral, +/turf/open/floor/plasteel/dark, +/area/chapel/office) +"owI" = ( +/obj/structure/cable/white{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/turf/open/floor/plasteel, +/area/maintenance/port/fore) +"ozr" = ( +/obj/effect/turf_decal/delivery, +/obj/machinery/hydroponics/soil, +/obj/item/seeds/grape, +/turf/open/floor/plasteel, +/area/hydroponics/garden/abandoned{ + name = "Maintenance Garden" + }) "oIl" = ( /obj/machinery/atmospherics/components/unary/portables_connector/visible{ dir = 1 @@ -127152,6 +127543,19 @@ }, /turf/open/floor/plasteel/dark, /area/science/mixing) +"oOb" = ( +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/machinery/door/window{ + req_one_access_txt = "48,50" + }, +/obj/effect/turf_decal/bot, +/turf/open/floor/plasteel, +/area/quartermaster/sorting) "oSD" = ( /obj/machinery/meter, /obj/machinery/atmospherics/pipe/manifold/general/visible{ @@ -127242,6 +127646,15 @@ }, /turf/open/floor/plating, /area/science/research/abandoned) +"pHf" = ( +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/turf/open/floor/plasteel, +/area/maintenance/port/fore) "pQm" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/cable/white{ @@ -127281,6 +127694,19 @@ /obj/effect/spawner/lootdrop/keg, /turf/open/floor/plating, /area/crew_quarters/abandoned_gambling_den) +"qMR" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 2 + }, +/turf/open/floor/plating, +/area/chapel/office) +"rbY" = ( +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/closet/crate/coffin, +/turf/open/floor/plating, +/area/chapel/office) "rhO" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on{ dir = 1 @@ -127328,6 +127754,16 @@ }, /turf/open/floor/plasteel, /area/quartermaster/miningoffice) +"rYR" = ( +/obj/structure/cable/white{ + icon_state = "4-8" + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/turf/open/floor/plasteel, +/area/maintenance/port/aft) "saw" = ( /turf/closed/wall, /area/science/circuit) @@ -127339,6 +127775,13 @@ /obj/machinery/door/poddoor/incinerator_toxmix, /turf/open/floor/engine/vacuum, /area/science/mixing) +"tbC" = ( +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral, +/turf/open/floor/plasteel, +/area/maintenance/port/fore) "tmi" = ( /obj/effect/turf_decal/stripes/line{ dir = 4 @@ -127352,14 +127795,58 @@ }, /turf/open/floor/plasteel, /area/crew_quarters/fitness/recreation) +"tAi" = ( +/obj/structure/reagent_dispensers/watertank, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral, +/turf/open/floor/plasteel, +/area/maintenance/port/fore) "tCh" = ( /turf/closed/wall, /area/science/misc_lab) +"tEW" = ( +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/structure/bodycontainer/morgue, +/turf/open/floor/plasteel/dark, +/area/chapel/office) "tMk" = ( /turf/open/floor/plasteel/white/side{ dir = 10 }, /area/science/misc_lab) +"tOQ" = ( +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/machinery/computer/pod/old{ + density = 0; + icon = 'icons/obj/airlock_machines.dmi'; + icon_state = "airlock_control_standby"; + id = "chapelgun"; + name = "Mass Driver Controller"; + pixel_x = -24; + pixel_y = 0 + }, +/turf/open/floor/plasteel/dark, +/area/chapel/office) "tRT" = ( /obj/effect/turf_decal/tile/blue{ dir = 4 @@ -127443,10 +127930,45 @@ }, /turf/open/floor/plasteel/white, /area/science/mixing) +"vFw" = ( +/obj/machinery/door/window/northright{ + name = "Coffin Storage" + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/closet/crate/coffin, +/turf/open/floor/plating, +/area/chapel/office) +"vON" = ( +/obj/structure/cable/white{ + icon_state = "4-8" + }, +/obj/structure/cable/white{ + icon_state = "2-4" + }, +/obj/effect/turf_decal/tile/blue, +/obj/effect/turf_decal/tile/blue{ + dir = 8 + }, +/turf/open/floor/plasteel, +/area/maintenance/port/aft) "wei" = ( /obj/effect/turf_decal/stripes/line, /turf/open/floor/plasteel, /area/science/circuit) +"whX" = ( +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/turf/open/floor/plasteel, +/area/maintenance/port/fore) "wAA" = ( /obj/structure/sign/nanotrasen, /turf/closed/wall/r_wall, @@ -127567,6 +128089,22 @@ /obj/effect/turf_decal/bot, /turf/open/floor/plasteel, /area/science/research) +"xWZ" = ( +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/turf/open/floor/plasteel/dark, +/area/chapel/office) "xXn" = ( /obj/machinery/atmospherics/components/unary/vent_pump/siphon/atmos/toxins_mixing_output, /turf/open/floor/engine/vacuum, @@ -156473,7 +157011,7 @@ arB aug alg alg -aAd +whX aKg alf aMO @@ -156730,7 +157268,7 @@ aAb aAb aAb aAb -arB +pHf aKh alf aMN @@ -156984,11 +157522,11 @@ aAb aBg aCv aDx -aCw +aCv aFJ aAb aIH -aoY +tAi alf aMP aDw @@ -157239,8 +157777,8 @@ axI ayU aAb aBh -aCw -aCw +aCv +aCv aCv aFK aHl @@ -157496,13 +158034,13 @@ axJ aoY aAb aBi -aCw +aCv aCw aEB aFL aAb -arB -alg +aIH +tbC avm arB arB @@ -157754,11 +158292,11 @@ alf aAb aBj aCv -aCw +oaP aEC aFM aAb -alg +aIH ary aLz aLz @@ -157885,7 +158423,7 @@ edL eep eff aad -ajr +aeH aaa ajr aaa @@ -158011,11 +158549,11 @@ alg aAb aBk aCv -aCw +ozr aEC aFN aAb -arA +aIH aKi aLz aMQ @@ -158142,7 +158680,7 @@ edM eeq dLY aad -aad +gFk aaa aad aaa @@ -158267,13 +158805,13 @@ axL ayV aAb aBl -aCw +aCv aDy aED aFO aHm aII -aKj +mdk aLz aMR aOq @@ -158524,13 +159062,13 @@ axM ayW aAb aBm -aCw -aCw +aCv +aCv aEE aFP aHn aIJ -aKj +iiH aLz aMS aOr @@ -158782,12 +159320,12 @@ ayX aAb aBn aCx -aCw -aCw +ibC +aCv aFQ aAb -asQ -arB +owI +iiH aLz aMT aOs @@ -159040,7 +159578,7 @@ aAc aBo aCy aDz -aEF +aDz aFR aHo aIK @@ -159160,7 +159698,7 @@ dXz dYt dON dOl -eap +vON eaX dYu ect @@ -159295,7 +159833,7 @@ alf alf aAb aBp -aCw +aCv aDA aCv aFJ @@ -159416,8 +159954,8 @@ dON dON dON dON -dZJ -ean +gQw +rYR ebc ebQ ecu @@ -159558,7 +160096,7 @@ aAb aAb aAb aIL -arB +tbC aLz aLz aLz @@ -159675,16 +160213,16 @@ dWI dZf dZM eat -dLY -dLY -dLY -dLY -dLY -dLY -dLY +dZN +dZN +dZN +dZN +fHS +dZN +dZN dLY aad -ajr +aeH aad aad aaa @@ -159815,7 +160353,7 @@ aEG aFS aHp aIM -aEG +obe aLB aFS aEG @@ -159930,20 +160468,20 @@ dWJ dLW dYu dZg -dYu -dYu -dZg -ebR -dLW -ecQ -edl -aad +hLO +jhK +dZN +owr +nOV +tOQ +gJj +qMR +ivF +aaa +iyd aaa aaa -aad -aaa -aaa -aad +iyd aaa aaa aaa @@ -160119,7 +160657,7 @@ caG chU cjt ckR -cmt +kZu cnR cpv cqQ @@ -160187,15 +160725,15 @@ dTw dTw dTw dTw -dLX -dLW -dLW -dLW -ecv -dNt -edl -aad -aad +dZN +dZN +hei +gNJ +jPA +jPA +vFw +rbY +dTw aad aad aad @@ -160436,7 +160974,7 @@ dPJ dQC dRB dSz -dTx +tEW dUi dTx dVN @@ -160444,11 +160982,11 @@ dTx dXB dYv dTw -dZN -dZN -dZN -dZN -dZN +dZO +kzw +enO +xWZ +mXJ dTw dTw dTw @@ -160701,9 +161239,9 @@ dUj dXC dYw dZh -dZO +ijd eau -ebd +edr ebS ecw dTw @@ -162636,7 +163174,7 @@ axX azd aAj aBA -asQ +asK aDL aEO aGc @@ -162893,7 +163431,7 @@ axY aze aAk aBB -asM +asK aDL aEP aGd @@ -163406,7 +163944,7 @@ auh auh auh auh -aBD +aBz aCG aDL aER @@ -167523,7 +168061,7 @@ aCP avQ aFe aGp -aHH +oOb aJg aKF aLP @@ -172210,7 +172748,7 @@ bsE cAm cBI cDo -cFc +aaq cAm cHW cIW @@ -174469,7 +175007,7 @@ aaa aaa aad aQQ -aez +aQQ aUp aVY aXE @@ -174726,7 +175264,7 @@ aaa aaa aad aQR -aSs +ost aUq aVR aXF @@ -176583,7 +177121,7 @@ cFr cGP cqd cJe -cKT +aar cMq cAw cPM diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index 75d7466371..43c8b1155b 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -2,6 +2,17 @@ "aaa" = ( /turf/open/space/basic, /area/space) +"aab" = ( +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 5 + }, +/obj/structure/sign/poster/official/random{ + pixel_y = -32 + }, +/obj/structure/table, +/obj/structure/bedsheetbin/towel, +/turf/open/floor/plasteel/freezer, +/area/crew_quarters/toilet/restrooms) "aac" = ( /obj/effect/landmark/carpspawn, /turf/open/space, @@ -2017,7 +2028,7 @@ /turf/open/floor/plasteel/dark, /area/crew_quarters/heads/hos) "aeu" = ( -/obj/machinery/computer/prisoner, +/obj/machinery/computer/prisoner/management, /turf/open/floor/plasteel/dark, /area/crew_quarters/heads/hos) "aev" = ( @@ -8416,7 +8427,7 @@ /turf/open/floor/plating, /area/security/warden) "apI" = ( -/obj/machinery/computer/prisoner{ +/obj/machinery/computer/prisoner/management{ dir = 4 }, /obj/structure/cable/yellow{ @@ -10514,7 +10525,7 @@ /turf/open/floor/plating, /area/maintenance/port/fore) "atK" = ( -/obj/machinery/computer/gulag_teleporter_computer{ +/obj/machinery/computer/prisoner/gulag_teleporter_computer{ dir = 1 }, /turf/open/floor/plasteel/dark, @@ -20376,6 +20387,7 @@ /obj/machinery/keycard_auth{ pixel_y = 23 }, +/obj/item/clipboard, /turf/open/floor/plasteel, /area/quartermaster/qm) "aNS" = ( @@ -21064,6 +21076,7 @@ departmentType = 2; pixel_x = 32 }, +/obj/item/stamp/qm, /turf/open/floor/plasteel, /area/quartermaster/qm) "aPl" = ( @@ -21619,12 +21632,12 @@ /turf/open/floor/plasteel, /area/quartermaster/qm) "aQt" = ( -/obj/structure/table, -/obj/item/clipboard, -/obj/item/stamp/qm, /obj/machinery/status_display/supply{ pixel_x = 32 }, +/obj/machinery/computer/card/minor/qm{ + dir = 8 + }, /turf/open/floor/plasteel, /area/quartermaster/qm) "aQu" = ( @@ -30781,7 +30794,7 @@ /obj/structure/cable/yellow{ icon_state = "2-4" }, -/obj/machinery/computer/prisoner, +/obj/machinery/computer/prisoner/management, /obj/effect/turf_decal/tile/red{ dir = 1 }, @@ -43775,6 +43788,7 @@ /turf/open/floor/wood, /area/library) "bGt" = ( +/obj/effect/landmark/barthpot, /turf/open/floor/wood{ icon_state = "wood-broken7" }, @@ -57384,6 +57398,7 @@ /obj/effect/turf_decal/tile/blue{ dir = 8 }, +/obj/effect/mapping_helpers/airlock/unres, /turf/open/floor/plasteel/white, /area/medical/medbay/central) "cha" = ( @@ -57404,6 +57419,7 @@ /obj/effect/turf_decal/tile/blue{ dir = 8 }, +/obj/effect/mapping_helpers/airlock/unres, /turf/open/floor/plasteel/white, /area/medical/medbay/central) "chb" = ( @@ -66401,6 +66417,9 @@ /obj/effect/turf_decal/tile/blue{ dir = 8 }, +/obj/effect/mapping_helpers/airlock/unres{ + dir = 4 + }, /turf/open/floor/plasteel/white, /area/medical/genetics/cloning) "cxZ" = ( @@ -78455,6 +78474,7 @@ /turf/open/floor/engine, /area/science/xenobiology) "dbq" = ( +/mob/living/simple_animal/hostile/retaliate/goose, /turf/open/floor/wood{ icon_state = "wood-broken6" }, @@ -80877,15 +80897,6 @@ }, /turf/open/floor/plasteel, /area/quartermaster/warehouse) -"dhD" = ( -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 5 - }, -/obj/structure/sign/poster/official/random{ - pixel_y = -32 - }, -/turf/open/floor/plasteel/freezer, -/area/crew_quarters/toilet/restrooms) "dhE" = ( /obj/structure/sign/poster/contraband/random{ pixel_x = 32 @@ -118782,7 +118793,7 @@ aBu aCB aDU aFg -dhD +aab axC axC axC diff --git a/_maps/map_files/OmegaStation/OmegaStation.dmm b/_maps/map_files/OmegaStation/OmegaStation.dmm index 0c55f05fcb..24a5cd834a 100644 --- a/_maps/map_files/OmegaStation/OmegaStation.dmm +++ b/_maps/map_files/OmegaStation/OmegaStation.dmm @@ -955,6 +955,19 @@ }, /turf/open/floor/plasteel/dark, /area/bridge) +"abn" = ( +/obj/structure/table, +/obj/machinery/camera{ + c_tag = "Locker Room East"; + dir = 8 + }, +/obj/effect/turf_decal/bot, +/obj/effect/turf_decal/tile/blue{ + dir = 4 + }, +/obj/structure/bedsheetbin/color, +/turf/open/floor/plasteel/white/corner, +/area/crew_quarters/dorms) "abo" = ( /obj/effect/turf_decal/tile/neutral, /obj/effect/turf_decal/tile/neutral{ @@ -15282,19 +15295,6 @@ }, /turf/open/floor/plasteel, /area/crew_quarters/dorms) -"aAJ" = ( -/obj/structure/table, -/obj/structure/bedsheetbin, -/obj/machinery/camera{ - c_tag = "Locker Room East"; - dir = 8 - }, -/obj/effect/turf_decal/bot, -/obj/effect/turf_decal/tile/blue{ - dir = 4 - }, -/turf/open/floor/plasteel/white/corner, -/area/crew_quarters/dorms) "aAK" = ( /obj/structure/sign/poster/random, /turf/closed/wall, @@ -26273,7 +26273,7 @@ /turf/open/floor/wood, /area/library) "aUZ" = ( -/obj/machinery/atmospherics/pipe/manifold/supply/hidden, +/obj/effect/landmark/barthpot, /turf/open/floor/wood, /area/library) "aVa" = ( @@ -27287,6 +27287,9 @@ /obj/effect/turf_decal/stripes/line{ dir = 1 }, +/obj/effect/mapping_helpers/airlock/unres{ + dir = 1 + }, /turf/open/floor/plasteel, /area/medical/medbay/zone3) "aWM" = ( @@ -28598,6 +28601,9 @@ /obj/effect/turf_decal/stripes/line{ dir = 4 }, +/obj/effect/mapping_helpers/airlock/unres{ + dir = 8 + }, /turf/open/floor/plasteel, /area/medical/medbay/zone3) "aYU" = ( @@ -29134,6 +29140,9 @@ /obj/effect/turf_decal/stripes/line{ dir = 4 }, +/obj/effect/mapping_helpers/airlock/unres{ + dir = 8 + }, /turf/open/floor/plasteel, /area/medical/medbay/zone3) "aZQ" = ( @@ -82325,7 +82334,7 @@ awQ axK ayC awQ -aAJ +abn aBT awQ aDI diff --git a/_maps/map_files/PubbyStation/PubbyStation.dmm b/_maps/map_files/PubbyStation/PubbyStation.dmm index ee97af14fc..386ab45c6b 100644 --- a/_maps/map_files/PubbyStation/PubbyStation.dmm +++ b/_maps/map_files/PubbyStation/PubbyStation.dmm @@ -2,6 +2,33 @@ "aaa" = ( /turf/open/space/basic, /area/space) +"aab" = ( +/obj/machinery/newscaster{ + pixel_x = 32 + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/effect/turf_decal/tile/blue{ + dir = 4 + }, +/obj/effect/turf_decal/tile/blue{ + dir = 8 + }, +/obj/structure/bedsheetbin/color, +/turf/open/floor/plasteel/cafeteria, +/area/crew_quarters/dorms) +"aac" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 9 + }, +/obj/structure/table, +/obj/structure/bedsheetbin/towel, +/turf/open/floor/plasteel/freezer, +/area/crew_quarters/toilet/restrooms) "aad" = ( /obj/effect/spawner/lootdrop/maintenance, /turf/open/floor/plating{ @@ -4897,7 +4924,7 @@ /turf/open/floor/plasteel/showroomfloor, /area/security/warden) "amT" = ( -/obj/machinery/computer/prisoner, +/obj/machinery/computer/prisoner/management, /obj/machinery/airalarm{ pixel_y = 22 }, @@ -6072,7 +6099,7 @@ /turf/open/floor/plating, /area/security/brig) "apF" = ( -/obj/machinery/computer/gulag_teleporter_computer{ +/obj/machinery/computer/prisoner/gulag_teleporter_computer{ dir = 1 }, /turf/open/floor/plasteel/dark, @@ -7048,7 +7075,7 @@ /turf/open/floor/plasteel/dark, /area/bridge) "arR" = ( -/obj/machinery/computer/prisoner, +/obj/machinery/computer/prisoner/management, /obj/effect/turf_decal/tile/red{ dir = 1 }, @@ -7254,22 +7281,6 @@ }, /turf/open/floor/plasteel/cafeteria, /area/crew_quarters/dorms) -"asg" = ( -/obj/structure/bedsheetbin, -/obj/machinery/newscaster{ - pixel_x = 32 - }, -/obj/structure/cable{ - icon_state = "1-8" - }, -/obj/effect/turf_decal/tile/blue{ - dir = 4 - }, -/obj/effect/turf_decal/tile/blue{ - dir = 8 - }, -/turf/open/floor/plasteel/cafeteria, -/area/crew_quarters/dorms) "ash" = ( /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, @@ -14880,15 +14891,6 @@ }, /turf/open/floor/plasteel/freezer, /area/crew_quarters/toilet/restrooms) -"aJo" = ( -/obj/structure/cable{ - icon_state = "1-8" - }, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ - dir = 9 - }, -/turf/open/floor/plasteel/freezer, -/area/crew_quarters/toilet/restrooms) "aJp" = ( /obj/item/chair, /turf/open/floor/plating, @@ -24477,16 +24479,11 @@ /turf/open/floor/plasteel/dark, /area/science/robotics/mechbay) "bfB" = ( -/obj/structure/table, /obj/machinery/requests_console{ department = "Cargo Bay"; departmentType = 2; pixel_x = -30 }, -/obj/item/paper_bin{ - layer = 2.9 - }, -/obj/item/pen, /obj/effect/turf_decal/tile/brown{ dir = 1 }, @@ -24494,6 +24491,9 @@ /obj/effect/turf_decal/tile/brown{ dir = 8 }, +/obj/machinery/computer/card/minor/qm{ + dir = 4 + }, /turf/open/floor/plasteel, /area/quartermaster/qm) "bfC" = ( @@ -27566,6 +27566,7 @@ }, /obj/structure/disposalpipe/segment, /obj/machinery/atmospherics/pipe/simple/supply/hidden, +/obj/effect/mapping_helpers/airlock/unres, /turf/open/floor/plasteel/freezer, /area/storage/emergency/port) "bnx" = ( @@ -29314,6 +29315,9 @@ /obj/structure/disposalpipe/segment{ dir = 4 }, +/obj/effect/mapping_helpers/airlock/unres{ + dir = 8 + }, /turf/open/floor/plasteel/white, /area/medical/genetics) "brb" = ( @@ -30153,6 +30157,7 @@ /obj/effect/turf_decal/tile/blue{ dir = 8 }, +/obj/effect/mapping_helpers/airlock/unres, /turf/open/floor/plasteel/white, /area/medical/medbay/central) "bsI" = ( @@ -30164,6 +30169,7 @@ name = "Medbay" }, /obj/effect/turf_decal/tile/blue, +/obj/effect/mapping_helpers/airlock/unres, /turf/open/floor/plasteel/white, /area/medical/medbay/central) "bsJ" = ( @@ -47466,8 +47472,8 @@ /area/hydroponics/garden/monastery) "cgL" = ( /obj/structure/closet/cabinet, -/obj/item/clothing/suit/holidaypriest, -/obj/item/clothing/suit/nun, +/obj/item/clothing/suit/chaplain/holidaypriest, +/obj/item/clothing/suit/chaplain/nun, /obj/item/clothing/head/nun_hood, /obj/machinery/button/door{ id = "Cell1"; @@ -47834,8 +47840,8 @@ /area/space/nearstation) "cio" = ( /obj/structure/closet/cabinet, -/obj/item/clothing/suit/holidaypriest, -/obj/item/clothing/suit/nun, +/obj/item/clothing/suit/chaplain/holidaypriest, +/obj/item/clothing/suit/chaplain/nun, /obj/item/clothing/head/nun_hood, /obj/machinery/button/door{ id = "Cell2"; @@ -50476,8 +50482,8 @@ /obj/structure/closet, /obj/item/storage/backpack/cultpack, /obj/item/clothing/head/nun_hood, -/obj/item/clothing/suit/nun, -/obj/item/clothing/suit/holidaypriest, +/obj/item/clothing/suit/chaplain/nun, +/obj/item/clothing/suit/chaplain/holidaypriest, /obj/effect/turf_decal/tile/neutral{ dir = 1 }, @@ -54387,6 +54393,10 @@ }, /turf/open/floor/plating, /area/maintenance/department/cargo) +"ggg" = ( +/mob/living/simple_animal/hostile/retaliate/goose, +/turf/open/floor/wood, +/area/maintenance/department/crew_quarters/dorms) "gih" = ( /obj/machinery/atmospherics/pipe/simple/cyan/visible{ dir = 4 @@ -60870,6 +60880,10 @@ }, /turf/open/floor/plasteel, /area/engine/engineering) +"vkd" = ( +/obj/effect/landmark/barthpot, +/turf/open/floor/carpet, +/area/library/lounge) "vlF" = ( /obj/item/coin/silver, /obj/effect/decal/cleanable/oil{ @@ -62094,6 +62108,7 @@ name = "Port Emergency Storage"; req_access_txt = "0" }, +/obj/effect/mapping_helpers/airlock/unres, /turf/open/floor/plasteel/freezer, /area/storage/emergency/port) "xSX" = ( @@ -79865,7 +79880,7 @@ ckT xhj xhj cwK -xhj +vkd xhj cxn xhj @@ -99275,7 +99290,7 @@ cBk jhD cBo alQ -alb +ggg cBw noC aiS @@ -100830,7 +100845,7 @@ aiT aiS apX cod -asg +aab atj apX avi @@ -102389,7 +102404,7 @@ aFH aGG aHo aIk -aJo +aac aGF aEd aMr diff --git a/_maps/map_files/debug/runtimestation.dmm b/_maps/map_files/debug/runtimestation.dmm index 3bdf64ac27..feb8fc8cc0 100644 --- a/_maps/map_files/debug/runtimestation.dmm +++ b/_maps/map_files/debug/runtimestation.dmm @@ -523,7 +523,7 @@ /turf/open/floor/plasteel, /area/science) "bC" = ( -/obj/machinery/computer/gulag_teleporter_computer{ +/obj/machinery/computer/prisoner/gulag_teleporter_computer{ dir = 4 }, /turf/open/floor/plasteel, diff --git a/_maps/map_files/generic/CentCom.dmm b/_maps/map_files/generic/CentCom.dmm index 115ad3d363..80e80cd6a9 100644 --- a/_maps/map_files/generic/CentCom.dmm +++ b/_maps/map_files/generic/CentCom.dmm @@ -1264,9 +1264,9 @@ /area/holodeck/rec_center/chapelcourt) "dw" = ( /obj/structure/table/wood/fancy, -/obj/item/clothing/suit/nun, +/obj/item/clothing/suit/chaplain/nun, /obj/item/clothing/head/nun_hood, -/obj/item/clothing/suit/holidaypriest, +/obj/item/clothing/suit/chaplain/holidaypriest, /turf/open/floor/holofloor{ dir = 8; icon_state = "dark" @@ -3864,7 +3864,7 @@ /turf/open/floor/plasteel, /area/centcom/control) "jS" = ( -/obj/machinery/computer/prisoner, +/obj/machinery/computer/prisoner/management, /obj/effect/turf_decal/stripes/line, /turf/open/floor/plasteel, /area/centcom/control) @@ -5857,7 +5857,7 @@ /turf/open/floor/plasteel, /area/centcom/control) "nY" = ( -/obj/machinery/computer/prisoner{ +/obj/machinery/computer/prisoner/management{ dir = 1 }, /obj/effect/turf_decal/stripes/line{ @@ -9840,7 +9840,7 @@ id = "XCCFerry"; name = "Hanger Bay Shutters"; pixel_y = 24; - req_access_txt = "2" + req_access_txt = "101" }, /obj/effect/turf_decal/stripes/line{ dir = 5 @@ -10495,7 +10495,7 @@ /turf/open/floor/plasteel/dark, /area/centcom/control) "yv" = ( -/obj/machinery/computer/prisoner{ +/obj/machinery/computer/prisoner/management{ dir = 1 }, /obj/machinery/light, diff --git a/_maps/map_files/generic/City_of_Cogs.dmm b/_maps/map_files/generic/City_of_Cogs.dmm index 889abe66c3..584564ba2a 100644 --- a/_maps/map_files/generic/City_of_Cogs.dmm +++ b/_maps/map_files/generic/City_of_Cogs.dmm @@ -47,11 +47,6 @@ /obj/machinery/sleeper/clockwork, /turf/open/floor/clockwork/reebe, /area/reebe/city_of_cogs) -"am" = ( -/obj/structure/table/reinforced/brass, -/obj/item/storage/firstaid, -/turf/open/floor/clockwork/reebe, -/area/reebe/city_of_cogs) "an" = ( /obj/structure/noticeboard, /obj/item/paper/fluff/ruins/djstation{ @@ -84,15 +79,6 @@ }, /turf/open/floor/clockwork/reebe, /area/reebe/city_of_cogs) -"at" = ( -/obj/structure/table/reinforced/brass, -/obj/item/clockwork/slab, -/obj/item/clockwork/slab, -/obj/item/clockwork/slab, -/obj/item/clockwork/slab, -/obj/item/clockwork/slab, -/turf/open/floor/clockwork/reebe, -/area/reebe/city_of_cogs) "au" = ( /obj/structure/table/reinforced/brass, /obj/item/radio/intercom/ratvar, @@ -333,6 +319,10 @@ /obj/structure/window/reinforced/clockwork/fulltile, /turf/open/indestructible/clock_spawn_room, /area/reebe/city_of_cogs) +"bt" = ( +/obj/structure/table/bronze, +/turf/open/floor/clockwork/reebe, +/area/reebe/city_of_cogs) "bu" = ( /obj/structure/table/reinforced/brass, /turf/open/indestructible/clock_spawn_room, @@ -349,17227 +339,17367 @@ }, /turf/open/indestructible/clock_spawn_room, /area/reebe/city_of_cogs) +"bE" = ( +/obj/structure/table/reinforced/brass, +/obj/item/storage/firstaid, +/obj/item/healthanalyzer/advanced, +/obj/item/healthanalyzer/advanced, +/obj/item/healthanalyzer/advanced, +/obj/item/healthanalyzer/advanced, +/turf/open/floor/clockwork/reebe, +/area/reebe/city_of_cogs) +"eV" = ( +/obj/structure/chair/stool/bar/brass, +/turf/open/indestructible/clock_spawn_room, +/area/reebe/city_of_cogs) +"nj" = ( +/obj/structure/table/bronze, +/turf/open/indestructible/clock_spawn_room, +/area/reebe/city_of_cogs) +"ww" = ( +/obj/structure/table/bronze, +/obj/item/camera_film, +/turf/open/indestructible/clock_spawn_room, +/area/reebe/city_of_cogs) +"xH" = ( +/obj/structure/chair/stool/brass, +/turf/open/indestructible/clock_spawn_room, +/area/reebe/city_of_cogs) +"ym" = ( +/obj/structure/table/bronze, +/obj/item/storage/belt/utility/servant, +/obj/item/storage/belt/utility/servant, +/turf/open/floor/clockwork/reebe, +/area/reebe/city_of_cogs) +"zb" = ( +/turf/open/space/basic, +/area/space) +"EE" = ( +/obj/structure/table/bronze, +/obj/item/camera, +/turf/open/indestructible/clock_spawn_room, +/area/reebe/city_of_cogs) +"Nz" = ( +/obj/structure/table/bronze, +/obj/item/implantcase, +/obj/item/implantcase, +/obj/item/implantcase, +/obj/item/implanter, +/obj/item/storage/backpack/duffelbag/sec/surgery, +/turf/open/floor/clockwork/reebe, +/area/reebe/city_of_cogs) +"NH" = ( +/obj/structure/table/bronze, +/obj/item/taperecorder, +/turf/open/indestructible/clock_spawn_room, +/area/reebe/city_of_cogs) +"VP" = ( +/obj/structure/table/reinforced/brass, +/obj/item/clockwork/slab, +/obj/item/clockwork/slab, +/obj/item/clockwork/slab, +/obj/item/clockwork/slab, +/obj/item/clockwork/slab, +/obj/item/clockwork/slab, +/obj/item/clockwork/slab, +/obj/item/clockwork/slab, +/obj/item/clockwork/slab, +/turf/open/floor/clockwork/reebe, +/area/reebe/city_of_cogs) +"WT" = ( +/turf/closed/wall/clockwork, +/area/reebe) +"Yy" = ( +/obj/structure/table/optable, +/turf/open/floor/clockwork/reebe, +/area/reebe/city_of_cogs) (1,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (2,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (3,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (4,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (5,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (6,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (7,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (8,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (9,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (10,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (11,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (12,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (13,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (14,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (15,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (16,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (17,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (18,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (19,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (20,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (21,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (22,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (23,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (24,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (25,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (26,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (27,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (28,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (29,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (30,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (31,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (32,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (33,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (34,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (35,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (36,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (37,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (38,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (39,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (40,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (41,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (42,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (43,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (44,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (45,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (46,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (47,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (48,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (49,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (50,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (51,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (52,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (53,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (54,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (55,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (56,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (57,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (58,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (59,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (60,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (61,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (62,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (63,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (64,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (65,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (66,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (67,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (68,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -17677,156 +17807,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (69,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -17934,156 +18064,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (70,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -18191,156 +18321,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (71,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -18448,156 +18578,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (72,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -18705,156 +18835,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (73,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -18962,156 +19092,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (74,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -19219,156 +19349,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (75,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -19476,156 +19606,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (76,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -19733,156 +19863,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (77,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -19990,156 +20120,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (78,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -20247,156 +20377,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (79,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -20504,156 +20634,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (80,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -20761,156 +20891,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (81,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -21018,156 +21148,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (82,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -21275,156 +21405,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (83,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -21532,156 +21662,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (84,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -21789,156 +21919,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (85,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -22046,156 +22176,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (86,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -22303,156 +22433,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (87,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -22560,156 +22690,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (88,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -22817,156 +22947,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (89,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -23074,156 +23204,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (90,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -23331,156 +23461,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (91,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -23588,156 +23718,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (92,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -23845,156 +23975,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (93,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -24102,156 +24232,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (94,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -24359,156 +24489,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (95,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -24554,6 +24684,7 @@ aa aa aa aa +ab aa aa aa @@ -24615,157 +24746,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (96,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -24791,6 +24921,58 @@ aa aa aa aa +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +aF +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab aa aa aa @@ -24821,1805 +25003,670 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (97,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +aF +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (98,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +aF +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (99,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(100,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -aF -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(101,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -aF -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(102,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -aF -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(103,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -26671,6 +25718,16 @@ ab ab ab ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab aF ab ab @@ -26717,166 +25774,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(104,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +(100,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -26928,6 +25975,16 @@ ab ab ab ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab aF ab ab @@ -26974,166 +26031,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(105,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +(101,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -27185,6 +26232,16 @@ ab ab ab ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab aF ab ab @@ -27231,166 +26288,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(106,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +(102,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -27442,6 +26489,16 @@ ab ab ab ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab aF ab ab @@ -27488,180 +26545,180 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(107,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +(103,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab ab ab ab @@ -27745,166 +26802,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(108,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +(104,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -27956,6 +27003,16 @@ ab ab ab ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +aF aF ab ab @@ -28002,166 +27059,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(109,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +(105,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -28213,6 +27260,16 @@ ab ab aF aF +aF +aF +aF +aF +aF +aF +aF +aF +aF +aG aY ae ae @@ -28259,164 +27316,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(110,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +(106,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -28448,8 +27497,16 @@ ab ab ab ab -ab -ab +aF +aF +aF +aF +aF +aF +aF +aF +aF +aF aF aF aF @@ -28491,8 +27548,8 @@ aT aT aT aT -aT -aT +nj +nj ah ah ah @@ -28516,111 +27573,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(111,1,1) = {" +(107,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -28635,61 +27737,6 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab ab ab ab @@ -28727,6 +27774,16 @@ aG aG aG aG +aG +aG +aG +aG +aG +aG +aG +aG +aG +aj aS bu bu @@ -28748,8 +27805,8 @@ aT aT aT aT -aT -aT +xH +EE bo aX bo @@ -28773,168 +27830,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(112,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +(108,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -28956,13 +28001,15 @@ ab ab ab ab +ab +ab ae ag ag ah ar aj -aj +bt ah aj aj @@ -28984,6 +28031,16 @@ aj aj aj aj +aj +aj +aj +aj +aj +aj +aj +aj +aj +aj aS bw bw @@ -29005,8 +28062,8 @@ aT aR aT aR -aT -aT +eV +NH bo aZ bo @@ -29030,168 +28087,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(113,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +(109,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -29213,6 +28258,8 @@ ab ab ab ab +ab +ab ae ag ag @@ -29241,6 +28288,16 @@ aj aj aj aj +aj +aj +aj +aj +aj +aj +aj +aj +aj +aj aS aT aT @@ -29262,8 +28319,8 @@ aT aT aT aT -aT -aT +xH +nj bo ba bo @@ -29287,167 +28344,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(114,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +(110,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -29470,13 +28516,14 @@ ab ab ab ab +ab ae ag ag ah -at -aj +VP aj +ym ah aj aj @@ -29498,6 +28545,16 @@ aj aj aj aj +aj +aj +aj +aj +aj +aj +aj +aj +aj +aj aS aT aT @@ -29519,8 +28576,8 @@ aT aR aT aR -aT -aT +eV +nj bo bb bo @@ -29544,167 +28601,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(115,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +(111,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -29728,6 +28774,7 @@ ab ab ab ab +ab ae ae ah @@ -29755,6 +28802,16 @@ aj aj aj aj +aj +aj +aj +aj +aj +aj +aj +aj +aj +aj aS aT aT @@ -29776,8 +28833,8 @@ aT aT aT aT -aT -aT +xH +ww bo bc bo @@ -29801,167 +28858,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(116,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +(112,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -29986,6 +29032,7 @@ ab ab ab ab +ab ae an au @@ -30012,6 +29059,16 @@ aj aj aj aj +aj +aj +aj +aj +aj +aj +aj +aj +aj +aj aS aT aT @@ -30033,8 +29090,8 @@ aT aR aT aR -aT -aT +eV +nj bo bd bo @@ -30058,167 +29115,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(117,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +(113,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -30243,6 +29289,7 @@ ab ab ab ab +ab ah ah av @@ -30269,6 +29316,16 @@ aj aj aj aj +aj +aj +aj +aj +aj +aj +aj +aj +aj +aj aS aT aT @@ -30290,8 +29347,8 @@ aT aT aT aT -aT -aT +xH +nj bo be bo @@ -30315,167 +29372,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(118,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +(114,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -30499,6 +29545,7 @@ ab ab ab ab +ab ae ai ao @@ -30526,6 +29573,16 @@ aj aj aj aj +aj +aj +aj +aj +aj +aj +aj +aj +aj +aj aS aT aT @@ -30547,8 +29604,8 @@ aT aT aT aT -aT -aT +EE +nj ah ah ah @@ -30572,167 +29629,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(119,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +(115,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -30756,6 +29802,7 @@ ab ab ab ab +ab ae ah ah @@ -30783,6 +29830,16 @@ aj aj aj aj +aj +aj +aj +aj +aj +aj +aj +aj +aj +aj aS aT aT @@ -30829,167 +29886,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(120,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +(116,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -31011,6 +30057,7 @@ ab ab ab ab +ab ae ae ag @@ -31040,6 +30087,16 @@ aj aj aj aj +aj +aj +aj +aj +aj +aj +aj +aj +aj +aj aS aT aT @@ -31061,8 +30118,8 @@ aT aT aT aT -aT -aT +ww +nj ah ah ah @@ -31086,167 +30143,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(121,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +(117,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -31266,6 +30312,7 @@ ab ab ab ab +ab ah ah ah @@ -31297,6 +30344,16 @@ aj aj aj aj +aj +aj +aj +aj +aj +aj +aj +aj +aj +aj aS aT aT @@ -31318,8 +30375,8 @@ aT aT aT aT -aT -aT +xH +nj bo bf bo @@ -31343,167 +30400,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(122,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +(118,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -31522,6 +30568,7 @@ ab ab ab ab +ab ac ah aj @@ -31554,6 +30601,16 @@ aj aj aj aj +aj +aj +aj +aj +aj +aj +aj +aj +aj +aj aS aT aT @@ -31575,8 +30632,8 @@ aT aR aT aR -aT -aT +eV +nj bo bg bo @@ -31600,167 +30657,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(123,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +(119,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -31779,6 +30825,7 @@ ab ab ab ab +ab ae ah aj @@ -31811,6 +30858,16 @@ aj aj aj aj +aj +aj +aj +aj +aj +aj +aj +aj +aj +aj aS aT aT @@ -31832,8 +30889,8 @@ aT aT aT aT -aT -aT +xH +EE bo bk bo @@ -31857,167 +30914,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(124,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +(120,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -32035,6 +31081,7 @@ ab ab ab ab +ab ae ag ai @@ -32068,6 +31115,16 @@ aj aj aj aj +aj +aj +aj +aj +aj +aj +aj +aj +aj +aj aS aT aT @@ -32089,8 +31146,8 @@ aT aR aT aR -aT -aT +eV +nj bo bl bo @@ -32114,111 +31171,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(125,1,1) = {" +(121,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -32228,61 +31330,6 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab ab ab ab @@ -32325,6 +31372,16 @@ aj aj aj aj +aj +aj +aj +aj +aj +aj +aj +aj +aj +aj aS aT aT @@ -32346,8 +31403,8 @@ aT aT aT aT -aT -aT +xH +nj bo bm bo @@ -32371,111 +31428,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(126,1,1) = {" +(122,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -32485,61 +31587,6 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab ab ab ab @@ -32582,6 +31629,16 @@ aj aj aj aj +aj +aj +aj +aj +aj +aj +aj +aj +aj +aj aS aT aT @@ -32603,8 +31660,8 @@ aT aR aT aR -aT -aT +eV +nj bo bn bo @@ -32628,111 +31685,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(127,1,1) = {" +(123,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -32742,61 +31844,6 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab ab ab ab @@ -32839,6 +31886,16 @@ aj aj aj aj +aj +aj +aj +aj +aj +aj +aj +aj +aj +aj aS aT aT @@ -32860,8 +31917,8 @@ aT aT aT aT -aT -aT +xH +nj bo aX bo @@ -32885,111 +31942,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(128,1,1) = {" +(124,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -32999,61 +32101,6 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab ab ab ab @@ -33096,6 +32143,16 @@ aj aj aj aj +aj +aj +aj +aj +aj +aj +aj +aj +aj +aj aS aT aT @@ -33117,8 +32174,8 @@ aT aT aT aT -aT -aT +NH +EE ah ah ah @@ -33142,111 +32199,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(129,1,1) = {" +(125,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -33256,61 +32358,6 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab ab ab ab @@ -33353,6 +32400,16 @@ aj aj aj aj +aj +aj +aj +aj +aj +aj +aj +aj +aj +aj aS aT aT @@ -33399,111 +32456,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(130,1,1) = {" +(126,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -33513,61 +32615,6 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab ab ab ab @@ -33610,6 +32657,16 @@ aj aj aj aj +aj +aj +aj +aj +aj +aj +aj +aj +aj +aj aS aT aT @@ -33631,8 +32688,8 @@ aT aT aT aT -aT -aT +nj +nj ah ah ah @@ -33656,165 +32713,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(131,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +(127,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -33829,7 +32877,6 @@ ab ab ab ab -ac ad ab ab @@ -33867,6 +32914,16 @@ aj aj aj aj +aj +aj +aj +aj +aj +aj +aj +aj +aj +aj aS aT aT @@ -33888,8 +32945,8 @@ aT aT aT aT -aT -aT +xH +EE bo aZ bo @@ -33913,111 +32970,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(132,1,1) = {" +(128,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -34027,61 +33129,6 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab ab ab ab @@ -34124,6 +33171,16 @@ aj aj aj aj +aj +aj +aj +aj +aj +aj +aj +aj +aj +aj aS aT aT @@ -34145,8 +33202,8 @@ aT aR aT aR -aT -aT +eV +nj bo ba bo @@ -34170,111 +33227,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(133,1,1) = {" +(129,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -34284,61 +33386,6 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab ab ab ab @@ -34381,6 +33428,16 @@ aj aj aj aj +aj +aj +aj +aj +aj +aj +aj +aj +aj +aj aS aT aT @@ -34402,8 +33459,8 @@ aT aT aT aT -aT -aT +xH +NH bo bb bo @@ -34427,111 +33484,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(134,1,1) = {" +(130,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -34541,61 +33643,6 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab ab ab ab @@ -34638,6 +33685,16 @@ aj aj aj aj +aj +aj +aj +aj +aj +aj +aj +aj +aj +aj aS aT aT @@ -34659,8 +33716,8 @@ aT aR aT aR -aT -aT +eV +nj bo bc bo @@ -34684,166 +33741,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(135,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +(131,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -34869,9 +33916,9 @@ ab ab ae ai -am -aj +bE aj +Yy aj aj aA @@ -34895,6 +33942,16 @@ aj aj aj aj +aj +aj +aj +aj +aj +aj +aj +aj +aj +aj aS aT aT @@ -34916,8 +33973,8 @@ aT aT aT aT -aT -aT +xH +ww bo bd bo @@ -34941,166 +33998,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(136,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +(132,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -35128,7 +34175,7 @@ ae ah al aj -aj +Nz aj aC ah @@ -35152,6 +34199,16 @@ aj aj aj aj +aj +aj +aj +aj +aj +aj +aj +aj +aj +aG aS bx bx @@ -35173,8 +34230,8 @@ aT aR aT aR -aT -aT +eV +EE bo be bo @@ -35198,178 +34255,168 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(137,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +(133,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab ab ab ab @@ -35409,6 +34456,16 @@ aG aG aG aG +aG +aG +aG +aG +aG +aG +aG +aG +aG +aG aS bu bu @@ -35430,8 +34487,8 @@ aT aT aT aT -aT -aT +xH +nj bo bf bo @@ -35455,178 +34512,168 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(138,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +(134,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab ab ab ab @@ -35665,7 +34712,17 @@ aF aF aF aF -aG +aF +aF +aF +aF +aF +aF +aF +aF +aF +aF +ab aS ah ah @@ -35687,8 +34744,8 @@ aT aT aT aT -aT -aT +nj +nj ah ah ah @@ -35712,181 +34769,181 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(139,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +(135,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +aa +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab ab ab ab @@ -35969,181 +35026,181 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(140,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +(136,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab ab ab ab @@ -36226,181 +35283,181 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(141,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +(137,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab ab ab ab @@ -36483,181 +35540,181 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(142,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +(138,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab ab ab ab @@ -36740,166 +35797,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(143,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +(139,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -36951,6 +35998,16 @@ ab ab ab ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab aF ab ab @@ -36997,181 +36054,181 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(144,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +(140,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab ab ab ab @@ -37254,181 +36311,181 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} -(145,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +(141,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab ab ab ab @@ -37511,6 +36568,670 @@ aa aa aa aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +"} +(142,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +aF +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +"} +(143,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +aF +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +"} +(144,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -37536,7 +37257,58 @@ aa aa aa aa +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab aa +aF +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab aa aa aa @@ -37567,6 +37339,156 @@ aa aa aa aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +"} +(145,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -37614,156 +37536,216 @@ aa aa aa aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (146,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -aF -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -37871,156 +37853,156 @@ aa aa aa aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (147,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -aF -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -38128,156 +38110,156 @@ aa aa aa aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (148,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -aF -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -38385,8 +38367,156 @@ aa aa aa aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (149,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -38494,156 +38624,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (150,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -38751,156 +38881,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (151,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -39008,156 +39138,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (152,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -39265,156 +39395,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (153,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -39522,156 +39652,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (154,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -39779,156 +39909,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (155,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -40036,156 +40166,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (156,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -40293,156 +40423,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (157,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -40550,156 +40680,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (158,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -40807,156 +40937,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (159,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -41064,156 +41194,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (160,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -41321,156 +41451,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (161,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -41578,156 +41708,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (162,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -41835,156 +41965,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (163,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -42092,156 +42222,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (164,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -42349,156 +42479,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (165,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -42606,156 +42736,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (166,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -42863,156 +42993,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (167,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -43120,156 +43250,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (168,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -43377,156 +43507,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (169,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -43634,156 +43764,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (170,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -43891,156 +44021,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (171,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -44148,156 +44278,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (172,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -44405,156 +44535,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (173,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -44662,156 +44792,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (174,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -44919,156 +45049,156 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (175,1,1) = {" +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT aa aa aa @@ -45176,20712 +45306,20646 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (176,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +WT +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (177,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (178,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (179,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (180,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (181,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (182,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (183,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (184,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (185,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (186,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (187,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (188,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (189,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (190,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (191,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (192,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (193,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (194,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (195,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (196,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (197,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (198,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (199,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (200,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (201,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (202,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (203,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (204,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (205,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (206,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (207,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (208,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (209,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (210,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (211,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (212,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (213,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (214,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (215,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (216,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (217,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (218,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (219,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (220,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (221,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (222,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (223,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (224,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (225,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (226,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (227,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (228,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (229,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (230,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (231,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (232,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (233,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (234,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (235,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (236,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (237,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (238,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (239,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (240,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (241,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (242,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (243,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (244,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (245,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (246,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (247,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (248,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (249,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (250,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (251,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (252,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (253,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (254,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} (255,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb +zb "} diff --git a/code/__DEFINES/DNA.dm b/code/__DEFINES/DNA.dm index 4ed099d9e2..60fb49f780 100644 --- a/code/__DEFINES/DNA.dm +++ b/code/__DEFINES/DNA.dm @@ -98,7 +98,16 @@ #define DRINKSBLOOD 15 #define NOEYES 16 #define MARKINGS 17 +#define MUTCOLORS2 18 +#define MUTCOLORS3 19 +#define NOAROUSAL 20 //Stops all arousal effects +#define NOGENITALS 21 //Cannot create, use, or otherwise have genitals +#define MATRIXED 22 //if icon is color matrix'd +#define SKINTONE 23 //uses skin tones +#define HORNCOLOR 24 +#define WINGCOLOR 25 +//organ slots #define ORGAN_SLOT_BRAIN "brain" #define ORGAN_SLOT_APPENDIX "appendix" #define ORGAN_SLOT_RIGHT_ARM_AUG "r_arm_device" @@ -122,3 +131,8 @@ #define ORGAN_SLOT_BRAIN_ANTISTUN "brain_antistun" #define ORGAN_SLOT_TAIL "tail" #define ORGAN_SLOT_PENIS "penis" + +////organ defines +#define STANDARD_ORGAN_THRESHOLD 100 +#define STANDARD_ORGAN_HEALING 0.001 +#define STANDARD_ORGAN_DECAY 0.00222 //designed to fail organs when left to decay for ~15 minutes \ No newline at end of file diff --git a/code/__DEFINES/access.dm b/code/__DEFINES/access.dm index c9d545fc03..c2021a86f2 100644 --- a/code/__DEFINES/access.dm +++ b/code/__DEFINES/access.dm @@ -6,7 +6,7 @@ #define ACCESS_MORGUE 6 #define ACCESS_TOX 7 //R&D department, R&D console, burn chamber on some maps #define ACCESS_TOX_STORAGE 8 //Toxins storage, burn chamber on some maps -#define ACCESS_GENETICS 9 +#define ACCESS_GENETICS 9 #define ACCESS_ENGINE 10 //Engineering area, power monitor, power flow control console #define ACCESS_ENGINE_EQUIP 11 //APCs, EngiVend/YouTool, engineering equipment lockers #define ACCESS_MAINT_TUNNELS 12 @@ -64,6 +64,8 @@ #define ACCESS_WEAPONS 66 //Weapon authorization for secbots #define ACCESS_NETWORK 67 //NTnet diagnostics/monitoring software #define ACCESS_CLONING 68 //Cloning room and clone pod ejection +#define ACCESS_ENTER_GENPOP 69 +#define ACCESS_LEAVE_GENPOP 70 //BEGIN CENTCOM ACCESS /*Should leave plenty of room if we need to add more access levels. diff --git a/code/__DEFINES/admin.dm b/code/__DEFINES/admin.dm index fb42bc46c0..b875998f0a 100644 --- a/code/__DEFINES/admin.dm +++ b/code/__DEFINES/admin.dm @@ -81,3 +81,10 @@ #define SPAM_TRIGGER_WARNING 5 //Number of identical messages required before the spam-prevention will warn you to stfu #define SPAM_TRIGGER_AUTOMUTE 10 //Number of identical messages required before the spam-prevention will automute you + +///Max length of a keypress command before it's considered to be a forged packet/bogus command +#define MAX_KEYPRESS_COMMANDLENGTH 16 +///Max amount of keypress messages per second over two seconds before client is autokicked +#define MAX_KEYPRESS_AUTOKICK 100 +///Length of held key rolling buffer +#define HELD_KEY_BUFFER_LENGTH 15 diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm index e35defd485..b2f05fd5f8 100644 --- a/code/__DEFINES/antagonists.dm +++ b/code/__DEFINES/antagonists.dm @@ -38,5 +38,5 @@ //Gangshit #define NOT_DOMINATING -1 -#define MAX_LEADERS_GANG 3 +#define MAX_LEADERS_GANG 4 #define INITIAL_DOM_ATTEMPTS 3 diff --git a/code/__DEFINES/atom_hud.dm b/code/__DEFINES/atom_hud.dm index 4fd1669771..0e4f0f3a6e 100644 --- a/code/__DEFINES/atom_hud.dm +++ b/code/__DEFINES/atom_hud.dm @@ -23,8 +23,9 @@ #define AI_DETECT_HUD "19" #define NANITE_HUD "20" #define DIAG_NANITE_FULL_HUD "21" +#define RAD_HUD "22" //radation alerts for medical huds //for antag huds. these are used at the /mob level -#define ANTAG_HUD "22" +#define ANTAG_HUD "23" //by default everything in the hud_list of an atom is an image //a value in hud_list with one of these will change that behavior diff --git a/code/__DEFINES/citadel_defines.dm b/code/__DEFINES/citadel_defines.dm index 81b12c46e3..d966c73d23 100644 --- a/code/__DEFINES/citadel_defines.dm +++ b/code/__DEFINES/citadel_defines.dm @@ -40,7 +40,7 @@ #define BALLS_SACK_SIZE_DEF 8 #define BALLS_SACK_SIZE_MAX 40 -#define CUM_RATE 5 +#define CUM_RATE 0.035 #define CUM_RATE_MULT 1 #define CUM_EFFICIENCY 1//amount of nutrition required per life() @@ -89,17 +89,6 @@ //Damage stuffs #define AROUSAL "arousal" -//DNA stuffs. Remember to change this if upstream adds more snowflake options - - -//Species stuffs. Remember to change this if upstream updates species flags -#define MUTCOLORS2 35 -#define MUTCOLORS3 36 -#define NOAROUSAL 37 //Stops all arousal effects -#define NOGENITALS 38 //Cannot create, use, or otherwise have genitals -#define MATRIXED 39 //if icon is color matrix'd -#define SKINTONE 40 //uses skin tones - //Citadel istypes #define isgenital(A) (istype(A, /obj/item/organ/genital)) @@ -123,7 +112,6 @@ #define STAMINA_CRIT 140 //crit for stamina damage. forces a rest, and stops movement until stamina goes back to stamina softcrit #define STAMINA_SOFTCRIT_TRADITIONAL 0 //same as STAMINA_SOFTCRIT except for the more traditional health calculations #define STAMINA_CRIT_TRADITIONAL -40 //ditto, but for STAMINA_CRIT -#define MIN_MELEE_STAMCOST 1.25 //Minimum cost for swinging items around. Will be extra useful when stats and skills are introduced. #define CRAWLUNDER_DELAY 30 //Delay for crawling under a standing mob diff --git a/code/__DEFINES/clockcult.dm b/code/__DEFINES/clockcult.dm index 47b00e67f7..2f2f94413b 100644 --- a/code/__DEFINES/clockcult.dm +++ b/code/__DEFINES/clockcult.dm @@ -8,6 +8,7 @@ GLOBAL_VAR_INIT(clockwork_construction_value, 0) //The total value of all structures built by the clockwork cult GLOBAL_VAR_INIT(clockwork_vitality, 0) //How much Vitality is stored, total GLOBAL_VAR_INIT(clockwork_power, 0) //How many watts of power are globally available to the clockwork cult +GLOBAL_VAR_INIT(neovgre_exists, 0) //Does neovgre exist? GLOBAL_LIST_EMPTY(all_clockwork_objects) //All clockwork items, structures, and effects in existence GLOBAL_LIST_EMPTY(all_clockwork_mobs) //All clockwork SERVANTS (not creatures) in existence diff --git a/code/__DEFINES/colors.dm b/code/__DEFINES/colors.dm index 06c3c352ca..cc2cd8834a 100644 --- a/code/__DEFINES/colors.dm +++ b/code/__DEFINES/colors.dm @@ -4,15 +4,15 @@ #define COLOR_INPUT_ENABLED "#D3B5B5" #define COLOR_DARKMODE_INFO_BUTTONS_BG "#40628A" -#define COLOR_DARKMODE_ISSUE_BUTTON_BG "#ce4242" -#define COLOR_DARKMODE_BACKGROUND "#202020" -#define COLOR_DARKMODE_DARKBACKGROUND "#171717" -#define COLOR_DARKMODE_TEXT "#f0f0f0" +#define COLOR_DARKMODE_ISSUE_BUTTON_BG "#A92C2C" +#define COLOR_DARKMODE_BACKGROUND "#272727" +#define COLOR_DARKMODE_DARKBACKGROUND "#242424" +#define COLOR_DARKMODE_TEXT "#E0E0E0" -#define COLOR_WHITEMODE_INFO_BUTTONS_BG "#90b3dd" -#define COLOR_WHITEMODE_ISSUE_BUTTON_BG "#ef7f7f" -#define COLOR_WHITEMODE_BACKGROUND "#ffffff" -#define COLOR_WHITEMODE_DARKBACKGROUND "#eeeeee" +#define COLOR_WHITEMODE_INFO_BUTTONS_BG "#90B3DD" +#define COLOR_WHITEMODE_ISSUE_BUTTON_BG "#EF7F7F" +#define COLOR_WHITEMODE_BACKGROUND "#F0F0F0" +#define COLOR_WHITEMODE_DARKBACKGROUND "#E6E6E6" #define COLOR_WHITEMODE_TEXT "#000000" #define COLOR_FLOORTILE_GRAY "#8D8B8B" diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm index 7cab82149d..e31d2a278e 100644 --- a/code/__DEFINES/combat.dm +++ b/code/__DEFINES/combat.dm @@ -183,4 +183,16 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list( #define BODY_ZONE_PRECISE_R_FOOT "r_foot" //We will round to this value in damage calculations. -#define DAMAGE_PRECISION 0.1 \ No newline at end of file +#define DAMAGE_PRECISION 0.1 + +//items total mass, used to calculate their attacks' stamina costs. If not defined, the cost will be (w_class * 1.25) +#define TOTAL_MASS_TINY_ITEM 1.25 +#define TOTAL_MASS_SMALL_ITEM 2.5 +#define TOTAL_MASS_NORMAL_ITEM 3.75 +#define TOTAL_MASS_BULKY_ITEM 5 +#define TOTAL_MASS_HUGE_ITEM 6.25 +#define TOTAL_MASS_GIGANTIC_ITEM 7.5 + +#define TOTAL_MASS_HAND_REPLACEMENT 5 //standard punching stamina cost. most hand replacements are huge items anyway. +#define TOTAL_MASS_MEDIEVAL_WEAPON 3.6 //very, very generic average sword/warpick/etc. weight in pounds. +#define TOTAL_MASS_TOY_SWORD 1.5 diff --git a/code/__DEFINES/components.dm b/code/__DEFINES/components.dm index e01bf5669b..c2482f6fbf 100644 --- a/code/__DEFINES/components.dm +++ b/code/__DEFINES/components.dm @@ -24,7 +24,7 @@ // start global signals with "!", this used to be necessary but now it's just a formatting choice #define COMSIG_GLOB_NEW_Z "!new_z" //from base of datum/controller/subsystem/mapping/proc/add_new_zlevel(): (list/args) #define COMSIG_GLOB_VAR_EDIT "!var_edit" //called after a successful var edit somewhere in the world: (list/args) - +#define COMSIG_GLOB_LIVING_SAY_SPECIAL "!say_special" //global living say plug - use sparingly: (mob/speaker , message) ////////////////////////////////////////////////////////////////// // /datum signals @@ -121,8 +121,13 @@ #define COMSIG_MOVABLE_HEAR "movable_hear" //from base of atom/movable/Hear(): (message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode) #define COMSIG_MOVABLE_DISPOSING "movable_disposing" //called when the movable is added to a disposal holder object for disposal movement: (obj/structure/disposalholder/holder, obj/machinery/disposal/source) +// /mind signals +#define COMSIG_MIND_TRANSFER "mind_transfer" //from base of mind/transfer_to(): (new_character, old_character) + // /mob signals #define COMSIG_MOB_DEATH "mob_death" //from base of mob/death(): (gibbed) +#define COMSIG_MOB_GHOSTIZE "mob_ghostize" //from base of mob/Ghostize() (can_reenter_corpse) + #define COMPONENT_BLOCK_GHOSTING 1 #define COMSIG_MOB_ALLOWED "mob_allowed" //from base of obj/allowed(mob/M): (/obj) returns bool, if TRUE the mob has id access to the obj #define COMSIG_MOB_RECEIVE_MAGIC "mob_receive_magic" //from base of mob/anti_magic_check(): (magic, holy, protection_sources) #define COMPONENT_BLOCK_MAGIC 1 @@ -132,6 +137,7 @@ #define COMSIG_MOB_ITEM_AFTERATTACK "mob_item_afterattack" //from base of obj/item/afterattack(): (atom/target, mob/user, proximity_flag, click_parameters) #define COMSIG_MOB_ATTACK_RANGED "mob_attack_ranged" //from base of mob/RangedAttack(): (atom/A, params) #define COMSIG_MOB_THROW "mob_throw" //from base of /mob/throw_item(): (atom/target) +#define COMSIG_MOB_KEY_CHANGE "mob_key_change" //from base of /mob/transfer_ckey() #define COMSIG_MOB_UPDATE_SIGHT "mob_update_sight" //from base of /mob/update_sight(): () #define COMSIG_MOB_SAY "mob_say" // from /mob/living/say(): (proc args list) #define COMPONENT_UPPERCASE_SPEECH 1 @@ -159,6 +165,9 @@ #define COMSIG_OBJ_BREAK "obj_break" //from base of /obj/obj_break(): (damage_flag) #define COMSIG_OBJ_SETANCHORED "obj_setanchored" //called in /obj/structure/setAnchored(): (value) +// /machinery signals +#define COMSIG_MACHINE_EJECT_OCCUPANT "eject_occupant" //from base of obj/machinery/dropContents() (occupant) + // /obj/item signals #define COMSIG_ITEM_ATTACK "item_attack" //from base of obj/item/attack(): (/mob/living/target, /mob/living/user) #define COMSIG_ITEM_ATTACK_SELF "item_attack_self" //from base of obj/item/attack_self(): (/mob) @@ -188,6 +197,7 @@ #define COMPONENT_DELETE_OLD_IMPLANT 4 #define COMSIG_IMPLANT_EXISTING_UPLINK "implant_uplink_exists" //called on implants being implanted into someone with an uplink implant: (datum/component/uplink) //This uses all return values of COMSIG_IMPLANT_OTHER +#define COMSIG_IMPLANT_REMOVING "implant_removing" //from base of /obj/item/implant/proc/removed() (list/args) // /obj/item/pda signals #define COMSIG_PDA_CHANGE_RINGTONE "pda_change_ringtone" //called on pda when the user changes the ringtone: (mob/living/user, new_ringtone) @@ -221,6 +231,8 @@ //Mood #define COMSIG_ADD_MOOD_EVENT "add_mood" //Called when you send a mood event from anywhere in the code. #define COMSIG_CLEAR_MOOD_EVENT "clear_mood" //Called when you clear a mood event from anywhere in the code. +#define COMSIG_INCREASE_SANITY "decrease_sanity" //Called when you want to increase sanity from anywhere in the code. +#define COMSIG_DECREASE_SANITY "increase_sanity" //Same as above but to decrease sanity instead. //NTnet #define COMSIG_COMPONENT_NTNET_RECEIVE "ntnet_receive" //called on an object by its NTNET connection component on receive. (sending_id(number), sending_netname(text), data(datum/netdata)) diff --git a/code/__DEFINES/construction.dm b/code/__DEFINES/construction.dm index ee51fb6909..c394d003d8 100644 --- a/code/__DEFINES/construction.dm +++ b/code/__DEFINES/construction.dm @@ -109,3 +109,5 @@ #define RCD_AIRLOCK 2 #define RCD_DECONSTRUCT 3 #define RCD_WINDOWGRILLE 4 +#define RCD_MACHINE 8 +#define RCD_COMPUTER 16 \ No newline at end of file diff --git a/code/__DEFINES/donator_groupings.dm b/code/__DEFINES/donator_groupings.dm new file mode 100644 index 0000000000..4b210609f2 --- /dev/null +++ b/code/__DEFINES/donator_groupings.dm @@ -0,0 +1,18 @@ +#define DONATOR_GROUP_TIER_1_CONFIG_PATH /datum/config_entry/keyed_list/donator_group/tier_1_donators +#define DONATOR_GROUP_TIER_2_CONFIG_PATH /datum/config_entry/keyed_list/donator_group/tier_2_donators +#define DONATOR_GROUP_TIER_3_CONFIG_PATH /datum/config_entry/keyed_list/donator_group/tier_3_donators + +#define DONATOR_GROUP_TIER_1_CONFIG_SUBPATH keyed_list/donator_group/tier_1_donators +#define DONATOR_GROUP_TIER_2_CONFIG_SUBPATH keyed_list/donator_group/tier_2_donators +#define DONATOR_GROUP_TIER_3_CONFIG_SUBPATH keyed_list/donator_group/tier_3_donators + +#define TIER_1_DONATORS CONFIG_GET(DONATOR_GROUP_TIER_1_CONFIG_SUBPATH) +#define TIER_2_DONATORS CONFIG_GET(DONATOR_GROUP_TIER_2_CONFIG_SUBPATH) +#define TIER_3_DONATORS CONFIG_GET(DONATOR_GROUP_TIER_3_CONFIG_SUBPATH) + +//flags +#define DONATOR_GROUP_TIER_1 "T1" +#define DONATOR_GROUP_TIER_2 "T2" +#define DONATOR_GROUP_TIER_3 "T3" + +#define IS_CKEY_DONATOR_GROUP(ckey, groupid) is_donator_group(ckey, groupid) diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags.dm index d64fa30047..d9b30bf0e3 100644 --- a/code/__DEFINES/flags.dm +++ b/code/__DEFINES/flags.dm @@ -10,6 +10,8 @@ #define CHECK_BITFIELD(variable, flag) (variable & (flag)) #define TOGGLE_BITFIELD(variable, flag) (variable ^= (flag)) +#define CHECK_MULTIPLE_BITFIELDS(flagvar, flags) (((flagvar) & (flags)) == (flags)) + GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768)) // for /datum/var/datum_flags diff --git a/code/__DEFINES/inventory.dm b/code/__DEFINES/inventory.dm index 95a8a2c885..24d381d1a8 100644 --- a/code/__DEFINES/inventory.dm +++ b/code/__DEFINES/inventory.dm @@ -234,3 +234,6 @@ GLOBAL_LIST_INIT(security_wintercoat_allowed, typecacheof(list( /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman, /obj/item/toy))) + +//Internals checker +#define GET_INTERNAL_SLOTS(C) list(C.head, C.wear_mask) diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index 8ff40c3ef9..1709714904 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -50,15 +50,16 @@ #define isgolem(A) (is_species(A, /datum/species/golem)) #define islizard(A) (is_species(A, /datum/species/lizard)) #define isplasmaman(A) (is_species(A, /datum/species/plasmaman)) -#define ispodperson(A) (is_species(A, /datum/species/podperson)) +#define ispodperson(A) (is_species(A, /datum/species/pod)) #define isflyperson(A) (is_species(A, /datum/species/fly)) #define isjellyperson(A) (is_species(A, /datum/species/jelly)) #define isslimeperson(A) (is_species(A, /datum/species/jelly/slime)) #define isluminescent(A) (is_species(A, /datum/species/jelly/luminescent)) #define iszombie(A) (is_species(A, /datum/species/zombie)) -#define ismoth(A) (is_species(A, /datum/species/moth)) +#define ismoth(A) (is_species(A, /datum/species/insect)) #define ishumanbasic(A) (is_species(A, /datum/species/human)) #define iscatperson(A) (ishumanbasic(A) && istype(A.dna.species, /datum/species/human/felinid) ) +#define isdwarf(A) (is_species(A, /datum/species/dwarf)) //more carbon mobs #define ismonkey(A) (istype(A, /mob/living/carbon/monkey)) diff --git a/code/__DEFINES/jobs.dm b/code/__DEFINES/jobs.dm index dc4080a789..ed45da9923 100644 --- a/code/__DEFINES/jobs.dm +++ b/code/__DEFINES/jobs.dm @@ -48,3 +48,42 @@ #define JOB_UNAVAILABLE_PLAYTIME 3 #define JOB_UNAVAILABLE_ACCOUNTAGE 4 #define JOB_UNAVAILABLE_SLOTFULL 5 +#define JOB_UNAVAILABLE_SPECIESLOCK 6 + +#define DEFAULT_RELIGION "Christianity" +#define DEFAULT_DEITY "Space Jesus" + +#define JOB_DISPLAY_ORDER_DEFAULT 0 + +#define JOB_DISPLAY_ORDER_ASSISTANT 1 +#define JOB_DISPLAY_ORDER_CAPTAIN 2 +#define JOB_DISPLAY_ORDER_HEAD_OF_PERSONNEL 3 +#define JOB_DISPLAY_ORDER_BARTENDER 4 +#define JOB_DISPLAY_ORDER_COOK 5 +#define JOB_DISPLAY_ORDER_BOTANIST 6 +#define JOB_DISPLAY_ORDER_JANITOR 7 +#define JOB_DISPLAY_ORDER_CLOWN 8 +#define JOB_DISPLAY_ORDER_MIME 9 +#define JOB_DISPLAY_ORDER_CURATOR 10 +#define JOB_DISPLAY_ORDER_LAWYER 11 +#define JOB_DISPLAY_ORDER_CHAPLAIN 12 +#define JOB_DISPLAY_ORDER_QUARTERMASTER 13 +#define JOB_DISPLAY_ORDER_CARGO_TECHNICIAN 14 +#define JOB_DISPLAY_ORDER_SHAFT_MINER 15 +#define JOB_DISPLAY_ORDER_CHIEF_ENGINEER 16 +#define JOB_DISPLAY_ORDER_STATION_ENGINEER 17 +#define JOB_DISPLAY_ORDER_ATMOSPHERIC_TECHNICIAN 18 +#define JOB_DISPLAY_ORDER_CHIEF_MEDICAL_OFFICER 19 +#define JOB_DISPLAY_ORDER_MEDICAL_DOCTOR 20 +#define JOB_DISPLAY_ORDER_CHEMIST 21 +#define JOB_DISPLAY_ORDER_GENETICIST 22 +#define JOB_DISPLAY_ORDER_VIROLOGIST 23 +#define JOB_DISPLAY_ORDER_RESEARCH_DIRECTOR 24 +#define JOB_DISPLAY_ORDER_SCIENTIST 25 +#define JOB_DISPLAY_ORDER_ROBOTICIST 26 +#define JOB_DISPLAY_ORDER_HEAD_OF_SECURITY 27 +#define JOB_DISPLAY_ORDER_WARDEN 28 +#define JOB_DISPLAY_ORDER_DETECTIVE 29 +#define JOB_DISPLAY_ORDER_SECURITY_OFFICER 30 +#define JOB_DISPLAY_ORDER_AI 31 +#define JOB_DISPLAY_ORDER_CYBORG 32 diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers.dm index 8891c06f75..5e903997e4 100644 --- a/code/__DEFINES/layers.dm +++ b/code/__DEFINES/layers.dm @@ -39,6 +39,7 @@ #define DOOR_HELPER_LAYER 2.71 //keep this above OPEN_DOOR_LAYER #define PROJECTILE_HIT_THRESHHOLD_LAYER 2.75 //projectiles won't hit objects at or below this layer if possible #define TABLE_LAYER 2.8 +#define TRAY_LAYER 2.85 #define BELOW_OBJ_LAYER 2.9 #define LOW_ITEM_LAYER 2.95 //#define OBJ_LAYER 3 //For easy recordkeeping; this is a byond define diff --git a/code/__DEFINES/logging.dm b/code/__DEFINES/logging.dm index 8234059a36..fe50319295 100644 --- a/code/__DEFINES/logging.dm +++ b/code/__DEFINES/logging.dm @@ -16,6 +16,7 @@ #define INVESTIGATE_EXONET "exonet" #define INVESTIGATE_NANITES "nanites" #define INVESTIGATE_CIRCUIT "circuit" +#define INVESTIGATE_FERMICHEM "fermichem" #define INVESTIGATE_RCD "rcd" // Logging types for log_message() @@ -34,6 +35,7 @@ #define LOG_GAME (1 << 12) #define LOG_ADMIN_PRIVATE (1 << 13) #define LOG_ASAY (1 << 14) +#define LOG_VIRUS (1 << 15) //Individual logging panel pages #define INDIVIDUAL_ATTACK_LOG (LOG_ATTACK) diff --git a/code/__DEFINES/maths.dm b/code/__DEFINES/maths.dm index d344f7f010..5bce51293f 100644 --- a/code/__DEFINES/maths.dm +++ b/code/__DEFINES/maths.dm @@ -201,4 +201,10 @@ return list(region_x1 & region_x2, region_y1 & region_y2) +#define EXP_DISTRIBUTION(desired_mean) ( -(1/(1/desired_mean)) * log(rand(1, 1000) * 0.001) ) + +#define LORENTZ_DISTRIBUTION(x, s) ( s*TAN(TODEGREES(PI*(rand()-0.5))) + x ) +#define LORENTZ_CUMULATIVE_DISTRIBUTION(x, y, s) ( (1/PI)*TORADIANS(arctan((x-y)/s)) + 1/2 ) + +#define RULE_OF_THREE(a, b, x) ((a*x)/b) // ) diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index 2ba1563001..bccf1f28dd 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -57,7 +57,7 @@ Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a s #define BODYPARTS_LAYER 28 //Initially "AUGMENTS", this was repurposed to be a catch-all bodyparts flag #define MARKING_LAYER 27 //Matrixed body markings because clashing with snouts? #define BODY_ADJ_LAYER 26 //certain mutantrace features (snout, body markings) that must appear above the body parts -#define GENITALS_ADJ_LAYER 25 +#define GENITALS_FRONT_LAYER 25 //Draws some genitalia above clothes and the TAUR body if need be. #define BODY_LAYER 24 //underwear, undershirts, socks, eyes, lips(makeup) #define FRONT_MUTATIONS_LAYER 23 //mutations that should appear above body, body_adj and bodyparts layer (e.g. laser eyes) #define DAMAGE_LAYER 22 //damage indicators (cuts and burns) @@ -69,7 +69,6 @@ Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a s #define EARS_LAYER 17 #define BODY_TAUR_LAYER 16 #define SUIT_LAYER 15 -#define GENITALS_FRONT_LAYER 14 //Draws some genitalia above clothes and the TAUR body if need be. #define GLASSES_LAYER 13 #define BELT_LAYER 12 //Possible make this an overlay of somethign required to wear a belt? #define SUIT_STORE_LAYER 11 @@ -83,7 +82,7 @@ Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a s #define HANDS_LAYER 3 #define BODY_FRONT_LAYER 2 #define FIRE_LAYER 1 //If you're on fire -#define TOTAL_LAYERS 31 //KEEP THIS UP-TO-DATE OR SHIT WILL BREAK ;_; +#define TOTAL_LAYERS 30 //KEEP THIS UP-TO-DATE OR SHIT WILL BREAK ;_; //Human Overlay Index Shortcuts for alternate_worn_layer, layers //Because I *KNOW* somebody will think layer+1 means "above" @@ -315,7 +314,7 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S #define MAP_MAXZ 6 // Defib stats -#define DEFIB_TIME_LIMIT 120 +#define DEFIB_TIME_LIMIT 1500 #define DEFIB_TIME_LOSS 60 // Diagonal movement @@ -473,6 +472,9 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S #define EGG_LAYING_MESSAGES list("lays an egg.","squats down and croons.","begins making a huge racket.","begins clucking raucously.") +// list of all null rod weapons +#define HOLY_WEAPONS /obj/item/nullrod, /obj/item/twohanded/dualsaber/hypereutactic/chaplain, /obj/item/gun/energy/laser/redtag/hitscan/chaplain, /obj/item/multitool/chaplain, /obj/item/melee/baseball_bat/chaplain + // Used by PDA and cartridge code to reduce repetitiveness of spritesheets #define PDAIMG(what) {""} @@ -496,4 +498,7 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S #define PREF_SAVELOAD_COOLDOWN 5 #define VOMIT_TOXIC 1 -#define VOMIT_PURPLE 2 \ No newline at end of file +#define VOMIT_PURPLE 2 + +//Misc text define. Does 4 spaces. Used as a makeshift tabulator. +#define FOURSPACES "    " diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index 1d1dda6d99..5bd0ee5b3b 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -116,6 +116,7 @@ #define BIOWARE_GENERIC "generic" #define BIOWARE_NERVES "nerves" #define BIOWARE_CIRCULATION "circulation" +#define BIOWARE_LIGAMENTS "ligaments" //Health hud screws for carbon mobs #define SCREWYHUD_NONE 0 @@ -203,8 +204,6 @@ #define MAX_CHICKENS 50 -#define UNHEALING_EAR_DAMAGE 100 - #define INCORPOREAL_MOVE_BASIC 1 #define INCORPOREAL_MOVE_SHADOW 2 // leaves a trail of shadows @@ -233,11 +232,15 @@ #define OFFSET_S_STORE "s_store" #define OFFSET_FACEMASK "mask" #define OFFSET_HEAD "head" -#define OFFSET_FACE "face" +#define OFFSET_EYES "eyes" +#define OFFSET_LIPS "lips" #define OFFSET_BELT "belt" #define OFFSET_BACK "back" #define OFFSET_SUIT "suit" #define OFFSET_NECK "neck" +#define OFFSET_HAIR "hair" +#define OFFSET_FHAIR "fhair" +#define OFFSET_MUTPARTS "mutantparts" //MINOR TWEAKS/MISC #define AGE_MIN 18 //youngest a character can be //CITADEL EDIT - 17 --> 18 @@ -256,6 +259,9 @@ #define MAX_QUIRKS 6 //The maximum amount of quirks one character can have at roundstart +#define MAX_REVIVE_FIRE_DAMAGE 180 +#define MAX_REVIVE_BRUTE_DAMAGE 180 + // AI Toggles #define AI_CAMERA_LUMINOSITY 5 #define AI_VOX // Comment out if you don't want VOX to be enabled and have players download the voice sounds. @@ -264,3 +270,6 @@ #define BODYPART_LIFE_UPDATE_HEALTH (1<<0) #define HUMAN_FIRE_STACK_ICON_NUM 3 + +#define PULL_PRONE_SLOWDOWN 0.6 +#define HUMAN_CARRY_SLOWDOWN 0 \ No newline at end of file diff --git a/code/__DEFINES/movespeed_modification.dm b/code/__DEFINES/movespeed_modification.dm index 9f8d310193..12a3c331ec 100644 --- a/code/__DEFINES/movespeed_modification.dm +++ b/code/__DEFINES/movespeed_modification.dm @@ -28,4 +28,11 @@ #define MOVESPEED_ID_SIMPLEMOB_VARSPEED "SIMPLEMOB_VARSPEED_MODIFIER" #define MOVESPEED_ID_ADMIN_VAREDIT "ADMIN_VAREDIT_MODIFIER" -#define MOVESPEED_ID_PAI_SPACEWALK_SPEEDMOD "PAI_SPACEWALK_MODIFIER" \ No newline at end of file +#define MOVESPEED_ID_PAI_SPACEWALK_SPEEDMOD "PAI_SPACEWALK_MODIFIER" + +#define MOVESPEED_ID_SANITY "MOOD_SANITY" + +#define MOVESPEED_ID_PRONE_DRAGGING "PRONE_DRAG" +#define MOVESPEED_ID_HUMAN_CARRYING "HUMAN_CARRY" + +#define MOVESPEED_ID_TASED_STATUS "TASED" \ No newline at end of file diff --git a/code/__DEFINES/obj_flags.dm b/code/__DEFINES/obj_flags.dm index 5c21fbbc71..1917d73a1b 100644 --- a/code/__DEFINES/obj_flags.dm +++ b/code/__DEFINES/obj_flags.dm @@ -10,6 +10,7 @@ #define UNIQUE_RENAME (1<<6) // can you customize the description/name of the thing? #define USES_TGUI (1<<7) //put on things that use tgui on ui_interact instead of custom/old UI. #define FROZEN (1<<8) +#define SHOVABLE_ONTO (1<<9) //called on turf.shove_act() to consider whether an object should have a niche effect (defined in their own shove_act()) when someone is pushed onto it, or do a sanity CanPass() check. // If you add new ones, be sure to add them to /obj/Initialize as well for complete mapping support @@ -33,8 +34,17 @@ #define LAVAPROTECT (1<<0) #define STOPSPRESSUREDAMAGE (1<<1) //SUIT and HEAD items which stop pressure damage. To stop you taking all pressure damage you must have both a suit and head item with this flag. #define BLOCK_GAS_SMOKE_EFFECT (1<<2) // blocks the effect that chemical clouds would have on a mob --glasses, mask and helmets ONLY! -#define MASKINTERNALS (1<<3) // mask allows internals +#define ALLOWINTERNALS (1<<3) // mask allows internals #define NOSLIP (1<<4) //prevents from slipping on wet floors, in space etc #define THICKMATERIAL (1<<5) //prevents syringes, parapens and hypos if the external suit or helmet (if targeting head) has this flag. Example: space suits, biosuit, bombsuits, thick suits that cover your body. #define VOICEBOX_TOGGLABLE (1<<6) // The voicebox in this clothing can be toggled. #define VOICEBOX_DISABLED (1<<7) // The voicebox is currently turned off. + +// Flags for the organ_flags var on /obj/item/organ + +#define ORGAN_SYNTHETIC (1<<0) //Synthetic organs, or cybernetic organs. Reacts to EMPs and don't deteriorate or heal +#define ORGAN_FROZEN (1<<1) //Frozen organs, don't deteriorate +#define ORGAN_FAILING (1<<2) //Failing organs perform damaging effects until replaced or fixed +#define ORGAN_EXTERNAL (1<<3) //Was this organ implanted/inserted/etc, if true will not be removed during species change. +#define ORGAN_VITAL (1<<4) //Currently only the brain +#define ORGAN_NO_SPOIL (1<<5) //Do not spoil under any circumstances diff --git a/code/__DEFINES/preferences.dm b/code/__DEFINES/preferences.dm index 02f151dcd9..0992b2e586 100644 --- a/code/__DEFINES/preferences.dm +++ b/code/__DEFINES/preferences.dm @@ -69,4 +69,9 @@ //Flags in the players table in the db #define DB_FLAG_EXEMPT 1 -#define DEFAULT_CYBORG_NAME "Default Cyborg Name" \ No newline at end of file +#define DEFAULT_CYBORG_NAME "Default Cyborg Name" + +//Job preferences levels +#define JP_LOW 1 +#define JP_MEDIUM 2 +#define JP_HIGH 3 diff --git a/code/__DEFINES/reactions.dm b/code/__DEFINES/reactions.dm index 1c36120a0c..9579571174 100644 --- a/code/__DEFINES/reactions.dm +++ b/code/__DEFINES/reactions.dm @@ -25,46 +25,20 @@ #define NOBLIUM_FORMATION_ENERGY 2e9 //1 Mole of Noblium takes the planck energy to condense. //Research point amounts #define NOBLIUM_RESEARCH_AMOUNT 1000 -#define BZ_RESEARCH_AMOUNT 150 +#define BZ_RESEARCH_SCALE 4 +#define BZ_RESEARCH_MAX_AMOUNT 400 #define MIASMA_RESEARCH_AMOUNT 160 #define STIMULUM_RESEARCH_AMOUNT 50 //Plasma fusion properties #define FUSION_ENERGY_THRESHOLD 3e9 //Amount of energy it takes to start a fusion reaction -#define FUSION_TEMPERATURE_THRESHOLD 1000 //Temperature required to start a fusion reaction #define FUSION_MOLE_THRESHOLD 250 //Mole count required (tritium/plasma) to start a fusion reaction -#define FUSION_RELEASE_ENERGY_SUPER 3e9 //Amount of energy released in the fusion process, super tier -#define FUSION_RELEASE_ENERGY_HIGH 1e9 //Amount of energy released in the fusion process, high tier -#define FUSION_RELEASE_ENERGY_MID 5e8 //Amount of energy released in the fusion process, mid tier -#define FUSION_RELEASE_ENERGY_LOW 1e8 //Amount of energy released in the fusion process, low tier -#define FUSION_MEDIATION_FACTOR 80 //Arbitrary -#define FUSION_SUPER_TIER_THRESHOLD 50 //anything above this is super tier -#define FUSION_HIGH_TIER_THRESHOLD 20 //anything above this and below 50 is high tier -#define FUSION_MID_TIER_THRESHOLD 5 //anything above this and below 20 is mid tier - below this is low tier, but that doesnt need a define -#define FUSION_ENERGY_DIVISOR_SUPER 25 //power_ratio is divided by this during energy calculations -#define FUSION_ENERGY_DIVISOR_HIGH 20 -#define FUSION_ENERGY_DIVISOR_MID 10 -#define FUSION_ENERGY_DIVISOR_LOW 2 -#define FUSION_GAS_CREATION_FACTOR_TRITIUM 0.40 //trit - one gas rather than two, so think about that when calculating stuff - 40% in total -#define FUSION_GAS_CREATION_FACTOR_STIM 0.05 //stim percentage creation from high tier - 5%, 60% in total with pluox -#define FUSION_GAS_CREATION_FACTOR_PLUOX 0.55 //pluox percentage creation from high tier - 55%, 60% in total with stim -#define FUSION_GAS_CREATION_FACTOR_NITRYL 0.20 //nitryl and N2O - 80% in total -#define FUSION_GAS_CREATION_FACTOR_N2O 0.60 //nitryl and N2O - 80% in total -#define FUSION_GAS_CREATION_FACTOR_BZ 0.05 //BZ - 5% - 90% in total with CO2 -#define FUSION_GAS_CREATION_FACTOR_CO2 0.85 //CO2 - 85% - 90% in total with BZ -#define FUSION_MID_TIER_RAD_PROB_FACTOR 2 //probability of radpulse is power ratio * this for whatever tier -#define FUSION_LOW_TIER_RAD_PROB_FACTOR 5 -#define FUSION_EFFICIENCY_BASE 60 //used in the fusion efficiency calculations -#define FUSION_EFFICIENCY_DIVISOR 0.6 //ditto -#define FUSION_RADIATION_FACTOR 15000 //horizontal asymptote -#define FUSION_RADIATION_CONSTANT 30 //equation is form of (ax) / (x + b), where a = radiation factor and b = radiation constant and x = power ratio (https://www.desmos.com/calculator/4i1f296phl) -#define FUSION_ZAP_POWER_ASYMPTOTE 50000 //maximum value - not enough to instacrit but it'll still hurt like shit -#define FUSION_ZAP_POWER_CONSTANT 75 //equation is of from [ax / (x + b)] + c, where a = zap power asymptote, b = zap power constant, c = zap power base and x = power ratio -#define FUSION_ZAP_POWER_BASE 1000 //(https://www.desmos.com/calculator/vvbmhf4unm) -#define FUSION_ZAP_RANGE_SUPER 9 //range of the tesla zaps that occur from fusion -#define FUSION_ZAP_RANGE_HIGH 7 -#define FUSION_ZAP_RANGE_MID 5 -#define FUSION_ZAP_RANGE_LOW 3 -#define FUSION_PARTICLE_FACTOR_SUPER 4 //# of particles fired out is equal to rand(3,6) * this for whatever tier -#define FUSION_PARTICLE_FACTOR_HIGH 3 -#define FUSION_PARTICLE_FACTOR_MID 2 -#define FUSION_PARTICLE_FACTOR_LOW 1 +#define FUSION_TRITIUM_CONVERSION_COEFFICIENT (1e-10) +#define INSTABILITY_GAS_POWER_FACTOR 0.003 +#define FUSION_TRITIUM_MOLES_USED 1 +#define PLASMA_BINDING_ENERGY 20000000 +#define TOROID_VOLUME_BREAKEVEN 1000 +#define FUSION_TEMPERATURE_THRESHOLD 10000 +#define PARTICLE_CHANCE_CONSTANT (-20000000) +#define FUSION_RAD_MAX 2000 +#define FUSION_RAD_COEFFICIENT (-1000) +#define FUSION_INSTABILITY_ENDOTHERMALITY 2 diff --git a/code/__DEFINES/reagents.dm b/code/__DEFINES/reagents.dm index c3682d905d..36ea64de2c 100644 --- a/code/__DEFINES/reagents.dm +++ b/code/__DEFINES/reagents.dm @@ -2,7 +2,13 @@ #define LIQUID 2 #define GAS 3 -// reagents_flags defines +//reagents reaction var defines +#define REAGENT_NORMAL_PH 7.000 +#define REAGENT_PH_ACCURACY 0.001 +#define REAGENT_PURITY_ACCURACY 0.001 +#define DEFAULT_SPECIFIC_HEAT 200 + +// container_type defines #define INJECTABLE (1<<0) // Makes it possible to add reagents through droppers and syringes. #define DRAWABLE (1<<1) // Makes it possible to remove reagents through syringes. @@ -28,3 +34,17 @@ #define DEL_REAGENT 1 // reagent deleted (fully cleared) #define ADD_REAGENT 2 // reagent added #define REM_REAGENT 3 // reagent removed (may still exist) + +//reagent bitflags, used for altering how they works +#define REAGENT_DEAD_PROCESS (1<<0) //calls on_mob_dead() if present in a dead body +#define REAGENT_DONOTSPLIT (1<<1) //Do not split the chem at all during processing +#define REAGENT_ONLYINVERSE (1<<2) //Only invert chem, no splitting +#define REAGENT_ONMOBMERGE (1<<3) //Call on_mob_life proc when reagents are merging. +#define REAGENT_INVISIBLE (1<<4) //Doesn't appear on handheld health analyzers. +#define REAGENT_FORCEONNEW (1<<5) //Forces a on_new() call without a data overhead +#define REAGENT_SNEAKYNAME (1<<6) //When inverted, the inverted chem uses the name of the original chem +#define REAGENT_SPLITRETAINVOL (1<<7) //Retains initial volume of chem when splitting + +//Chemical reaction flags, for determining reaction specialties +#define REACTION_CLEAR_IMPURE (1<<0) //Convert into impure/pure on reaction completion +#define REACTION_CLEAR_INVERSE (1<<1) //Convert into inverse on reaction completion when purity is low enough diff --git a/code/__DEFINES/robots.dm b/code/__DEFINES/robots.dm index 0820d63247..a05e6f6160 100644 --- a/code/__DEFINES/robots.dm +++ b/code/__DEFINES/robots.dm @@ -50,3 +50,7 @@ #define ASSEMBLY_THIRD_STEP 2 #define ASSEMBLY_FOURTH_STEP 3 #define ASSEMBLY_FIFTH_STEP 4 + + +//Checks to determine borg availability depending on the server's config. These are defines in the interest of reducing copypasta +#define BORG_SEC_AVAILABLE (!CONFIG_GET(flag/disable_secborg) && GLOB.security_level >= CONFIG_GET(number/minimum_secborg_alert)) \ No newline at end of file diff --git a/code/__DEFINES/stat.dm b/code/__DEFINES/stat.dm index 1d3ea1347a..b975aa1f89 100644 --- a/code/__DEFINES/stat.dm +++ b/code/__DEFINES/stat.dm @@ -8,6 +8,9 @@ #define UNCONSCIOUS 2 #define DEAD 3 +//Maximum healthiness an individual can have +#define MAX_SATIETY 600 + // bitflags for machine stat variable #define BROKEN (1<<0) #define NOPOWER (1<<1) diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm index ffaaa04d0f..332d36f2f4 100644 --- a/code/__DEFINES/status_effects.dm +++ b/code/__DEFINES/status_effects.dm @@ -44,6 +44,10 @@ #define STATUS_EFFECT_SLEEPING /datum/status_effect/incapacitating/sleeping //the affected is asleep +#define STATUS_EFFECT_TASED /datum/status_effect/electrode //the affected has been tased, preventing fine muscle control + +#define STATUS_EFFECT_PACIFY /datum/status_effect/pacify //the affected is pacified, preventing direct hostile actions + #define STATUS_EFFECT_BELLIGERENT /datum/status_effect/belligerent //forces the affected to walk, doing damage if they try to run #define STATUS_EFFECT_GEISTRACKER /datum/status_effect/geis_tracker //if you're using geis, this tracks that and keeps you from using scripture diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 19d0540e0e..d4086bc4d9 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -83,7 +83,9 @@ #define INIT_ORDER_SHUTTLE -21 #define INIT_ORDER_MINOR_MAPPING -40 #define INIT_ORDER_PATH -50 -#define INIT_ORDER_PERSISTENCE -100 +#define INIT_ORDER_PERSISTENCE -95 +#define INIT_ORDER_CHAT -100 //Should be last to ensure chat remains smooth during init. + // Subsystem fire priority, from lowest to highest priority // If the subsystem isn't listed here it's either DEFAULT or PROCESS (if it's a processing subsystem child) @@ -93,6 +95,7 @@ #define FIRE_PRIORITY_SERVER_MAINT 10 #define FIRE_PRIORITY_RESEARCH 10 #define FIRE_PRIORITY_VIS 10 +#define FIRE_PRIORITY_VORE 10 #define FIRE_PRIORITY_GARBAGE 15 #define FIRE_PRIORITY_WET_FLOORS 20 #define FIRE_PRIORITY_AIR 20 @@ -113,6 +116,7 @@ #define FIRE_PRIORITY_MOBS 100 #define FIRE_PRIORITY_TGUI 110 #define FIRE_PRIORITY_TICKER 200 +#define FIRE_PRIORITY_CHAT 400 #define FIRE_PRIORITY_OVERLAYS 500 #define FIRE_PRIORITY_INPUT 1000 // This must always always be the max highest priority. Player input must never be lost. diff --git a/code/__DEFINES/time.dm b/code/__DEFINES/time.dm index c5d6f3051e..f13f13510b 100644 --- a/code/__DEFINES/time.dm +++ b/code/__DEFINES/time.dm @@ -31,4 +31,4 @@ When using time2text(), please use "DDD" to find the weekday. Refrain from using #define WORLDTIMEOFDAY2TEXT(format) GAMETIMESTAMP(format, world.timeofday) #define TIME_STAMP(format, showds) showds ? "[WORLDTIMEOFDAY2TEXT(format)]:[world.timeofday % 10]" : WORLDTIMEOFDAY2TEXT(format) #define STATION_TIME(display_only) ((((world.time - SSticker.round_start_time) * SSticker.station_time_rate_multiplier) + SSticker.gametime_offset) % 864000) - (display_only? GLOB.timezoneOffset : 0) -#define STATION_TIME_TIMESTAMP(format) time2text(STATION_TIME(TRUE), format) \ No newline at end of file +#define STATION_TIME_TIMESTAMP(format) time2text(STATION_TIME(TRUE), format) diff --git a/code/__DEFINES/tools.dm b/code/__DEFINES/tools.dm index 878d35608d..00e08129ae 100644 --- a/code/__DEFINES/tools.dm +++ b/code/__DEFINES/tools.dm @@ -8,6 +8,12 @@ #define TOOL_ANALYZER "analyzer" #define TOOL_MINING "mining" #define TOOL_SHOVEL "shovel" +#define TOOL_RETRACTOR "retractor" +#define TOOL_HEMOSTAT "hemostat" +#define TOOL_CAUTERY "cautery" +#define TOOL_DRILL "drill" +#define TOOL_SCALPEL "scalpel" +#define TOOL_SAW "saw" // If delay between the start and the end of tool operation is less than MIN_TOOL_SOUND_DELAY, diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index 7bcb4881f0..e22dcfbbe0 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -81,6 +81,7 @@ #define TRAIT_PUSHIMMUNE "push_immunity" #define TRAIT_SHOCKIMMUNE "shock_immunity" #define TRAIT_STABLEHEART "stable_heart" +#define TRAIT_STABLELIVER "stable_liver" #define TRAIT_RESISTHEAT "resist_heat" #define TRAIT_RESISTHEATHANDS "resist_heat_handsonly" //For when you want to be able to touch hot things, but still want fire to be an issue. #define TRAIT_RESISTCOLD "resist_cold" @@ -95,6 +96,8 @@ #define TRAIT_NOHUNGER "no_hunger" #define TRAIT_EASYDISMEMBER "easy_dismember" #define TRAIT_LIMBATTACHMENT "limb_attach" +#define TRAIT_NOLIMBDISABLE "no_limb_disable" +#define TRAIT_EASYLIMBDISABLE "easy_limb_disable" #define TRAIT_TOXINLOVER "toxinlover" #define TRAIT_NOBREATH "no_breath" #define TRAIT_ANTIMAGIC "anti_magic" @@ -108,6 +111,9 @@ #define TRAIT_NOHARDCRIT "nohardcrit" #define TRAIT_NOSOFTCRIT "nosoftcrit" #define TRAIT_MINDSHIELD "mindshield" +#define TRAIT_DISSECTED "dissected" +#define TRAIT_FEARLESS "fearless" +#define TRAIT_UNSTABLE "unstable" #define TRAIT_PARALYSIS_L_ARM "para-l-arm" //These are used for brain-based paralysis, where replacing the limb won't fix it #define TRAIT_PARALYSIS_R_ARM "para-r-arm" #define TRAIT_PARALYSIS_L_LEG "para-l-leg" @@ -116,6 +122,10 @@ #define TRAIT_LAW_ENFORCEMENT_METABOLISM "law-enforcement-metabolism" #define TRAIT_STRONG_GRABBER "strong_grabber" #define TRAIT_CALCIUM_HEALER "calcium_healer" +#define TRAIT_CAPTAIN_METABOLISM "captain-metabolism" +#define TRAIT_ABDUCTOR_TRAINING "abductor-training" +#define TRAIT_ABDUCTOR_SCIENTIST_TRAINING "abductor-scientist-training" +#define TRAIT_SURGEON "surgeon" //non-mob traits #define TRAIT_PARALYSIS "paralysis" //Used for limb-based paralysis, where replacing the limb will fix it @@ -128,6 +138,7 @@ #define TRAIT_HEAVY_SLEEPER "heavy_sleeper" #define TRAIT_NIGHT_VISION "night_vision" #define TRAIT_LIGHT_STEP "light_step" +#define TRAIT_SILENT_STEP "silent_step" #define TRAIT_SPEEDY_STEP "speedy_step" #define TRAIT_SPIRITUAL "spiritual" #define TRAIT_VORACIOUS "voracious" @@ -143,12 +154,15 @@ #define TRAIT_CROCRIN_IMMUNE "crocin_immune" #define TRAIT_NYMPHO "nymphomania" #define TRAIT_MASO "masochism" +#define TRAIT_HIGH_BLOOD "high_blood" +#define TRAIT_PHARMA "hepatic_pharmacokinesis" #define TRAIT_PARA "paraplegic" #define TRAIT_EMPATH "empath" #define TRAIT_FRIENDLY "friendly" #define TRAIT_ASSBLASTUSA "assblastusa" #define TRAIT_CULT_EYES "cult_eyes" + // common trait sources #define TRAIT_GENERIC "generic" #define EYE_DAMAGE "eye_damage" @@ -156,6 +170,7 @@ #define OBESITY "obesity" #define MAGIC_TRAIT "magic" #define TRAUMA_TRAIT "trauma" +#define DISEASE_TRAIT "disease" #define SPECIES_TRAIT "species" #define ORGAN_TRAIT "organ" #define JOB_TRAIT "job" @@ -169,6 +184,7 @@ // unique trait sources, still defines #define STATUE_MUTE "statue" +#define CLONING_POD_TRAIT "cloning-pod" #define CHANGELING_DRAIN "drain" #define CHANGELING_HIVEMIND_MUTE "ling_mute" #define ABYSSAL_GAZE_BLIND "abyssal_gaze" @@ -197,4 +213,5 @@ #define FLIGHTSUIT_TRAIT "flightsuit" #define LOCKED_HELMET_TRAIT "locked-helmet" #define NINJA_SUIT_TRAIT "ninja-suit" -#define ANTI_DROP_IMPLANT_TRAIT "anti-drop-implant" \ No newline at end of file +#define ANTI_DROP_IMPLANT_TRAIT "anti-drop-implant" +#define ABDUCTOR_ANTAGONIST "abductor-antagonist" \ No newline at end of file diff --git a/code/__DEFINES/voreconstants.dm b/code/__DEFINES/voreconstants.dm index 710b11ae16..9c91de0be2 100644 --- a/code/__DEFINES/voreconstants.dm +++ b/code/__DEFINES/voreconstants.dm @@ -20,7 +20,7 @@ GLOBAL_LIST_INIT(player_sizes_list, list("Macro" = SIZESCALE_HUGE, "Big" = SIZES // Edited to make the new travis check go away */ -GLOBAL_LIST_INIT(vore_sounds, list( +GLOBAL_LIST_INIT(pred_vore_sounds, list( "Gulp" = 'sound/vore/pred/swallow_01.ogg', "Swallow" = 'sound/vore/pred/swallow_02.ogg', "Insertion1" = 'sound/vore/pred/insertion_01.ogg', @@ -40,7 +40,27 @@ GLOBAL_LIST_INIT(vore_sounds, list( "None" = null )) -GLOBAL_LIST_INIT(release_sounds, list( +GLOBAL_LIST_INIT(prey_vore_sounds, list( + "Gulp" = 'sound/vore/prey/swallow_01.ogg', + "Swallow" = 'sound/vore/prey/swallow_02.ogg', + "Insertion1" = 'sound/vore/prey/insertion_01.ogg', + "Insertion2" = 'sound/vore/prey/insertion_02.ogg', + "Tauric Swallow" = 'sound/vore/prey/taurswallow.ogg', + "Stomach Move" = 'sound/vore/prey/stomachmove.ogg', + "Schlorp" = 'sound/vore/prey/schlorp.ogg', + "Squish1" = 'sound/vore/prey/squish_01.ogg', + "Squish2" = 'sound/vore/prey/squish_02.ogg', + "Squish3" = 'sound/vore/prey/squish_03.ogg', + "Squish4" = 'sound/vore/prey/squish_04.ogg', + "Rustle (cloth)" = 'sound/effects/rustle5.ogg', + "Rustle 2 (cloth)" = 'sound/effects/rustle2.ogg', + "Rustle 3 (cloth)" = 'sound/effects/rustle3.ogg', + "Rustle 4 (cloth)" = 'sound/effects/rustle4.ogg', + "Rustle 5 (cloth)" = 'sound/effects/rustle5.ogg', + "None" = null + )) + +GLOBAL_LIST_INIT(pred_release_sounds, list( "Rustle (cloth)" = 'sound/effects/rustle1.ogg', "Rustle 2 (cloth)" = 'sound/effects/rustle2.ogg', "Rustle 3 (cloth)" = 'sound/effects/rustle3.ogg', @@ -51,3 +71,15 @@ GLOBAL_LIST_INIT(release_sounds, list( "Splatter" = 'sound/effects/splat.ogg', "None" = null )) + +GLOBAL_LIST_INIT(prey_release_sounds, list( + "Rustle (cloth)" = 'sound/effects/rustle1.ogg', + "Rustle 2 (cloth)" = 'sound/effects/rustle2.ogg', + "Rustle 3 (cloth)" = 'sound/effects/rustle3.ogg', + "Rustle 4 (cloth)" = 'sound/effects/rustle4.ogg', + "Rustle 5 (cloth)" = 'sound/effects/rustle5.ogg', + "Stomach Move" = 'sound/vore/prey/stomachmove.ogg', + "Pred Escape" = 'sound/vore/prey/escape.ogg', + "Splatter" = 'sound/effects/splat.ogg', + "None" = null + )) diff --git a/code/__HELPERS/_cit_helpers.dm b/code/__HELPERS/_cit_helpers.dm index 668b151b6e..86d0a34e3e 100644 --- a/code/__HELPERS/_cit_helpers.dm +++ b/code/__HELPERS/_cit_helpers.dm @@ -58,6 +58,7 @@ GLOBAL_LIST_EMPTY(ipc_antennas_list) //Genitals and Arousal Lists GLOBAL_LIST_EMPTY(cock_shapes_list)//global_lists.dm for the list initializations //Now also _DATASTRUCTURES globals.dm GLOBAL_LIST_EMPTY(cock_shapes_icons) //Associated list for names->icon_states for cockshapes. +GLOBAL_LIST_EMPTY(gentlemans_organ_names) GLOBAL_LIST_EMPTY(balls_shapes_list) GLOBAL_LIST_EMPTY(balls_shapes_icons) GLOBAL_LIST_EMPTY(breasts_size_list) @@ -93,6 +94,12 @@ GLOBAL_LIST_INIT(dildo_colors, list(//mostly neon colors "Purple" = "#e300ff"//purple )) +GLOBAL_LIST_INIT(meat_types, list( + "Mammalian" = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/mammal, + "Aquatic" = /obj/item/reagent_containers/food/snacks/carpmeat/aquatic, + "Avian" = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/avian, + "Inesct" = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/insect)) + //Crew objective and miscreants stuff GLOBAL_VAR_INIT(miscreants_allowed, FALSE) diff --git a/code/__HELPERS/_logging.dm b/code/__HELPERS/_logging.dm index ac17df5773..c19a7a64b0 100644 --- a/code/__HELPERS/_logging.dm +++ b/code/__HELPERS/_logging.dm @@ -58,6 +58,10 @@ if (CONFIG_GET(flag/log_game)) WRITE_LOG(GLOB.world_game_log, "GAME: [text]") +/proc/log_virus(text) + if (CONFIG_GET(flag/log_virus)) + WRITE_LOG(GLOB.world_virus_log, "VIRUS: [text]") + /proc/log_access(text) if (CONFIG_GET(flag/log_access)) WRITE_LOG(GLOB.world_game_log, "ACCESS: [text]") diff --git a/code/__HELPERS/cmp.dm b/code/__HELPERS/cmp.dm index e09ebcb10c..37f36a7e0d 100644 --- a/code/__HELPERS/cmp.dm +++ b/code/__HELPERS/cmp.dm @@ -81,3 +81,6 @@ GLOBAL_VAR_INIT(cmp_field, "name") /proc/cmp_advdisease_resistance_asc(datum/disease/advance/A, datum/disease/advance/B) return A.totalResistance() - B.totalResistance() + +/proc/cmp_job_display_asc(datum/job/A, datum/job/B) + return A.display_order - B.display_order diff --git a/code/__HELPERS/donator_groupings.dm b/code/__HELPERS/donator_groupings.dm new file mode 100644 index 0000000000..bdff20553a --- /dev/null +++ b/code/__HELPERS/donator_groupings.dm @@ -0,0 +1,25 @@ +/* +Current specifications: + +Donator groups in __DEFINES/donator_groupings.dm, config entries in controllers/configuration/entries/donator.dm + +3 groups, Tier 1/2/3 +Each tier includes the one before it (ascending) +For fast lookups, this is generated using regenerate_donator_grouping_list() + +*/ + +/proc/is_donator_group(ckey, group) + ckey = ckey(ckey) //make sure it's ckey'd. + var/list/L = GLOB.donators_by_group[group] + return L && L.Find(ckey) + +/proc/regenerate_donator_grouping_list() + GLOB.donators_by_group = list() //reinit everything + var/list/donator_list = GLOB.donators_by_group //cache + var/list/tier_1 = TIER_1_DONATORS + donator_list[DONATOR_GROUP_TIER_1] = tier_1.Copy() //The .Copy() is to "decouple"/make a new list, rather than letting the global list impact the config list. + var/list/tier_2 = tier_1 + TIER_2_DONATORS //Using + on lists implies making new lists, so we don't need to manually Copy(). + donator_list[DONATOR_GROUP_TIER_2] = tier_2 + var/list/tier_3 = tier_2 + TIER_3_DONATORS + donator_list[DONATOR_GROUP_TIER_3] = tier_3 diff --git a/code/__HELPERS/files.dm b/code/__HELPERS/files.dm index 7f0b5a3c07..5271b407a5 100644 --- a/code/__HELPERS/files.dm +++ b/code/__HELPERS/files.dm @@ -3,7 +3,7 @@ for(var/file in args) src << browse_rsc(file) -/client/proc/browse_files(root="data/logs/", max_iterations=10, list/valid_extensions=list("txt","log","htm", "html")) +/client/proc/browse_files(root="data/logs/", max_iterations=10, list/valid_extensions=list("txt","log","htm", "html", "md")) var/path = root for(var/i=0, i[GLOB.round_id]" : GLOB.round_id - parts += "[GLOB.TAB]Round ID: [info]" + parts += "[FOURSPACES]Round ID: [info]" var/list/voting_results = SSvote.stored_gamemode_votes if(length(voting_results)) - parts += "[GLOB.TAB]Voting: " + parts += "[FOURSPACES]Voting: " var/total_score = 0 for(var/choice in voting_results) var/score = voting_results[choice] total_score += score - parts += "[GLOB.TAB][GLOB.TAB][choice]: [score]" + parts += "[FOURSPACES][FOURSPACES][choice]: [score]" - parts += "[GLOB.TAB]Shift Duration: [DisplayTimeText(world.time - SSticker.round_start_time)]" - parts += "[GLOB.TAB]Station Integrity: [mode.station_was_nuked ? "Destroyed" : "[popcount["station_integrity"]]%"]" + parts += "[FOURSPACES]Shift Duration: [DisplayTimeText(world.time - SSticker.round_start_time)]" + parts += "[FOURSPACES]Station Integrity: [mode.station_was_nuked ? "Destroyed" : "[popcount["station_integrity"]]%"]" var/total_players = GLOB.joined_player_list.len if(total_players) - parts+= "[GLOB.TAB]Total Population: [total_players]" + parts+= "[FOURSPACES]Total Population: [total_players]" if(station_evacuated) - parts += "
[GLOB.TAB]Evacuation Rate: [popcount[POPCOUNT_ESCAPEES]] ([PERCENT(popcount[POPCOUNT_ESCAPEES]/total_players)]%)" - parts += "[GLOB.TAB](on emergency shuttle): [popcount[POPCOUNT_SHUTTLE_ESCAPEES]] ([PERCENT(popcount[POPCOUNT_SHUTTLE_ESCAPEES]/total_players)]%)" - parts += "[GLOB.TAB]Survival Rate: [popcount[POPCOUNT_SURVIVORS]] ([PERCENT(popcount[POPCOUNT_SURVIVORS]/total_players)]%)" + parts += "
[FOURSPACES]Evacuation Rate: [popcount[POPCOUNT_ESCAPEES]] ([PERCENT(popcount[POPCOUNT_ESCAPEES]/total_players)]%)" + parts += "[FOURSPACES](on emergency shuttle): [popcount[POPCOUNT_SHUTTLE_ESCAPEES]] ([PERCENT(popcount[POPCOUNT_SHUTTLE_ESCAPEES]/total_players)]%)" + parts += "[FOURSPACES]Survival Rate: [popcount[POPCOUNT_SURVIVORS]] ([PERCENT(popcount[POPCOUNT_SURVIVORS]/total_players)]%)" if(SSblackbox.first_death) var/list/ded = SSblackbox.first_death if(ded.len) - parts += "[GLOB.TAB]First Death: [ded["name"]], [ded["role"]], at [ded["area"]]. Damage taken: [ded["damage"]].[ded["last_words"] ? " Their last words were: \"[ded["last_words"]]\"" : ""]" + parts += "[FOURSPACES]First Death: [ded["name"]], [ded["role"]], at [ded["area"]]. Damage taken: [ded["damage"]].[ded["last_words"] ? " Their last words were: \"[ded["last_words"]]\"" : ""]" //ignore this comment, it fixes the broken sytax parsing caused by the " above else - parts += "[GLOB.TAB]Nobody died this shift!" + parts += "[FOURSPACES]Nobody died this shift!" + if(istype(SSticker.mode, /datum/game_mode/dynamic)) + var/datum/game_mode/dynamic/mode = SSticker.mode + parts += "[FOURSPACES]Threat level: [mode.threat_level]" + parts += "[FOURSPACES]Threat left: [mode.threat]" + parts += "[FOURSPACES]Executed rules:" + for(var/datum/dynamic_ruleset/rule in mode.executed_rules) + parts += "[FOURSPACES][FOURSPACES][rule.ruletype] - [rule.name]: -[rule.cost] threat" return parts.Join("
") /client/proc/roundend_report_file() diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm index 1ee5ce986f..6908a5057f 100644 --- a/code/__HELPERS/text.dm +++ b/code/__HELPERS/text.dm @@ -791,3 +791,6 @@ GLOBAL_LIST_INIT(binary, list("0","1")) rearranged += cword message = "[prefix][jointext(rearranged," ")]" . = message + +#define is_alpha(X) ((text2ascii(X) <= 122) && (text2ascii(X) >= 97)) +#define is_digit(X) ((length(X) == 1) && (length(text2num(X)) == 1)) \ No newline at end of file diff --git a/code/__HELPERS/time.dm b/code/__HELPERS/time.dm index b28e7b5807..f0d5a7b252 100644 --- a/code/__HELPERS/time.dm +++ b/code/__HELPERS/time.dm @@ -73,3 +73,11 @@ GLOBAL_VAR_INIT(rollovercheck_last_timeofday, 0) /proc/daysSince(realtimev) return round((world.realtime - realtimev) / (24 HOURS)) + +/proc/worldtime2text() + return gameTimestamp("hh:mm:ss", world.time) + +/proc/gameTimestamp(format = "hh:mm:ss", wtime=null) + if(!wtime) + wtime = world.time + return time2text(wtime - GLOB.timezoneOffset, format) diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 7e078184b7..3c8d62ce3a 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -1487,6 +1487,7 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new) /obj/item/reagent_containers/food/snacks/grown/nettle, // base type /obj/item/reagent_containers/food/snacks/deepfryholder, /obj/item/reagent_containers/food/snacks/grown/shell, + /obj/item/reagent_containers/food/snacks/clothing, /obj/item/reagent_containers/food/snacks/store/bread ) blocked |= typesof(/obj/item/reagent_containers/food/snacks/customizable) diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index bb9fc98b8e..755105dc27 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -32,6 +32,7 @@ GLOBAL_LIST_INIT(bitfields, list( "UNIQUE_RENAME" = UNIQUE_RENAME, "USES_TGUI" = USES_TGUI, "FROZEN" = FROZEN, + "SHOVABLE_ONTO" = SHOVABLE_ONTO ), "datum_flags" = list( "DF_USE_TAG" = DF_USE_TAG, @@ -136,7 +137,7 @@ GLOBAL_LIST_INIT(bitfields, list( "LAVAPROTECT" = LAVAPROTECT, "STOPSPRESSUREDAMAGE" = STOPSPRESSUREDAMAGE, "BLOCK_GAS_SMOKE_EFFECT" = BLOCK_GAS_SMOKE_EFFECT, - "MASKINTERNALS" = MASKINTERNALS, + "ALLOWINTERNALS" = ALLOWINTERNALS, "NOSLIP" = NOSLIP, "THICKMATERIAL" = THICKMATERIAL, "VOICEBOX_TOGGLABLE" = VOICEBOX_TOGGLABLE, @@ -171,10 +172,32 @@ GLOBAL_LIST_INIT(bitfields, list( "rad_flags" = list( "RAD_PROTECT_CONTENTS" = RAD_PROTECT_CONTENTS, "RAD_NO_CONTAMINATE" = RAD_NO_CONTAMINATE, - ), + ), "disease_flags" = list( "CURABLE" = CURABLE, "CAN_CARRY" = CAN_CARRY, "CAN_RESIST" = CAN_RESIST - ), - )) \ No newline at end of file + ), + "chemical_flags" = list( + "REAGENT_DEAD_PROCESS" = REAGENT_DEAD_PROCESS, + "REAGENT_DONOTSPLIT" = REAGENT_DONOTSPLIT, + "REAGENT_ONLYINVERSE" = REAGENT_ONLYINVERSE, + "REAGENT_ONMOBMERGE" = REAGENT_ONMOBMERGE, + "REAGENT_INVISIBLE" = REAGENT_INVISIBLE, + "REAGENT_FORCEONNEW" = REAGENT_FORCEONNEW, + "REAGENT_SNEAKYNAME" = REAGENT_SNEAKYNAME, + "REAGENT_SPLITRETAINVOL" = REAGENT_SPLITRETAINVOL + ), + "clear_conversion" = list( + "REACTION_CLEAR_IMPURE" = REACTION_CLEAR_IMPURE, + "REACTION_CLEAR_INVERSE" = REACTION_CLEAR_INVERSE + ), + "organ_flags" = list( + "ORGAN_SYNTHETIC" = ORGAN_SYNTHETIC, + "ORGAN_FROZEN" = ORGAN_FROZEN, + "ORGAN_FAILING" = ORGAN_FAILING, + "ORGAN_EXTERNAL" = ORGAN_EXTERNAL, + "ORGAN_VITAL" = ORGAN_VITAL, + "ORGAN_NO_SPOIL" = ORGAN_NO_SPOIL + ), + )) diff --git a/code/_globalvars/lists/flavor_misc.dm b/code/_globalvars/lists/flavor_misc.dm index d09368d7b7..a2135b93b2 100644 --- a/code/_globalvars/lists/flavor_misc.dm +++ b/code/_globalvars/lists/flavor_misc.dm @@ -33,8 +33,10 @@ GLOBAL_LIST_EMPTY(animated_tails_list_human) GLOBAL_LIST_EMPTY(ears_list) GLOBAL_LIST_EMPTY(wings_list) GLOBAL_LIST_EMPTY(wings_open_list) +GLOBAL_LIST_EMPTY(deco_wings_list) GLOBAL_LIST_EMPTY(r_wings_list) -GLOBAL_LIST_EMPTY(moth_wings_list) +GLOBAL_LIST_EMPTY(insect_wings_list) +GLOBAL_LIST_EMPTY(insect_fluffs_list) GLOBAL_LIST_EMPTY(caps_list) GLOBAL_LIST_INIT(ghost_forms_with_directions_list, list("ghost")) //stores the ghost forms that support directional sprites diff --git a/code/_globalvars/lists/maintenance_loot.dm b/code/_globalvars/lists/maintenance_loot.dm index d92ab17584..c25ebf5b0a 100644 --- a/code/_globalvars/lists/maintenance_loot.dm +++ b/code/_globalvars/lists/maintenance_loot.dm @@ -107,9 +107,10 @@ GLOBAL_LIST_INIT(maintenance_loot, list( /obj/item/storage/toolbox/artistic = 2, /obj/item/toy/eightball = 1, /obj/item/reagent_containers/pill/floorpill = 1, - /obj/item/reagent_containers/food/snacks/cannedpeaches/maint = 1, + /obj/item/reagent_containers/food/snacks/cannedpeaches/maint = 2, /obj/item/storage/daki = 3, //VERY IMPORTANT CIT CHANGE - adds bodypillows to maint /obj/item/storage/pill_bottle/penis_enlargement = 2, + /obj/item/storage/pill_bottle/breast_enlargement = 2, /obj/item/clothing/shoes/wheelys = 1, /obj/item/clothing/shoes/kindleKicks = 1, /obj/item/autosurgeon/penis = 1, diff --git a/code/_globalvars/lists/misc.dm b/code/_globalvars/lists/misc.dm new file mode 100644 index 0000000000..1dcde53a72 --- /dev/null +++ b/code/_globalvars/lists/misc.dm @@ -0,0 +1 @@ +GLOBAL_LIST_EMPTY(donators_by_group) //group id = donator list of ckeys diff --git a/code/_globalvars/lists/poll_ignore.dm b/code/_globalvars/lists/poll_ignore.dm index 94723cae38..626bba9fc3 100644 --- a/code/_globalvars/lists/poll_ignore.dm +++ b/code/_globalvars/lists/poll_ignore.dm @@ -13,6 +13,7 @@ #define POLL_IGNORE_GOLEM "golem" #define POLL_IGNORE_SWARMER "swarmer" #define POLL_IGNORE_DRONE "drone" +#define POLL_IGNORE_CLONE "clone" GLOBAL_LIST_INIT(poll_ignore_desc, list( POLL_IGNORE_SENTIENCE_POTION = "Sentience potion", @@ -28,6 +29,7 @@ GLOBAL_LIST_INIT(poll_ignore_desc, list( POLL_IGNORE_GOLEM = "Golems", POLL_IGNORE_SWARMER = "Swarmer shells", POLL_IGNORE_DRONE = "Drone shells", + POLL_IGNORE_CLONE = "Defective/SDGF clones" )) GLOBAL_LIST_INIT(poll_ignore, init_poll_ignore()) diff --git a/code/_globalvars/logging.dm b/code/_globalvars/logging.dm index bd7f4afe62..8e5da083e3 100644 --- a/code/_globalvars/logging.dm +++ b/code/_globalvars/logging.dm @@ -26,6 +26,8 @@ GLOBAL_VAR(query_debug_log) GLOBAL_PROTECT(query_debug_log) GLOBAL_VAR(world_job_debug_log) GLOBAL_PROTECT(world_job_debug_log) +GLOBAL_VAR(world_virus_log) +GLOBAL_PROTECT(world_virus_log) GLOBAL_LIST_EMPTY(bombers) GLOBAL_PROTECT(bombers) diff --git a/code/_globalvars/misc.dm b/code/_globalvars/misc.dm index e7b2ae6cbe..037e5067d8 100644 --- a/code/_globalvars/misc.dm +++ b/code/_globalvars/misc.dm @@ -6,8 +6,6 @@ GLOBAL_VAR_INIT(timezoneOffset, 0) // The difference betwen midnight (of the hos // However it'd be ok to use for accessing attack logs and such too, which are even laggier. GLOBAL_VAR_INIT(fileaccess_timer, 0) -GLOBAL_VAR_INIT(TAB, "    ") - GLOBAL_DATUM_INIT(data_core, /datum/datacore, new) GLOBAL_VAR_INIT(CELLRATE, 0.002) // conversion ratio between a watt-tick and kilojoule diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index 4af61c99c7..b73696ed80 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -67,7 +67,7 @@ /mob/proc/ClickOn( atom/A, params ) if(world.time <= next_click) return - next_click = world.time + 1 + next_click = world.time + world.tick_lag if(check_click_intercept(params,A)) return diff --git a/code/_onclick/cyborg.dm b/code/_onclick/cyborg.dm index 006207c3f3..7f63b74945 100644 --- a/code/_onclick/cyborg.dm +++ b/code/_onclick/cyborg.dm @@ -55,6 +55,17 @@ var/obj/item/W = get_active_held_item() + if(!W && A.Adjacent(src) && (isobj(A) || ismob(A))) + var/atom/movable/C = A + if(C.can_buckle && C.has_buckled_mobs()) + if(C.buckled_mobs.len > 1) + var/unbuckled = input(src, "Who do you wish to unbuckle?","Unbuckle Who?") as null|mob in C.buckled_mobs + if(C.user_unbuckle_mob(unbuckled,src)) + return + else + if(C.user_unbuckle_mob(C.buckled_mobs[1],src)) + return + if(!W && get_dist(src,A) <= interaction_range) A.attack_robot(src) return diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index 5ee4ae0f8a..f796f75407 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -157,7 +157,7 @@ var/image/item_overlay = image(holding) item_overlay.alpha = 92 - if(!user.can_equip(holding, slot_id, disable_warning = TRUE)) + if(!user.can_equip(holding, slot_id, TRUE)) item_overlay.color = "#FF0000" else item_overlay.color = "#00ff00" @@ -290,16 +290,19 @@ icon_state = "internal0" else if(!C.getorganslot(ORGAN_SLOT_BREATHING_TUBE)) - if(!istype(C.wear_mask, /obj/item/clothing/mask)) + var/obj/item/clothing/check + var/internals = FALSE + + for(check in GET_INTERNAL_SLOTS(C)) + if(istype(check, /obj/item/clothing/mask)) + var/obj/item/clothing/mask/M = check + if(M.mask_adjusted) + M.adjustmask(C) + if(CHECK_BITFIELD(check.clothing_flags, ALLOWINTERNALS)) + internals = TRUE + if(!internals) to_chat(C, "You are not wearing an internals mask!") - return 1 - else - var/obj/item/clothing/mask/M = C.wear_mask - if(M.mask_adjusted) // if mask on face but pushed down - M.adjustmask(C) // adjust it back - if( !(M.clothing_flags & MASKINTERNALS) ) - to_chat(C, "You are not wearing an internals mask!") - return + return var/obj/item/I = C.is_holding_item_of_type(/obj/item/tank) if(I) diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 3896c3eac3..6455b4ccb6 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -171,3 +171,7 @@ if(prob(2)) playsound(src, 'sound/weapons/dink.ogg', 30, 1) return 1 + +/obj/item/proc/getweight() + return total_mass || w_class * 1.25 + diff --git a/code/controllers/configuration/config_entry.dm b/code/controllers/configuration/config_entry.dm index 49ff1c8d49..3ac103affc 100644 --- a/code/controllers/configuration/config_entry.dm +++ b/code/controllers/configuration/config_entry.dm @@ -19,6 +19,7 @@ var/abstract_type = /datum/config_entry //do not instantiate if type matches this var/vv_VAS = TRUE //Force validate and set on VV. VAS proccall guard will run regardless. + var/postload_required = FALSE //requires running OnPostload() var/dupes_allowed = FALSE @@ -72,6 +73,9 @@ /datum/config_entry/proc/DeprecationUpdate(value) return +/datum/config_entry/proc/OnPostload() + return + /datum/config_entry/string config_entry_value = "" abstract_type = /datum/config_entry/string @@ -80,7 +84,7 @@ /datum/config_entry/string/vv_edit_var(var_name, var_value) return var_name != "auto_trim" && ..() -/datum/config_entry/string/ValidateAndSet(str_val) +/datum/config_entry/string/ValidateAndSet(str_val, during_load) if(!VASProcCallGuard(str_val)) return FALSE config_entry_value = auto_trim ? trim(str_val) : str_val diff --git a/code/controllers/configuration/configuration.dm b/code/controllers/configuration/configuration.dm index 0232081c1a..ea2919f342 100644 --- a/code/controllers/configuration/configuration.dm +++ b/code/controllers/configuration/configuration.dm @@ -101,6 +101,7 @@ log_config("Loading config file [filename]...") var/list/lines = world.file2list("[directory]/[filename]") var/list/_entries = entries + var/list/postload_required = list() for(var/L in lines) L = trim(L) if(!L) @@ -157,18 +158,24 @@ else warning("[new_ver.type] is deprecated but gave no proper return for DeprecationUpdate()") - var/validated = E.ValidateAndSet(value) + var/validated = E.ValidateAndSet(value, TRUE) if(!validated) log_config("Failed to validate setting \"[value]\" for [entry]") else if(E.modified && !E.dupes_allowed) log_config("Duplicate setting for [entry] ([value], [E.resident_file]) detected! Using latest.") + if(E.postload_required) + postload_required[E] = TRUE E.resident_file = filename if(validated) E.modified = TRUE + for(var/i in postload_required) + var/datum/config_entry/E = i + E.OnPostload() + ++. /datum/controller/configuration/can_vv_get(var_name) diff --git a/code/controllers/configuration/entries/donator.dm b/code/controllers/configuration/entries/donator.dm new file mode 100644 index 0000000000..b74d5f5839 --- /dev/null +++ b/code/controllers/configuration/entries/donator.dm @@ -0,0 +1,22 @@ +/datum/config_entry/keyed_list/donator_group + key_mode = KEY_MODE_TEXT + value_mode = VALUE_MODE_FLAG + abstract_type = /datum/config_entry/keyed_list/donator_group + +//If we're in the middle of a config load, only do the regeneration afterwards to prevent this from wasting a massive amount of CPU for list regenerations. +/datum/config_entry/keyed_list/donator_group/ValidateAndSet(str_val, during_load) + . = ..() + if(. && during_load) + regenerate_donator_grouping_list() + +/datum/config_entry/keyed_list/donator_group/OnPostload() + . = ..() + regenerate_donator_grouping_list() + +//This is kinda weird in that the config entries are defined here but all the handling/calculations are in __HELPERS/donator_groupings.dm + +/datum/config_entry/keyed_list/donator_group/tier_1_donators + +/datum/config_entry/keyed_list/donator_group/tier_2_donators + +/datum/config_entry/keyed_list/donator_group/tier_3_donators diff --git a/code/controllers/configuration/entries/game_options.dm b/code/controllers/configuration/entries/game_options.dm index cfd57b4850..cf0caebb61 100644 --- a/code/controllers/configuration/entries/game_options.dm +++ b/code/controllers/configuration/entries/game_options.dm @@ -70,6 +70,9 @@ /datum/config_entry/flag/disable_peaceborg +/datum/config_entry/number/minimum_secborg_alert //Minimum alert level for secborgs to be chosen. + config_entry_value = 3 + /datum/config_entry/number/traitor_scaling_coeff //how much does the amount of players get divided by to determine traitors config_entry_value = 6 min_val = 1 diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm index 595e1d9ca0..aab71fd015 100644 --- a/code/controllers/configuration/entries/general.dm +++ b/code/controllers/configuration/entries/general.dm @@ -39,6 +39,8 @@ /datum/config_entry/flag/log_game // log game events +/datum/config_entry/flag/log_virus // log virology data + /datum/config_entry/flag/log_vote // log voting /datum/config_entry/flag/log_whisper // log client whisper @@ -173,6 +175,9 @@ /datum/config_entry/string/banappeals /datum/config_entry/string/wikiurl + config_entry_value = "https://katlin.dog/citadel-wiki" + +/datum/config_entry/string/wikiurltg config_entry_value = "http://www.tgstation13.org/wiki" /datum/config_entry/string/forumurl diff --git a/code/controllers/subsystem/assets.dm b/code/controllers/subsystem/assets.dm index 7285298283..7b6554bd3f 100644 --- a/code/controllers/subsystem/assets.dm +++ b/code/controllers/subsystem/assets.dm @@ -6,7 +6,17 @@ SUBSYSTEM_DEF(assets) var/list/preload = list() /datum/controller/subsystem/assets/Initialize(timeofday) - for(var/type in typesof(/datum/asset)) + + var/list/priority_assets = list( + /datum/asset/simple/oui_theme_nano, + /datum/asset/simple/goonchat + ) + + for(var/type in priority_assets) + var/datum/asset/A = new type() + A.register() + + for(var/type in typesof(/datum/asset) - (priority_assets | list(/datum/asset, /datum/asset/simple))) var/datum/asset/A = type if (type != initial(A._abstract)) get_asset_datum(type) diff --git a/code/controllers/subsystem/blackbox.dm b/code/controllers/subsystem/blackbox.dm index 72dfed6af0..58476d472f 100644 --- a/code/controllers/subsystem/blackbox.dm +++ b/code/controllers/subsystem/blackbox.dm @@ -294,7 +294,7 @@ Versioning var/lakey = L.lastattackerckey var/sqlbrute = L.getBruteLoss() var/sqlfire = L.getFireLoss() - var/sqlbrain = L.getBrainLoss() + var/sqlbrain = L.getOrganLoss(ORGAN_SLOT_BRAIN) var/sqloxy = L.getOxyLoss() var/sqltox = L.getToxLoss() var/sqlclone = L.getCloneLoss() @@ -308,7 +308,7 @@ Versioning if(!SSdbcore.Connect()) return - + sqlname = sanitizeSQL(sqlname) sqlkey = sanitizeSQL(sqlkey) sqljob = sanitizeSQL(sqljob) diff --git a/code/controllers/subsystem/chat.dm b/code/controllers/subsystem/chat.dm new file mode 100644 index 0000000000..37e53e8990 --- /dev/null +++ b/code/controllers/subsystem/chat.dm @@ -0,0 +1,67 @@ +SUBSYSTEM_DEF(chat) + name = "Chat" + flags = SS_TICKER|SS_NO_INIT + wait = 1 + priority = FIRE_PRIORITY_CHAT + init_order = INIT_ORDER_CHAT + var/list/payload = list() + + +/datum/controller/subsystem/chat/fire() + for(var/i in payload) + var/client/C = i + C << output(payload[C], "browseroutput:output") + payload -= C + + if(MC_TICK_CHECK) + return + + +/datum/controller/subsystem/chat/proc/queue(target, message, handle_whitespace = TRUE) + if(!target || !message) + return + + if(!istext(message)) + stack_trace("to_chat called with invalid input type") + return + + if(target == world) + target = GLOB.clients + + //Some macros remain in the string even after parsing and fuck up the eventual output + message = replacetext(message, "\improper", "") + message = replacetext(message, "\proper", "") + if(handle_whitespace) + message = replacetext(message, "\n", "
") + message = replacetext(message, "\t", "[FOURSPACES][FOURSPACES]") + message += "
" + + + //url_encode it TWICE, this way any UTF-8 characters are able to be decoded by the Javascript. + //Do the double-encoding here to save nanoseconds + var/twiceEncoded = url_encode(url_encode(message)) + + if(islist(target)) + for(var/I in target) + var/client/C = CLIENT_FROM_VAR(I) //Grab us a client if possible + + if(!C?.chatOutput || C.chatOutput.broken) //A player who hasn't updated his skin file. + continue + + if(!C.chatOutput.loaded) //Client still loading, put their messages in a queue + C.chatOutput.messageQueue += message + continue + + payload[C] += twiceEncoded + + else + var/client/C = CLIENT_FROM_VAR(target) //Grab us a client if possible + + if(!C?.chatOutput || C.chatOutput.broken) //A player who hasn't updated his skin file. + return + + if(!C.chatOutput.loaded) //Client still loading, put their messages in a queue + C.chatOutput.messageQueue += message + return + + payload[C] += twiceEncoded diff --git a/code/controllers/subsystem/input.dm b/code/controllers/subsystem/input.dm index 221d04dad5..cc09ca816e 100644 --- a/code/controllers/subsystem/input.dm +++ b/code/controllers/subsystem/input.dm @@ -23,7 +23,7 @@ SUBSYSTEM_DEF(input) // This is for when macro sets are eventualy datumized /datum/controller/subsystem/input/proc/setup_default_macro_sets() var/list/static/default_macro_sets - + if(default_macro_sets) macro_sets = default_macro_sets return @@ -49,6 +49,7 @@ SUBSYSTEM_DEF(input) "old_hotkeys" = list( "Tab" = "\".winset \\\"mainwindow.macro=old_default input.focus=true input.background-color=[COLOR_INPUT_ENABLED]\\\"\"", "O" = "ooc", + "L" = "looc", "T" = "say", "M" = "me", "Back" = "\".winset \\\"input.text=\\\"\\\"\\\"\"", // This makes it so backspace can remove default inputs diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm index 4001c666ee..ea7e7ce812 100644 --- a/code/controllers/subsystem/job.dm +++ b/code/controllers/subsystem/job.dm @@ -110,13 +110,16 @@ SUBSYSTEM_DEF(job) if(job.required_playtime_remaining(player.client)) JobDebug("FOC player not enough xp, Player: [player]") continue + if(!player.client.prefs.pref_species.qualifies_for_rank(job.title, player.client.prefs.features)) + JobDebug("FOC non-human failed, Player: [player]") + continue if(flag && (!(flag in player.client.prefs.be_special))) JobDebug("FOC flag failed, Player: [player], Flag: [flag], ") continue if(player.mind && job.title in player.mind.restricted_roles) JobDebug("FOC incompatible with antagonist role, Player: [player]") continue - if(player.client.prefs.GetJobDepartment(job, level) & job.flag) + if(player.client.prefs.job_preferences["[job.title]"] == level) JobDebug("FOC pass, Player: [player], Level:[level]") candidates += player return candidates @@ -145,6 +148,10 @@ SUBSYSTEM_DEF(job) JobDebug("GRJ player not old enough, Player: [player]") continue + if(!player.client.prefs.pref_species.qualifies_for_rank(job.title, player.client.prefs.features)) + JobDebug("GRJ non-human failed, Player: [player]") + continue + if(job.required_playtime_remaining(player.client)) JobDebug("GRJ player not enough xp, Player: [player]") continue @@ -182,7 +189,7 @@ SUBSYSTEM_DEF(job) if((job.current_positions >= job.total_positions) && job.total_positions != -1) continue var/list/candidates = FindOccupationCandidates(job, level) - if(!candidates.len) + if(!candidates?.len) continue var/mob/dead/new_player/candidate = pick(candidates) if(AssignRole(candidate, command_position)) @@ -200,7 +207,7 @@ SUBSYSTEM_DEF(job) if((job.current_positions >= job.total_positions) && job.total_positions != -1) continue var/list/candidates = FindOccupationCandidates(job, level) - if(!candidates.len) + if(!candidates?.len) continue var/mob/dead/new_player/candidate = pick(candidates) AssignRole(candidate, command_position) @@ -228,7 +235,7 @@ SUBSYSTEM_DEF(job) * fills var "assigned_role" for all ready players. * This proc must not have any side effect besides of modifying "assigned_role". **/ -/datum/controller/subsystem/job/proc/DivideOccupations() +/datum/controller/subsystem/job/proc/DivideOccupations(list/required_jobs) //Setup new player list and get the jobs list JobDebug("Running DO") @@ -241,14 +248,14 @@ SUBSYSTEM_DEF(job) //Get the players who are ready for(var/mob/dead/new_player/player in GLOB.player_list) - if(player.ready == PLAYER_READY_TO_PLAY && player.mind && !player.mind.assigned_role) + if(player.ready == PLAYER_READY_TO_PLAY && player.check_preferences() && player.mind && !player.mind.assigned_role) unassigned += player initial_players_to_assign = unassigned.len - JobDebug("DO, Len: [unassigned.len]") + JobDebug("DO, Len: [unassigned?.len]") if(unassigned.len == 0) - return 0 + return validate_required_jobs(required_jobs) //Scale number of open security officer slots to population setup_officer_positions() @@ -269,8 +276,8 @@ SUBSYSTEM_DEF(job) //People who wants to be the overflow role, sure, go on. JobDebug("DO, Running Overflow Check 1") var/datum/job/overflow = GetJob(SSjob.overflow_role) - var/list/overflow_candidates = FindOccupationCandidates(overflow, 3) - JobDebug("AC1, Candidates: [overflow_candidates.len]") + var/list/overflow_candidates = FindOccupationCandidates(overflow, JP_LOW) + JobDebug("AC1, Candidates: [overflow_candidates?.len]") for(var/mob/dead/new_player/player in overflow_candidates) JobDebug("AC1 pass, Player: [player]") AssignRole(player, SSjob.overflow_role) @@ -297,7 +304,8 @@ SUBSYSTEM_DEF(job) // Loop through all levels from high to low var/list/shuffledoccupations = shuffle(occupations) - for(var/level = 1 to 3) + var/list/levels = list(JP_HIGH,JP_MEDIUM,JP_LOW) + for(var/level in levels) //Check the head jobs first each level CheckHeadPositions(level) @@ -326,13 +334,17 @@ SUBSYSTEM_DEF(job) if(job.required_playtime_remaining(player.client)) JobDebug("DO player not enough xp, Player: [player], Job:[job.title]") continue + + if(!player.client.prefs.pref_species.qualifies_for_rank(job.title, player.client.prefs.features)) + JobDebug("DO non-human failed, Player: [player], Job:[job.title]") + continue if(player.mind && job.title in player.mind.restricted_roles) JobDebug("DO incompatible with antagonist role, Player: [player], Job:[job.title]") continue // If the player wants that job on this level, then try give it to him. - if(player.client.prefs.GetJobDepartment(job, level) & job.flag) + if(player.client.prefs.job_preferences["[job.title]"] == level) // If the job isn't filled if((job.current_positions < job.spawn_positions) || job.spawn_positions == -1) JobDebug("DO pass, Player: [player], Level:[level], Job:[job.title]") @@ -351,9 +363,28 @@ SUBSYSTEM_DEF(job) //Mop up people who can't leave. for(var/mob/dead/new_player/player in unassigned) //Players that wanted to back out but couldn't because they're antags (can you feel the edge case?) if(!GiveRandomJob(player)) - AssignRole(player, SSjob.overflow_role) //If everything is already filled, make them an assistant + if(!AssignRole(player, SSjob.overflow_role)) //If everything is already filled, make them an assistant + return FALSE //Living on the edge, the forced antagonist couldn't be assigned to overflow role (bans, client age) - just reroll - return 1 + return validate_required_jobs(required_jobs) + +/datum/controller/subsystem/job/proc/validate_required_jobs(list/required_jobs) + if(!required_jobs.len) + return TRUE + for(var/required_group in required_jobs) + var/group_ok = TRUE + for(var/rank in required_group) + var/datum/job/J = GetJob(rank) + if(!J) + SSticker.mode.setup_error = "Invalid job [rank] in gamemode required jobs." + return FALSE + if(J.current_positions < required_group[rank]) + group_ok = FALSE + break + if(group_ok) + return TRUE + SSticker.mode.setup_error = "Required jobs not present." + return FALSE //We couldn't find a job from prefs for this guy. /datum/controller/subsystem/job/proc/HandleUnassigned(mob/dead/new_player/player) @@ -406,7 +437,7 @@ SUBSYSTEM_DEF(job) if(length(GLOB.jobspawn_overrides[rank])) S = pick(GLOB.jobspawn_overrides[rank]) if(S) - SendToAtom(H, S, buckle = FALSE) + S.JoinPlayerHere(H, FALSE) if(!S) //if there isn't a spawnpoint send them to latejoin, if there's no latejoin go yell at your mapper log_world("Couldn't find a round start spawn point for [rank]") SendToLateJoin(H) @@ -418,7 +449,7 @@ SUBSYSTEM_DEF(job) if(job) if(!job.dresscodecompliant)// CIT CHANGE - dress code compliance equip_loadout(N, H) // CIT CHANGE - allows players to spawn with loadout items - var/new_mob = job.equip(H, null, null, joined_late) + var/new_mob = job.equip(H, null, null, joined_late , null, M.client) if(ismob(new_mob)) H = new_mob if(!joined_late) @@ -428,12 +459,18 @@ SUBSYSTEM_DEF(job) SSpersistence.antag_rep_change[M.client.ckey] += job.GetAntagRep() +/* if(M.client.holder) + if(CONFIG_GET(flag/auto_deadmin_players) || (M.client.prefs?.toggles & DEADMIN_ALWAYS)) + M.client.holder.auto_deadmin() + else + handle_auto_deadmin_roles(M.client, rank) */ + to_chat(M, "You are the [rank].") if(job) to_chat(M, "As the [rank] you answer directly to [job.supervisors]. Special circumstances may change this.") - to_chat(M, "To speak on your departments radio, use the :h button. To see others, look closely at your headset.") + job.radio_help_message(M) if(job.req_admin_notify) - to_chat(M, "You are playing a job that is important for Game Progression. If you have to disconnect, please notify the admins via adminhelp.") + to_chat(M, "You are playing a job that is important for Game Progression. If you have to disconnect immediately, please notify the admins via adminhelp. Otherwise put your locker gear back into the locker and cryo out.") if(job.custom_spawn_text) to_chat(M, "[job.custom_spawn_text]") if(CONFIG_GET(number/minimal_access_threshold)) @@ -446,12 +483,24 @@ SUBSYSTEM_DEF(job) equip_loadout(N, H, TRUE)//CIT CHANGE - makes players spawn with in-backpack loadout items properly. A little hacky but it works return H - +/* +/datum/controller/subsystem/job/proc/handle_auto_deadmin_roles(client/C, rank) + if(!C?.holder) + return TRUE + var/datum/job/job = GetJob(rank) + if(!job) + return + if((job.auto_deadmin_role_flags & DEADMIN_POSITION_HEAD) && (CONFIG_GET(flag/auto_deadmin_heads) || (C.prefs?.toggles & DEADMIN_POSITION_HEAD))) + return C.holder.auto_deadmin() + else if((job.auto_deadmin_role_flags & DEADMIN_POSITION_SECURITY) && (CONFIG_GET(flag/auto_deadmin_security) || (C.prefs?.toggles & DEADMIN_POSITION_SECURITY))) + return C.holder.auto_deadmin() + else if((job.auto_deadmin_role_flags & DEADMIN_POSITION_SILICON) && (CONFIG_GET(flag/auto_deadmin_silicons) || (C.prefs?.toggles & DEADMIN_POSITION_SILICON))) //in the event there's ever psuedo-silicon roles added, ie synths. + return C.holder.auto_deadmin()*/ /datum/controller/subsystem/job/proc/setup_officer_positions() var/datum/job/J = SSjob.GetJob("Security Officer") if(!J) - throw EXCEPTION("setup_officer_positions(): Security officer job is missing") + CRASH("setup_officer_positions(): Security officer job is missing") var/ssc = CONFIG_GET(number/security_scaling_coeff) if(ssc > 0) @@ -502,13 +551,15 @@ SUBSYSTEM_DEF(job) if(job.required_playtime_remaining(player.client)) young++ continue - if(player.client.prefs.GetJobDepartment(job, 1) & job.flag) - high++ - else if(player.client.prefs.GetJobDepartment(job, 2) & job.flag) - medium++ - else if(player.client.prefs.GetJobDepartment(job, 3) & job.flag) - low++ - else never++ //not selected + switch(player.client.prefs.job_preferences["[job.title]"]) + if(JP_HIGH) + high++ + if(JP_MEDIUM) + medium++ + if(JP_LOW) + low++ + else + never++ SSblackbox.record_feedback("nested tally", "job_preferences", high, list("[job.title]", "high")) SSblackbox.record_feedback("nested tally", "job_preferences", medium, list("[job.title]", "medium")) SSblackbox.record_feedback("nested tally", "job_preferences", low, list("[job.title]", "low")) @@ -551,51 +602,61 @@ SUBSYSTEM_DEF(job) newjob.spawn_positions = J.spawn_positions newjob.current_positions = J.current_positions -/datum/controller/subsystem/job/proc/SendToAtom(mob/M, atom/A, buckle) - if(buckle && isliving(M) && istype(A, /obj/structure/chair)) - var/obj/structure/chair/C = A - if(C.buckle_mob(M, FALSE, FALSE)) - return - M.forceMove(get_turf(A)) +/atom/proc/JoinPlayerHere(mob/M, buckle) + // By default, just place the mob on the same turf as the marker or whatever. + M.forceMove(get_turf(src)) + +/obj/structure/chair/JoinPlayerHere(mob/M, buckle) + // Placing a mob in a chair will attempt to buckle it, or else fall back to default. + if (buckle && isliving(M) && buckle_mob(M, FALSE, FALSE)) + return + ..() /datum/controller/subsystem/job/proc/SendToLateJoin(mob/M, buckle = TRUE) + var/atom/destination if(M.mind && M.mind.assigned_role && length(GLOB.jobspawn_overrides[M.mind.assigned_role])) //We're doing something special today. - SendToAtom(M,pick(GLOB.jobspawn_overrides[M.mind.assigned_role]),FALSE) + destination = pick(GLOB.jobspawn_overrides[M.mind.assigned_role]) + destination.JoinPlayerHere(M, FALSE) return if(latejoin_trackers.len) - SendToAtom(M, pick(latejoin_trackers), buckle) - else - //bad mojo - var/area/shuttle/arrival/A = GLOB.areas_by_type[/area/shuttle/arrival] - if(A) - //first check if we can find a chair - var/obj/structure/chair/C = locate() in A - if(C) - SendToAtom(M, C, buckle) - return - else //last hurrah - var/list/avail = list() - for(var/turf/T in A) - if(!is_blocked_turf(T, TRUE)) - avail += T - if(avail.len) - SendToAtom(M, pick(avail), FALSE) - return + destination = pick(latejoin_trackers) + destination.JoinPlayerHere(M, buckle) + return - //pick an open spot on arrivals and dump em - var/list/arrivals_turfs = shuffle(get_area_turfs(/area/shuttle/arrival)) - if(arrivals_turfs.len) - for(var/turf/T in arrivals_turfs) - if(!is_blocked_turf(T, TRUE)) - SendToAtom(M, T, FALSE) - return - //last chance, pick ANY spot on arrivals and dump em - SendToAtom(M, arrivals_turfs[1], FALSE) - else - var/msg = "Unable to send mob [M] to late join!" - message_admins(msg) - CRASH(msg) + //bad mojo + var/area/shuttle/arrival/A = GLOB.areas_by_type[/area/shuttle/arrival] + if(A) + //first check if we can find a chair + var/obj/structure/chair/C = locate() in A + if(C) + C.JoinPlayerHere(M, buckle) + return + + //last hurrah + var/list/avail = list() + for(var/turf/T in A) + if(!is_blocked_turf(T, TRUE)) + avail += T + if(avail.len) + destination = pick(avail) + destination.JoinPlayerHere(M, FALSE) + return + + //pick an open spot on arrivals and dump em + var/list/arrivals_turfs = shuffle(get_area_turfs(/area/shuttle/arrival)) + if(arrivals_turfs.len) + for(var/turf/T in arrivals_turfs) + if(!is_blocked_turf(T, TRUE)) + T.JoinPlayerHere(M, FALSE) + return + //last chance, pick ANY spot on arrivals and dump em + destination = arrivals_turfs[1] + destination.JoinPlayerHere(M, FALSE) + else + var/msg = "Unable to send mob [M] to late join!" + message_admins(msg) + CRASH(msg) /////////////////////////////////// @@ -637,4 +698,4 @@ SUBSYSTEM_DEF(job) . |= player.mind /datum/controller/subsystem/job/proc/JobDebug(message) - log_job_debug(message) \ No newline at end of file + log_job_debug(message) diff --git a/code/controllers/subsystem/processing/chemistry.dm b/code/controllers/subsystem/processing/chemistry.dm new file mode 100644 index 0000000000..da31d65fb3 --- /dev/null +++ b/code/controllers/subsystem/processing/chemistry.dm @@ -0,0 +1,5 @@ +PROCESSING_SUBSYSTEM_DEF(chemistry) + wait = 5 + flags = SS_KEEP_TIMING + + diff --git a/code/controllers/subsystem/processing/quirks.dm b/code/controllers/subsystem/processing/quirks.dm index a6c86a3576..4af54b8c70 100644 --- a/code/controllers/subsystem/processing/quirks.dm +++ b/code/controllers/subsystem/processing/quirks.dm @@ -9,6 +9,7 @@ PROCESSING_SUBSYSTEM_DEF(quirks) runlevels = RUNLEVEL_GAME var/list/quirks = list() //Assoc. list of all roundstart quirk datum types; "name" = /path/ + var/list/quirk_names_by_path = list() var/list/quirk_points = list() //Assoc. list of quirk names and their "point cost"; positive numbers are good traits, and negative ones are bad var/list/quirk_objects = list() //A list of all quirk objects in the game, since some may process @@ -22,11 +23,68 @@ PROCESSING_SUBSYSTEM_DEF(quirks) var/datum/quirk/T = V quirks[initial(T.name)] = T quirk_points[initial(T.name)] = initial(T.value) + quirk_names_by_path[T] = initial(T.name) -/datum/controller/subsystem/processing/quirks/proc/AssignQuirks(mob/living/user, client/cli, spawn_effects) +/datum/controller/subsystem/processing/quirks/proc/AssignQuirks(mob/living/user, client/cli, spawn_effects, roundstart = FALSE, datum/job/job, silent = FALSE, mob/to_chat_target) GenerateQuirks(cli) - for(var/V in cli.prefs.character_quirks) + var/list/quirks = cli.prefs.character_quirks.Copy() + var/list/cut + if(job && job.blacklisted_quirks) + cut = filter_quirks(quirks, job) + for(var/V in quirks) user.add_quirk(V, spawn_effects) + if(!silent && LAZYLEN(cut)) + to_chat(to_chat_target || user, "All of your non-neutral character quirks have been cut due to these quirks conflicting with your job assignment: [english_list(cut)].") + +/datum/controller/subsystem/processing/quirks/proc/quirk_path_by_name(name) + return quirks[name] + +/datum/controller/subsystem/processing/quirks/proc/quirk_points_by_name(name) + return quirk_points[name] + +/datum/controller/subsystem/processing/quirks/proc/quirk_name_by_path(path) + return quirk_names_by_path[path] + +/datum/controller/subsystem/processing/quirks/proc/total_points(list/quirk_names) + . = 0 + for(var/i in quirk_names) + . += quirk_points_by_name(i) + +/datum/controller/subsystem/processing/quirks/proc/filter_quirks(list/quirks, datum/job/job) + var/list/cut = list() + var/list/banned_names = list() + for(var/i in job.blacklisted_quirks) + var/name = quirk_name_by_path(i) + if(name) + banned_names += name + var/list/blacklisted = quirks & banned_names + if(length(blacklisted)) + for(var/i in blacklisted) + quirks -= i + cut += i + + /* //Code to automatically reduce positive quirks until balance is even. + var/points_used = total_points(quirks) + if(points_used > 0) + //they owe us points, let's collect. + for(var/i in quirks) + var/points = quirk_points_by_name(i) + if(points > 0) + cut += i + quirks -= i + points_used -= points + if(points_used <= 0) + break + */ + + //Nah, let's null all non-neutrals out. + if(cut.len) + for(var/i in quirks) + if(quirk_points_by_name(i) != 0) + //cut += i -- Commented out: Only show the ones that triggered the quirk purge. + quirks -= i + + return cut /datum/controller/subsystem/processing/quirks/proc/GenerateQuirks(client/user) if(user.prefs.character_quirks.len) diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index 47945e4333..14e1e86f7d 100755 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -255,7 +255,7 @@ SUBSYSTEM_DEF(ticker) var/can_continue = 0 can_continue = src.mode.pre_setup() //Choose antagonists CHECK_TICK - SSjob.DivideOccupations() //Distribute jobs + can_continue = can_continue && SSjob.DivideOccupations(mode.required_jobs) //Distribute jobs CHECK_TICK if(!GLOB.Debug2) @@ -385,7 +385,7 @@ SUBSYSTEM_DEF(ticker) if(player.mind.assigned_role != player.mind.special_role) SSjob.EquipRank(N, player.mind.assigned_role, 0) if(CONFIG_GET(flag/roundstart_traits) && ishuman(N.new_character)) - SSquirks.AssignQuirks(N.new_character, N.client, TRUE) + SSquirks.AssignQuirks(N.new_character, N.client, TRUE, TRUE, SSjob.GetJob(player.mind.assigned_role), FALSE, N) CHECK_TICK if(captainless) for(var/mob/dead/new_player/N in GLOB.player_list) diff --git a/code/controllers/subsystem/vore.dm b/code/controllers/subsystem/vore.dm index faaa297ca3..ca34f9ab61 100644 --- a/code/controllers/subsystem/vore.dm +++ b/code/controllers/subsystem/vore.dm @@ -7,7 +7,7 @@ SUBSYSTEM_DEF(bellies) name = "Bellies" - priority = 5 + priority = FIRE_PRIORITY_VORE wait = 1 SECONDS flags = SS_KEEP_TIMING|SS_NO_INIT runlevels = RUNLEVEL_GAME|RUNLEVEL_POSTGAME diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index f432e44b18..2f56c69384 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -87,17 +87,20 @@ SUBSYSTEM_DEF(vote) /datum/controller/subsystem/vote/proc/announce_result() var/list/winners = get_result() var/text + var/was_roundtype_vote = mode == "roundtype" if(winners.len > 0) if(question) text += "[question]" else text += "[capitalize(mode)] Vote" - stored_gamemode_votes = list() + if(was_roundtype_vote) + stored_gamemode_votes = list() for(var/i=1,i<=choices.len,i++) var/votes = choices[choices[i]] if(!votes) votes = 0 - stored_gamemode_votes[choices[i]] = votes + if(was_roundtype_vote) + stored_gamemode_votes[choices[i]] = votes text += "\n[choices[i]]: [obfuscated ? "???" : votes]" //CIT CHANGE - adds obfuscated votes if(mode != "custom") if(winners.len > 1 && !obfuscated) //CIT CHANGE - adds obfuscated votes diff --git a/code/datums/action.dm b/code/datums/action.dm index f64a549b29..fd33ef79b5 100644 --- a/code/datums/action.dm +++ b/code/datums/action.dm @@ -494,6 +494,7 @@ else to_chat(owner, "Your hands are full!") +//MGS Box /datum/action/item_action/agent_box name = "Deploy Box" desc = "Find inner peace, here, in the box." @@ -502,21 +503,27 @@ icon_icon = 'icons/mob/actions/actions_items.dmi' button_icon_state = "deploy_box" var/cooldown = 0 - var/obj/structure/closet/cardboard/agent/box + var/boxtype = /obj/structure/closet/cardboard/agent +//Handles open and closing the box /datum/action/item_action/agent_box/Trigger() - if(!..()) + . = ..() + if(!.) return FALSE - if(QDELETED(box)) - if(cooldown < world.time - 100) - box = new(owner.drop_location()) - owner.forceMove(box) - cooldown = world.time - owner.playsound_local(box, 'sound/misc/box_deploy.ogg', 50, TRUE) - else - owner.forceMove(box.drop_location()) + if(istype(owner.loc, /obj/structure/closet/cardboard/agent)) + var/obj/structure/closet/cardboard/agent/box = owner.loc + owner.playsound_local(box, 'sound/misc/box_deploy.ogg', 50, TRUE) + box.open() + return + //Box closing from here on out. + if(!isturf(owner.loc)) //Don't let the player use this to escape mechs/welded closets. + to_chat(owner, "You need more space to activate this implant.") + return + if(cooldown < world.time - 100) + var/box = new boxtype(owner.drop_location()) + owner.forceMove(box) + cooldown = world.time owner.playsound_local(box, 'sound/misc/box_deploy.ogg', 50, TRUE) - QDEL_NULL(box) //Preset for spells /datum/action/spell_action diff --git a/code/datums/brain_damage/hypnosis.dm b/code/datums/brain_damage/hypnosis.dm new file mode 100644 index 0000000000..8909d1b85f --- /dev/null +++ b/code/datums/brain_damage/hypnosis.dm @@ -0,0 +1,72 @@ +/datum/brain_trauma/hypnosis + name = "Hypnosis" + desc = "Patient's unconscious is completely enthralled by a word or sentence, focusing their thoughts and actions on it." + scan_desc = "looping thought pattern" + gain_text = "" + lose_text = "" + resilience = TRAUMA_RESILIENCE_SURGERY + var/hypnotic_phrase = "" + var/regex/target_phrase + +/datum/brain_trauma/hypnosis/New(phrase, quirk = FALSE) + if(!phrase) + qdel(src) + if(quirk == TRUE) + hypnotic_phrase = phrase + else + friendliify(phrase) + if(IsAdminAdvancedProcCall()) + to_chat(usr, "Hypnosis New() skipped due to try/catch incompatibility with admin proccalling.") + qdel(src) + try + target_phrase = new("(\\b[hypnotic_phrase]\\b)","ig") + catch(var/exception/e) + stack_trace("[e] on [e.file]:[e.line]") + qdel(src) + ..() + +/datum/brain_trauma/hypnosis/proc/friendliify(phrase) + phrase = replacetext(lowertext(phrase), "kill", "hug") + phrase = replacetext(lowertext(phrase), "murder", "cuddle") + phrase = replacetext(lowertext(phrase), "harm", "snuggle") + phrase = replacetext(lowertext(phrase), "decapitate", "headpat") + phrase = replacetext(lowertext(phrase), "strangle", "meow at") + phrase = replacetext(lowertext(phrase), "suicide", "self-love") + phrase = replacetext(lowertext(phrase), "lynch", "kiss") + hypnotic_phrase = phrase + +/datum/brain_trauma/hypnosis/on_gain() + message_admins("[ADMIN_LOOKUPFLW(owner)] was hypnotized with the phrase '[hypnotic_phrase]'.") + log_game("[key_name(owner)] was hypnotized with the phrase '[hypnotic_phrase]'.") + to_chat(owner, "[hypnotic_phrase]") + to_chat(owner, "[pick("You feel your thoughts focusing on this phrase... you can't seem to get it out of your head.",\ + "Your head hurts, but this is all you can think of. It must be vitally important.",\ + "You feel a part of your mind repeating this over and over. You need to follow these words.",\ + "Something about this sounds... right, for some reason. You feel like you should follow these words.",\ + "These words keep echoing in your mind. You find yourself completely fascinated by them.")]") + if(!HAS_TRAIT(owner, "hypnotherapy")) + to_chat(owner, "You've been hypnotized by this sentence. You must follow these words. If it isn't a clear order, you can freely interpret how to do so,\ + as long as you act like the words are your highest priority.") + else + to_chat(owner, "You've been hypnotized by this sentence. You feel an incredible desire to follow these words, but are able to resist it somewhat. If it isn't a clear order, you can freely interpret how to do so,\ + however this does not take precedence over your other objectives.") + ..() + +/datum/brain_trauma/hypnosis/on_lose() + message_admins("[ADMIN_LOOKUPFLW(owner)] is no longer hypnotized with the phrase '[hypnotic_phrase]'.") + log_game("[key_name(owner)] is no longer hypnotized with the phrase '[hypnotic_phrase]'.") + to_chat(owner, "You suddenly snap out of your fixation. The phrase '[hypnotic_phrase]' no longer feels important to you.") + ..() + +/datum/brain_trauma/hypnosis/on_life() + ..() + if(prob(2)) + switch(rand(1,2)) + if(1) + to_chat(owner, "...[lowertext(hypnotic_phrase)]...") + if(2) + new /datum/hallucination/chat(owner, TRUE, FALSE, "[hypnotic_phrase]") + +/datum/brain_trauma/hypnosis/on_hear(message, speaker, message_language, raw_message, radio_freq) + message = target_phrase.Replace(message, "$1") + return message diff --git a/code/datums/brain_damage/imaginary_friend.dm b/code/datums/brain_damage/imaginary_friend.dm index 1bc7d8e3be..5bbc5de4a5 100644 --- a/code/datums/brain_damage/imaginary_friend.dm +++ b/code/datums/brain_damage/imaginary_friend.dm @@ -46,7 +46,7 @@ var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [owner]'s imaginary friend?", ROLE_PAI, null, null, 75, friend) if(LAZYLEN(candidates)) var/mob/dead/observer/C = pick(candidates) - friend.key = C.key + C.transfer_ckey(friend, FALSE) friend_initialized = TRUE else qdel(src) diff --git a/code/datums/brain_damage/phobia.dm b/code/datums/brain_damage/phobia.dm index 6723c89ba5..f802555c7e 100644 --- a/code/datums/brain_damage/phobia.dm +++ b/code/datums/brain_damage/phobia.dm @@ -31,6 +31,8 @@ /datum/brain_trauma/mild/phobia/on_life() ..() + if(HAS_TRAIT(owner, TRAIT_FEARLESS)) + return if(is_blind(owner)) return if(world.time > next_check && world.time > next_scare) @@ -70,6 +72,8 @@ /datum/brain_trauma/mild/phobia/on_hear(message, speaker, message_language, raw_message, radio_freq) if(!owner.can_hear() || world.time < next_scare) //words can't trigger you if you can't hear them *taps head* return message + if(HAS_TRAIT(owner, TRAIT_FEARLESS)) + return message for(var/word in trigger_words) var/reg = regex("(\\b|\\A)[REGEX_QUOTE(word)]'?s*(\\b|\\Z)", "i") @@ -79,6 +83,8 @@ return message /datum/brain_trauma/mild/phobia/handle_speech(datum/source, list/speech_args) + if(HAS_TRAIT(owner, TRAIT_FEARLESS)) + return for(var/word in trigger_words) var/reg = regex("(\\b|\\A)[REGEX_QUOTE(word)]'?s*(\\b|\\Z)", "i") diff --git a/code/datums/brain_damage/severe.dm b/code/datums/brain_damage/severe.dm index d094c162d7..890e9cf903 100644 --- a/code/datums/brain_damage/severe.dm +++ b/code/datums/brain_damage/severe.dm @@ -254,3 +254,20 @@ /datum/brain_trauma/severe/pacifism/on_lose() REMOVE_TRAIT(owner, TRAIT_PACIFISM, TRAUMA_TRAIT) ..() + +//ported from TG +/datum/brain_trauma/severe/hypnotic_stupor + name = "Hypnotic Stupor" + desc = "Patient is prone to episodes of extreme stupor that leaves them extremely suggestible." + scan_desc = "oneiric feedback loop" + gain_text = "You feel somewhat dazed." + lose_text = "You feel like a fog was lifted from your mind." + +/datum/brain_trauma/severe/hypnotic_stupor/on_lose() //hypnosis must be cleared separately, but brain surgery should get rid of both anyway + ..() + owner.remove_status_effect(/datum/status_effect/trance) + +/datum/brain_trauma/severe/hypnotic_stupor/on_life() + ..() + if(prob(1) && !owner.has_status_effect(/datum/status_effect/trance)) + owner.apply_status_effect(/datum/status_effect/trance, rand(100,300), FALSE) diff --git a/code/datums/brain_damage/split_personality.dm b/code/datums/brain_damage/split_personality.dm index 653b8a98c0..1a26ea7a14 100644 --- a/code/datums/brain_damage/split_personality.dm +++ b/code/datums/brain_damage/split_personality.dm @@ -26,7 +26,7 @@ var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [owner]'s split personality?", ROLE_PAI, null, null, 75, stranger_backseat) if(LAZYLEN(candidates)) var/mob/dead/observer/C = pick(candidates) - stranger_backseat.key = C.key + C.transfer_ckey(stranger_backseat, FALSE) log_game("[key_name(stranger_backseat)] became [key_name(owner)]'s split personality.") message_admins("[ADMIN_LOOKUPFLW(stranger_backseat)] became [ADMIN_LOOKUPFLW(owner)]'s split personality.") else @@ -184,7 +184,7 @@ var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [owner]'s brainwashed mind?", null, null, null, 75, stranger_backseat) if(LAZYLEN(candidates)) var/mob/dead/observer/C = pick(candidates) - stranger_backseat.key = C.key + C.transfer_ckey(stranger_backseat, FALSE) else qdel(src) diff --git a/code/datums/components/caltrop.dm b/code/datums/components/caltrop.dm index 838a1b576a..f0333072a8 100644 --- a/code/datums/components/caltrop.dm +++ b/code/datums/components/caltrop.dm @@ -37,9 +37,9 @@ if(O.status == BODYPART_ROBOTIC) return - var/feetCover = (H.wear_suit && (H.wear_suit.body_parts_covered & FEET)) || (H.w_uniform && (H.w_uniform.body_parts_covered & FEET)) + var/feetCover = (H.wear_suit && (H.wear_suit.body_parts_covered & FEET)) || (H.w_uniform && (H.w_uniform.body_parts_covered & FEET) || (H.shoes && (H.shoes.body_parts_covered & FEET))) - if(!(flags & CALTROP_BYPASS_SHOES) && (H.shoes || feetCover)) + if(!(flags & CALTROP_BYPASS_SHOES) && feetCover) return if((H.movement_type & FLYING) || H.buckled) diff --git a/code/datums/components/earhealing.dm b/code/datums/components/earhealing.dm index 6eb71285e0..bd3d57480d 100644 --- a/code/datums/components/earhealing.dm +++ b/code/datums/components/earhealing.dm @@ -26,5 +26,5 @@ if(!HAS_TRAIT(wearer, TRAIT_DEAF)) var/obj/item/organ/ears/ears = wearer.getorganslot(ORGAN_SLOT_EARS) if (ears) - ears.deaf = max(ears.deaf - 1, (ears.ear_damage < UNHEALING_EAR_DAMAGE ? 0 : 1)) // Do not clear deafness while above the unhealing ear damage threshold - ears.ear_damage = max(ears.ear_damage - 0.1, 0) + ears.deaf = max(ears.deaf - 1, (ears.damage < ears.maxHealth ? 0 : 1)) // Do not clear deafness if our ears are too damaged + ears.damage = max(ears.damage - 0.1, 0) diff --git a/code/datums/components/footstep.dm b/code/datums/components/footstep.dm index bfcc49f453..c4e65ea120 100644 --- a/code/datums/components/footstep.dm +++ b/code/datums/components/footstep.dm @@ -1,105 +1,108 @@ -/datum/component/footstep - var/steps = 0 - var/volume - var/e_range - -/datum/component/footstep/Initialize(volume_ = 0.5, e_range_ = -1) - if(!isliving(parent)) - return COMPONENT_INCOMPATIBLE - volume = volume_ - e_range = e_range_ - RegisterSignal(parent, list(COMSIG_MOVABLE_MOVED), .proc/play_footstep) - -/datum/component/footstep/proc/play_footstep() - var/turf/open/T = get_turf(parent) - if(!istype(T)) - return - - var/mob/living/LM = parent - var/v = volume - var/e = e_range - if(!T.footstep || LM.buckled || LM.lying || !LM.canmove || LM.resting || LM.buckled || LM.throwing || LM.movement_type & (VENTCRAWLING | FLYING)) - if (LM.lying && !(!T.footstep || LM.movement_type & (VENTCRAWLING | FLYING))) //play crawling sound if we're lying - playsound(T, 'sound/effects/footstep/crawl1.ogg', 15 * v) - return - - if(iscarbon(LM)) - var/mob/living/carbon/C = LM - if(!C.get_bodypart(BODY_ZONE_L_LEG) && !C.get_bodypart(BODY_ZONE_R_LEG)) - return - if(ishuman(C) && C.m_intent == MOVE_INTENT_WALK) - v /= 2 - e -= 5 - steps++ - - if(steps >= 3) - steps = 0 - - else - return - - if(prob(80) && !LM.has_gravity(T)) // don't need to step as often when you hop around - return - - //begin playsound shenanigans// - - //for barefooted non-clawed mobs like monkeys - if(isbarefoot(LM)) - playsound(T, pick(GLOB.barefootstep[T.barefootstep][1]), - GLOB.barefootstep[T.barefootstep][2] * v, - TRUE, - GLOB.barefootstep[T.barefootstep][3] + e) - return - - //for xenomorphs, dogs, and other clawed mobs - if(isclawfoot(LM)) - if(isalienadult(LM)) //xenos are stealthy and get quieter footsteps - v /= 3 - e -= 5 - - playsound(T, pick(GLOB.clawfootstep[T.clawfootstep][1]), - GLOB.clawfootstep[T.clawfootstep][2] * v, - TRUE, - GLOB.clawfootstep[T.clawfootstep][3] + e) - return - - //for megafauna and other large and imtimidating mobs such as the bloodminer - if(isheavyfoot(LM)) - playsound(T, pick(GLOB.heavyfootstep[T.heavyfootstep][1]), - GLOB.heavyfootstep[T.heavyfootstep][2] * v, - TRUE, - GLOB.heavyfootstep[T.heavyfootstep][3] + e) - return - - //for slimes - if(isslime(LM)) - playsound(T, 'sound/effects/footstep/slime1.ogg', 15 * v) - return - - //for (simple) humanoid mobs (clowns, russians, pirates, etc.) - if(isshoefoot(LM)) - if(!ishuman(LM)) - playsound(T, pick(GLOB.footstep[T.footstep][1]), - GLOB.footstep[T.footstep][2] * v, - TRUE, - GLOB.footstep[T.footstep][3] + e) - return - if(ishuman(LM)) //for proper humans, they're special - var/mob/living/carbon/human/H = LM - var/feetCover = (H.wear_suit && (H.wear_suit.body_parts_covered & FEET)) || (H.w_uniform && (H.w_uniform.body_parts_covered & FEET)) - - if (H.dna.features["taur"] == "Naga" || H.dna.features["taur"] == "Tentacle") //are we a naga or tentacle taur creature - playsound(T, 'sound/effects/footstep/crawl1.ogg', 15 * v) - return - - if(H.shoes || feetCover) //are we wearing shoes - playsound(T, pick(GLOB.footstep[T.footstep][1]), - GLOB.footstep[T.footstep][2] * v, - TRUE, - GLOB.footstep[T.footstep][3] + e) - - if((!H.shoes && !feetCover)) //are we NOT wearing shoes - playsound(T, pick(GLOB.barefootstep[T.barefootstep][1]), - GLOB.barefootstep[T.barefootstep][2] * v, - TRUE, +/datum/component/footstep + var/steps = 0 + var/volume + var/e_range + +/datum/component/footstep/Initialize(volume_ = 0.5, e_range_ = -1) + if(!isliving(parent)) + return COMPONENT_INCOMPATIBLE + volume = volume_ + e_range = e_range_ + RegisterSignal(parent, list(COMSIG_MOVABLE_MOVED), .proc/play_footstep) + +/datum/component/footstep/proc/play_footstep() + var/turf/open/T = get_turf(parent) + if(!istype(T)) + return + + var/mob/living/LM = parent + var/v = volume + var/e = e_range + if(!T.footstep || LM.buckled || LM.lying || !LM.canmove || LM.resting || LM.buckled || LM.throwing || LM.movement_type & (VENTCRAWLING | FLYING)) + if (LM.lying && !LM.buckled && !(!T.footstep || LM.movement_type & (VENTCRAWLING | FLYING))) //play crawling sound if we're lying + playsound(T, 'sound/effects/footstep/crawl1.ogg', 15 * v) + return + + if(HAS_TRAIT(LM, TRAIT_SILENT_STEP)) + return + + if(iscarbon(LM)) + var/mob/living/carbon/C = LM + if(!C.get_bodypart(BODY_ZONE_L_LEG) && !C.get_bodypart(BODY_ZONE_R_LEG)) + return + if(ishuman(C) && C.m_intent == MOVE_INTENT_WALK) + v /= 2 + e -= 5 + steps++ + + if(steps >= 3) + steps = 0 + + else + return + + if(prob(80) && !LM.has_gravity(T)) // don't need to step as often when you hop around + return + + //begin playsound shenanigans// + + //for barefooted non-clawed mobs like monkeys + if(isbarefoot(LM)) + playsound(T, pick(GLOB.barefootstep[T.barefootstep][1]), + GLOB.barefootstep[T.barefootstep][2] * v, + TRUE, + GLOB.barefootstep[T.barefootstep][3] + e) + return + + //for xenomorphs, dogs, and other clawed mobs + if(isclawfoot(LM)) + if(isalienadult(LM)) //xenos are stealthy and get quieter footsteps + v /= 3 + e -= 5 + + playsound(T, pick(GLOB.clawfootstep[T.clawfootstep][1]), + GLOB.clawfootstep[T.clawfootstep][2] * v, + TRUE, + GLOB.clawfootstep[T.clawfootstep][3] + e) + return + + //for megafauna and other large and imtimidating mobs such as the bloodminer + if(isheavyfoot(LM)) + playsound(T, pick(GLOB.heavyfootstep[T.heavyfootstep][1]), + GLOB.heavyfootstep[T.heavyfootstep][2] * v, + TRUE, + GLOB.heavyfootstep[T.heavyfootstep][3] + e) + return + + //for slimes + if(isslime(LM)) + playsound(T, 'sound/effects/footstep/slime1.ogg', 15 * v) + return + + //for (simple) humanoid mobs (clowns, russians, pirates, etc.) + if(isshoefoot(LM)) + if(!ishuman(LM)) + playsound(T, pick(GLOB.footstep[T.footstep][1]), + GLOB.footstep[T.footstep][2] * v, + TRUE, + GLOB.footstep[T.footstep][3] + e) + return + if(ishuman(LM)) //for proper humans, they're special + var/mob/living/carbon/human/H = LM + var/feetCover = (H.wear_suit && (H.wear_suit.body_parts_covered & FEET)) || (H.w_uniform && (H.w_uniform.body_parts_covered & FEET) || (H.shoes && (H.shoes.body_parts_covered & FEET))) + + if (H.dna.features["taur"] == "Naga" || H.dna.features["taur"] == "Tentacle") //are we a naga or tentacle taur creature + playsound(T, 'sound/effects/footstep/crawl1.ogg', 15 * v) + return + + if(feetCover) //are we wearing shoes + playsound(T, pick(GLOB.footstep[T.footstep][1]), + GLOB.footstep[T.footstep][2] * v, + TRUE, + GLOB.footstep[T.footstep][3] + e) + + if(!feetCover) //are we NOT wearing shoes + playsound(T, pick(GLOB.barefootstep[T.barefootstep][1]), + GLOB.barefootstep[T.barefootstep][2] * v, + TRUE, GLOB.barefootstep[T.barefootstep][3] + e) \ No newline at end of file diff --git a/code/datums/components/mood.dm b/code/datums/components/mood.dm index b32921a4ce..eb381af577 100644 --- a/code/datums/components/mood.dm +++ b/code/datums/components/mood.dm @@ -6,6 +6,7 @@ var/sanity = 100 //Current sanity var/shown_mood //Shown happiness, this is what others can see when they try to examine you, prevents antag checking by noticing traitors are always very happy. var/mood_level = 5 //To track what stage of moodies they're on + var/sanity_level = 5 //To track what stage of sanity they're on var/mood_modifier = 1 //Modifier to allow certain mobs to be less affected by moodlets var/datum/mood_event/list/mood_events = list() var/insanity_effect = 0 //is the owner being punished for low mood? If so, how much? @@ -20,6 +21,8 @@ RegisterSignal(parent, COMSIG_ADD_MOOD_EVENT, .proc/add_event) RegisterSignal(parent, COMSIG_CLEAR_MOOD_EVENT, .proc/clear_event) + RegisterSignal(parent, COMSIG_INCREASE_SANITY, .proc/IncreaseSanity) + RegisterSignal(parent, COMSIG_DECREASE_SANITY, .proc/DecreaseSanity) RegisterSignal(parent, COMSIG_MOB_HUD_CREATED, .proc/modify_hud) var/mob/living/owner = parent @@ -118,6 +121,8 @@ if(owner.client && owner.hud_used) if(sanity < 25) screen_obj.icon_state = "mood_insane" + else if (owner.has_status_effect(/datum/status_effect/chem/enthrall))//Fermichem enthral chem, maybe change? + screen_obj.icon_state = "mood_entrance" else screen_obj.icon_state = "mood[mood_level]" @@ -126,23 +131,23 @@ switch(mood_level) if(1) - DecreaseSanity(0.2) + DecreaseSanity(src, 0.2) if(2) - DecreaseSanity(0.125, SANITY_CRAZY) + DecreaseSanity(src, 0.125, SANITY_CRAZY) if(3) - DecreaseSanity(0.075, SANITY_UNSTABLE) + DecreaseSanity(src, 0.075, SANITY_UNSTABLE) if(4) - DecreaseSanity(0.025, SANITY_DISTURBED) + DecreaseSanity(src, 0.025, SANITY_DISTURBED) if(5) - IncreaseSanity(0.1) + IncreaseSanity(src, 0.1) if(6) - IncreaseSanity(0.15) + IncreaseSanity(src, 0.15) if(7) - IncreaseSanity(0.20) + IncreaseSanity(src, 0.20) if(8) - IncreaseSanity(0.25, SANITY_GREAT) + IncreaseSanity(src, 0.25, SANITY_GREAT) if(9) - IncreaseSanity(0.4, SANITY_GREAT) + IncreaseSanity(src, 0.4, SANITY_GREAT) if(insanity_effect != holdmyinsanityeffect) if(insanity_effect > holdmyinsanityeffect) @@ -163,9 +168,61 @@ HandleNutrition(owner) -/datum/component/mood/proc/DecreaseSanity(amount, minimum = SANITY_INSANE) +/datum/component/mood/proc/setSanity(amount, minimum=SANITY_INSANE, maximum=SANITY_NEUTRAL)//I'm sure bunging this in here will have no negative repercussions. + var/mob/living/master = parent + + if(amount == sanity) + return + // If we're out of the acceptable minimum-maximum range move back towards it in steps of 0.5 + // If the new amount would move towards the acceptable range faster then use it instead + if(sanity < minimum && amount < sanity + 0.5) + amount = sanity + 0.5 + else if(sanity > maximum && amount > sanity - 0.5) + amount = sanity - 0.5 + + // Disturbed stops you from getting any more sane + if(HAS_TRAIT(master, TRAIT_UNSTABLE)) + sanity = min(amount,sanity) + else + sanity = amount + + switch(sanity) + if(SANITY_INSANE to SANITY_CRAZY) + setInsanityEffect(MAJOR_INSANITY_PEN) + master.add_movespeed_modifier(MOVESPEED_ID_SANITY, TRUE, 100, override=TRUE, multiplicative_slowdown=1.5) //Did we change something ? movetypes is runtiming, movetypes=(~FLYING)) + sanity_level = 6 + if(SANITY_CRAZY to SANITY_UNSTABLE) + setInsanityEffect(MINOR_INSANITY_PEN) + master.add_movespeed_modifier(MOVESPEED_ID_SANITY, TRUE, 100, override=TRUE, multiplicative_slowdown=1)//, movetypes=(~FLYING)) + sanity_level = 5 + if(SANITY_UNSTABLE to SANITY_DISTURBED) + setInsanityEffect(0) + master.add_movespeed_modifier(MOVESPEED_ID_SANITY, TRUE, 100, override=TRUE, multiplicative_slowdown=0.5)//, movetypes=(~FLYING)) + sanity_level = 4 + if(SANITY_DISTURBED to SANITY_NEUTRAL) + setInsanityEffect(0) + master.remove_movespeed_modifier(MOVESPEED_ID_SANITY, TRUE) + sanity_level = 3 + if(SANITY_NEUTRAL+1 to SANITY_GREAT+1) //shitty hack but +1 to prevent it from responding to super small differences + setInsanityEffect(0) + master.remove_movespeed_modifier(MOVESPEED_ID_SANITY, TRUE) + sanity_level = 2 + if(SANITY_GREAT+1 to INFINITY) + setInsanityEffect(0) + master.remove_movespeed_modifier(MOVESPEED_ID_SANITY, TRUE) + sanity_level = 1 + //update_mood_icon() + +/datum/component/mood/proc/setInsanityEffect(newval)//More code so that the previous proc works + if(newval == insanity_effect) + return + var/mob/living/master = parent + master.crit_threshold = (master.crit_threshold - insanity_effect) + newval + insanity_effect = newval + +/datum/component/mood/proc/DecreaseSanity(datum/source, amount, minimum = SANITY_INSANE) if(sanity < minimum) //This might make KevinZ stop fucking pinging me. - IncreaseSanity(0.5) + IncreaseSanity(src, 0.5) else sanity = max(minimum, sanity - amount) if(sanity < SANITY_UNSTABLE) @@ -174,9 +231,13 @@ else insanity_effect = (MINOR_INSANITY_PEN) -/datum/component/mood/proc/IncreaseSanity(amount, maximum = SANITY_NEUTRAL) +/datum/component/mood/proc/IncreaseSanity(datum/source, amount, maximum = SANITY_NEUTRAL) + // Disturbed stops you from getting any more sane - I'm just gonna bung this in here + var/mob/living/owner = parent + if(HAS_TRAIT(owner, TRAIT_UNSTABLE)) + return if(sanity > maximum) - DecreaseSanity(0.5) //Removes some sanity to go back to our current limit. + DecreaseSanity(src, 0.5) //Removes some sanity to go back to our current limit. else sanity = min(maximum, sanity + amount) if(sanity > SANITY_CRAZY) @@ -195,7 +256,7 @@ if(the_event.timeout) addtimer(CALLBACK(src, .proc/clear_event, null, category), the_event.timeout, TIMER_UNIQUE|TIMER_OVERRIDE) return 0 //Don't have to update the event. - the_event = new type(src, param) + the_event = new type(src, param)//This causes a runtime for some reason, was this me? No - there's an event floating around missing a definition. mood_events[category] = the_event update_mood() @@ -203,6 +264,8 @@ if(the_event.timeout) addtimer(CALLBACK(src, .proc/clear_event, null, category), the_event.timeout, TIMER_UNIQUE|TIMER_OVERRIDE) + return the_event + /datum/component/mood/proc/clear_event(datum/source, category) var/datum/mood_event/event = mood_events[category] if(!event) diff --git a/code/datums/components/riding.dm b/code/datums/components/riding.dm index 7b80f87657..0af90f694c 100644 --- a/code/datums/components/riding.dm +++ b/code/datums/components/riding.dm @@ -162,12 +162,12 @@ if(!Process_Spacemove(direction) || !isturf(AM.loc)) return step(AM, direction) - + if((direction & (direction - 1)) && (AM.loc == next)) //moved diagonally last_move_diagonal = TRUE else last_move_diagonal = FALSE - + handle_vehicle_layer() handle_vehicle_offsets() else @@ -195,21 +195,47 @@ . = ..() RegisterSignal(parent, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, .proc/on_host_unarmed_melee) +/datum/component/riding/human/vehicle_mob_unbuckle(datum/source, mob/living/M, force = FALSE) + var/mob/living/carbon/human/H = parent + H.remove_movespeed_modifier(MOVESPEED_ID_HUMAN_CARRYING) + . = ..() + +/datum/component/riding/human/vehicle_mob_buckle(datum/source, mob/living/M, force = FALSE) + . = ..() + var/mob/living/carbon/human/H = parent + H.add_movespeed_modifier(MOVESPEED_ID_HUMAN_CARRYING, multiplicative_slowdown = HUMAN_CARRY_SLOWDOWN) + /datum/component/riding/human/proc/on_host_unarmed_melee(atom/target) - var/mob/living/carbon/human/AM = parent - if(AM.a_intent == INTENT_DISARM && (target in AM.buckled_mobs)) + var/mob/living/carbon/human/H = parent + if(H.a_intent == INTENT_DISARM && (target in H.buckled_mobs)) force_dismount(target) /datum/component/riding/human/handle_vehicle_layer() var/atom/movable/AM = parent if(AM.buckled_mobs && AM.buckled_mobs.len) - if(AM.dir == SOUTH) - AM.layer = ABOVE_MOB_LAYER + for(var/mob/M in AM.buckled_mobs) //ensure proper layering of piggyback and carry, sometimes weird offsets get applied + M.layer = MOB_LAYER + if(!AM.buckle_lying) + if(AM.dir == SOUTH) + AM.layer = ABOVE_MOB_LAYER + else + AM.layer = OBJ_LAYER else - AM.layer = OBJ_LAYER + if(AM.dir == NORTH) + AM.layer = OBJ_LAYER + else + AM.layer = ABOVE_MOB_LAYER else AM.layer = MOB_LAYER +/datum/component/riding/human/get_offsets(pass_index) + var/mob/living/carbon/human/H = parent + if(H.buckle_lying) + return list(TEXT_NORTH = list(0, 6), TEXT_SOUTH = list(0, 6), TEXT_EAST = list(0, 6), TEXT_WEST = list(0, 6)) + else + return list(TEXT_NORTH = list(0, 6), TEXT_SOUTH = list(0, 6), TEXT_EAST = list(-6, 4), TEXT_WEST = list( 6, 4)) + + /datum/component/riding/human/force_dismount(mob/living/user) var/atom/movable/AM = parent AM.unbuckle_mob(user) @@ -273,12 +299,15 @@ M.throw_at(target, 14, 5, AM) M.Knockdown(60) -/datum/component/riding/proc/equip_buckle_inhands(mob/living/carbon/human/user, amount_required = 1) +/datum/component/riding/proc/equip_buckle_inhands(mob/living/carbon/human/user, amount_required = 1, riding_target_override = null) var/atom/movable/AM = parent var/amount_equipped = 0 for(var/amount_needed = amount_required, amount_needed > 0, amount_needed--) var/obj/item/riding_offhand/inhand = new /obj/item/riding_offhand(user) - inhand.rider = user + if(!riding_target_override) + inhand.rider = user + else + inhand.rider = riding_target_override inhand.parent = AM if(user.put_in_hands(inhand, TRUE)) amount_equipped++ @@ -318,7 +347,7 @@ . = ..() /obj/item/riding_offhand/equipped() - if(loc != rider) + if(loc != rider && loc != parent) selfdeleting = TRUE qdel(src) . = ..() diff --git a/code/datums/components/storage/concrete/emergency.dm b/code/datums/components/storage/concrete/emergency.dm index 48880ff605..348821a913 100644 --- a/code/datums/components/storage/concrete/emergency.dm +++ b/code/datums/components/storage/concrete/emergency.dm @@ -36,3 +36,4 @@ /datum/component/storage/concrete/emergency/proc/unlock_me(datum/source) if(locked) set_locked(source, FALSE) + return TRUE diff --git a/code/datums/components/storage/concrete/pockets.dm b/code/datums/components/storage/concrete/pockets.dm index e0a23b0209..fe5e1e5217 100644 --- a/code/datums/components/storage/concrete/pockets.dm +++ b/code/datums/components/storage/concrete/pockets.dm @@ -52,18 +52,18 @@ . = ..() cant_hold = typecacheof(list(/obj/item/screwdriver/power)) can_hold = typecacheof(list( - /obj/item/kitchen/knife, /obj/item/switchblade, /obj/item/pen, + /obj/item/kitchen/knife, /obj/item/switchblade, /obj/item/pen, /obj/item/melee/cultblade/dagger, /obj/item/scalpel, /obj/item/reagent_containers/syringe, /obj/item/dnainjector, /obj/item/reagent_containers/hypospray/medipen, /obj/item/reagent_containers/dropper, /obj/item/implanter, /obj/item/screwdriver, /obj/item/weldingtool/mini, - /obj/item/firing_pin + /obj/item/firing_pin, /obj/item/gun/ballistic/automatic/pistol/mag )) /datum/component/storage/concrete/pockets/shoes/clown/Initialize() . = ..() cant_hold = typecacheof(list(/obj/item/screwdriver/power)) can_hold = typecacheof(list( - /obj/item/kitchen/knife, /obj/item/switchblade, /obj/item/pen, + /obj/item/kitchen/knife, /obj/item/switchblade, /obj/item/pen, /obj/item/melee/cultblade/dagger, /obj/item/scalpel, /obj/item/reagent_containers/syringe, /obj/item/dnainjector, /obj/item/reagent_containers/hypospray/medipen, /obj/item/reagent_containers/dropper, /obj/item/implanter, /obj/item/screwdriver, /obj/item/weldingtool/mini, diff --git a/code/datums/components/storage/storage.dm b/code/datums/components/storage/storage.dm index 0c701cb943..adec6f67ce 100644 --- a/code/datums/components/storage/storage.dm +++ b/code/datums/components/storage/storage.dm @@ -234,7 +234,7 @@ /datum/component/storage/proc/quick_empty(mob/M) var/atom/A = parent - if((!ishuman(M) && (A.loc != M)) || (M.stat != CONSCIOUS) || M.restrained() || !M.canmove) + if(!M.canUseStorage() || !A.Adjacent(M) || M.incapacitated()) return if(check_locked(null, M, TRUE)) return FALSE diff --git a/code/datums/components/uplink.dm b/code/datums/components/uplink.dm index 8982530ab6..2c3b7518ba 100644 --- a/code/datums/components/uplink.dm +++ b/code/datums/components/uplink.dm @@ -24,8 +24,9 @@ GLOBAL_LIST_EMPTY(uplinks) var/unlock_note var/unlock_code var/failsafe_code + var/datum/ui_state/checkstate -/datum/component/uplink/Initialize(_owner, _lockable = TRUE, _enabled = FALSE, datum/game_mode/_gamemode, starting_tc = 20) +/datum/component/uplink/Initialize(_owner, _lockable = TRUE, _enabled = FALSE, datum/game_mode/_gamemode, starting_tc = 20, datum/ui_state/_checkstate) if(!isitem(parent)) return COMPONENT_INCOMPATIBLE @@ -57,6 +58,7 @@ GLOBAL_LIST_EMPTY(uplinks) active = _enabled gamemode = _gamemode telecrystals = starting_tc + checkstate = _checkstate if(!lockable) active = TRUE locked = FALSE @@ -115,6 +117,7 @@ GLOBAL_LIST_EMPTY(uplinks) /datum/component/uplink/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.inventory_state) + state = checkstate ? checkstate : state active = TRUE ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) @@ -123,6 +126,12 @@ GLOBAL_LIST_EMPTY(uplinks) ui.set_style("syndicate") ui.open() +/datum/component/uplink/ui_host(mob/user) + if(istype(parent, /obj/item/implant)) //implants are like organs, not really located inside mobs codewise. + var/obj/item/implant/I = parent + return I.imp_in + return ..() + /datum/component/uplink/ui_data(mob/user) if(!user.mind) return diff --git a/code/datums/components/virtual_reality.dm b/code/datums/components/virtual_reality.dm new file mode 100644 index 0000000000..750cc045ce --- /dev/null +++ b/code/datums/components/virtual_reality.dm @@ -0,0 +1,128 @@ +/datum/component/virtual_reality + dupe_mode = COMPONENT_DUPE_ALLOWED //mindswap memes, shouldn't stack up otherwise. + var/datum/mind/mastermind // where is my mind t. pixies + var/datum/mind/current_mind + var/obj/machinery/vr_sleeper/vr_sleeper + var/datum/action/quit_vr/quit_action + var/you_die_in_the_game_you_die_for_real = FALSE + var/datum/component/virtual_reality/inception //The component works on a very fragile link betwixt mind, ckey and death. + +/datum/component/virtual_reality/Initialize(mob/M, obj/machinery/vr_sleeper/gaming_pod, yolo = FALSE, new_char = TRUE) + if(!ismob(parent) || !istype(M)) + return COMPONENT_INCOMPATIBLE + var/mob/vr_M = parent + mastermind = M.mind + RegisterSignal(M, list(COMSIG_MOB_DEATH, COMSIG_PARENT_QDELETED), .proc/game_over) + RegisterSignal(M, COMSIG_MOB_KEY_CHANGE, .proc/switch_player) + RegisterSignal(mastermind, COMSIG_MIND_TRANSFER, .proc/switch_player) + you_die_in_the_game_you_die_for_real = yolo + quit_action = new() + if(gaming_pod) + vr_sleeper = gaming_pod + RegisterSignal(vr_sleeper, COMSIG_ATOM_EMAG_ACT, .proc/you_only_live_once) + RegisterSignal(vr_sleeper, COMSIG_MACHINE_EJECT_OCCUPANT, .proc/revert_to_reality) + vr_M.ckey = M.ckey + var/datum/component/virtual_reality/clusterfk = M.GetComponent(/datum/component/virtual_reality) + if(clusterfk && !clusterfk.inception) + clusterfk.inception = src + SStgui.close_user_uis(M, src) + +/datum/component/virtual_reality/RegisterWithParent() + var/mob/M = parent + current_mind = M.mind + quit_action.Grant(M) + RegisterSignal(quit_action, COMSIG_ACTION_TRIGGER, .proc/revert_to_reality) + RegisterSignal(M, list(COMSIG_MOB_DEATH, COMSIG_PARENT_QDELETED), .proc/game_over) + RegisterSignal(M, COMSIG_MOB_GHOSTIZE, .proc/be_a_quitter) + RegisterSignal(M, COMSIG_MOB_KEY_CHANGE, .proc/pass_me_the_remote) + RegisterSignal(current_mind, COMSIG_MIND_TRANSFER, .proc/pass_me_the_remote) + mastermind.current.audiovisual_redirect = M + if(vr_sleeper) + vr_sleeper.vr_mob = M + +/datum/component/virtual_reality/UnregisterFromParent() + quit_action.Remove(parent) + UnregisterSignal(parent, list(COMSIG_MOB_DEATH, COMSIG_PARENT_QDELETED, COMSIG_MOB_KEY_CHANGE, COMSIG_MOB_GHOSTIZE)) + UnregisterSignal(current_mind, COMSIG_MIND_TRANSFER) + UnregisterSignal(quit_action, COMSIG_ACTION_TRIGGER) + current_mind = null + mastermind.current.audiovisual_redirect = null + +/datum/component/virtual_reality/proc/switch_player(datum/source, mob/new_mob, mob/old_mob) + if(vr_sleeper || !new_mob.mind) + // Machineries currently don't deal up with the occupant being polymorphed et similar... Or did something fuck up? + revert_to_reality() + return + old_mob.audiovisual_redirect = null + new_mob.audiovisual_redirect = parent + +/datum/component/virtual_reality/proc/action_trigger(datum/signal_source, datum/action/source) + if(source != quit_action) + return COMPONENT_ACTION_BLOCK_TRIGGER + revert_to_reality(signal_source) + +/datum/component/virtual_reality/proc/you_only_live_once() + if(you_die_in_the_game_you_die_for_real || vr_sleeper?.only_current_user_can_interact) + return FALSE + you_die_in_the_game_you_die_for_real = TRUE + return TRUE + +/datum/component/virtual_reality/proc/pass_me_the_remote(datum/source, mob/new_mob) + if(new_mob == mastermind.current) + revert_to_reality(source) + return TRUE + new_mob.TakeComponent(src) + return TRUE + +/datum/component/virtual_reality/PostTransfer() + if(!ismob(parent)) + return COMPONENT_INCOMPATIBLE + +/datum/component/virtual_reality/proc/revert_to_reality(datum/source) + quit_it() + +/datum/component/virtual_reality/proc/game_over(datum/source) + quit_it(TRUE, TRUE) + +/datum/component/virtual_reality/proc/be_a_quitter(datum/source, can_reenter_corpse) + quit_it() + return COMPONENT_BLOCK_GHOSTING + +/datum/component/virtual_reality/proc/virtual_reality_in_a_virtual_reality(mob/player, killme = FALSE, datum/component/virtual_reality/yo_dawg) + var/mob/M = parent + quit_it(FALSE, killme, player, yo_dawg) + yo_dawg.inception = null + if(killme) + M.death(FALSE) + +/datum/component/virtual_reality/proc/quit_it(deathcheck = FALSE, cleanup = FALSE, mob/override) + var/mob/M = parent + var/mob/dreamer = override ? override : mastermind.current + if(!mastermind) + to_chat(M, "You feel a dreadful sensation, something terrible happened. You try to wake up, but you find yourself unable to...") + else + var/key_transfer = FALSE + if(inception?.parent) + inception.virtual_reality_in_a_virtual_reality(dreamer, cleanup, src) + else + key_transfer = TRUE + if(key_transfer) + M.transfer_ckey(dreamer, FALSE) + dreamer.stop_sound_channel(CHANNEL_HEARTBEAT) + dreamer.audiovisual_redirect = null + if(deathcheck && you_die_in_the_game_you_die_for_real) + to_chat(mastermind, "You feel everything fading away...") + dreamer.death(FALSE) + if(cleanup) + var/obj/effect/vr_clean_master/cleanbot = locate() in get_area(M) + if(cleanbot) + LAZYADD(cleanbot.corpse_party, M) + if(vr_sleeper) + vr_sleeper.vr_mob = null + vr_sleeper = null + qdel(src) + +/datum/component/virtual_reality/Destroy() + var/datum/action/quit_vr/delet_me = quit_action + . = ..() + qdel(delet_me) \ No newline at end of file diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm index f0fb7f6095..cfbd8be32c 100644 --- a/code/datums/datumvars.dm +++ b/code/datums/datumvars.dm @@ -94,10 +94,23 @@ TOXIN:[M.getToxLoss()] OXY:[M.getOxyLoss()] CLONE:[M.getCloneLoss()] - BRAIN:[M.getBrainLoss()] + BRAIN:[M.getOrganLoss(ORGAN_SLOT_BRAIN)] STAMINA:[M.getStaminaLoss()] AROUSAL:[M.getArousalLoss()] - + "} + if(GLOB.Debug2) + atomsnowflake += {" + HEART:[M.getOrganLoss(ORGAN_SLOT_HEART)] + LIVER:[M.getOrganLoss(ORGAN_SLOT_LIVER)] + LUNGS:[M.getOrganLoss(ORGAN_SLOT_LUNGS)] + EYES:[M.getOrganLoss(ORGAN_SLOT_EYES)] + EARS:[M.getOrganLoss(ORGAN_SLOT_EARS)] + STOMACH:[M.getOrganLoss(ORGAN_SLOT_STOMACH)] + TONGUE:[M.getOrganLoss(ORGAN_SLOT_TONGUE)] + APPENDIX:[M.getOrganLoss(ORGAN_SLOT_APPENDIX)] + "} + atomsnowflake += {" + "} else atomsnowflake += "[D]" @@ -1334,8 +1347,8 @@ L.adjustOxyLoss(amount) newamt = L.getOxyLoss() if("brain") - L.adjustBrainLoss(amount) - newamt = L.getBrainLoss() + L.adjustOrganLoss(ORGAN_SLOT_BRAIN, amount) + newamt = L.getOrganLoss(ORGAN_SLOT_BRAIN) if("clone") L.adjustCloneLoss(amount) newamt = L.getCloneLoss() @@ -1345,6 +1358,30 @@ if("arousal") L.adjustArousalLoss(amount) newamt = L.getArousalLoss() + if("heart") + L.adjustOrganLoss(ORGAN_SLOT_HEART, amount) + newamt = L.getOrganLoss(ORGAN_SLOT_HEART) + if("liver") + L.adjustOrganLoss(ORGAN_SLOT_LIVER, amount) + newamt = L.getOrganLoss(ORGAN_SLOT_LIVER) + if("lungs") + L.adjustOrganLoss(ORGAN_SLOT_LUNGS, amount) + newamt = L.getOrganLoss(ORGAN_SLOT_LUNGS) + if("eye_sight") + L.adjustOrganLoss(ORGAN_SLOT_EYES, amount) + newamt = L.getOrganLoss(ORGAN_SLOT_EYES) + if("ears") + L.adjustOrganLoss(ORGAN_SLOT_EARS, amount) + newamt = L.getOrganLoss(ORGAN_SLOT_EARS) + if("stomach") + L.adjustOrganLoss(ORGAN_SLOT_STOMACH, amount) + newamt = L.getOrganLoss(ORGAN_SLOT_STOMACH) + if("tongue") + L.adjustOrganLoss(ORGAN_SLOT_TONGUE, amount) + newamt = L.getOrganLoss(ORGAN_SLOT_TONGUE) + if("appendix") + L.adjustOrganLoss(ORGAN_SLOT_APPENDIX, amount) + newamt = L.getOrganLoss(ORGAN_SLOT_APPENDIX) else to_chat(usr, "You caused an error. DEBUG: Text:[Text] Mob:[L]") return @@ -1360,4 +1397,4 @@ return var/mob/living/carbon/human/H = locate(href_list["copyoutfit"]) in GLOB.carbon_list if(istype(H)) - H.copy_outfit() \ No newline at end of file + H.copy_outfit() diff --git a/code/datums/diseases/_MobProcs.dm b/code/datums/diseases/_MobProcs.dm index e1432bf9a6..c125a9b7c7 100644 --- a/code/datums/diseases/_MobProcs.dm +++ b/code/datums/diseases/_MobProcs.dm @@ -144,3 +144,9 @@ if(!((locate(thing) in bodyparts) || (locate(thing) in internal_organs))) return FALSE return ..() + +/mob/living/proc/CanSpreadAirborneDisease() + return !is_mouth_covered() + +/mob/living/carbon/CanSpreadAirborneDisease() + return !((head && (head.flags_cover & HEADCOVERSMOUTH) && (head.armor.getRating("bio") >= 25)) || (wear_mask && (wear_mask.flags_cover & MASKCOVERSMOUTH) && (wear_mask.armor.getRating("bio") >= 25))) \ No newline at end of file diff --git a/code/datums/diseases/_disease.dm b/code/datums/diseases/_disease.dm index 0af4eea8ac..8a6966666e 100644 --- a/code/datums/diseases/_disease.dm +++ b/code/datums/diseases/_disease.dm @@ -55,6 +55,13 @@ D.after_add() infectee.med_hud_set_status() + var/turf/source_turf = get_turf(infectee) + log_virus("[key_name(infectee)] was infected by virus: [src.admin_details()] at [loc_name(source_turf)]") + +//Return a string for admin logging uses, should describe the disease in detail +/datum/disease/proc/admin_details() + return "[src.name] : [src.type]" + /datum/disease/proc/stage_act() var/cure = has_cure() @@ -65,15 +72,17 @@ if(!cure) if(prob(stage_prob)) - stage = min(stage + 1,max_stages) + update_stage(min(stage + 1,max_stages)) else if(prob(cure_chance)) - stage = max(stage - 1, 1) + update_stage(max(stage - 1, 1)) if(disease_flags & CURABLE) if(cure && prob(cure_chance)) cure() +/datum/disease/proc/update_stage(new_stage) + stage = new_stage /datum/disease/proc/has_cure() if(!(disease_flags & CURABLE)) diff --git a/code/datums/diseases/advance/advance.dm b/code/datums/diseases/advance/advance.dm index f506f44ad5..8d5e915b31 100644 --- a/code/datums/diseases/advance/advance.dm +++ b/code/datums/diseases/advance/advance.dm @@ -31,13 +31,43 @@ var/id = "" var/processing = FALSE var/mutable = TRUE //set to FALSE to prevent most in-game methods of altering the disease via virology + var/oldres //To prevent setting new cures unless resistance changes. - // The order goes from easy to cure to hard to cure. + // The order goes from easy to cure to hard to cure. Keep in mind that sentient diseases pick two cures from tier 6 and up, ensure they wont react away in bodies. var/static/list/advance_cures = list( - "sodiumchloride", "sugar", "orangejuice", - "spaceacillin", "salglu_solution", "ethanol", - "leporazine", "synaptizine", "lipolicide", - "silver", "gold" + list( // level 1 + "copper", "silver", "iodine", "iron", "carbon" + ), + list( // level 2 + "potassium", "ethanol", "lithium", "silicon", "bromine" + ), + list( // level 3 + "sodiumchloride", "sugar", "orangejuice", "tomatojuice", "milk" + ), + list( //level 4 + "spaceacillin", "salglu_solution", "epinephrine", "charcoal" + ), + list( //level 5 + "oil", "synaptizine", "mannitol", "space_drugs", "cryptobiolin" + ), + list( // level 6 + "phenol", "inacusiate", "oculine", "antihol" + ), + list( // level 7 + "leporazine", "mindbreaker", "corazone" + ), + list( // level 8 + "pax", "happiness", "ephedrine" + ), + list( // level 9 + "lipolicide", "sal_acid" + ), + list( // level 10 + "haloperidol", "aranesp", "diphenhydramine" + ), + list( //level 11 + "modafinil", "anacea" + ) ) /* @@ -80,15 +110,22 @@ return if(symptoms && symptoms.len) - if(!processing) processing = TRUE for(var/datum/symptom/S in symptoms) - S.Start(src) + if(S.Start(src)) //this will return FALSE if the symptom is neutered + S.next_activation = world.time + rand(S.symptom_delay_min * 10, S.symptom_delay_max * 10) + S.on_stage_change(src) for(var/datum/symptom/S in symptoms) S.Activate(src) +// Tell symptoms stage changed +/datum/disease/advance/update_stage(new_stage) + ..() + for(var/datum/symptom/S in symptoms) + S.on_stage_change(src) + // Compares type then ID. /datum/disease/advance/IsSame(datum/disease/advance/D) @@ -108,9 +145,18 @@ A.properties = properties.Copy() A.id = id A.mutable = mutable + A.oldres = oldres //this is a new disease starting over at stage 1, so processing is not copied return A +//Describe this disease to an admin in detail (for logging) +/datum/disease/advance/admin_details() + var/list/name_symptoms = list() + for(var/datum/symptom/S in symptoms) + name_symptoms += S.name + return "[name] sym:[english_list(name_symptoms)] r:[totalResistance()] s:[totalStealth()] ss:[totalStageSpeed()] t:[totalTransmittable()]" + + /* NEW PROCS @@ -161,6 +207,10 @@ /datum/disease/advance/proc/Refresh(new_name = FALSE) GenerateProperties() AssignProperties() + if(processing && symptoms && symptoms.len) + for(var/datum/symptom/S in symptoms) + S.Start(src) + S.on_stage_change(src) id = null var/the_id = GetDiseaseID() @@ -250,7 +300,10 @@ /datum/disease/advance/proc/GenerateCure() if(properties && properties.len) var/res = CLAMP(properties["resistance"] - (symptoms.len / 2), 1, advance_cures.len) - cures = list(advance_cures[res]) + if(res == oldres) + return + cures = list(pick(advance_cures[res])) + oldres = res // Get the cure name from the cure_id var/datum/reagent/D = GLOB.chemical_reagents_list[cures[1]] @@ -309,28 +362,28 @@ return id -// Add a symptom, if it is over the limit (with a small chance to be able to go over) -// we take a random symptom away and add the new one. +// Add a symptom, if it is over the limit we take a random symptom away and add the new one. /datum/disease/advance/proc/AddSymptom(datum/symptom/S) if(HasSymptom(S)) return - if(symptoms.len < (VIRUS_SYMPTOM_LIMIT - 1) + rand(-1, 1)) - symptoms += S - else + if(!(symptoms.len < (VIRUS_SYMPTOM_LIMIT - 1) + rand(-1, 1))) RemoveSymptom(pick(symptoms)) - symptoms += S + symptoms += S + S.OnAdd(src) // Simply removes the symptom. /datum/disease/advance/proc/RemoveSymptom(datum/symptom/S) symptoms -= S + S.OnRemove(src) // Neuter a symptom, so it will only affect stats /datum/disease/advance/proc/NeuterSymptom(datum/symptom/S) if(!S.neutered) S.neutered = TRUE S.name += " (neutered)" + S.OnRemove(src) /* @@ -384,7 +437,7 @@ var/i = VIRUS_SYMPTOM_LIMIT - var/datum/disease/advance/D = new(0, null) + var/datum/disease/advance/D = new() D.symptoms = list() var/list/symptoms = list() @@ -412,9 +465,6 @@ D.AssignName(new_name) D.Refresh() - for(var/datum/disease/advance/AD in SSdisease.active_diseases) - AD.Refresh() - for(var/mob/living/carbon/human/H in shuffle(GLOB.alive_mob_list)) if(!is_station_level(H.z)) continue @@ -425,8 +475,8 @@ var/list/name_symptoms = list() for(var/datum/symptom/S in D.symptoms) name_symptoms += S.name - message_admins("[key_name_admin(user)] has triggered a custom virus outbreak of [D.name]! It has these symptoms: [english_list(name_symptoms)]") - + message_admins("[key_name_admin(user)] has triggered a custom virus outbreak of [D.admin_details()]") + log_virus("[key_name(user)] has triggered a custom virus outbreak of [D.admin_details()]!") /datum/disease/advance/proc/totalStageSpeed() return properties["stage_rate"] diff --git a/code/datums/diseases/advance/symptoms/choking.dm b/code/datums/diseases/advance/symptoms/choking.dm index 81cdad8042..a54b132de1 100644 --- a/code/datums/diseases/advance/symptoms/choking.dm +++ b/code/datums/diseases/advance/symptoms/choking.dm @@ -144,5 +144,5 @@ Bonus /datum/symptom/asphyxiation/proc/Asphyxiate_death(mob/living/M, datum/disease/advance/A) var/get_damage = rand(25,35) * power M.adjustOxyLoss(get_damage) - M.adjustBrainLoss(get_damage/2) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, get_damage/2) return 1 diff --git a/code/datums/diseases/advance/symptoms/confusion.dm b/code/datums/diseases/advance/symptoms/confusion.dm index e7315c6bb1..260c6888d7 100644 --- a/code/datums/diseases/advance/symptoms/confusion.dm +++ b/code/datums/diseases/advance/symptoms/confusion.dm @@ -55,7 +55,7 @@ Bonus to_chat(M, "You can't think straight!") M.confused = min(100 * power, M.confused + 8) if(brain_damage) - M.adjustBrainLoss(3 * power, 80) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 3 * power, 80) M.updatehealth() return diff --git a/code/datums/diseases/advance/symptoms/cough.dm b/code/datums/diseases/advance/symptoms/cough.dm index 83d93c55e0..e4283101f5 100644 --- a/code/datums/diseases/advance/symptoms/cough.dm +++ b/code/datums/diseases/advance/symptoms/cough.dm @@ -70,6 +70,6 @@ BONUS addtimer(CALLBACK(M, /mob/.proc/emote, "cough"), 6) addtimer(CALLBACK(M, /mob/.proc/emote, "cough"), 12) addtimer(CALLBACK(M, /mob/.proc/emote, "cough"), 18) - if(infective) + if(infective && M.CanSpreadAirborneDisease()) A.spread(1) diff --git a/code/datums/diseases/advance/symptoms/deafness.dm b/code/datums/diseases/advance/symptoms/deafness.dm index cc388f0b59..3718104b48 100644 --- a/code/datums/diseases/advance/symptoms/deafness.dm +++ b/code/datums/diseases/advance/symptoms/deafness.dm @@ -50,9 +50,9 @@ Bonus if(5) if(power > 2) var/obj/item/organ/ears/ears = M.getorganslot(ORGAN_SLOT_EARS) - if(istype(ears) && ears.ear_damage < UNHEALING_EAR_DAMAGE) + if(istype(ears) && ears.damage < ears.maxHealth) to_chat(M, "Your ears pop painfully and start bleeding!") - ears.ear_damage = max(ears.ear_damage, UNHEALING_EAR_DAMAGE) + ears.damage = max(ears.damage, ears.maxHealth) M.emote("scream") else to_chat(M, "Your ears pop and begin ringing loudly!") diff --git a/code/datums/diseases/advance/symptoms/heal.dm b/code/datums/diseases/advance/symptoms/heal.dm index e666c7acd6..1ab3456c22 100644 --- a/code/datums/diseases/advance/symptoms/heal.dm +++ b/code/datums/diseases/advance/symptoms/heal.dm @@ -219,8 +219,10 @@ level = 8 passive_message = "The pain from your wounds makes you feel oddly sleepy..." var/deathgasp = FALSE + var/stabilize = FALSE var/active_coma = FALSE //to prevent multiple coma procs threshold_desc = "Stealth 2: Host appears to die when falling into a coma.
\ + Resistance 4: The virus also stabilizes the host while they are in critical condition.
\ Stage Speed 7: Increases healing speed." /datum/symptom/heal/coma/Start(datum/disease/advance/A) @@ -228,9 +230,25 @@ return if(A.properties["stage_rate"] >= 7) power = 1.5 + if(A.properties["resistance"] >= 4) + stabilize = TRUE if(A.properties["stealth"] >= 2) deathgasp = TRUE +/datum/symptom/heal/coma/on_stage_change(datum/disease/advance/A) //mostly copy+pasted from the code for self-respiration's TRAIT_NOBREATH stuff + if(!..()) + return FALSE + if(A.stage >= 4 && stabilize) + ADD_TRAIT(A.affected_mob, TRAIT_NOCRITDAMAGE, DISEASE_TRAIT) + else + REMOVE_TRAIT(A.affected_mob, TRAIT_NOCRITDAMAGE, DISEASE_TRAIT) + return TRUE + +/datum/symptom/heal/coma/End(datum/disease/advance/A) + if(!..()) + return + REMOVE_TRAIT(A.affected_mob, TRAIT_NOCRITDAMAGE, DISEASE_TRAIT) + /datum/symptom/heal/coma/CanHeal(datum/disease/advance/A) var/mob/living/M = A.affected_mob if(HAS_TRAIT(M, TRAIT_DEATHCOMA)) diff --git a/code/datums/diseases/advance/symptoms/nanites.dm b/code/datums/diseases/advance/symptoms/nanites.dm index f288b24068..b18e089a41 100644 --- a/code/datums/diseases/advance/symptoms/nanites.dm +++ b/code/datums/diseases/advance/symptoms/nanites.dm @@ -25,7 +25,7 @@ if(!..()) return var/mob/living/carbon/M = A.affected_mob - SEND_SIGNAL(M, COMSIG_NANITE_ADJUST_VOLUME, src, power) + SEND_SIGNAL(M, COMSIG_NANITE_ADJUST_VOLUME, power) if(reverse_boost && SEND_SIGNAL(M, COMSIG_HAS_NANITES)) if(prob(A.stage_prob)) A.stage = min(A.stage + 1,A.max_stages) diff --git a/code/datums/diseases/advance/symptoms/oxygen.dm b/code/datums/diseases/advance/symptoms/oxygen.dm index 7bb6934707..65f8307101 100644 --- a/code/datums/diseases/advance/symptoms/oxygen.dm +++ b/code/datums/diseases/advance/symptoms/oxygen.dm @@ -44,9 +44,25 @@ Bonus if(4, 5) M.adjustOxyLoss(-7, 0) M.losebreath = max(0, M.losebreath - 4) - if(regenerate_blood && M.blood_volume < BLOOD_VOLUME_NORMAL) + if(regenerate_blood && M.blood_volume < (BLOOD_VOLUME_NORMAL * M.blood_ratio)) M.blood_volume += 1 else if(prob(base_message_chance)) to_chat(M, "[pick("Your lungs feel great.", "You realize you haven't been breathing.", "You don't feel the need to breathe.")]") return + +/datum/symptom/oxygen/on_stage_change(datum/disease/advance/A) + if(!..()) + return FALSE + var/mob/living/carbon/M = A.affected_mob + if(A.stage >= 4) + ADD_TRAIT(M, TRAIT_NOBREATH, DISEASE_TRAIT) + else + REMOVE_TRAIT(M, TRAIT_NOBREATH, DISEASE_TRAIT) + return TRUE + +/datum/symptom/oxygen/End(datum/disease/advance/A) + if(!..()) + return + if(A.stage >= 4) + REMOVE_TRAIT(A.affected_mob, TRAIT_NOBREATH, DISEASE_TRAIT) \ No newline at end of file diff --git a/code/datums/diseases/advance/symptoms/sensory.dm b/code/datums/diseases/advance/symptoms/sensory.dm index 8d7cc5ed70..2705e0b168 100644 --- a/code/datums/diseases/advance/symptoms/sensory.dm +++ b/code/datums/diseases/advance/symptoms/sensory.dm @@ -51,7 +51,7 @@ M.hallucination = max(0, M.hallucination - 10) if(A.stage >= 5) - M.adjustBrainLoss(-3) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, -3) if(trauma_heal_mild && iscarbon(M)) var/mob/living/carbon/C = M if(prob(10)) @@ -100,8 +100,8 @@ else if(M.eye_blind || M.eye_blurry) M.set_blindness(0) M.set_blurriness(0) - else if(eyes.eye_damage > 0) - M.adjust_eye_damage(-1) + else if(eyes.damage > 0) + eyes.applyOrganDamage(-1) else if(prob(base_message_chance)) - to_chat(M, "[pick("Your eyes feel great.","You feel like your eyes can focus more clearly.", "You don't feel the need to blink.","Your ears feel great.","Your healing feels more acute.")]") \ No newline at end of file + to_chat(M, "[pick("Your eyes feel great.","You feel like your eyes can focus more clearly.", "You don't feel the need to blink.","Your ears feel great.","Your healing feels more acute.")]") diff --git a/code/datums/diseases/advance/symptoms/sneeze.dm b/code/datums/diseases/advance/symptoms/sneeze.dm index 8fe70c542f..5e21fb3dd9 100644 --- a/code/datums/diseases/advance/symptoms/sneeze.dm +++ b/code/datums/diseases/advance/symptoms/sneeze.dm @@ -48,4 +48,5 @@ Bonus M.emote("sniff") else M.emote("sneeze") - A.spread(4 + power) \ No newline at end of file + if(M.CanSpreadAirborneDisease()) //don't spread germs if they covered their mouth + A.spread(4 + power) \ No newline at end of file diff --git a/code/datums/diseases/advance/symptoms/species.dm b/code/datums/diseases/advance/symptoms/species.dm index d0c32f3244..a8b18ae735 100644 --- a/code/datums/diseases/advance/symptoms/species.dm +++ b/code/datums/diseases/advance/symptoms/species.dm @@ -8,12 +8,14 @@ level = 5 severity = 0 -/datum/symptom/undead_adaptation/Start(datum/disease/advance/A) - if(!..()) - return +/datum/symptom/undead_adaptation/OnAdd(datum/disease/advance/A) A.process_dead = TRUE A.infectable_biotypes |= MOB_UNDEAD +/datum/symptom/undead_adaptation/OnRemove(datum/disease/advance/A) + A.process_dead = FALSE + A.infectable_biotypes -= MOB_UNDEAD + /datum/symptom/inorganic_adaptation name = "Inorganic Biology" desc = "The virus can survive and replicate even in an inorganic environment, increasing its resistance and infection rate." @@ -24,7 +26,8 @@ level = 5 severity = 0 -/datum/symptom/inorganic_adaptation/Start(datum/disease/advance/A) - if(!..()) - return - A.infectable_biotypes |= MOB_INORGANIC \ No newline at end of file +/datum/symptom/inorganic_adaptation/OnAdd(datum/disease/advance/A) + A.infectable_biotypes |= MOB_INORGANIC + +/datum/symptom/inorganic_adaptation/OnRemove(datum/disease/advance/A) + A.infectable_biotypes -= MOB_INORGANIC \ No newline at end of file diff --git a/code/datums/diseases/advance/symptoms/symptoms.dm b/code/datums/diseases/advance/symptoms/symptoms.dm index e42b68cc05..99dbd397a2 100644 --- a/code/datums/diseases/advance/symptoms/symptoms.dm +++ b/code/datums/diseases/advance/symptoms/symptoms.dm @@ -38,11 +38,10 @@ return CRASH("We couldn't assign an ID!") -// Called when processing of the advance disease, which holds this symptom, starts. +// Called when processing of the advance disease that holds this symptom infects a host and upon each Refresh() of that advance disease. /datum/symptom/proc/Start(datum/disease/advance/A) if(neutered) return FALSE - next_activation = world.time + rand(symptom_delay_min * 10, symptom_delay_max * 10) //so it doesn't instantly activate on infection return TRUE // Called when the advance disease is going to be deleted or when the advance disease stops processing. @@ -60,6 +59,11 @@ next_activation = world.time + rand(symptom_delay_min * 10, symptom_delay_max * 10) return TRUE +/datum/symptom/proc/on_stage_change(datum/disease/advance/A) + if(neutered) + return FALSE + return TRUE + /datum/symptom/proc/Copy() var/datum/symptom/new_symp = new type new_symp.name = name @@ -69,3 +73,9 @@ /datum/symptom/proc/generate_threshold_desc() return + +/datum/symptom/proc/OnAdd(datum/disease/advance/A) //Overload when a symptom needs to be active before processing, like changing biotypes. + return + +/datum/symptom/proc/OnRemove(datum/disease/advance/A) //But dont forget to remove them too. + return \ No newline at end of file diff --git a/code/datums/diseases/advance/symptoms/vision.dm b/code/datums/diseases/advance/symptoms/vision.dm index d1cc6905a6..b4a33cb837 100644 --- a/code/datums/diseases/advance/symptoms/vision.dm +++ b/code/datums/diseases/advance/symptoms/vision.dm @@ -45,7 +45,7 @@ Bonus return var/mob/living/carbon/M = A.affected_mob var/obj/item/organ/eyes/eyes = M.getorganslot(ORGAN_SLOT_EYES) - if(istype(eyes)) + if(eyes) switch(A.stage) if(1, 2) if(prob(base_message_chance) && !suppress_warning) @@ -53,20 +53,20 @@ Bonus if(3, 4) to_chat(M, "Your eyes burn!") M.blur_eyes(10) - M.adjust_eye_damage(1) + eyes.applyOrganDamage(1) else M.blur_eyes(20) - M.adjust_eye_damage(5) - if(eyes.eye_damage >= 10) + eyes.applyOrganDamage(5) + if(eyes.damage >= 10) M.become_nearsighted(EYE_DAMAGE) - if(prob(eyes.eye_damage - 10 + 1)) + if(prob(eyes.damage - 10 + 1)) if(!remove_eyes) if(!HAS_TRAIT(M, TRAIT_BLIND)) to_chat(M, "You go blind!") - M.become_blind(EYE_DAMAGE) + eyes.applyOrganDamage(eyes.maxHealth) else M.visible_message("[M]'s eyes fall off their sockets!", "Your eyes fall off their sockets!") eyes.Remove(M) eyes.forceMove(get_turf(M)) else - to_chat(M, "Your eyes burn horrifically!") \ No newline at end of file + to_chat(M, "Your eyes burn horrifically!") diff --git a/code/datums/diseases/appendicitis.dm b/code/datums/diseases/appendicitis.dm index 5708447542..be7e6ceecd 100644 --- a/code/datums/diseases/appendicitis.dm +++ b/code/datums/diseases/appendicitis.dm @@ -27,8 +27,10 @@ A.update_icon() if(prob(3)) to_chat(affected_mob, "You feel a stabbing pain in your abdomen!") + affected_mob.adjustOrganLoss(ORGAN_SLOT_APPENDIX, 5) affected_mob.Stun(rand(40,60)) affected_mob.adjustToxLoss(1) if(3) if(prob(1)) affected_mob.vomit(95) + affected_mob.adjustOrganLoss(ORGAN_SLOT_APPENDIX, 15) diff --git a/code/datums/diseases/brainrot.dm b/code/datums/diseases/brainrot.dm index 0a34501763..98ae74270b 100644 --- a/code/datums/diseases/brainrot.dm +++ b/code/datums/diseases/brainrot.dm @@ -24,7 +24,7 @@ if(prob(2)) to_chat(affected_mob, "You don't feel like yourself.") if(prob(5)) - affected_mob.adjustBrainLoss(1, 170) + affected_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, 1, 170) affected_mob.updatehealth() if(3) if(prob(2)) @@ -32,7 +32,7 @@ if(prob(2)) affected_mob.emote("drool") if(prob(10)) - affected_mob.adjustBrainLoss(2, 170) + affected_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, 2, 170) affected_mob.updatehealth() if(prob(2)) to_chat(affected_mob, "Your try to remember something important...but can't.") @@ -43,7 +43,7 @@ if(prob(2)) affected_mob.emote("drool") if(prob(15)) - affected_mob.adjustBrainLoss(3, 170) + affected_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, 3, 170) affected_mob.updatehealth() if(prob(2)) to_chat(affected_mob, "Strange buzzing fills your head, removing all thoughts.") diff --git a/code/datums/diseases/transformation.dm b/code/datums/diseases/transformation.dm index b295f5f10b..083a1f9c6c 100644 --- a/code/datums/diseases/transformation.dm +++ b/code/datums/diseases/transformation.dm @@ -67,7 +67,7 @@ if(affected_mob.mind) affected_mob.mind.transfer_to(new_mob) else - new_mob.key = affected_mob.key + affected_mob.transfer_ckey(new_mob) new_mob.name = affected_mob.real_name new_mob.real_name = new_mob.name @@ -82,7 +82,7 @@ to_chat(affected_mob, "Your mob has been taken over by a ghost! Appeal your job ban if you want to avoid this in the future!") message_admins("[key_name_admin(C)] has taken control of ([key_name_admin(affected_mob)]) to replace a jobbaned player.") affected_mob.ghostize(0) - affected_mob.key = C.key + C.transfer_ckey(affected_mob) else to_chat(new_mob, "Your mob has been claimed by death! Appeal your job ban if you want to avoid this in the future!") new_mob.death() diff --git a/code/datums/ert.dm b/code/datums/ert.dm index d61c95c8f2..4b4cce3794 100644 --- a/code/datums/ert.dm +++ b/code/datums/ert.dm @@ -21,8 +21,8 @@ /datum/ert/amber code = "Amber" - leader_role = /datum/antagonist/ert/commander/red - roles = list(/datum/antagonist/ert/security/red, /datum/antagonist/ert/medic/red, /datum/antagonist/ert/engineer/red) + leader_role = /datum/antagonist/ert/commander/amber + roles = list(/datum/antagonist/ert/security/amber, /datum/antagonist/ert/medic/amber, /datum/antagonist/ert/engineer/amber) /datum/ert/red leader_role = /datum/antagonist/ert/commander/red @@ -55,3 +55,13 @@ rename_team = "Inquisition" mission = "Destroy any traces of paranormal activity aboard the station." polldesc = "a Nanotrasen paranormal response team" + +/datum/ert/greybois + code = "Green" + teamsize = 1 + opendoors = FALSE + enforce_human = FALSE + roles = list(/datum/antagonist/greybois) + leader_role = /datum/antagonist/greybois/greygod + rename_team = "Emergency Assistants" + polldesc = "an Emergency Assistant" diff --git a/code/datums/helper_datums/teleport.dm b/code/datums/helper_datums/teleport.dm index 6462a1998a..4d1986cccf 100644 --- a/code/datums/helper_datums/teleport.dm +++ b/code/datums/helper_datums/teleport.dm @@ -8,7 +8,7 @@ // no_effects: disable the default effectin/effectout of sparks // forceMove: if false, teleport will use Move() proc (dense objects will prevent teleportation) // forced: whether or not to ignore no_teleport -/proc/do_teleport(atom/movable/teleatom, atom/destination, precision=null, forceMove = FALSE, datum/effect_system/effectin=null, datum/effect_system/effectout=null, asoundin=null, asoundout=null, no_effects=FALSE, channel=TELEPORT_CHANNEL_BLUESPACE, forced = FALSE) +/proc/do_teleport(atom/movable/teleatom, atom/destination, precision=null, forceMove = TRUE, datum/effect_system/effectin=null, datum/effect_system/effectout=null, asoundin=null, asoundout=null, no_effects=FALSE, channel=TELEPORT_CHANNEL_BLUESPACE, forced = FALSE) // teleporting most effects just deletes them var/static/list/delete_atoms = typecacheof(list( /obj/effect, diff --git a/code/datums/looping_sounds/_looping_sound.dm b/code/datums/looping_sounds/_looping_sound.dm index 1b7a304494..49942976ce 100644 --- a/code/datums/looping_sounds/_looping_sound.dm +++ b/code/datums/looping_sounds/_looping_sound.dm @@ -96,4 +96,4 @@ /datum/looping_sound/proc/on_stop() if(end_sound) - play(end_sound) \ No newline at end of file + play(end_sound) diff --git a/code/datums/map_config.dm b/code/datums/map_config.dm index 99b84a1b35..dcc16f1ba5 100644 --- a/code/datums/map_config.dm +++ b/code/datums/map_config.dm @@ -18,7 +18,7 @@ var/map_file = "BoxStation.dmm" var/traits = null - var/space_ruin_levels = 1 //Citadel edit - reduces the default space ruin z-level count to 1 + var/space_ruin_levels = 2 var/space_empty_levels = 1 var/minetype = "lavaland" diff --git a/code/datums/martial/cqc.dm b/code/datums/martial/cqc.dm index 71545476ff..c7644997ee 100644 --- a/code/datums/martial/cqc.dm +++ b/code/datums/martial/cqc.dm @@ -79,7 +79,7 @@ "[A] kicks your head, knocking you out!") playsound(get_turf(A), 'sound/weapons/genhit1.ogg', 50, 1, -1) D.SetSleeping(300) - D.adjustBrainLoss(15, 150) + D.adjustOrganLoss(ORGAN_SLOT_BRAIN, 15, 150) return TRUE /datum/martial_art/cqc/proc/Pressure(mob/living/carbon/human/A, mob/living/carbon/human/D) diff --git a/code/datums/martial/psychotic_brawl.dm b/code/datums/martial/psychotic_brawl.dm index 8f1a33a8b3..34301516dc 100644 --- a/code/datums/martial/psychotic_brawl.dm +++ b/code/datums/martial/psychotic_brawl.dm @@ -46,7 +46,7 @@ D.apply_damage(rand(5,10), BRUTE, BODY_ZONE_HEAD) A.apply_damage(rand(5,10), BRUTE, BODY_ZONE_HEAD) if(!istype(D.head,/obj/item/clothing/head/helmet/) && !istype(D.head,/obj/item/clothing/head/hardhat)) - D.adjustBrainLoss(5) + D.adjustOrganLoss(ORGAN_SLOT_BRAIN, 5) A.Stun(rand(10,45)) D.Knockdown(rand(5,30))//CIT CHANGE - makes stuns from martial arts always use Knockdown instead of Stun for the sake of consistency if(5,6) diff --git a/code/datums/martial/sleeping_carp.dm b/code/datums/martial/sleeping_carp.dm index e205d7a435..801e8c8c7a 100644 --- a/code/datums/martial/sleeping_carp.dm +++ b/code/datums/martial/sleeping_carp.dm @@ -224,7 +224,7 @@ H.visible_message("[user] delivers a heavy hit to [H]'s head, knocking [H.p_them()] out cold!", \ "[user] knocks you unconscious!") H.SetSleeping(600) - H.adjustBrainLoss(15, 150) + H.adjustOrganLoss(ORGAN_SLOT_BRAIN, 15, 150) else return ..() diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 8e61801e15..68efe93254 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -19,9 +19,9 @@ - IMPORTANT NOTE 2, if you want a player to become a ghost, use mob.ghostize() It does all the hard work for you. - When creating a new mob which will be a new IC character (e.g. putting a shade in a construct or randomly selecting - a ghost to become a xeno during an event). Simply assign the key or ckey like you've always done. + a ghost to become a xeno during an event), use this mob proc. - new_mob.key = key + mob.transfer_ckey(new_mob) The Login proc will handle making a new mind for that mobtype (including setting up stuff like mind.name). Simple! However if you want that mind to have any special properties like being a traitor etc you will have to do that @@ -89,6 +89,7 @@ return language_holder /datum/mind/proc/transfer_to(mob/new_character, var/force_key_move = 0) + var/old_character = current if(current) // remove ourself from our old body's mind variable current.mind = null SStgui.on_transfer(current, new_character) @@ -99,7 +100,7 @@ if(key) if(new_character.key != key) //if we're transferring into a body with a key associated which is not ours - new_character.ghostize(1) //we'll need to ghostize so that key isn't mobless. + new_character.ghostize(TRUE, TRUE) //we'll need to ghostize so that key isn't mobless. else key = new_character.key @@ -123,6 +124,7 @@ transfer_martial_arts(new_character) if(active || force_key_move) new_character.key = key //now transfer the key to link the client to our new body + SEND_SIGNAL(src, COMSIG_MIND_TRANSFER, new_character, old_character) //CIT CHANGE - makes arousal update when transfering bodies if(isliving(new_character)) //New humans and such are by default enabled arousal. Let's always use the new mind's prefs. diff --git a/code/datums/mood_events/drink_events.dm b/code/datums/mood_events/drink_events.dm index 5d0eb0e0cb..70acffdb8f 100644 --- a/code/datums/mood_events/drink_events.dm +++ b/code/datums/mood_events/drink_events.dm @@ -6,24 +6,24 @@ /datum/mood_event/quality_nice description = "That drink wasn't bad at all.\n" mood_change = 1 - timeout = 1200 + timeout = 2 MINUTES /datum/mood_event/quality_good description = "That drink was pretty good.\n" mood_change = 2 - timeout = 1200 + timeout = 2 MINUTES /datum/mood_event/quality_verygood description = "That drink was great!\n" mood_change = 3 - timeout = 1200 + timeout = 2 MINUTES /datum/mood_event/quality_fantastic description = "That drink was amazing!\n" mood_change = 4 - timeout = 1200 + timeout = 2 MINUTES /datum/mood_event/amazingtaste description = "Amazing taste!\n" - mood_change = 50 + mood_change = 50 //Is this not really high..? timeout = 10 MINUTES diff --git a/code/datums/mood_events/drug_events.dm b/code/datums/mood_events/drug_events.dm index 40c239180e..469bf80979 100644 --- a/code/datums/mood_events/drug_events.dm +++ b/code/datums/mood_events/drug_events.dm @@ -37,3 +37,19 @@ /datum/mood_event/withdrawal_critical/add_effects(drug_name) description = "[drug_name]! [drug_name]! [drug_name]!\n" + +/datum/mood_event/happiness_drug + description = "I can't feel anything and I never want this to end.\n" + mood_change = 10 + +/datum/mood_event/happiness_drug_good_od + description = "YES! YES!! YES!!!\n" + mood_change = 20 + timeout = 300 + //special_screen_obj = "mood_happiness_good" Originally in tg, but I personally think they look dumb + +/datum/mood_event/happiness_drug_bad_od + description = "NO! NO!! NO!!!\n" + mood_change = -20 + timeout = 300 + //special_screen_obj = "mood_happiness_bad" Originally in tg diff --git a/code/datums/mood_events/generic_negative_events.dm b/code/datums/mood_events/generic_negative_events.dm index b2b03fb56b..f747c563ad 100644 --- a/code/datums/mood_events/generic_negative_events.dm +++ b/code/datums/mood_events/generic_negative_events.dm @@ -1,3 +1,5 @@ + + /datum/mood_event/handcuffed description = "I guess my antics have finally caught up with me.\n" mood_change = -1 @@ -17,7 +19,7 @@ /datum/mood_event/burnt_thumb description = "I shouldn't play with lighters...\n" mood_change = -1 - timeout = 1200 + timeout = 2 MINUTES /datum/mood_event/cold description = "It's way too cold in here.\n" @@ -30,17 +32,17 @@ /datum/mood_event/creampie description = "I've been creamed. Tastes like pie flavor.\n" mood_change = -2 - timeout = 1800 + timeout = 3 MINUTES /datum/mood_event/slipped description = "I slipped. I should be more careful next time...\n" mood_change = -2 - timeout = 1800 + timeout = 3 MINUTES /datum/mood_event/eye_stab description = "I used to be an adventurer like you, until I took a screwdriver to the eye.\n" mood_change = -4 - timeout = 1800 + timeout = 3 MINUTES /datum/mood_event/delam //SM delamination description = "Those God damn engineers can't do anything right...\n" @@ -50,12 +52,12 @@ /datum/mood_event/depression description = "I feel sad for no particular reason.\n" mood_change = -9 - timeout = 1200 + timeout = 2 MINUTES /datum/mood_event/shameful_suicide //suicide_acts that return SHAME, like sord description = "I can't even end it all!\n" mood_change = -10 - timeout = 600 + timeout = 1 MINUTES /datum/mood_event/dismembered description = "AHH! I WAS USING THAT LIMB!\n" @@ -69,7 +71,7 @@ /datum/mood_event/tased description = "There's no \"z\" in \"taser\". It's in the zap.\n" mood_change = -3 - timeout = 1200 + timeout = 2 MINUTES /datum/mood_event/embedded description = "Pull it out!\n" @@ -78,7 +80,7 @@ /datum/mood_event/table description = "Someone threw me on a table!\n" mood_change = -2 - timeout = 1200 + timeout = 2 MINUTES /datum/mood_event/table/add_effects() if(ishuman(owner)) @@ -117,6 +119,30 @@ description = "I'm missing my family heirloom...\n" mood_change = -4 +/datum/mood_event/healsbadman + description = "I feel a lot better, but wow that was disgusting.\n" + mood_change = -4 + timeout = 2 MINUTES + +/datum/mood_event/jittery + description = "I'm nervous and on edge and I can't stand still!!\n" + mood_change = -2 + +/datum/mood_event/vomit + description = "I just threw up. Gross.\n" + mood_change = -2 + timeout = 2 MINUTES + +/datum/mood_event/vomitself + description = "I just threw up all over myself. This is disgusting.\n" + mood_change = -4 + timeout = 3 MINUTES + +/datum/mood_event/painful_medicine + description = "Medicine may be good for me but right now it stings like hell.\n" + mood_change = -5 + timeout = 1 MINUTES + /datum/mood_event/loud_gong description = "That loud gong noise really hurt my ears!\n" mood_change = -3 @@ -143,3 +169,10 @@ /datum/mood_event/sad_empath/add_effects(mob/sadtarget) description = "[sadtarget.name] seems upset...\n" + +/datum/mood_event/revenant_blight + description = "Just give up, honk...\n" + mood_change = -5 + +/datum/mood_event/revenant_blight/add_effects() + description = "Just give up, [pick("no one will miss you", "there is nothing you can do to help", "even a clown would be more useful than you", "does it even matter in the end?")]...\n" diff --git a/code/datums/mood_events/generic_positive_events.dm b/code/datums/mood_events/generic_positive_events.dm index 051a548d1d..422ec4476c 100644 --- a/code/datums/mood_events/generic_positive_events.dm +++ b/code/datums/mood_events/generic_positive_events.dm @@ -1,7 +1,7 @@ /datum/mood_event/hug description = "Hugs are nice.\n" mood_change = 1 - timeout = 1200 + timeout = 2 MINUTES /datum/mood_event/arcade description = "I beat the arcade game!\n" @@ -50,7 +50,7 @@ /datum/mood_event/jolly description = "I feel happy for no particular reason.\n" mood_change = 6 - timeout = 1200 + timeout = 2 MINUTES /datum/mood_event/focused description = "I have a goal, and I will reach it, whatever it takes!\n" //Used for syndies, nukeops etc so they can focus on their goals @@ -76,6 +76,20 @@ mood_change = 3 timeout = 600 +/datum/mood_event/chemical_euphoria + description = "Heh...hehehe...hehe...\n" + mood_change = 4 + + /datum/mood_event/chemical_laughter + description = "Laughter really is the best medicine! Or is it?\n" + mood_change = 4 + timeout = 3 MINUTES + + /datum/mood_event/chemical_superlaughter + description = "*WHEEZE*\n" + mood_change = 12 + timeout = 3 MINUTES + /datum/mood_event/betterhug description = "Someone was very nice to me.\n" mood_change = 3 @@ -94,8 +108,8 @@ /datum/mood_event/happy_empath description = "Someone seems happy!\n" - mood_change = 2 + mood_change = 3 timeout = 600 /datum/mood_event/happy_empath/add_effects(var/mob/happytarget) - description = "[happytarget.name]'s happiness is infectious!\n" + description = "[happytarget.name]'s happiness is infectious!\n" diff --git a/code/datums/mood_events/needs_events.dm b/code/datums/mood_events/needs_events.dm index 75b7e6931f..eb58f2aa92 100644 --- a/code/datums/mood_events/needs_events.dm +++ b/code/datums/mood_events/needs_events.dm @@ -59,4 +59,4 @@ /datum/mood_event/nice_shower description = "I have recently had a nice shower.\n" mood_change = 2 - timeout = 1800 + timeout = 3 MINUTES diff --git a/code/datums/mutations/body.dm b/code/datums/mutations/body.dm index 461c221ff8..a32220aa43 100644 --- a/code/datums/mutations/body.dm +++ b/code/datums/mutations/body.dm @@ -63,16 +63,14 @@ /datum/mutation/human/dwarfism/on_acquiring(mob/living/carbon/human/owner) if(..()) return - owner.resize = 0.8 - owner.update_transform() + owner.transform = owner.transform.Scale(1, 0.8) owner.pass_flags |= PASSTABLE owner.visible_message("[owner] suddenly shrinks!", "Everything around you seems to grow..") /datum/mutation/human/dwarfism/on_losing(mob/living/carbon/human/owner) if(..()) return - owner.resize = 1.25 - owner.update_transform() + owner.transform = owner.transform.Scale(1, 1.25) owner.pass_flags &= ~PASSTABLE owner.visible_message("[owner] suddenly grows!", "Everything around you seems to shrink..") diff --git a/code/datums/mutations/speech.dm b/code/datums/mutations/speech.dm index 21adc944f6..f02b7f185f 100644 --- a/code/datums/mutations/speech.dm +++ b/code/datums/mutations/speech.dm @@ -91,32 +91,29 @@ message = replacetext(message," oh god "," cheese and crackers ") message = replacetext(message," jesus "," gee wiz ") message = replacetext(message," weak "," strong ") - message = replacetext(message," kill "," hug ") - message = replacetext(message," murder "," tease ") + message = replacetext(message," kill yourself "," hug ") message = replacetext(message," ugly "," beautiful ") message = replacetext(message," douchbag "," nice guy ") message = replacetext(message," whore "," lady ") - message = replacetext(message," nerd "," smart guy ") + message = replacetext(message," nerd "," smarty pants ") message = replacetext(message," moron "," fun person ") message = replacetext(message," IT'S LOOSE "," EVERYTHING IS FINE ") message = replacetext(message," sex "," hug fight ") message = replacetext(message," idiot "," genius ") message = replacetext(message," fat "," thin ") - message = replacetext(message," beer "," water with ice ") - message = replacetext(message," drink "," water ") + message = replacetext(message," beer "," liquid bread ") + message = replacetext(message," drink "," liquid ") message = replacetext(message," feminist "," empowered woman ") - message = replacetext(message," i hate you "," you're mean ") - message = replacetext(message," nigger "," african american ") + message = replacetext(message," i hate you "," you're a mean ") message = replacetext(message," jew "," jewish ") message = replacetext(message," shit "," shiz ") message = replacetext(message," crap "," poo ") message = replacetext(message," slut "," tease ") message = replacetext(message," ass "," butt ") message = replacetext(message," damn "," dang ") - message = replacetext(message," fuck "," ") message = replacetext(message," penis "," privates ") message = replacetext(message," cunt "," privates ") - message = replacetext(message," dick "," jerk ") + message = replacetext(message," dick "," privates ") message = replacetext(message," vagina "," privates ") speech_args[SPEECH_MESSAGE] = trim(message) @@ -281,4 +278,4 @@ /datum/mutation/human/stoner/on_losing(mob/living/carbon/human/owner) ..() owner.grant_language(/datum/language/common) - owner.remove_language(/datum/language/beachbum) \ No newline at end of file + owner.remove_language(/datum/language/beachbum) diff --git a/code/datums/outfit.dm b/code/datums/outfit.dm index 1f5c28d3c2..8386b59d97 100755 --- a/code/datums/outfit.dm +++ b/code/datums/outfit.dm @@ -21,6 +21,7 @@ var/l_hand = null var/internals_slot = null //ID of slot containing a gas tank var/list/backpack_contents = null // In the list(path=count,otherpath=count) format + var/box // Internals box. Will be inserted at the start of backpack_contents var/list/implants = null var/accessory = null @@ -83,6 +84,13 @@ H.equip_to_slot_or_del(new l_pocket(H),SLOT_L_STORE) if(r_pocket) H.equip_to_slot_or_del(new r_pocket(H),SLOT_R_STORE) + + if(box) + if(!backpack_contents) + backpack_contents = list() + backpack_contents.Insert(1, box) + backpack_contents[box] = 1 + if(backpack_contents) for(var/path in backpack_contents) var/number = backpack_contents[path] @@ -104,7 +112,7 @@ H.update_action_buttons_icon() if(implants) for(var/implant_type in implants) - var/obj/item/implant/I = new implant_type(H) + var/obj/item/implant/I = new implant_type I.implant(H, null, TRUE) H.update_body() diff --git a/code/datums/radiation_wave.dm b/code/datums/radiation_wave.dm index 5fb777f9c5..6118428547 100644 --- a/code/datums/radiation_wave.dm +++ b/code/datums/radiation_wave.dm @@ -103,7 +103,6 @@ /obj/structure/cable, /obj/machinery/atmospherics, /obj/item/ammo_casing, - /obj/item/implant, /obj/singularity )) if(!can_contaminate || blacklisted[thing.type]) diff --git a/code/datums/ruins/space.dm b/code/datums/ruins/space.dm index 22fca23902..9762426608 100644 --- a/code/datums/ruins/space.dm +++ b/code/datums/ruins/space.dm @@ -305,3 +305,9 @@ suffix = "spacehermit.dmm" name = "Space Hermit" description = "A late awakening cryo pod in a crashed escape pod wakes up to find what befell of his fellow survivors. Contains all the necessary resources to actually make it out alive. Good luck." + +/datum/map_template/ruin/space/advancedlab + id = "advancedlab" + suffix = "advancedlab.dmm" + name = "Abductor Replication Lab" + description = "Some scientists tried and almost succeeded to recreate abductor tools. Somewhat slower and a bit less modern than their originals, these tools are the best you can get if you aren't an alien." diff --git a/code/datums/status_effects/buffs.dm b/code/datums/status_effects/buffs.dm index 0512977d1a..563d06ca57 100644 --- a/code/datums/status_effects/buffs.dm +++ b/code/datums/status_effects/buffs.dm @@ -170,7 +170,7 @@ tick_interval = 4 alert_type = /obj/screen/alert/status_effect/his_grace var/bloodlust = 0 - + /obj/screen/alert/status_effect/his_grace name = "His Grace" desc = "His Grace hungers, and you must feed Him." @@ -208,6 +208,7 @@ owner.adjustToxLoss(-grace_heal, TRUE, TRUE) owner.adjustOxyLoss(-(grace_heal * 2)) owner.adjustCloneLoss(-grace_heal) + owner.adjustStaminaLoss(-(grace_heal * 25)) /datum/status_effect/his_grace/on_remove() owner.log_message("lost His Grace's stun immunity", LOG_ATTACK) @@ -520,7 +521,7 @@ itemUser.adjustToxLoss(-1.5, forced = TRUE) //Because Slime People are people too itemUser.adjustOxyLoss(-1.5) itemUser.adjustStaminaLoss(-1.5) - itemUser.adjustBrainLoss(-1.5) + itemUser.adjustOrganLoss(ORGAN_SLOT_BRAIN, -1.5) itemUser.adjustCloneLoss(-0.5) //Becasue apparently clone damage is the bastion of all health //Heal all those around you, unbiased for(var/mob/living/L in view(7, owner)) @@ -532,7 +533,7 @@ L.adjustToxLoss(-3.5, forced = TRUE) //Because Slime People are people too L.adjustOxyLoss(-3.5) L.adjustStaminaLoss(-3.5) - L.adjustBrainLoss(-3.5) + L.adjustOrganLoss(ORGAN_SLOT_BRAIN, -3.5) L.adjustCloneLoss(-1) //Becasue apparently clone damage is the bastion of all health else if(issilicon(L)) L.adjustBruteLoss(-3.5) diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm index 1c77520108..186c988595 100644 --- a/code/datums/status_effects/debuffs.dm +++ b/code/datums/status_effects/debuffs.dm @@ -80,6 +80,36 @@ desc = "You've fallen asleep. Wait a bit and you should wake up. Unless you don't, considering how helpless you are." icon_state = "asleep" +//TASER +/datum/status_effect/electrode + id = "tased" + blocks_combatmode = TRUE + status_type = STATUS_EFFECT_REPLACE + alert_type = null + +/datum/status_effect/electrode/on_creation(mob/living/new_owner, set_duration) + if(isnum(set_duration)) + duration = set_duration + . = ..() + if(iscarbon(owner)) + var/mob/living/carbon/C = owner + if(C.combatmode) + C.toggle_combat_mode(TRUE) + C.add_movespeed_modifier(MOVESPEED_ID_TASED_STATUS, TRUE, override = TRUE, multiplicative_slowdown = 8) + +/datum/status_effect/electrode/on_remove() + if(iscarbon(owner)) + var/mob/living/carbon/C = owner + C.remove_movespeed_modifier(MOVESPEED_ID_TASED_STATUS) + . = ..() + +/datum/status_effect/electrode/tick() + if(owner) + owner.adjustStaminaLoss(5) //if you really want to try to stamcrit someone with a taser alone, you can, but it'll take time and good timing. + +/datum/status_effect/electrode/nextmove_modifier() //why is this a proc. its no big deal since this doesnt get called often at all but literally w h y + return 2 + //OTHER DEBUFFS /datum/status_effect/his_wrath //does minor damage over time unless holding His Grace id = "his_wrath" @@ -259,9 +289,9 @@ status_type = STATUS_EFFECT_REPLACE alert_type = null var/mutable_appearance/marked_underlay - var/obj/item/twohanded/required/kinetic_crusher/hammer_synced + var/obj/item/twohanded/kinetic_crusher/hammer_synced -/datum/status_effect/crusher_mark/on_creation(mob/living/new_owner, obj/item/twohanded/required/kinetic_crusher/new_hammer_synced) +/datum/status_effect/crusher_mark/on_creation(mob/living/new_owner, obj/item/twohanded/kinetic_crusher/new_hammer_synced) . = ..() if(.) hammer_synced = new_hammer_synced @@ -358,19 +388,20 @@ else new /obj/effect/temp_visual/bleed(get_turf(owner)) -/mob/living/proc/apply_necropolis_curse(set_curse) +/mob/living/proc/apply_necropolis_curse(set_curse, duration = 10 MINUTES) var/datum/status_effect/necropolis_curse/C = has_status_effect(STATUS_EFFECT_NECROPOLIS_CURSE) if(!set_curse) set_curse = pick(CURSE_BLINDING, CURSE_SPAWNING, CURSE_WASTING, CURSE_GRASPING) if(QDELETED(C)) - apply_status_effect(STATUS_EFFECT_NECROPOLIS_CURSE, set_curse) + apply_status_effect(STATUS_EFFECT_NECROPOLIS_CURSE, set_curse, duration) + else C.apply_curse(set_curse) - C.duration += 3000 //additional curses add 5 minutes + C.duration += duration * 0.5 //additional curses add half their duration /datum/status_effect/necropolis_curse id = "necrocurse" - duration = 6000 //you're cursed for 10 minutes have fun + duration = 10 MINUTES //you're cursed for 10 minutes have fun tick_interval = 50 alert_type = null var/curse_flags = NONE @@ -378,7 +409,9 @@ var/effect_cooldown = 100 var/obj/effect/temp_visual/curse/wasting_effect = new -/datum/status_effect/necropolis_curse/on_creation(mob/living/new_owner, set_curse) +/datum/status_effect/necropolis_curse/on_creation(mob/living/new_owner, set_curse, _duration) + if(_duration) + duration = _duration . = ..() if(.) apply_curse(set_curse) @@ -507,3 +540,101 @@ desc = "Your body is covered in blue ichor! You can't be revived by vitality matrices." icon_state = "ichorial_stain" alerttooltipstyle = "clockcult" + +datum/status_effect/pacify + id = "pacify" + status_type = STATUS_EFFECT_REPLACE + tick_interval = 1 + duration = 100 + alert_type = null + +/datum/status_effect/pacify/on_creation(mob/living/new_owner, set_duration) + if(isnum(set_duration)) + duration = set_duration + . = ..() + +/datum/status_effect/pacify/on_apply() + ADD_TRAIT(owner, TRAIT_PACIFISM, "status_effect") + return ..() + +/datum/status_effect/pacify/on_remove() + REMOVE_TRAIT(owner, TRAIT_PACIFISM, "status_effect") + +/datum/status_effect/trance + id = "trance" + status_type = STATUS_EFFECT_UNIQUE + duration = 300 + tick_interval = 10 + examine_text = "SUBJECTPRONOUN seems slow and unfocused." + var/stun = TRUE + var/triggered = FALSE + alert_type = null + +/obj/screen/alert/status_effect/trance + name = "Trance" + desc = "Everything feels so distant, and you can feel your thoughts forming loops inside your head..." + icon_state = "high" + +/datum/status_effect/trance/tick() + if(HAS_TRAIT(owner, "hypnotherapy")) + if(triggered == TRUE) + UnregisterSignal(owner, COMSIG_MOVABLE_HEAR) + RegisterSignal(owner, COMSIG_MOVABLE_HEAR, .proc/hypnotize) + ADD_TRAIT(owner, TRAIT_MUTE, "trance") + if(!owner.has_quirk(/datum/quirk/monochromatic)) + owner.add_client_colour(/datum/client_colour/monochrome) + to_chat(owner, "[pick("You feel your thoughts slow down...", "You suddenly feel extremely dizzy...", "You feel like you're in the middle of a dream...","You feel incredibly relaxed...")]") + triggered = FALSE + else + return + if(stun) + owner.Stun(60, TRUE, TRUE) + owner.dizziness = 20 + +/datum/status_effect/trance/on_apply() + if(!iscarbon(owner)) + return FALSE + if(HAS_TRAIT(owner, "hypnotherapy")) + RegisterSignal(owner, COMSIG_MOVABLE_HEAR, .proc/listen) + return TRUE + alert_type = /obj/screen/alert/status_effect/trance + RegisterSignal(owner, COMSIG_MOVABLE_HEAR, .proc/hypnotize) + ADD_TRAIT(owner, TRAIT_MUTE, "trance") + if(!owner.has_quirk(/datum/quirk/monochromatic)) + owner.add_client_colour(/datum/client_colour/monochrome) + owner.visible_message("[stun ? "[owner] stands still as [owner.p_their()] eyes seem to focus on a distant point." : ""]", \ + "[pick("You feel your thoughts slow down...", "You suddenly feel extremely dizzy...", "You feel like you're in the middle of a dream...","You feel incredibly relaxed...")]") + return TRUE + +/datum/status_effect/trance/on_creation(mob/living/new_owner, _duration, _stun = TRUE, source_quirk = FALSE)//hypnoquirk makes no visible message, prevents self antag messages, and places phrase below objectives. + duration = _duration + stun = _stun + if(source_quirk == FALSE && HAS_TRAIT(owner, "hypnotherapy")) + REMOVE_TRAIT(owner, "hypnotherapy", ROUNDSTART_TRAIT) + return ..() + +/datum/status_effect/trance/on_remove() + UnregisterSignal(owner, COMSIG_MOVABLE_HEAR) + REMOVE_TRAIT(owner, TRAIT_MUTE, "trance") + owner.dizziness = 0 + if(!owner.has_quirk(/datum/quirk/monochromatic)) + owner.remove_client_colour(/datum/client_colour/monochrome) + to_chat(owner, "You snap out of your trance!") + +/datum/status_effect/trance/proc/listen(datum/source, message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode) + to_chat(owner, "[speaker] accidentally sets off your implanted trigger, sending you into a hypnotic daze!") + triggered = TRUE + +/datum/status_effect/trance/proc/hypnotize(datum/source, message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode) + if(!owner.can_hear()) + return + if(speaker == owner) + return + var/mob/living/carbon/C = owner + C.cure_trauma_type(/datum/brain_trauma/hypnosis, TRAUMA_RESILIENCE_SURGERY) //clear previous hypnosis + if(HAS_TRAIT(C, "hypnotherapy")) + addtimer(CALLBACK(C, /mob/living/carbon.proc/gain_trauma, /datum/brain_trauma/hypnosis, TRAUMA_RESILIENCE_SURGERY, raw_message, TRUE), 10) + else + addtimer(CALLBACK(C, /mob/living/carbon.proc/gain_trauma, /datum/brain_trauma/hypnosis, TRAUMA_RESILIENCE_SURGERY, raw_message), 10) + addtimer(CALLBACK(C, /mob/living.proc/Stun, 60, TRUE, TRUE), 15) //Take some time to think about it + qdel(src) diff --git a/code/datums/status_effects/status_effect.dm b/code/datums/status_effects/status_effect.dm index c8bcd831e2..bc1cfba112 100644 --- a/code/datums/status_effects/status_effect.dm +++ b/code/datums/status_effects/status_effect.dm @@ -11,6 +11,7 @@ var/on_remove_on_mob_delete = FALSE //if we call on_remove() when the mob is deleted var/examine_text //If defined, this text will appear when the mob is examined - to use he, she etc. use "SUBJECTPRONOUN" and replace it in the examines themselves var/alert_type = /obj/screen/alert/status_effect //the alert thrown by the status effect, contains name and description + var/blocks_combatmode //Does this status effect prevent the user from toggling combat mode? var/obj/screen/alert/status_effect/linked_alert = null //the alert itself, if it exists /datum/status_effect/New(list/arguments) diff --git a/code/datums/traits/_quirk.dm b/code/datums/traits/_quirk.dm index cc6dd8db3f..12e34b0c90 100644 --- a/code/datums/traits/_quirk.dm +++ b/code/datums/traits/_quirk.dm @@ -13,7 +13,6 @@ var/mob/living/quirk_holder /datum/quirk/New(mob/living/quirk_mob, spawn_effects) - ..() if(!quirk_mob || (human_only && !ishuman(quirk_mob)) || quirk_mob.has_quirk(type)) qdel(src) quirk_holder = quirk_mob diff --git a/code/datums/traits/good.dm b/code/datums/traits/good.dm index 300a1264eb..dffdc92630 100644 --- a/code/datums/traits/good.dm +++ b/code/datums/traits/good.dm @@ -186,3 +186,20 @@ var/obj/item/autosurgeon/gloweyes/gloweyes = new(get_turf(H)) H.equip_to_slot(gloweyes, SLOT_IN_BACKPACK) H.regenerate_icons() + +/datum/quirk/bloodpressure + name = "Polycythemia vera" + desc = "You've a treated form of Polycythemia vera that increases the total blood volume inside of you as well as the rate of replenishment!" + value = 2 //I honeslty dunno if this is a good trait? I just means you use more of medbays blood and make janitors madder, but you also regen blood a lil faster. + mob_trait = TRAIT_HIGH_BLOOD + gain_text = "You feel full of blood!" + lose_text = "You feel like your blood pressure went down." + +/datum/quirk/bloodpressure/add() + var/mob/living/M = quirk_holder + M.blood_ratio = 1.2 + M.blood_volume += 150 + +/datum/quirk/bloodpressure/remove() + var/mob/living/M = quirk_holder + M.blood_ratio = 1 diff --git a/code/datums/traits/negative.dm b/code/datums/traits/negative.dm index 36c6733cf7..178e1aaeb0 100644 --- a/code/datums/traits/negative.dm +++ b/code/datums/traits/negative.dm @@ -119,7 +119,7 @@ medical_record_text = "Patient has a tumor in their brain that is slowly driving them to brain death." /datum/quirk/brainproblems/on_process() - quirk_holder.adjustBrainLoss(0.2) + quirk_holder.adjustOrganLoss(ORGAN_SLOT_BRAIN, 0.2) /datum/quirk/nearsighted //t. errorage name = "Nearsighted" @@ -345,12 +345,42 @@ gain_text = "You find yourself unable to speak!" lose_text = "You feel a growing strength in your vocal chords." medical_record_text = "Functionally mute, patient is unable to use their voice in any capacity." + var/datum/brain_trauma/severe/mute/mute /datum/quirk/mute/add() var/mob/living/carbon/human/H = quirk_holder - H.gain_trauma(TRAIT_MUTE, TRAUMA_RESILIENCE_SURGERY) + mute = new + H.gain_trauma(mute, TRAUMA_RESILIENCE_SURGERY) /datum/quirk/mute/on_process() if(quirk_holder.mind && LAZYLEN(quirk_holder.mind.antag_datums)) to_chat(quirk_holder, "Your antagonistic nature has caused your voice to be heard.") qdel(src) + + +/datum/quirk/unstable + name = "Unstable" + desc = "Due to past troubles, you are unable to recover your sanity if you lose it. Be very careful managing your mood!" + value = -2 + mob_trait = TRAIT_UNSTABLE + gain_text = "There's a lot on your mind right now." + lose_text = "Your mind finally feels calm." + medical_record_text = "Patient's mind is in a vulnerable state, and cannot recover from traumatic events." + +/datum/quirk/blindness + name = "Blind" + desc = "You are completely blind, nothing can counteract this." + value = -4 + gain_text = "You can't see anything." + lose_text = "You miraculously gain back your vision." + medical_record_text = "Subject has permanent blindness." + +/datum/quirk/blindness/add() + quirk_holder.become_blind(ROUNDSTART_TRAIT) + +/datum/quirk/blindness/on_spawn() + var/mob/living/carbon/human/H = quirk_holder + var/obj/item/clothing/glasses/sunglasses/blindfold/white/glasses = new(get_turf(H)) + if(!H.equip_to_slot_if_possible(glasses, SLOT_GLASSES, bypass_equip_delay_self = TRUE)) //if you can't put it on the user's eyes, put it in their hands, otherwise put it on their eyes eyes + H.put_in_hands(glasses) + H.regenerate_icons() diff --git a/code/datums/weather/weather_types/radiation_storm.dm b/code/datums/weather/weather_types/radiation_storm.dm index f3b8118087..6765cdf2cd 100644 --- a/code/datums/weather/weather_types/radiation_storm.dm +++ b/code/datums/weather/weather_types/radiation_storm.dm @@ -18,7 +18,7 @@ area_type = /area protected_areas = list(/area/maintenance, /area/ai_monitored/turret_protected/ai_upload, /area/ai_monitored/turret_protected/ai_upload_foyer, - /area/ai_monitored/turret_protected/ai, /area/storage/emergency/starboard, /area/storage/emergency/port, /area/shuttle) + /area/ai_monitored/turret_protected/ai, /area/storage/emergency/starboard, /area/storage/emergency/port, /area/shuttle, /area/security/prison) target_trait = ZTRAIT_STATION immunity_type = "rad" diff --git a/code/datums/wires/_wires.dm b/code/datums/wires/_wires.dm index f1b08ee18b..fab5a1313c 100644 --- a/code/datums/wires/_wires.dm +++ b/code/datums/wires/_wires.dm @@ -231,6 +231,9 @@ // Same for anyone with an abductor multitool. else if(user.is_holding_item_of_type(/obj/item/multitool/abductor)) reveal_wires = TRUE + // and advanced multitool + else if(user.is_holding_item_of_type(/obj/item/multitool/advanced)) + reveal_wires = TRUE // Station blueprints do that too, but only if the wires are not randomized. else if(user.is_holding_item_of_type(/obj/item/areaeditor/blueprints) && !randomize) diff --git a/code/game/area/Space_Station_13_areas.dm b/code/game/area/Space_Station_13_areas.dm index 8a40fc8b56..798cd9c026 100644 --- a/code/game/area/Space_Station_13_areas.dm +++ b/code/game/area/Space_Station_13_areas.dm @@ -339,6 +339,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station /area/crew_quarters/heads/captain name = "Captain's Office" icon_state = "captain" + clockwork_warp_allowed = FALSE /area/crew_quarters/heads/captain/private name = "Captain's Quarters" diff --git a/code/game/area/areas/ruins/space.dm b/code/game/area/areas/ruins/space.dm index 00a7fed012..d5ceb833b7 100644 --- a/code/game/area/areas/ruins/space.dm +++ b/code/game/area/areas/ruins/space.dm @@ -467,3 +467,8 @@ /area/ruin/space/has_grav/powered/ancient_shuttle name = "Ancient Shuttle" icon_state = "yellow" + +// Abductor Replication Lab +/area/ruin/space/has_grav/powered/advancedlab + name = "Abductor Replication Lab" + icon_state = "yellow" diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 88fe2c8d13..7c9dc3f4fe 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -235,6 +235,11 @@ SEND_SIGNAL(src, COMSIG_ATOM_BULLET_ACT, P, def_zone) . = P.on_hit(src, 0, def_zone) +//used on altdisarm() for special interactions between the shoved victim (target) and the src, with user being the one shoving the target on it. +// IMPORTANT: if you wish to add a new own shove_act() to a certain object, remember to add SHOVABLE_ONTO to its obj_flags bitfied var first. +/atom/proc/shove_act(mob/living/target, mob/living/user) + return FALSE + /atom/proc/in_contents_of(container)//can take class or object instance as argument if(ispath(container)) if(istype(src.loc, container)) @@ -379,7 +384,7 @@ SEND_SIGNAL(src, COMSIG_ATOM_ACID_ACT, acidpwr, acid_volume) /atom/proc/emag_act() - SEND_SIGNAL(src, COMSIG_ATOM_EMAG_ACT) + return SEND_SIGNAL(src, COMSIG_ATOM_EMAG_ACT) /atom/proc/rad_act(strength) SEND_SIGNAL(src, COMSIG_ATOM_RAD_ACT, strength) diff --git a/code/game/data_huds.dm b/code/game/data_huds.dm index 8506a4133a..65a7c6a954 100644 --- a/code/game/data_huds.dm +++ b/code/game/data_huds.dm @@ -18,7 +18,7 @@ /datum/atom_hud/data /datum/atom_hud/data/human/medical - hud_icons = list(STATUS_HUD, HEALTH_HUD, NANITE_HUD) + hud_icons = list(STATUS_HUD, HEALTH_HUD, NANITE_HUD, RAD_HUD) /datum/atom_hud/data/human/medical/basic @@ -162,6 +162,7 @@ holder.icon_state = "hud[RoundHealth(src)]" var/icon/I = icon(icon, icon_state, dir) holder.pixel_y = I.Height() - world.icon_size + med_hud_set_radstatus() //for carbon suit sensors /mob/living/carbon/med_hud_set_health() @@ -211,6 +212,22 @@ holder.icon_state = "hudhealthy" +/mob/living/proc/med_hud_set_radstatus() + var/image/radholder = hud_list[RAD_HUD] + var/icon/I = icon(icon, icon_state, dir) + radholder.pixel_y = I.Height() - world.icon_size + var/mob/living/M = src + var/rads = M.radiation + switch(rads) + if(-INFINITY to RAD_MOB_SAFE) + radholder.icon_state = "hudradsafe" + if((RAD_MOB_SAFE+1) to RAD_MOB_MUTATE) + radholder.icon_state = "hudraddanger" + if((RAD_MOB_MUTATE+1) to RAD_MOB_VOMIT) + radholder.icon_state = "hudradlethal" + if((RAD_MOB_VOMIT+1) to INFINITY) + radholder.icon_state = "hudradnuke" + /*********************************************** Security HUDs! Basic mode shows only the job. ************************************************/ diff --git a/code/game/gamemodes/brother/traitor_bro.dm b/code/game/gamemodes/brother/traitor_bro.dm index 18611ebfcb..8bbe7f54ed 100644 --- a/code/game/gamemodes/brother/traitor_bro.dm +++ b/code/game/gamemodes/brother/traitor_bro.dm @@ -6,7 +6,7 @@ name = "traitor+brothers" config_tag = "traitorbro" restricted_jobs = list("AI", "Cyborg") - protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Quartermaster", "Chief Engineer", "Research Director") + protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") announce_span = "danger" announce_text = "There are Syndicate agents and Blood Brothers on the station!\n\ diff --git a/code/game/gamemodes/clock_cult/clock_cult.dm b/code/game/gamemodes/clock_cult/clock_cult.dm index 94ca86e0dd..51a34f4194 100644 --- a/code/game/gamemodes/clock_cult/clock_cult.dm +++ b/code/game/gamemodes/clock_cult/clock_cult.dm @@ -52,7 +52,7 @@ Credit where due: if(!istype(M)) return FALSE if(M.mind) - if(ishuman(M) && (M.mind.assigned_role in list("Captain", "Chaplain"))) + if(M.mind.assigned_role in list("Captain", "Chaplain")) return FALSE if(M.mind.enslaved_to && !is_servant_of_ratvar(M.mind.enslaved_to)) return FALSE @@ -135,7 +135,7 @@ Credit where due: required_enemies = 3 recommended_enemies = 5 enemy_minimum_age = 7 - protected_jobs = list("AI", "Cyborg", "Security Officer", "Warden", "Detective", "Head of Security", "Captain") //Silicons can eventually be converted + protected_jobs = list("AI", "Cyborg", "Security Officer", "Warden", "Detective", "Head of Security", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") //Silicons can eventually be converted restricted_jobs = list("Chaplain", "Captain") announce_span = "brass" announce_text = "Servants of Ratvar are trying to summon the Justiciar!\n\ @@ -275,7 +275,7 @@ Credit where due: gloves = /obj/item/clothing/gloves/color/yellow belt = /obj/item/storage/belt/utility/servant backpack_contents = list(/obj/item/storage/box/engineer = 1, \ - /obj/item/clockwork/replica_fabricator = 1, /obj/item/stack/tile/brass/fifty = 1, /obj/item/paper/servant_primer = 1, /obj/item/reagent_containers/food/drinks/holyoil = 1) + /obj/item/clockwork/replica_fabricator = 1, /obj/item/stack/tile/brass/fifty = 1, /obj/item/paper/servant_primer = 1, /obj/item/reagent_containers/food/drinks/bottle/holyoil = 1) id = /obj/item/pda var/plasmaman //We use this to determine if we should activate internals in post_equip() diff --git a/code/game/gamemodes/cult/cult.dm b/code/game/gamemodes/cult/cult.dm index 8f091b6372..497cc2f1c3 100644 --- a/code/game/gamemodes/cult/cult.dm +++ b/code/game/gamemodes/cult/cult.dm @@ -16,7 +16,7 @@ if(!istype(M)) return FALSE if(M.mind) - if(ishuman(M) && (M.mind.assigned_role in list("Captain", "Chaplain"))) + if(M.mind.assigned_role in list("Captain", "Chaplain")) return FALSE if(specific_cult && specific_cult.is_sacrifice_target(M.mind)) return FALSE @@ -35,8 +35,8 @@ config_tag = "cult" antag_flag = ROLE_CULTIST false_report_weight = 10 - restricted_jobs = list("Chaplain","AI", "Cyborg", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel") - protected_jobs = list() + restricted_jobs = list("AI", "Cyborg") + protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") required_players = 30 required_enemies = 3 recommended_enemies = 5 diff --git a/code/game/gamemodes/dynamic/dynamic.dm b/code/game/gamemodes/dynamic/dynamic.dm new file mode 100644 index 0000000000..e22b785670 --- /dev/null +++ b/code/game/gamemodes/dynamic/dynamic.dm @@ -0,0 +1,748 @@ +#define CURRENT_LIVING_PLAYERS 1 +#define CURRENT_LIVING_ANTAGS 2 +#define CURRENT_DEAD_PLAYERS 3 +#define CURRENT_OBSERVERS 4 + +#define ONLY_RULESET 1 +#define HIGHLANDER_RULESET 2 +#define TRAITOR_RULESET 4 +#define MINOR_RULESET 8 + +#define RULESET_STOP_PROCESSING 1 + +// -- Injection delays +GLOBAL_VAR_INIT(dynamic_latejoin_delay_min, (5 MINUTES)) +GLOBAL_VAR_INIT(dynamic_latejoin_delay_max, (25 MINUTES)) + +GLOBAL_VAR_INIT(dynamic_midround_delay_min, (15 MINUTES)) +GLOBAL_VAR_INIT(dynamic_midround_delay_max, (35 MINUTES)) + +// Are HIGHLANDER_RULESETs allowed to stack? +GLOBAL_VAR_INIT(dynamic_no_stacking, TRUE) +// A number between -5 and +5. +// A negative value will give a more peaceful round and +// a positive value will give a round with higher threat. +GLOBAL_VAR_INIT(dynamic_curve_centre, 0) +// A number between 0.5 and 4. +// Higher value will favour extreme rounds and +// lower value rounds closer to the average. +GLOBAL_VAR_INIT(dynamic_curve_width, 1.8) +// If enabled only picks a single starting rule and executes only autotraitor midround ruleset. +GLOBAL_VAR_INIT(dynamic_classic_secret, FALSE) +// How many roundstart players required for high population override to take effect. +GLOBAL_VAR_INIT(dynamic_high_pop_limit, 55) +// If enabled does not accept or execute any rulesets. +GLOBAL_VAR_INIT(dynamic_forced_extended, FALSE) +// How high threat is required for HIGHLANDER_RULESETs stacking. +// This is independent of dynamic_no_stacking. +GLOBAL_VAR_INIT(dynamic_stacking_limit, 90) +// List of forced roundstart rulesets. +GLOBAL_LIST_EMPTY(dynamic_forced_roundstart_ruleset) +// Forced threat level, setting this to zero or higher forces the roundstart threat to the value. +GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1) + +/datum/game_mode/dynamic + name = "dynamic mode" + config_tag = "dynamic" + + announce_span = "danger" + announce_text = "Dynamic mode!" // This needs to be changed maybe + + reroll_friendly = FALSE; + + // Threat logging vars + /// The "threat cap", threat shouldn't normally go above this and is used in ruleset calculations + var/threat_level = 0 + /// Set at the beginning of the round. Spent by the mode to "purchase" rules. + var/threat = 0 + /// Running information about the threat. Can store text or datum entries. + var/list/threat_log = list() + /// List of roundstart rules used for selecting the rules. + var/list/roundstart_rules = list() + /// List of latejoin rules used for selecting the rules. + var/list/latejoin_rules = list() + /// List of midround rules used for selecting the rules. + var/list/midround_rules = list() + /** # Pop range per requirement. + * If the value is five the range is: + * 0-4, 5-9, 10-14, 15-19, 20-24, 25-29, 30-34, 35-39, 40-54, 45+ + * If it is six the range is: + * 0-5, 6-11, 12-17, 18-23, 24-29, 30-35, 36-41, 42-47, 48-53, 54+ + * If it is seven the range is: + * 0-6, 7-13, 14-20, 21-27, 28-34, 35-41, 42-48, 49-55, 56-62, 63+ + */ + var/pop_per_requirement = 6 + /// The requirement used for checking if a second rule should be selected. + var/list/second_rule_req = list(100, 100, 80, 70, 60, 50, 30, 20, 10, 0) + /// The requirement used for checking if a third rule should be selected. + var/list/third_rule_req = list(100, 100, 100, 90, 80, 70, 60, 50, 40, 30) + /// Threat requirement for a second ruleset when high pop override is in effect. + var/high_pop_second_rule_req = 40 + /// Threat requirement for a third ruleset when high pop override is in effect. + var/high_pop_third_rule_req = 60 + /// Number of players who were ready on roundstart. + var/roundstart_pop_ready = 0 + /// List of candidates used on roundstart rulesets. + var/list/candidates = list() + /// Rules that are processed, rule_process is called on the rules in this list. + var/list/current_rules = list() + /// List of executed rulesets. + var/list/executed_rules = list() + /// Associative list of current players, in order: living players, living antagonists, dead players and observers. + var/list/list/current_players = list(CURRENT_LIVING_PLAYERS, CURRENT_LIVING_ANTAGS, CURRENT_DEAD_PLAYERS, CURRENT_OBSERVERS) + /// When world.time is over this number the mode tries to inject a latejoin ruleset. + var/latejoin_injection_cooldown = 0 + /// When world.time is over this number the mode tries to inject a midround ruleset. + var/midround_injection_cooldown = 0 + /// When TRUE GetInjectionChance returns 100. + var/forced_injection = FALSE + /// Forced ruleset to be executed for the next latejoin. + var/datum/dynamic_ruleset/latejoin/forced_latejoin_rule = null + /// When current_players was updated last time. + var/pop_last_updated = 0 + /// How many percent of the rounds are more peaceful. + var/peaceful_percentage = 50 + /// If a highlander executed. + var/highlander_executed = FALSE + /// If a only ruleset has been executed. + var/only_ruleset_executed = FALSE + +/datum/game_mode/dynamic/admin_panel() + var/list/dat = list("Game Mode Panel

Game Mode Panel

") + dat += "Dynamic Mode \[VV\]
" + dat += "Threat Level: [threat_level]
" + + dat += "Threat to Spend: [threat] \[Adjust\] \[View Log\]
" + dat += "
" + dat += "Parameters: centre = [GLOB.dynamic_curve_centre] ; width = [GLOB.dynamic_curve_width].
" + dat += "On average, [peaceful_percentage]% of the rounds are more peaceful.
" + dat += "Forced extended: [GLOB.dynamic_forced_extended ? "On" : "Off"]
" + dat += "Classic secret (only autotraitor): [GLOB.dynamic_classic_secret ? "On" : "Off"]
" + dat += "No stacking (only one round-ender): [GLOB.dynamic_no_stacking ? "On" : "Off"]
" + dat += "Stacking limit: [GLOB.dynamic_stacking_limit] \[Adjust\]" + dat += "
" + dat += "Executed rulesets: " + if (executed_rules.len > 0) + dat += "
" + for (var/datum/dynamic_ruleset/DR in executed_rules) + dat += "[DR.ruletype] - [DR.name]
" + else + dat += "none.
" + dat += "
Injection Timers: ([get_injection_chance(TRUE)]% chance)
" + dat += "Latejoin: [(latejoin_injection_cooldown-world.time)>60*10 ? "[round((latejoin_injection_cooldown-world.time)/60/10,0.1)] minutes" : "[(latejoin_injection_cooldown-world.time)] seconds"] \[Now!\]
" + dat += "Midround: [(midround_injection_cooldown-world.time)>60*10 ? "[round((midround_injection_cooldown-world.time)/60/10,0.1)] minutes" : "[(midround_injection_cooldown-world.time)] seconds"] \[Now!\]
" + usr << browse(dat.Join(), "window=gamemode_panel;size=500x500") + +/datum/game_mode/dynamic/Topic(href, href_list) + if (..()) // Sanity, maybe ? + return + if(!check_rights(R_ADMIN)) + message_admins("[usr.key] has attempted to override the game mode panel!") + log_admin("[key_name(usr)] tried to use the game mode panel without authorization.") + return + if (href_list["forced_extended"]) + GLOB.dynamic_forced_extended = !GLOB.dynamic_forced_extended + else if (href_list["no_stacking"]) + GLOB.dynamic_no_stacking = !GLOB.dynamic_no_stacking + else if (href_list["classic_secret"]) + GLOB.dynamic_classic_secret = !GLOB.dynamic_classic_secret + else if (href_list["adjustthreat"]) + var/threatadd = input("Specify how much threat to add (negative to subtract). This can inflate the threat level.", "Adjust Threat", 0) as null|num + if(!threatadd) + return + if(threatadd > 0) + create_threat(threatadd) + else + spend_threat(-threatadd) + else if (href_list["injectlate"]) + latejoin_injection_cooldown = 0 + forced_injection = TRUE + message_admins("[key_name(usr)] forced a latejoin injection.", 1) + else if (href_list["injectmid"]) + midround_injection_cooldown = 0 + forced_injection = TRUE + message_admins("[key_name(usr)] forced a midround injection.", 1) + else if (href_list["threatlog"]) + show_threatlog(usr) + else if (href_list["stacking_limit"]) + GLOB.dynamic_stacking_limit = input(usr,"Change the threat limit at which round-endings rulesets will start to stack.", "Change stacking limit", null) as num + + admin_panel() // Refreshes the window + +// Checks if there are HIGHLANDER_RULESETs and calls the rule's round_result() proc +/datum/game_mode/dynamic/set_round_result() + for(var/datum/dynamic_ruleset/rule in executed_rules) + if(rule.flags & HIGHLANDER_RULESET) + if(rule.check_finished()) // Only the rule that actually finished the round sets round result. + return rule.round_result() + // If it got to this part, just pick one highlander if it exists + for(var/datum/dynamic_ruleset/rule in executed_rules) + if(rule.flags & HIGHLANDER_RULESET) + return rule.round_result() + return ..() + +/datum/game_mode/dynamic/send_intercept() + . = "Central Command Status Summary
" + switch(round(threat_level)) + if(0 to 19) + update_playercounts() + if(!current_players[CURRENT_LIVING_ANTAGS].len) + . += "Peaceful Waypoint
" + . += "Your station orbits deep within controlled, core-sector systems and serves as a waypoint for routine traffic through Nanotrasen's trade empire. Due to the combination of high security, interstellar traffic, and low strategic value, it makes any direct threat of violence unlikely. Your primary enemies will be incompetence and bored crewmen: try to organize team-building events to keep staffers interested and productive." + else + . += "Core Territory
" + . += "Your station orbits within reliably mundane, secure space. Although Nanotrasen has a firm grip on security in your region, the valuable resources and strategic position aboard your station make it a potential target for infiltrations. Monitor crew for non-loyal behavior, but expect a relatively tame shift free of large-scale destruction. We expect great things from your station." + if(20 to 39) + . += "Anomalous Exogeology
" + . += "Although your station lies within what is generally considered Nanotrasen-controlled space, the course of its orbit has caused it to cross unusually close to exogeological features with anomalous readings. Although these features offer opportunities for our research department, it is known that these little understood readings are often correlated with increased activity from competing interstellar organizations and individuals, among them the Wizard Federation and Cult of the Geometer of Blood - all known competitors for Anomaly Type B sites. Exercise elevated caution." + if(40 to 65) + . += "Contested System
" + . += "Your station's orbit passes along the edge of Nanotrasen's sphere of influence. While subversive elements remain the most likely threat against your station, hostile organizations are bolder here, where our grip is weaker. Exercise increased caution against elite Syndicate strike forces, or Executives forbid, some kind of ill-conceived unionizing attempt." + if(66 to 79) + . += "Uncharted Space
" + . += "Congratulations and thank you for participating in the NT 'Frontier' space program! Your station is actively orbiting a high value system far from the nearest support stations. Little is known about your region of space, and the opportunity to encounter the unknown invites greater glory. You are encouraged to elevate security as necessary to protect Nanotrasen assets." + if(80 to 99) + . += "Black Orbit
" + . += "As part of a mandatory security protocol, we are required to inform you that as a result of your orbital pattern directly behind an astrological body (oriented from our nearest observatory), your station will be under decreased monitoring and support. It is anticipated that your extreme location and decreased surveillance could pose security risks. Avoid unnecessary risks and attempt to keep your station in one piece." + if(100) + . += "Impending Doom
" + . += "Your station is somehow in the middle of hostile territory, in clear view of any enemy of the corporation. Your likelihood to survive is low, and station destruction is expected and almost inevitable. Secure any sensitive material and neutralize any enemy you will come across. It is important that you at least try to maintain the station.
" + . += "Good luck." + + if(station_goals.len) + . += "
Special Orders for [station_name()]:" + for(var/datum/station_goal/G in station_goals) + G.on_report() + . += G.get_report() + + print_command_report(., "Central Command Status Summary", announce=FALSE) + priority_announce("A summary has been copied and printed to all communications consoles.", "Security level elevated.", 'sound/ai/intercept.ogg') + if(GLOB.security_level < SEC_LEVEL_BLUE) + set_security_level(SEC_LEVEL_BLUE) + +// Yes, this is copy pasted from game_mode +/datum/game_mode/dynamic/check_finished(force_ending) + if(!SSticker.setup_done || !gamemode_ready) + return FALSE + if(replacementmode && round_converted == 2) + return replacementmode.check_finished() + if(SSshuttle.emergency && (SSshuttle.emergency.mode == SHUTTLE_ENDGAME)) + return TRUE + if(station_was_nuked) + return TRUE + if(force_ending) + return TRUE + for(var/datum/dynamic_ruleset/rule in executed_rules) + if(rule.flags & HIGHLANDER_RULESET) + return rule.check_finished() + +/datum/game_mode/dynamic/proc/show_threatlog(mob/admin) + if(!SSticker.HasRoundStarted()) + alert("The round hasn't started yet!") + return + + if(!check_rights(R_ADMIN)) + return + + var/list/out = list("Threat LogThreat Log
Starting Threat: [threat_level]
") + + for(var/entry in threat_log) + if(istext(entry)) + out += "[entry]
" + + out += "Remaining threat/threat_level: [threat]/[threat_level]" + + usr << browse(out.Join(), "window=threatlog;size=700x500") + +/// Generates the threat level using lorentz distribution and assigns peaceful_percentage. +/datum/game_mode/dynamic/proc/generate_threat() + var/relative_threat = LORENTZ_DISTRIBUTION(GLOB.dynamic_curve_centre, GLOB.dynamic_curve_width) + threat_level = round(lorentz_to_threat(relative_threat), 0.1) + + peaceful_percentage = round(LORENTZ_CUMULATIVE_DISTRIBUTION(relative_threat, GLOB.dynamic_curve_centre, GLOB.dynamic_curve_width), 0.01)*100 + + threat = threat_level + +/datum/game_mode/dynamic/can_start() + /* Disabled for now, had some changes that need to be tested and this might interfere with that. + if(GLOB.dynamic_curve_centre == 0) + // 10 is when the centre starts to decrease + // 6 is just 1 + 5 (from the maximum value and the one decreased) + // 1 just makes the curve look better, I don't know. + // Limited between 1 and 5 then inverted and rounded + // With this you get a centre curve that stays at -5 until 10 then first rapidly decreases but slows down at the end + GLOB.dynamic_curve_centre = round(-CLAMP((10*6/GLOB.player_list.len)-1, 0, 5), 0.5) + */ + message_admins("Dynamic mode parameters for the round:") + message_admins("Centre is [GLOB.dynamic_curve_centre], Width is [GLOB.dynamic_curve_width], Forced extended is [GLOB.dynamic_forced_extended ? "Enabled" : "Disabled"], No stacking is [GLOB.dynamic_no_stacking ? "Enabled" : "Disabled"].") + message_admins("Stacking limit is [GLOB.dynamic_stacking_limit], Classic secret is [GLOB.dynamic_classic_secret ? "Enabled" : "Disabled"], High population limit is [GLOB.dynamic_high_pop_limit].") + log_game("DYNAMIC: Dynamic mode parameters for the round:") + log_game("DYNAMIC: Centre is [GLOB.dynamic_curve_centre], Width is [GLOB.dynamic_curve_width], Forced extended is [GLOB.dynamic_forced_extended ? "Enabled" : "Disabled"], No stacking is [GLOB.dynamic_no_stacking ? "Enabled" : "Disabled"].") + log_game("DYNAMIC: Stacking limit is [GLOB.dynamic_stacking_limit], Classic secret is [GLOB.dynamic_classic_secret ? "Enabled" : "Disabled"], High population limit is [GLOB.dynamic_high_pop_limit].") + if(GLOB.dynamic_forced_threat_level >= 0) + threat_level = round(GLOB.dynamic_forced_threat_level, 0.1) + threat = threat_level + else + generate_threat() + + var/latejoin_injection_cooldown_middle = 0.5*(GLOB.dynamic_latejoin_delay_max + GLOB.dynamic_latejoin_delay_min) + latejoin_injection_cooldown = round(CLAMP(EXP_DISTRIBUTION(latejoin_injection_cooldown_middle), GLOB.dynamic_latejoin_delay_min, GLOB.dynamic_latejoin_delay_max)) + world.time + + var/midround_injection_cooldown_middle = 0.5*(GLOB.dynamic_midround_delay_max + GLOB.dynamic_midround_delay_min) + midround_injection_cooldown = round(CLAMP(EXP_DISTRIBUTION(midround_injection_cooldown_middle), GLOB.dynamic_midround_delay_min, GLOB.dynamic_midround_delay_max)) + world.time + log_game("DYNAMIC: Dynamic Mode initialized with a Threat Level of... [threat_level]!") + return TRUE + +/datum/game_mode/dynamic/pre_setup() + for (var/rule in subtypesof(/datum/dynamic_ruleset)) + var/datum/dynamic_ruleset/ruleset = new rule() + // Simple check if the ruleset should be added to the lists. + if(ruleset.name == "") + continue + switch(ruleset.ruletype) + if("Roundstart") + roundstart_rules += ruleset + if ("Latejoin") + latejoin_rules += ruleset + if ("Midround") + if (ruleset.weight) + midround_rules += ruleset + for(var/mob/dead/new_player/player in GLOB.player_list) + if(player.ready == PLAYER_READY_TO_PLAY && player.mind) + roundstart_pop_ready++ + candidates.Add(player) + log_game("DYNAMIC: Listing [roundstart_rules.len] round start rulesets, and [candidates.len] players ready.") + if (candidates.len <= 0) + return TRUE + if (roundstart_rules.len <= 0) + return TRUE + + if(GLOB.dynamic_forced_roundstart_ruleset.len > 0) + rigged_roundstart() + else + roundstart() + + var/starting_rulesets = "" + for (var/datum/dynamic_ruleset/roundstart/DR in executed_rules) + starting_rulesets += "[DR.name], " + candidates.Cut() + return TRUE + +/datum/game_mode/dynamic/post_setup(report) + update_playercounts() + + for(var/datum/dynamic_ruleset/roundstart/rule in executed_rules) + rule.candidates.Cut() // The rule should not use candidates at this point as they all are null. + if(!rule.execute()) + stack_trace("The starting rule \"[rule.name]\" failed to execute.") + ..() + +/// A simple roundstart proc used when dynamic_forced_roundstart_ruleset has rules in it. +/datum/game_mode/dynamic/proc/rigged_roundstart() + message_admins("[GLOB.dynamic_forced_roundstart_ruleset.len] rulesets being forced. Will now attempt to draft players for them.") + log_game("DYNAMIC: [GLOB.dynamic_forced_roundstart_ruleset.len] rulesets being forced. Will now attempt to draft players for them.") + for (var/datum/dynamic_ruleset/roundstart/rule in GLOB.dynamic_forced_roundstart_ruleset) + message_admins("Drafting players for forced ruleset [rule.name].") + log_game("DYNAMIC: Drafting players for forced ruleset [rule.name].") + rule.mode = src + rule.candidates = candidates.Copy() + rule.trim_candidates() + if (rule.ready(TRUE)) + picking_roundstart_rule(list(rule), forced = TRUE) + +/datum/game_mode/dynamic/proc/roundstart() + if (GLOB.dynamic_forced_extended) + log_game("DYNAMIC: Starting a round of forced extended.") + return TRUE + var/list/drafted_rules = list() + for (var/datum/dynamic_ruleset/roundstart/rule in roundstart_rules) + if (rule.acceptable(roundstart_pop_ready, threat_level) && threat >= rule.cost) // If we got the population and threat required + rule.candidates = candidates.Copy() + rule.trim_candidates() + if (rule.ready() && rule.candidates.len > 0) + drafted_rules[rule] = rule.weight + + var/indice_pop = min(10,round(roundstart_pop_ready/pop_per_requirement)+1) + var/extra_rulesets_amount = 0 + if (GLOB.dynamic_classic_secret) + extra_rulesets_amount = 0 + else + if (roundstart_pop_ready > GLOB.dynamic_high_pop_limit) + message_admins("High Population Override is in effect! Threat Level will have more impact on which roles will appear, and player population less.") + log_game("DYNAMIC: High Population Override is in effect! Threat Level will have more impact on which roles will appear, and player population less.") + if (threat_level > high_pop_second_rule_req) + extra_rulesets_amount++ + if (threat_level > high_pop_third_rule_req) + extra_rulesets_amount++ + else + if (threat_level >= second_rule_req[indice_pop]) + extra_rulesets_amount++ + if (threat_level >= third_rule_req[indice_pop]) + extra_rulesets_amount++ + + if (drafted_rules.len > 0 && picking_roundstart_rule(drafted_rules)) + if (extra_rulesets_amount > 0) // We've got enough population and threat for a second rulestart rule + for (var/datum/dynamic_ruleset/roundstart/rule in drafted_rules) + if (rule.cost > threat) + drafted_rules -= rule + if (drafted_rules.len > 0 && picking_roundstart_rule(drafted_rules)) + if (extra_rulesets_amount > 1) // We've got enough population and threat for a third rulestart rule + for (var/datum/dynamic_ruleset/roundstart/rule in drafted_rules) + if (rule.cost > threat) + drafted_rules -= rule + picking_roundstart_rule(drafted_rules) + else + return FALSE + return TRUE + +/// Picks a random roundstart rule from the list given as an argument and executes it. +/datum/game_mode/dynamic/proc/picking_roundstart_rule(list/drafted_rules = list(), forced = FALSE) + var/datum/dynamic_ruleset/roundstart/starting_rule = pickweight(drafted_rules) + if(!starting_rule) + return FALSE + + if(!forced) + if(only_ruleset_executed) + return FALSE + // Check if a blocking ruleset has been executed. + else if(check_blocking(starting_rule.blocking_rules, executed_rules)) + drafted_rules -= starting_rule + if(drafted_rules.len <= 0) + return FALSE + starting_rule = pickweight(drafted_rules) + // Check if the ruleset is highlander and if a highlander ruleset has been executed + else if(starting_rule.flags & HIGHLANDER_RULESET) + if(threat < GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking) + if(highlander_executed) + drafted_rules -= starting_rule + if(drafted_rules.len <= 0) + return FALSE + starting_rule = pickweight(drafted_rules) + + log_game("DYNAMIC: Picking a [istype(starting_rule, /datum/dynamic_ruleset/roundstart/delayed/) ? " delayed " : ""] ruleset [starting_rule.name]") + + roundstart_rules -= starting_rule + drafted_rules -= starting_rule + + if (istype(starting_rule, /datum/dynamic_ruleset/roundstart/delayed/)) + var/datum/dynamic_ruleset/roundstart/delayed/rule = starting_rule + addtimer(CALLBACK(src, .proc/execute_delayed, rule), rule.delay) + + starting_rule.trim_candidates() + if (starting_rule.pre_execute()) + spend_threat(starting_rule.cost) + threat_log += "[worldtime2text()]: Roundstart [starting_rule.name] spent [starting_rule.cost]" + if(starting_rule.flags & HIGHLANDER_RULESET) + highlander_executed = TRUE + else if(starting_rule.flags & ONLY_RULESET) + only_ruleset_executed = TRUE + executed_rules += starting_rule + if (starting_rule.persistent) + current_rules += starting_rule + for(var/mob/M in starting_rule.assigned) + for (var/datum/dynamic_ruleset/roundstart/rule in roundstart_rules) + if (!rule.ready()) + drafted_rules -= rule // And removing rules that are no longer elligible + return TRUE + else + stack_trace("The starting rule \"[starting_rule.name]\" failed to pre_execute.") + return FALSE + +/// Executes delayed roundstart rules and has a hack in it. +/datum/game_mode/dynamic/proc/execute_delayed(datum/dynamic_ruleset/roundstart/delayed/rule) + update_playercounts() + rule.candidates = current_players[CURRENT_LIVING_PLAYERS].Copy() + rule.trim_candidates() + if(rule.execute()) + executed_rules += rule + if (rule.persistent) + current_rules += rule + return TRUE + else + stack_trace("The delayed roundstart rule \"[rule.name]\" failed to execute.") + return FALSE + +/// Picks a random midround OR latejoin rule from the list given as an argument and executes it. +/// Also this could be named better. +/datum/game_mode/dynamic/proc/picking_midround_latejoin_rule(list/drafted_rules = list(), forced = FALSE) + var/datum/dynamic_ruleset/rule = pickweight(drafted_rules) + if(!rule) + return FALSE + + if(!forced) + if(only_ruleset_executed) + return FALSE + // Check if a blocking ruleset has been executed. + else if(check_blocking(rule.blocking_rules, executed_rules)) + drafted_rules -= rule + if(drafted_rules.len <= 0) + return FALSE + rule = pickweight(drafted_rules) + // Check if the ruleset is highlander and if a highlander ruleset has been executed + else if(rule.flags & HIGHLANDER_RULESET) + if(threat < GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking) + if(highlander_executed) + drafted_rules -= rule + if(drafted_rules.len <= 0) + return FALSE + rule = pickweight(drafted_rules) + + if(!rule.repeatable) + if(rule.ruletype == "Latejoin") + latejoin_rules = remove_from_list(latejoin_rules, rule.type) + else if(rule.type == "Midround") + midround_rules = remove_from_list(midround_rules, rule.type) + + if (rule.execute()) + log_game("DYNAMIC: Injected a [rule.ruletype == "latejoin" ? "latejoin" : "midround"] ruleset [rule.name].") + spend_threat(rule.cost) + threat_log += "[worldtime2text()]: [rule.ruletype] [rule.name] spent [rule.cost]" + if(rule.flags & HIGHLANDER_RULESET) + highlander_executed = TRUE + else if(rule.flags & ONLY_RULESET) + only_ruleset_executed = TRUE + if(rule.ruletype == "Latejoin") + var/mob/M = pick(rule.candidates) + message_admins("[key_name(M)] joined the station, and was selected by the [rule.name] ruleset.") + log_game("DYNAMIC: [key_name(M)] joined the station, and was selected by the [rule.name] ruleset.") + executed_rules += rule + rule.candidates.Cut() + if (rule.persistent) + current_rules += rule + return TRUE + else + stack_trace("The [rule.ruletype] rule \"[rule.name]\" failed to execute.") + return FALSE + +/// An experimental proc to allow admins to call rules on the fly or have rules call other rules. +/datum/game_mode/dynamic/proc/picking_specific_rule(ruletype, forced = FALSE) + var/datum/dynamic_ruleset/midround/new_rule + if(ispath(ruletype)) + new_rule = new ruletype() // You should only use it to call midround rules though. + else if(istype(ruletype, /datum/dynamic_ruleset)) + new_rule = ruletype + else + return FALSE + + if(!new_rule) + return FALSE + + if(!forced) + if(only_ruleset_executed) + return FALSE + // Check if a blocking ruleset has been executed. + else if(check_blocking(new_rule.blocking_rules, executed_rules)) + return FALSE + // Check if the ruleset is highlander and if a highlander ruleset has been executed + else if(new_rule.flags & HIGHLANDER_RULESET) + if(threat < GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking) + if(highlander_executed) + return FALSE + + update_playercounts() + if ((forced || (new_rule.acceptable(current_players[CURRENT_LIVING_PLAYERS].len, threat_level) && new_rule.cost <= threat))) + new_rule.candidates = current_players.Copy() + new_rule.trim_candidates() + if (new_rule.ready(forced)) + spend_threat(new_rule.cost) + threat_log += "[worldtime2text()]: Forced rule [new_rule.name] spent [new_rule.cost]" + if (new_rule.execute()) // This should never fail since ready() returned 1 + if(new_rule.flags & HIGHLANDER_RULESET) + highlander_executed = TRUE + else if(new_rule.flags & ONLY_RULESET) + only_ruleset_executed = TRUE + log_game("DYNAMIC: Making a call to a specific ruleset...[new_rule.name]!") + executed_rules += new_rule + if (new_rule.persistent) + current_rules += new_rule + return TRUE + else if (forced) + log_game("DYNAMIC: The ruleset [new_rule.name] couldn't be executed due to lack of elligible players.") + return FALSE + +/datum/game_mode/dynamic/process() + if (pop_last_updated < world.time - (60 SECONDS)) + pop_last_updated = world.time + update_playercounts() + + for (var/datum/dynamic_ruleset/rule in current_rules) + if(rule.rule_process() == RULESET_STOP_PROCESSING) // If rule_process() returns 1 (RULESET_STOP_PROCESSING), stop processing. + current_rules -= rule + + if (midround_injection_cooldown < world.time) + if (GLOB.dynamic_forced_extended) + return + + // Somehow it manages to trigger midround multiple times so this was moved here. + // There is no way this should be able to trigger an injection twice now. + var/midround_injection_cooldown_middle = 0.5*(GLOB.dynamic_midround_delay_max + GLOB.dynamic_midround_delay_min) + midround_injection_cooldown = (round(CLAMP(EXP_DISTRIBUTION(midround_injection_cooldown_middle), GLOB.dynamic_midround_delay_min, GLOB.dynamic_midround_delay_max)) + world.time) + + // Time to inject some threat into the round + if(EMERGENCY_ESCAPED_OR_ENDGAMED) // Unless the shuttle is gone + return + + log_game("DYNAMIC: Checking state of the round.") + + update_playercounts() + + if (prob(get_injection_chance())) + var/list/drafted_rules = list() + for (var/datum/dynamic_ruleset/midround/rule in midround_rules) + if (rule.acceptable(current_players[CURRENT_LIVING_PLAYERS].len, threat_level) && threat >= rule.cost) + // Classic secret : only autotraitor/minor roles + if (GLOB.dynamic_classic_secret && !((rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET))) + continue + rule.candidates = list() + rule.candidates = current_players.Copy() + rule.trim_candidates() + if (rule.ready() && rule.candidates.len > 0) + drafted_rules[rule] = rule.get_weight() + if (drafted_rules.len > 0) + picking_midround_latejoin_rule(drafted_rules) + +/// Updates current_players. +/datum/game_mode/dynamic/proc/update_playercounts() + current_players[CURRENT_LIVING_PLAYERS] = list() + current_players[CURRENT_LIVING_ANTAGS] = list() + current_players[CURRENT_DEAD_PLAYERS] = list() + current_players[CURRENT_OBSERVERS] = list() + for (var/mob/M in GLOB.player_list) + if (istype(M, /mob/dead/new_player)) + continue + if (M.stat != DEAD) + current_players[CURRENT_LIVING_PLAYERS].Add(M) + if (M.mind && (M.mind.special_role || M.mind.antag_datums?.len > 0)) + current_players[CURRENT_LIVING_ANTAGS].Add(M) + else + if (istype(M,/mob/dead/observer)) + var/mob/dead/observer/O = M + if (O.started_as_observer) // Observers + current_players[CURRENT_OBSERVERS].Add(M) + continue + current_players[CURRENT_DEAD_PLAYERS].Add(M) // Players who actually died (and admins who ghosted, would be nice to avoid counting them somehow) + +/// Gets the chance for latejoin and midround injection, the dry_run argument is only used for forced injection. +/datum/game_mode/dynamic/proc/get_injection_chance(dry_run = FALSE) + if(forced_injection) + forced_injection = !dry_run + return 100 + var/chance = 0 + // If the high pop override is in effect, we reduce the impact of population on the antag injection chance + var/high_pop_factor = (current_players[CURRENT_LIVING_PLAYERS].len >= GLOB.dynamic_high_pop_limit) + var/max_pop_per_antag = max(5,15 - round(threat_level/10) - round(current_players[CURRENT_LIVING_PLAYERS].len/(high_pop_factor ? 10 : 5))) + if (!current_players[CURRENT_LIVING_ANTAGS].len) + chance += 50 // No antags at all? let's boost those odds! + else + var/current_pop_per_antag = current_players[CURRENT_LIVING_PLAYERS].len / current_players[CURRENT_LIVING_ANTAGS].len + if (current_pop_per_antag > max_pop_per_antag) + chance += min(50, 25+10*(current_pop_per_antag-max_pop_per_antag)) + else + chance += 25-10*(max_pop_per_antag-current_pop_per_antag) + if (current_players[CURRENT_DEAD_PLAYERS].len > current_players[CURRENT_LIVING_PLAYERS].len) + chance -= 30 // More than half the crew died? ew, let's calm down on antags + if (threat > 70) + chance += 15 + if (threat < 30) + chance -= 15 + return round(max(0,chance)) + +/// Removes type from the list +/datum/game_mode/dynamic/proc/remove_from_list(list/type_list, type) + for(var/I in type_list) + if(istype(I, type)) + type_list -= I + return type_list + +/// Checks if a type in blocking_list is in rule_list. +/datum/game_mode/dynamic/proc/check_blocking(list/blocking_list, list/rule_list) + if(blocking_list.len > 0) + for(var/blocking in blocking_list) + for(var/datum/executed in rule_list) + if(blocking == executed.type) + return TRUE + return FALSE + +/// Checks if client age is age or older. +/datum/game_mode/dynamic/proc/check_age(client/C, age) + enemy_minimum_age = age + if(get_remaining_days(C) == 0) + enemy_minimum_age = initial(enemy_minimum_age) + return TRUE // Available in 0 days = available right now = player is old enough to play. + enemy_minimum_age = initial(enemy_minimum_age) + return FALSE + +/datum/game_mode/dynamic/make_antag_chance(mob/living/carbon/human/newPlayer) + if (GLOB.dynamic_forced_extended) + return + if(EMERGENCY_ESCAPED_OR_ENDGAMED) // No more rules after the shuttle has left + return + + update_playercounts() + + if (forced_latejoin_rule) + forced_latejoin_rule.candidates = list(newPlayer) + forced_latejoin_rule.trim_candidates() + log_game("DYNAMIC: Forcing ruleset [forced_latejoin_rule]") + if (forced_latejoin_rule.ready(TRUE)) + picking_midround_latejoin_rule(list(forced_latejoin_rule), forced = TRUE) + forced_latejoin_rule = null + + else if (latejoin_injection_cooldown < world.time && prob(get_injection_chance())) + var/list/drafted_rules = list() + for (var/datum/dynamic_ruleset/latejoin/rule in latejoin_rules) + if (rule.acceptable(current_players[CURRENT_LIVING_PLAYERS].len, threat_level) && threat >= rule.cost) + // Classic secret : only autotraitor/minor roles + if (GLOB.dynamic_classic_secret && !((rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET))) + continue + // No stacking : only one round-enter, unless > stacking_limit threat. + if (threat < GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking) + if(rule.flags & HIGHLANDER_RULESET && highlander_executed) + continue + + rule.candidates = list(newPlayer) + rule.trim_candidates() + if (rule.ready()) + drafted_rules[rule] = rule.get_weight() + + if (drafted_rules.len > 0 && picking_midround_latejoin_rule(drafted_rules)) + var/latejoin_injection_cooldown_middle = 0.5*(GLOB.dynamic_latejoin_delay_max + GLOB.dynamic_latejoin_delay_min) + latejoin_injection_cooldown = round(CLAMP(EXP_DISTRIBUTION(latejoin_injection_cooldown_middle), GLOB.dynamic_latejoin_delay_min, GLOB.dynamic_latejoin_delay_max)) + world.time + +/// Refund threat, but no more than threat_level. +/datum/game_mode/dynamic/proc/refund_threat(regain) + threat = min(threat_level,threat+regain) + +/// Generate threat and increase the threat_level if it goes beyond, capped at 100 +/datum/game_mode/dynamic/proc/create_threat(gain) + threat = min(100, threat+gain) + if(threat > threat_level) + threat_level = threat + +/// Expend threat, can't fall under 0. +/datum/game_mode/dynamic/proc/spend_threat(cost) + threat = max(threat-cost,0) + +/// Turns the value generated by lorentz distribution to threat value between 0 and 100. +/datum/game_mode/dynamic/proc/lorentz_to_threat(x) + switch (x) + if (-INFINITY to -20) + return rand(0, 10) + if (-20 to -10) + return RULE_OF_THREE(-40, -20, x) + 50 + if (-10 to -5) + return RULE_OF_THREE(-30, -10, x) + 50 + if (-5 to -2.5) + return RULE_OF_THREE(-20, -5, x) + 50 + if (-2.5 to -0) + return RULE_OF_THREE(-10, -2.5, x) + 50 + if (0 to 2.5) + return RULE_OF_THREE(10, 2.5, x) + 50 + if (2.5 to 5) + return RULE_OF_THREE(20, 5, x) + 50 + if (5 to 10) + return RULE_OF_THREE(30, 10, x) + 50 + if (10 to 20) + return RULE_OF_THREE(40, 20, x) + 50 + if (20 to INFINITY) + return rand(90, 100) diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets.dm b/code/game/gamemodes/dynamic/dynamic_rulesets.dm new file mode 100644 index 0000000000..66afcbfb92 --- /dev/null +++ b/code/game/gamemodes/dynamic/dynamic_rulesets.dm @@ -0,0 +1,211 @@ +/datum/dynamic_ruleset + /// For admin logging and round end screen. + var/name = "" + /// For admin logging and round end screen, do not change this unless making a new rule type. + var/ruletype = "" + /// If set to TRUE, the rule won't be discarded after being executed, and dynamic will call rule_process() every time it ticks. + var/persistent = FALSE + /// If set to TRUE, dynamic mode will be able to draft this ruleset again later on. (doesn't apply for roundstart rules) + var/repeatable = FALSE + /// If set higher than 0 decreases weight by itself causing the ruleset to appear less often the more it is repeated. + var/repeatable_weight_decrease = 2 + /// List of players that are being drafted for this rule + var/list/mob/candidates = list() + /// List of players that were selected for this rule + var/list/datum/mind/assigned = list() + /// Preferences flag such as ROLE_WIZARD that need to be turned on for players to be antag + var/antag_flag = null + /// The antagonist datum that is assigned to the mobs mind on ruleset execution. + var/datum/antagonist/antag_datum = null + /// The required minimum account age for this ruleset. + var/minimum_required_age = 7 + /// If set, and config flag protect_roles_from_antagonist is false, then the rule will not pick players from these roles. + var/list/protected_roles = list() + /// If set, rule will deny candidates from those roles always. + var/list/restricted_roles = list() + /// If set, rule will only accept candidates from those roles, IMPORTANT: DOES NOT WORK ON ROUNDSTART RULESETS. + var/list/exclusive_roles = list() + /// If set, there needs to be a certain amount of players doing those roles (among the players who won't be drafted) for the rule to be drafted IMPORTANT: DOES NOT WORK ON ROUNDSTART RULESETS. + var/list/enemy_roles = list() + /// If enemy_roles was set, this is the amount of enemy job workers needed per threat_level range (0-10,10-20,etc) IMPORTANT: DOES NOT WORK ON ROUNDSTART RULESETS. + var/required_enemies = list(1,1,0,0,0,0,0,0,0,0) + /// The rule needs this many candidates (post-trimming) to be executed (example: Cult needs 4 players at round start) + var/required_candidates = 0 + /// 1 -> 9, probability for this rule to be picked against other rules + var/weight = 5 + /// Threat cost for this rule, this is decreased from the mode's threat when the rule is executed. + var/cost = 0 + /// A flag that determines how the ruleset is handled + /// HIGHLANDER_RULESET are rulesets can end the round. + /// TRAITOR_RULESET and MINOR_RULESET can't end the round and have no difference right now. + var/flags = 0 + /// Pop range per requirement. If zero defaults to mode's pop_per_requirement. + var/pop_per_requirement = 0 + /// Requirements are the threat level requirements per pop range. + /// With the default values, The rule will never get drafted below 10 threat level (aka: "peaceful extended"), and it requires a higher threat level at lower pops. + var/list/requirements = list(40,30,20,10,10,10,10,10,10,10) + /// An alternative, static requirement used instead when pop is over mode's high_pop_limit. + var/high_population_requirement = 10 + /// Reference to the mode, use this instead of SSticker.mode. + var/datum/game_mode/dynamic/mode = null + /// If a role is to be considered another for the purpose of banning. + var/antag_flag_override = null + /// If a ruleset type which is in this list has been executed, then the ruleset will not be executed. + var/list/blocking_rules = list() + /// The minimum amount of players required for the rule to be considered. + var/minimum_players = 0 + /// The maximum amount of players required for the rule to be considered. + /// Anything below zero or exactly zero is ignored. + var/maximum_players = 0 + + +/datum/dynamic_ruleset/New() + ..() + if(CONFIG_GET(flag/protect_roles_from_antagonist)) + restricted_roles += protected_roles + if(CONFIG_GET(flag/protect_assistant_from_antagonist)) + restricted_roles += "Assistant" + + if (istype(SSticker.mode, /datum/game_mode/dynamic)) + mode = SSticker.mode + else if (GLOB.master_mode != "dynamic") // This is here to make roundstart forced ruleset function. + qdel(src) + +/datum/dynamic_ruleset/roundstart // One or more of those drafted at roundstart + ruletype = "Roundstart" + +/datum/dynamic_ruleset/roundstart/delayed/ // Executed with a 30 seconds delay + var/delay = 30 SECONDS + var/required_type = /mob/living/carbon/human // No ghosts, new players or silicons allowed. + +// Can be drafted when a player joins the server +/datum/dynamic_ruleset/latejoin + ruletype = "Latejoin" + +/// By default, a rule is acceptable if it satisfies the threat level/population requirements. +/// If your rule has extra checks, such as counting security officers, do that in ready() instead +/datum/dynamic_ruleset/proc/acceptable(population = 0, threat_level = 0) + if(minimum_players > population) + return FALSE + if(maximum_players > 0 && population > maximum_players) + return FALSE + if (population >= GLOB.dynamic_high_pop_limit) + return (threat_level >= high_population_requirement) + else + pop_per_requirement = pop_per_requirement > 0 ? pop_per_requirement : mode.pop_per_requirement + var/indice_pop = min(10,round(population/pop_per_requirement)+1) + return (threat_level >= requirements[indice_pop]) + +/// This is called if persistent variable is true everytime SSTicker ticks. +/datum/dynamic_ruleset/proc/rule_process() + return + +/// Called on game mode pre_setup, used for non-delayed roundstart rulesets only. +/// Do everything you need to do before job is assigned here. +/// IMPORTANT: ASSIGN special_role HERE +/datum/dynamic_ruleset/proc/pre_execute() + return TRUE + +/// Called on post_setup on roundstart and when the rule executes on midround and latejoin. +/// Give your candidates or assignees equipment and antag datum here. +/datum/dynamic_ruleset/proc/execute() + for(var/datum/mind/M in assigned) + M.add_antag_datum(antag_datum) + return TRUE + +/// Called after delay set in ruleset. +/// Give your candidates or assignees equipment and antag datum here. +/datum/dynamic_ruleset/roundstart/delayed/execute() + if (SSticker && SSticker.current_state < GAME_STATE_PLAYING) + CRASH("The delayed ruleset [name] executed before the round started.") + +/// Here you can perform any additional checks you want. (such as checking the map etc) +/// Remember that on roundstart no one knows what their job is at this point. +/// IMPORTANT: If ready() returns TRUE, that means pre_execute() or execute() should never fail! +/datum/dynamic_ruleset/proc/ready(forced = 0) + if (required_candidates > candidates.len) + return FALSE + return TRUE + +/// Gets weight of the ruleset +/// Note that this decreases weight if repeatable is TRUE and repeatable_weight_decrease is higher than 0 +/// Note: If you don't want repeatable rulesets to decrease their weight use the weight variable directly +/datum/dynamic_ruleset/proc/get_weight() + if(repeatable && weight > 1 && repeatable_weight_decrease > 0) + for(var/datum/dynamic_ruleset/DR in mode.executed_rules) + if(istype(DR, type)) + weight = max(weight-repeatable_weight_decrease,1) + return weight + +/// Here you can remove candidates that do not meet your requirements. +/// This means if their job is not correct or they have disconnected you can remove them from candidates here. +/// Usually this does not need to be changed unless you need some specific requirements from your candidates. +/datum/dynamic_ruleset/proc/trim_candidates() + return + +/// Counts how many players are ready at roundstart. +/// Used only by non-delayed roundstart rulesets. +/datum/dynamic_ruleset/proc/num_players() + . = 0 + for(var/mob/dead/new_player/P in GLOB.player_list) + if(P.client && P.ready == PLAYER_READY_TO_PLAY) + . ++ + +/// Set mode result and news report here. +/// Only called if ruleset is flagged as HIGHLANDER_RULESET +/datum/dynamic_ruleset/proc/round_result() + +/// Checks if round is finished, return true to end the round. +/// Only called if ruleset is flagged as HIGHLANDER_RULESET +/datum/dynamic_ruleset/proc/check_finished() + return FALSE + +////////////////////////////////////////////// +// // +// ROUNDSTART RULESETS // +// // +////////////////////////////////////////////// + +/// Checks if candidates are connected and if they are banned or don't want to be the antagonist. +/datum/dynamic_ruleset/roundstart/trim_candidates() + for(var/mob/dead/new_player/P in candidates) + if (!P.client || !P.mind) // Are they connected? + candidates.Remove(P) + continue + if(!mode.check_age(P.client, minimum_required_age)) + candidates.Remove(P) + continue + if(P.mind.special_role) // We really don't want to give antag to an antag. + candidates.Remove(P) + continue + if (!(antag_flag in P.client.prefs.be_special) || jobban_isbanned(P.ckey, list(antag_flag, ROLE_SYNDICATE)) || (antag_flag_override && jobban_isbanned(P.ckey, list(antag_flag_override, ROLE_SYNDICATE))))//are they willing and not antag-banned? + candidates.Remove(P) + continue + +/// Checks if candidates are required mob type, connected, banned and if the job is exclusive to the role. +/datum/dynamic_ruleset/roundstart/delayed/trim_candidates() + . = ..() + for (var/mob/P in candidates) + if (!istype(P, required_type)) + candidates.Remove(P) // Can be a new_player, etc. + continue + if(!mode.check_age(P.client, minimum_required_age)) + candidates.Remove(P) + continue + if (!P.client || !P.mind || !P.mind.assigned_role) // Are they connected? + candidates.Remove(P) + continue + if(P.mind.special_role || P.mind.antag_datums?.len > 0) // Are they an antag already? + candidates.Remove(P) + continue + if (!(antag_flag in P.client.prefs.be_special) || jobban_isbanned(P.ckey, list(antag_flag, ROLE_SYNDICATE)) || (antag_flag_override && jobban_isbanned(P.ckey, list(antag_flag_override, ROLE_SYNDICATE))))//are they willing and not antag-banned? + candidates.Remove(P) + continue + if ((exclusive_roles.len > 0) && !(P.mind.assigned_role in exclusive_roles)) // Is the rule exclusive to their job? + candidates.Remove(P) + continue + +/// Do your checks if the ruleset is ready to be executed here. +/// Should ignore certain checks if forced is TRUE +/datum/dynamic_ruleset/roundstart/ready(forced = FALSE) + return ..() diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm new file mode 100644 index 0000000000..24b4c67357 --- /dev/null +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm @@ -0,0 +1,110 @@ +////////////////////////////////////////////// +// // +// LATEJOIN RULESETS // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/latejoin/trim_candidates() + for(var/mob/P in candidates) + if (!P.client || !P.mind || !P.mind.assigned_role) // Are they connected? + candidates.Remove(P) + continue + if(!mode.check_age(P.client, minimum_required_age)) + candidates.Remove(P) + continue + if (!(antag_flag in P.client.prefs.be_special) || jobban_isbanned(P.ckey, list(antag_flag, ROLE_SYNDICATE)) || (antag_flag_override && jobban_isbanned(P.ckey, list(antag_flag_override))))//are they willing and not antag-banned? + candidates.Remove(P) + continue + if (P.mind.assigned_role in restricted_roles) // Does their job allow for it? + candidates.Remove(P) + continue + if ((exclusive_roles.len > 0) && !(P.mind.assigned_role in exclusive_roles)) // Is the rule exclusive to their job? + candidates.Remove(P) + continue + +/datum/dynamic_ruleset/latejoin/ready(forced = 0) + if (!forced) + var/job_check = 0 + if (enemy_roles.len > 0) + for (var/mob/M in mode.current_players[CURRENT_LIVING_PLAYERS]) + if (M.stat == DEAD) + continue // Dead players cannot count as opponents + if (M.mind && M.mind.assigned_role && (M.mind.assigned_role in enemy_roles) && (!(M in candidates) || (M.mind.assigned_role in restricted_roles))) + job_check++ // Checking for "enemies" (such as sec officers). To be counters, they must either not be candidates to that rule, or have a job that restricts them from it + + var/threat = round(mode.threat_level/10) + if (job_check < required_enemies[threat]) + return FALSE + return ..() + +/datum/dynamic_ruleset/latejoin/execute() + var/mob/M = pick(candidates) + assigned += M.mind + M.mind.special_role = antag_flag + M.mind.add_antag_datum(antag_datum) + return TRUE + +////////////////////////////////////////////// +// // +// SYNDICATE TRAITORS // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/latejoin/infiltrator + name = "Syndicate Infiltrator" + antag_datum = /datum/antagonist/traitor + antag_flag = ROLE_TRAITOR + restricted_roles = list("AI", "Cyborg") + protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") + required_candidates = 1 + weight = 7 + cost = 5 + requirements = list(40,30,20,10,10,10,10,10,10,10) + high_population_requirement = 10 + repeatable = TRUE + flags = TRAITOR_RULESET + +////////////////////////////////////////////// +// // +// REVOLUTIONARY PROVOCATEUR // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/latejoin/provocateur + name = "Provocateur" + antag_datum = /datum/antagonist/rev/head + antag_flag = ROLE_REV_HEAD + antag_flag_override = ROLE_REV + restricted_roles = list("AI", "Cyborg", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") + enemy_roles = list("AI", "Cyborg", "Security Officer","Detective","Head of Security", "Captain", "Warden") + required_enemies = list(2,2,1,1,1,1,1,0,0,0) + required_candidates = 1 + weight = 2 + cost = 20 + requirements = list(101,101,70,40,30,20,20,20,20,20) + high_population_requirement = 50 + flags = HIGHLANDER_RULESET + var/required_heads = 3 + +/datum/dynamic_ruleset/latejoin/provocateur/ready(forced=FALSE) + if (forced) + required_heads = 1 + if(!..()) + return FALSE + var/head_check = 0 + for(var/mob/player in mode.current_players[CURRENT_LIVING_PLAYERS]) + if (player.mind.assigned_role in GLOB.command_positions) + head_check++ + return (head_check >= required_heads) + +/datum/dynamic_ruleset/latejoin/provocateur/execute() + var/mob/M = pick(candidates) + assigned += M.mind + M.mind.special_role = antag_flag + var/datum/antagonist/rev/head/new_head = new() + new_head.give_flash = TRUE + new_head.give_hud = TRUE + new_head.remove_clumsy = TRUE + new_head = M.mind.add_antag_datum(new_head) + new_head.rev_team.max_headrevs = 1 // Only one revhead if it is latejoin. + return TRUE diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm new file mode 100644 index 0000000000..4da085d5a9 --- /dev/null +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm @@ -0,0 +1,460 @@ +////////////////////////////////////////////// +// // +// MIDROUND RULESETS // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/midround // Can be drafted once in a while during a round + ruletype = "Midround" + /// If the ruleset should be restricted from ghost roles. + var/restrict_ghost_roles = TRUE + /// What type the ruleset is restricted to. + var/required_type = /mob/living/carbon/human + var/list/living_players = list() + var/list/living_antags = list() + var/list/dead_players = list() + var/list/list_observers = list() + +/datum/dynamic_ruleset/midround/from_ghosts + weight = 0 + /// Whether the ruleset should call generate_ruleset_body or not. + var/makeBody = TRUE + +/datum/dynamic_ruleset/midround/trim_candidates() + // Unlike the previous two types, these rulesets are not meant for /mob/dead/new_player + // And since I want those rulesets to be as flexible as possible, I'm not gonna put much here, + // + // All you need to know is that here, the candidates list contains 4 lists itself, indexed with the following defines: + // Candidates = list(CURRENT_LIVING_PLAYERS, CURRENT_LIVING_ANTAGS, CURRENT_DEAD_PLAYERS, CURRENT_OBSERVERS) + // So for example you can get the list of all current dead players with var/list/dead_players = candidates[CURRENT_DEAD_PLAYERS] + // Make sure to properly typecheck the mobs in those lists, as the dead_players list could contain ghosts, or dead players still in their bodies. + // We're still gonna trim the obvious (mobs without clients, jobbanned players, etc) + living_players = trim_list(mode.current_players[CURRENT_LIVING_PLAYERS]) + living_antags = trim_list(mode.current_players[CURRENT_LIVING_ANTAGS]) + dead_players = trim_list(mode.current_players[CURRENT_DEAD_PLAYERS]) + list_observers = trim_list(mode.current_players[CURRENT_OBSERVERS]) + +/datum/dynamic_ruleset/midround/proc/trim_list(list/L = list()) + var/list/trimmed_list = L.Copy() + var/antag_name = initial(antag_flag) + for(var/mob/M in trimmed_list) + if (!istype(M, required_type)) + trimmed_list.Remove(M) + continue + if (!M.client) // Are they connected? + trimmed_list.Remove(M) + continue + if(!mode.check_age(M.client, minimum_required_age)) + trimmed_list.Remove(M) + continue + if (!(antag_name in M.client.prefs.be_special) || jobban_isbanned(M.ckey, list(antag_name, ROLE_SYNDICATE)))//are they willing and not antag-banned? + trimmed_list.Remove(M) + continue + if (M.mind) + if (restrict_ghost_roles && M.mind.assigned_role in GLOB.exp_specialmap[EXP_TYPE_SPECIAL]) // Are they playing a ghost role? + trimmed_list.Remove(M) + continue + if (M.mind.assigned_role in restricted_roles || HAS_TRAIT(M, TRAIT_MINDSHIELD)) // Does their job allow it or are they mindshielded? + trimmed_list.Remove(M) + continue + if ((exclusive_roles.len > 0) && !(M.mind.assigned_role in exclusive_roles)) // Is the rule exclusive to their job? + trimmed_list.Remove(M) + continue + return trimmed_list + +// You can then for example prompt dead players in execute() to join as strike teams or whatever +// Or autotator someone + +// IMPORTANT, since /datum/dynamic_ruleset/midround may accept candidates from both living, dead, and even antag players, you need to manually check whether there are enough candidates +// (see /datum/dynamic_ruleset/midround/autotraitor/ready(var/forced = FALSE) for example) +/datum/dynamic_ruleset/midround/ready(forced = FALSE) + if (!forced) + var/job_check = 0 + if (enemy_roles.len > 0) + for (var/mob/M in living_players) + if (M.stat == DEAD) + continue // Dead players cannot count as opponents + if (M.mind && M.mind.assigned_role && (M.mind.assigned_role in enemy_roles) && (!(M in candidates) || (M.mind.assigned_role in restricted_roles))) + job_check++ // Checking for "enemies" (such as sec officers). To be counters, they must either not be candidates to that rule, or have a job that restricts them from it + + var/threat = round(mode.threat_level/10) + if (job_check < required_enemies[threat]) + return FALSE + return TRUE + +/datum/dynamic_ruleset/midround/from_ghosts/execute() + var/list/possible_candidates = list() + possible_candidates.Add(dead_players) + possible_candidates.Add(list_observers) + send_applications(possible_candidates) + if(assigned.len > 0) + return TRUE + else + return FALSE + +/// This sends a poll to ghosts if they want to be a ghost spawn from a ruleset. +/datum/dynamic_ruleset/midround/from_ghosts/proc/send_applications(list/possible_volunteers = list()) + if (possible_volunteers.len <= 0) // This shouldn't happen, as ready() should return FALSE if there is not a single valid candidate + message_admins("Possible volunteers was 0. This shouldn't appear, because of ready(), unless you forced it!") + return + message_admins("Polling [possible_volunteers.len] players to apply for the [name] ruleset.") + log_game("DYNAMIC: Polling [possible_volunteers.len] players to apply for the [name] ruleset.") + + candidates = pollGhostCandidates("The mode is looking for volunteers to become [antag_flag] for [name]", antag_flag, SSticker.mode, antag_flag, poll_time = 300) + + if(!candidates || candidates.len <= 0) + message_admins("The ruleset [name] received no applications.") + log_game("DYNAMIC: The ruleset [name] received no applications.") + mode.refund_threat(cost) + mode.threat_log += "[worldtime2text()]: Rule [name] refunded [cost] (no applications)" + mode.executed_rules -= src + return + + message_admins("[candidates.len] players volunteered for the ruleset [name].") + log_game("DYNAMIC: [candidates.len] players volunteered for [name].") + review_applications() + +/// Here is where you can check if your ghost applicants are valid for the ruleset. +/// Called by send_applications(). +/datum/dynamic_ruleset/midround/from_ghosts/proc/review_applications() + for (var/i = 1, i <= required_candidates, i++) + if(candidates.len <= 0) + if(i == 1) + // We have found no candidates so far and we are out of applicants. + mode.refund_threat(cost) + mode.threat_log += "[worldtime2text()]: Rule [name] refunded [cost] (all applications invalid)" + mode.executed_rules -= src + break + var/mob/applicant = pick(candidates) + candidates -= applicant + if(!isobserver(applicant)) + if(applicant.stat == DEAD) // Not an observer? If they're dead, make them one. + applicant = applicant.ghostize(FALSE) + else // Not dead? Disregard them, pick a new applicant + i-- + continue + + if(!applicant) + i-- + continue + + var/mob/new_character = applicant + + if (makeBody) + new_character = generate_ruleset_body(applicant) + + finish_setup(new_character, i) + assigned += applicant + notify_ghosts("[new_character] 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 = makeBody(applicant) + new_character.dna.remove_all_mutations() + return new_character + +/datum/dynamic_ruleset/midround/from_ghosts/proc/finish_setup(mob/new_character, index) + var/datum/antagonist/new_role = new antag_datum() + setup_role(new_role) + new_character.mind.add_antag_datum(new_role) + new_character.mind.special_role = antag_flag + +/datum/dynamic_ruleset/midround/from_ghosts/proc/setup_role(datum/antagonist/new_role) + return + +////////////////////////////////////////////// +// // +// SYNDICATE TRAITORS // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/midround/autotraitor + name = "Syndicate Sleeper Agent" + antag_datum = /datum/antagonist/traitor + antag_flag = ROLE_TRAITOR + restricted_roles = list("AI", "Cyborg", "Positronic Brain") + protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") + required_candidates = 1 + weight = 7 + cost = 10 + requirements = list(50,40,30,20,10,10,10,10,10,10) + repeatable = TRUE + high_population_requirement = 10 + flags = TRAITOR_RULESET + +/datum/dynamic_ruleset/midround/autotraitor/acceptable(population = 0, threat = 0) + var/player_count = mode.current_players[CURRENT_LIVING_PLAYERS].len + var/antag_count = mode.current_players[CURRENT_LIVING_ANTAGS].len + var/max_traitors = round(player_count / 10) + 1 + if ((antag_count < max_traitors) && prob(mode.threat_level))//adding traitors if the antag population is getting low + return ..() + else + return FALSE + +/datum/dynamic_ruleset/midround/autotraitor/trim_candidates() + ..() + for(var/mob/living/player in living_players) + if(issilicon(player)) // Your assigned role doesn't change when you are turned into a silicon. + living_players -= player + continue + if(is_centcom_level(player.z)) + living_players -= player // We don't autotator people in CentCom + continue + if(player.mind && (player.mind.special_role || player.mind.antag_datums?.len > 0)) + living_players -= player // We don't autotator people with roles already + +/datum/dynamic_ruleset/midround/autotraitor/ready(forced = FALSE) + if (required_candidates > living_players.len) + return FALSE + return ..() + +/datum/dynamic_ruleset/midround/autotraitor/execute() + var/mob/M = pick(living_players) + assigned += M + living_players -= M + var/datum/antagonist/traitor/newTraitor = new + M.mind.add_antag_datum(newTraitor) + return TRUE + + +////////////////////////////////////////////// +// // +// Malfunctioning AI // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/midround/malf + name = "Malfunctioning AI" + antag_datum = /datum/antagonist/traitor + antag_flag = ROLE_MALF + enemy_roles = list("Security Officer", "Warden","Detective","Head of Security", "Captain", "Scientist", "Chemist", "Research Director", "Chief Engineer") + exclusive_roles = list("AI") + required_enemies = list(4,4,4,4,4,4,2,2,2,0) + required_candidates = 1 + weight = 3 + cost = 35 + requirements = list(101,101,80,70,60,60,50,50,40,40) + high_population_requirement = 35 + required_type = /mob/living/silicon/ai + var/ion_announce = 33 + var/removeDontImproveChance = 10 + +/datum/dynamic_ruleset/midround/malf/trim_candidates() + ..() + candidates = candidates[CURRENT_LIVING_PLAYERS] + for(var/mob/living/player in candidates) + if(!isAI(player)) + candidates -= player + continue + if(is_centcom_level(player.z)) + candidates -= player + continue + if(player.mind && (player.mind.special_role || player.mind.antag_datums?.len > 0)) + candidates -= player + +/datum/dynamic_ruleset/midround/malf/execute() + if(!candidates || !candidates.len) + return FALSE + var/mob/living/silicon/ai/M = pick(candidates) + candidates -= M + assigned += M.mind + var/datum/antagonist/traitor/AI = new + M.mind.special_role = antag_flag + M.mind.add_antag_datum(AI) + if(prob(ion_announce)) + priority_announce("Ion storm detected near the station. Please check all AI-controlled equipment for errors.", "Anomaly Alert", 'sound/ai/ionstorm.ogg') + if(prob(removeDontImproveChance)) + M.replace_random_law(generate_ion_law(), list(LAW_INHERENT, LAW_SUPPLIED, LAW_ION)) + else + M.add_ion_law(generate_ion_law()) + return TRUE + +////////////////////////////////////////////// +// // +// WIZARD (GHOST) // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/midround/from_ghosts/wizard + name = "Wizard" + antag_datum = /datum/antagonist/wizard + antag_flag = ROLE_WIZARD + enemy_roles = list("Security Officer","Detective","Head of Security", "Captain") + required_enemies = list(2,2,1,1,1,1,1,0,0,0) + required_candidates = 1 + weight = 1 + cost = 20 + requirements = list(90,90,70,40,30,20,10,10,10,10) + high_population_requirement = 50 + repeatable = TRUE + +/datum/dynamic_ruleset/midround/from_ghosts/wizard/ready(forced = FALSE) + if (required_candidates > (dead_players.len + list_observers.len)) + return FALSE + if(GLOB.wizardstart.len == 0) + log_admin("Cannot accept Wizard ruleset. Couldn't find any wizard spawn points.") + message_admins("Cannot accept Wizard ruleset. Couldn't find any wizard spawn points.") + return FALSE + return ..() + +/datum/dynamic_ruleset/midround/from_ghosts/wizard/finish_setup(mob/new_character, index) + ..() + new_character.forceMove(pick(GLOB.wizardstart)) + +////////////////////////////////////////////// +// // +// NUCLEAR OPERATIVES (MIDROUND) // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/midround/from_ghosts/nuclear + name = "Nuclear Assault" + antag_flag = ROLE_OPERATIVE + antag_datum = /datum/antagonist/nukeop + enemy_roles = list("AI", "Cyborg", "Security Officer", "Warden","Detective","Head of Security", "Captain") + required_enemies = list(3,3,3,3,3,2,1,1,0,0) + required_candidates = 5 + weight = 5 + cost = 35 + requirements = list(90,90,90,80,60,40,30,20,10,10) + high_population_requirement = 10 + var/operative_cap = list(2,2,3,3,4,5,5,5,5,5) + var/datum/team/nuclear/nuke_team + flags = HIGHLANDER_RULESET + +/datum/dynamic_ruleset/midround/from_ghosts/nuclear/acceptable(population=0, threat=0) + if (locate(/datum/dynamic_ruleset/roundstart/nuclear) in mode.executed_rules) + return FALSE // Unavailable if nuke ops were already sent at roundstart + var/indice_pop = min(10,round(living_players.len/5)+1) + required_candidates = operative_cap[indice_pop] + return ..() + +/datum/dynamic_ruleset/midround/from_ghosts/nuclear/ready(forced = FALSE) + if (required_candidates > (dead_players.len + list_observers.len)) + return FALSE + return ..() + +/datum/dynamic_ruleset/midround/from_ghosts/nuclear/finish_setup(mob/new_character, index) + new_character.mind.special_role = "Nuclear Operative" + new_character.mind.assigned_role = "Nuclear Operative" + if (index == 1) // Our first guy is the leader + var/datum/antagonist/nukeop/leader/new_role = new + nuke_team = new_role.nuke_team + new_character.mind.add_antag_datum(new_role) + else + return ..() + +////////////////////////////////////////////// +// // +// BLOB (GHOST) // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/midround/from_ghosts/blob + name = "Blob" + antag_datum = /datum/antagonist/blob + antag_flag = ROLE_BLOB + enemy_roles = list("Security Officer", "Detective", "Head of Security", "Captain") + required_enemies = list(2,2,1,1,1,1,1,0,0,0) + required_candidates = 1 + weight = 4 + cost = 10 + requirements = list(101,101,101,80,60,50,30,20,10,10) + high_population_requirement = 50 + repeatable = TRUE + +/datum/dynamic_ruleset/midround/from_ghosts/blob/generate_ruleset_body(mob/applicant) + var/body = applicant.become_overmind() + return body + +////////////////////////////////////////////// +// // +// XENOMORPH (GHOST) // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/midround/from_ghosts/xenomorph + name = "Alien Infestation" + antag_datum = /datum/antagonist/xeno + antag_flag = ROLE_ALIEN + enemy_roles = list("Security Officer", "Detective", "Head of Security", "Captain") + required_enemies = list(2,2,1,1,1,1,1,0,0,0) + required_candidates = 1 + weight = 3 + cost = 10 + requirements = list(101,101,101,70,50,40,20,15,10,10) + high_population_requirement = 50 + repeatable = TRUE + var/list/vents = list() + +/datum/dynamic_ruleset/midround/from_ghosts/xenomorph/execute() + // 50% chance of being incremented by one + required_candidates += prob(50) + for(var/obj/machinery/atmospherics/components/unary/vent_pump/temp_vent in GLOB.machines) + if(QDELETED(temp_vent)) + continue + if(is_station_level(temp_vent.loc.z) && !temp_vent.welded) + var/datum/pipeline/temp_vent_parent = temp_vent.parents[1] + if(!temp_vent_parent) + continue // No parent vent + // Stops Aliens getting stuck in small networks. + // See: Security, Virology + if(temp_vent_parent.other_atmosmch.len > 20) + vents += temp_vent + if(!vents.len) + return FALSE + . = ..() + +/datum/dynamic_ruleset/midround/from_ghosts/xenomorph/generate_ruleset_body(mob/applicant) + var/obj/vent = pick_n_take(vents) + var/mob/living/carbon/alien/larva/new_xeno = new(vent.loc) + applicant.transfer_ckey(new_xeno, FALSE) + message_admins("[ADMIN_LOOKUPFLW(new_xeno)] has been made into an alien by the midround ruleset.") + log_game("DYNAMIC: [key_name(new_xeno)] was spawned as an alien by the midround ruleset.") + return new_xeno + +////////////////////////////////////////////// +// // +// NIGHTMARE (GHOST) // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/midround/from_ghosts/nightmare + name = "Nightmare" + antag_datum = /datum/antagonist/nightmare + antag_flag = "Nightmare" + antag_flag_override = ROLE_ALIEN + enemy_roles = list("Security Officer", "Detective", "Head of Security", "Captain") + required_enemies = list(2,2,1,1,1,1,1,0,0,0) + required_candidates = 1 + weight = 3 + cost = 10 + requirements = list(101,101,101,70,50,40,20,15,10,10) + high_population_requirement = 50 + repeatable = TRUE + var/list/spawn_locs = list() + +/datum/dynamic_ruleset/midround/from_ghosts/nightmare/execute() + for(var/X in GLOB.xeno_spawn) + var/turf/T = X + var/light_amount = T.get_lumcount() + if(light_amount < SHADOW_SPECIES_LIGHT_THRESHOLD) + spawn_locs += T + if(!spawn_locs.len) + return FALSE + . = ..() + +/datum/dynamic_ruleset/midround/from_ghosts/nightmare/generate_ruleset_body(mob/applicant) + var/datum/mind/player_mind = new /datum/mind(applicant.key) + player_mind.active = TRUE + + var/mob/living/carbon/human/S = new (pick(spawn_locs)) + player_mind.transfer_to(S) + player_mind.assigned_role = "Nightmare" + player_mind.special_role = "Nightmare" + player_mind.add_antag_datum(/datum/antagonist/nightmare) + S.set_species(/datum/species/shadow/nightmare) + + playsound(S, 'sound/magic/ethereal_exit.ogg', 50, 1, -1) + message_admins("[ADMIN_LOOKUPFLW(S)] has been made into a Nightmare by the midround ruleset.") + log_game("DYNAMIC: [key_name(S)] was spawned as a Nightmare by the midround ruleset.") + return S diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm new file mode 100644 index 0000000000..38ce6f68d0 --- /dev/null +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm @@ -0,0 +1,732 @@ + +////////////////////////////////////////////// +// // +// SYNDICATE TRAITORS // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/roundstart/traitor + name = "Traitors" + persistent = TRUE + antag_flag = ROLE_TRAITOR + antag_datum = /datum/antagonist/traitor/ + minimum_required_age = 0 + protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster", "Cyborg") + restricted_roles = list("Cyborg") + required_candidates = 1 + weight = 5 + cost = 10 + requirements = list(10,10,10,10,10,10,10,10,10,10) + high_population_requirement = 10 + var/autotraitor_cooldown = 450 // 15 minutes (ticks once per 2 sec) + +/datum/dynamic_ruleset/roundstart/traitor/pre_execute() + var/traitor_scaling_coeff = 10 - max(0,round(mode.threat_level/10)-5) // Above 50 threat level, coeff goes down by 1 for every 10 levels + var/num_traitors = min(round(mode.candidates.len / traitor_scaling_coeff) + 1, candidates.len) + for (var/i = 1 to num_traitors) + var/mob/M = pick(candidates) + candidates -= M + assigned += M.mind + M.mind.special_role = ROLE_TRAITOR + M.mind.restricted_roles = restricted_roles + return TRUE + +/datum/dynamic_ruleset/roundstart/traitor/rule_process() + if (autotraitor_cooldown > 0) + autotraitor_cooldown-- + else + autotraitor_cooldown = 450 // 15 minutes + message_admins("Checking if we can turn someone into a traitor.") + log_game("DYNAMIC: Checking if we can turn someone into a traitor.") + mode.picking_specific_rule(/datum/dynamic_ruleset/midround/autotraitor) + +////////////////////////////////////////// +// // +// BLOOD BROTHERS // +// // +////////////////////////////////////////// + +/datum/dynamic_ruleset/roundstart/traitorbro + name = "Blood Brothers" + antag_flag = ROLE_BROTHER + antag_datum = /datum/antagonist/brother/ + restricted_roles = list("AI", "Cyborg") + protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") + required_candidates = 2 + weight = 4 + cost = 10 + requirements = list(40,30,30,20,20,15,15,15,10,10) + high_population_requirement = 15 + var/list/datum/team/brother_team/pre_brother_teams = list() + var/const/team_amount = 2 // Hard limit on brother teams if scaling is turned off + var/const/min_team_size = 2 + +/datum/dynamic_ruleset/roundstart/traitorbro/pre_execute() + var/num_teams = team_amount + var/bsc = CONFIG_GET(number/brother_scaling_coeff) + if(bsc) + num_teams = max(1, round(num_players() / bsc)) + + for(var/j = 1 to num_teams) + if(candidates.len < min_team_size || candidates.len < required_candidates) + break + var/datum/team/brother_team/team = new + var/team_size = prob(10) ? min(3, candidates.len) : 2 + for(var/k = 1 to team_size) + var/mob/bro = pick(candidates) + candidates -= bro + assigned += bro.mind + team.add_member(bro.mind) + bro.mind.special_role = "brother" + bro.mind.restricted_roles = restricted_roles + pre_brother_teams += team + return TRUE + +/datum/dynamic_ruleset/roundstart/traitorbro/execute() + for(var/datum/team/brother_team/team in pre_brother_teams) + team.pick_meeting_area() + team.forge_brother_objectives() + for(var/datum/mind/M in team.members) + M.add_antag_datum(/datum/antagonist/brother, team) + team.update_name() + mode.brother_teams += pre_brother_teams + return TRUE + +////////////////////////////////////////////// +// // +// CHANGELINGS // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/roundstart/changeling + name = "Changelings" + antag_flag = ROLE_CHANGELING + antag_datum = /datum/antagonist/changeling + restricted_roles = list("AI", "Cyborg") + protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") + required_candidates = 1 + weight = 3 + cost = 30 + requirements = list(80,70,60,50,40,20,20,10,10,10) + high_population_requirement = 10 + var/team_mode_probability = 30 + +/datum/dynamic_ruleset/roundstart/changeling/pre_execute() + var/num_changelings = min(round(mode.candidates.len / 10) + 1, candidates.len) + for (var/i = 1 to num_changelings) + var/mob/M = pick(candidates) + candidates -= M + assigned += M.mind + M.mind.restricted_roles = restricted_roles + M.mind.special_role = ROLE_CHANGELING + return TRUE + +/datum/dynamic_ruleset/roundstart/changeling/execute() + var/team_mode = FALSE + if(prob(team_mode_probability)) + team_mode = TRUE + var/list/team_objectives = subtypesof(/datum/objective/changeling_team_objective) + var/list/possible_team_objectives = list() + for(var/T in team_objectives) + var/datum/objective/changeling_team_objective/CTO = T + if(assigned.len >= initial(CTO.min_lings)) + possible_team_objectives += T + + if(possible_team_objectives.len && prob(20*assigned.len)) + GLOB.changeling_team_objective_type = pick(possible_team_objectives) + for(var/datum/mind/changeling in assigned) + var/datum/antagonist/changeling/new_antag = new antag_datum() + new_antag.team_mode = team_mode + changeling.add_antag_datum(new_antag) + return TRUE + +////////////////////////////////////////////// +// // +// WIZARDS // +// // +////////////////////////////////////////////// + +// Dynamic is a wonderful thing that adds wizards to every round and then adds even more wizards during the round. +/datum/dynamic_ruleset/roundstart/wizard + name = "Wizard" + antag_flag = ROLE_WIZARD + antag_datum = /datum/antagonist/wizard + minimum_required_age = 14 + restricted_roles = list("Head of Security", "Captain") // Just to be sure that a wizard getting picked won't ever imply a Captain or HoS not getting drafted + required_candidates = 1 + weight = 1 + cost = 30 + requirements = list(90,90,70,40,30,20,10,10,10,10) + high_population_requirement = 10 + var/list/roundstart_wizards = list() + +/datum/dynamic_ruleset/roundstart/wizard/acceptable(population=0, threat=0) + if(GLOB.wizardstart.len == 0) + log_admin("Cannot accept Wizard ruleset. Couldn't find any wizard spawn points.") + message_admins("Cannot accept Wizard ruleset. Couldn't find any wizard spawn points.") + return FALSE + return ..() + +/datum/dynamic_ruleset/roundstart/wizard/pre_execute() + if(GLOB.wizardstart.len == 0) + return FALSE + + var/mob/M = pick(candidates) + if (M) + candidates -= M + assigned += M.mind + M.mind.assigned_role = ROLE_WIZARD + M.mind.special_role = ROLE_WIZARD + + return TRUE + +/datum/dynamic_ruleset/roundstart/wizard/execute() + for(var/datum/mind/M in assigned) + M.current.forceMove(pick(GLOB.wizardstart)) + M.add_antag_datum(new antag_datum()) + return TRUE + +////////////////////////////////////////////// +// // +// BLOOD CULT // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/roundstart/bloodcult + name = "Blood Cult" + antag_flag = ROLE_CULTIST + antag_datum = /datum/antagonist/cult + minimum_required_age = 14 + restricted_roles = list("AI", "Cyborg") + protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") + required_candidates = 2 + weight = 3 + cost = 30 + requirements = list(100,90,80,60,40,30,10,10,10,10) + high_population_requirement = 10 + pop_per_requirement = 5 + flags = HIGHLANDER_RULESET + var/cultist_cap = list(2,2,2,3,3,4,4,4,4,4) + var/datum/team/cult/main_cult + +/datum/dynamic_ruleset/roundstart/bloodcult/ready(forced = FALSE) + var/indice_pop = min(10,round(mode.roundstart_pop_ready/pop_per_requirement)+1) + required_candidates = cultist_cap[indice_pop] + . = ..() + +/datum/dynamic_ruleset/roundstart/bloodcult/pre_execute() + var/indice_pop = min(10,round(mode.roundstart_pop_ready/pop_per_requirement)+1) + var/cultists = cultist_cap[indice_pop] + for(var/cultists_number = 1 to cultists) + if(candidates.len <= 0) + break + var/mob/M = pick(candidates) + candidates -= M + assigned += M.mind + M.mind.special_role = ROLE_CULTIST + M.mind.restricted_roles = restricted_roles + return TRUE + +/datum/dynamic_ruleset/roundstart/bloodcult/execute() + main_cult = new + for(var/datum/mind/M in assigned) + var/datum/antagonist/cult/new_cultist = new antag_datum() + new_cultist.cult_team = main_cult + new_cultist.give_equipment = TRUE + M.add_antag_datum(new_cultist) + main_cult.setup_objectives() + return TRUE + +/datum/dynamic_ruleset/roundstart/bloodcult/round_result() + ..() + if(main_cult.check_cult_victory()) + SSticker.mode_result = "win - cult win" + SSticker.news_report = CULT_SUMMON + else + SSticker.mode_result = "loss - staff stopped the cult" + SSticker.news_report = CULT_FAILURE + +////////////////////////////////////////////// +// // +// NUCLEAR OPERATIVES // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/roundstart/nuclear + name = "Nuclear Emergency" + antag_flag = ROLE_OPERATIVE + antag_datum = /datum/antagonist/nukeop + var/datum/antagonist/antag_leader_datum = /datum/antagonist/nukeop/leader + minimum_required_age = 14 + restricted_roles = list("Head of Security", "Captain") // Just to be sure that a nukie getting picked won't ever imply a Captain or HoS not getting drafted + required_candidates = 5 + weight = 3 + cost = 40 + requirements = list(90,90,90,80,60,40,30,20,10,10) + high_population_requirement = 10 + pop_per_requirement = 5 + flags = HIGHLANDER_RULESET + var/operative_cap = list(2,2,2,3,3,3,4,4,5,5) + var/datum/team/nuclear/nuke_team + +/datum/dynamic_ruleset/roundstart/nuclear/ready(forced = FALSE) + var/indice_pop = min(10,round(mode.roundstart_pop_ready/pop_per_requirement)+1) + required_candidates = operative_cap[indice_pop] + . = ..() + +/datum/dynamic_ruleset/roundstart/nuclear/pre_execute() + // If ready() did its job, candidates should have 5 or more members in it + + var/indice_pop = min(10,round(mode.roundstart_pop_ready/5)+1) + var/operatives = operative_cap[indice_pop] + for(var/operatives_number = 1 to operatives) + if(candidates.len <= 0) + break + var/mob/M = pick(candidates) + candidates -= M + assigned += M.mind + M.mind.assigned_role = "Nuclear Operative" + M.mind.special_role = "Nuclear Operative" + return TRUE + +/datum/dynamic_ruleset/roundstart/nuclear/execute() + var/leader = TRUE + for(var/datum/mind/M in assigned) + if (leader) + leader = FALSE + var/datum/antagonist/nukeop/leader/new_op = M.add_antag_datum(antag_leader_datum) + nuke_team = new_op.nuke_team + else + var/datum/antagonist/nukeop/new_op = new antag_datum() + M.add_antag_datum(new_op) + return TRUE + +/datum/dynamic_ruleset/roundstart/nuclear/round_result() + var result = nuke_team.get_result() + switch(result) + if(NUKE_RESULT_FLUKE) + SSticker.mode_result = "loss - syndicate nuked - disk secured" + SSticker.news_report = NUKE_SYNDICATE_BASE + if(NUKE_RESULT_NUKE_WIN) + SSticker.mode_result = "win - syndicate nuke" + SSticker.news_report = STATION_NUKED + if(NUKE_RESULT_NOSURVIVORS) + SSticker.mode_result = "halfwin - syndicate nuke - did not evacuate in time" + SSticker.news_report = STATION_NUKED + if(NUKE_RESULT_WRONG_STATION) + SSticker.mode_result = "halfwin - blew wrong station" + SSticker.news_report = NUKE_MISS + if(NUKE_RESULT_WRONG_STATION_DEAD) + SSticker.mode_result = "halfwin - blew wrong station - did not evacuate in time" + SSticker.news_report = NUKE_MISS + if(NUKE_RESULT_CREW_WIN_SYNDIES_DEAD) + SSticker.mode_result = "loss - evacuation - disk secured - syndi team dead" + SSticker.news_report = OPERATIVES_KILLED + if(NUKE_RESULT_CREW_WIN) + SSticker.mode_result = "loss - evacuation - disk secured" + SSticker.news_report = OPERATIVES_KILLED + if(NUKE_RESULT_DISK_LOST) + SSticker.mode_result = "halfwin - evacuation - disk not secured" + SSticker.news_report = OPERATIVE_SKIRMISH + if(NUKE_RESULT_DISK_STOLEN) + SSticker.mode_result = "halfwin - detonation averted" + SSticker.news_report = OPERATIVE_SKIRMISH + else + SSticker.mode_result = "halfwin - interrupted" + SSticker.news_report = OPERATIVE_SKIRMISH + +////////////////////////////////////////////// +// // +// REVS // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/roundstart/delayed/revs + name = "Revolution" + persistent = TRUE + antag_flag = ROLE_REV_HEAD + antag_flag_override = ROLE_REV + antag_datum = /datum/antagonist/rev/head + minimum_required_age = 14 + restricted_roles = list("AI", "Cyborg", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") + required_candidates = 3 + weight = 2 + cost = 35 + requirements = list(101,101,70,40,30,20,10,10,10,10) + high_population_requirement = 10 + delay = 5 MINUTES + flags = HIGHLANDER_RULESET + // I give up, just there should be enough heads with 35 players... + minimum_players = 35 + var/datum/team/revolution/revolution + var/finished = 0 + +/datum/dynamic_ruleset/roundstart/delayed/revs/execute() + var/max_canditates = 4 + revolution = new() + for(var/i = 1 to max_canditates) + if(candidates.len <= 0) + break + var/mob/M = pick(candidates) + candidates -= M + assigned += M.mind + M.mind.restricted_roles = restricted_roles + M.mind.special_role = antag_flag + var/datum/antagonist/rev/head/new_head = new antag_datum() + new_head.give_flash = TRUE + new_head.give_hud = TRUE + new_head.remove_clumsy = TRUE + M.mind.add_antag_datum(new_head,revolution) + + revolution.update_objectives() + revolution.update_heads() + SSshuttle.registerHostileEnvironment(src) + + return TRUE + +/datum/dynamic_ruleset/roundstart/delayed/revs/rule_process() + if(check_rev_victory()) + finished = 1 + else if(check_heads_victory()) + finished = 2 + return + +/datum/dynamic_ruleset/roundstart/delayed/revs/check_finished() + if(CONFIG_GET(keyed_list/continuous)["revolution"]) + if(finished) + SSshuttle.clearHostileEnvironment(src) + return ..() + if(finished != 0) + return TRUE + else + return ..() + +/datum/dynamic_ruleset/roundstart/delayed/revs/proc/check_rev_victory() + for(var/datum/objective/mutiny/objective in revolution.objectives) + if(!(objective.check_completion())) + return FALSE + return TRUE + +/datum/dynamic_ruleset/roundstart/delayed/revs/proc/check_heads_victory() + for(var/datum/mind/rev_mind in revolution.head_revolutionaries()) + var/turf/T = get_turf(rev_mind.current) + if(!considered_afk(rev_mind) && considered_alive(rev_mind) && is_station_level(T.z)) + if(ishuman(rev_mind.current) || ismonkey(rev_mind.current)) + return FALSE + return TRUE + +/datum/dynamic_ruleset/roundstart/delayed/revs/round_result() + if(finished == 1) + SSticker.mode_result = "win - heads killed" + SSticker.news_report = REVS_WIN + else if(finished == 2) + SSticker.mode_result = "loss - rev heads killed" + SSticker.news_report = REVS_LOSE + +// Admin only rulesets. The threat requirement is 101 so it is not possible to roll them. + +////////////////////////////////////////////// +// // +// EXTENDED // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/roundstart/extended + name = "Extended" + antag_flag = null + antag_datum = null + restricted_roles = list() + required_candidates = 0 + weight = 3 + cost = 0 + requirements = list(101,101,101,101,101,101,101,101,101,101) + high_population_requirement = 101 + +/datum/dynamic_ruleset/roundstart/extended/pre_execute() + message_admins("Starting a round of extended.") + log_game("Starting a round of extended.") + mode.spend_threat(mode.threat) + return TRUE + +////////////////////////////////////////////// +// // +// CLOCKCULT // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/roundstart/clockcult + name = "Clockcult" + antag_flag = ROLE_SERVANT_OF_RATVAR + antag_datum = /datum/antagonist/clockcult + restricted_roles = list("AI", "Cyborg", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") + required_candidates = 4 + weight = 3 + cost = 0 + requirements = list(101,101,101,101,101,101,101,101,101,101) + high_population_requirement = 101 + flags = HIGHLANDER_RULESET + var/ark_time + +/datum/dynamic_ruleset/roundstart/clockcult/pre_execute() + var/list/errorList = list() + var/list/reebes = SSmapping.LoadGroup(errorList, "Reebe", "map_files/generic", "City_of_Cogs.dmm", default_traits = ZTRAITS_REEBE, silent = TRUE) + if(errorList.len) + message_admins("Reebe failed to load!") + log_game("Reebe failed to load!") + return FALSE + for(var/datum/parsed_map/PM in reebes) + PM.initTemplateBounds() + + var/starter_servants = 4 + var/number_players = num_players() + if(number_players > 30) + number_players -= 30 + starter_servants += round(number_players / 10) + starter_servants = min(starter_servants, 8) + for (var/i in 1 to starter_servants) + var/mob/servant = pick(candidates) + candidates -= servant + assigned += servant.mind + servant.mind.assigned_role = ROLE_SERVANT_OF_RATVAR + servant.mind.special_role = ROLE_SERVANT_OF_RATVAR + ark_time = 30 + round((number_players / 5)) + ark_time = min(ark_time, 35) + return TRUE + +/datum/dynamic_ruleset/roundstart/clockcult/execute() + var/list/spread_out_spawns = GLOB.servant_spawns.Copy() + for(var/datum/mind/servant in assigned) + var/mob/S = servant.current + if(!spread_out_spawns.len) + spread_out_spawns = GLOB.servant_spawns.Copy() + log_game("[key_name(servant)] was made an initial servant of Ratvar") + var/turf/T = pick_n_take(spread_out_spawns) + S.forceMove(T) + greet_servant(S) + equip_servant(S) + add_servant_of_ratvar(S, TRUE) + var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar //that's a mouthful + G.final_countdown(ark_time) + return TRUE + +/datum/dynamic_ruleset/roundstart/clockcult/proc/greet_servant(mob/M) //Description of their role + if(!M) + return 0 + to_chat(M, "You are a servant of Ratvar, the Clockwork Justiciar!") + to_chat(M, "You have approximately [ark_time] minutes until the Ark activates.") + to_chat(M, "Unlock Script scripture by converting a new servant.") + to_chat(M, "Application scripture will be unlocked halfway until the Ark's activation.") + M.playsound_local(get_turf(M), 'sound/ambience/antag/clockcultalr.ogg', 100, FALSE, pressure_affected = FALSE) + return 1 + +/datum/dynamic_ruleset/roundstart/clockcult/proc/equip_servant(mob/living/M) //Grants a clockwork slab to the mob, with one of each component + if(!M || !ishuman(M)) + return FALSE + var/mob/living/carbon/human/L = M + L.equipOutfit(/datum/outfit/servant_of_ratvar) + var/obj/item/clockwork/slab/S = new + var/slot = "At your feet" + var/list/slots = list("In your left pocket" = SLOT_L_STORE, "In your right pocket" = SLOT_R_STORE, "In your backpack" = SLOT_IN_BACKPACK, "On your belt" = SLOT_BELT) + if(ishuman(L)) + var/mob/living/carbon/human/H = L + slot = H.equip_in_one_of_slots(S, slots) + if(slot == "In your backpack") + slot = "In your [H.back.name]" + if(slot == "At your feet") + if(!S.forceMove(get_turf(L))) + qdel(S) + if(S && !QDELETED(S)) + to_chat(L, "There is a paper in your backpack! It'll tell you if anything's changed, as well as what to expect.") + to_chat(L, "[slot] is a clockwork slab, a multipurpose tool used to construct machines and invoke ancient words of power. If this is your first time \ + as a servant, you can find a concise tutorial in the Recollection category of its interface.") + to_chat(L, "If you want more information, you can read the wiki page to learn more.") + return TRUE + return FALSE + +/datum/dynamic_ruleset/roundstart/clockcult/round_result() + if(GLOB.clockwork_gateway_activated) + SSticker.news_report = CLOCK_SUMMON + SSticker.mode_result = "win - servants completed their objective (summon ratvar)" + else + SSticker.news_report = CULT_FAILURE + SSticker.mode_result = "loss - servants failed their objective (summon ratvar)" + +////////////////////////////////////////////// +// // +// CLOWN OPS // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/roundstart/nuclear/clown_ops + name = "Clown Ops" + antag_datum = /datum/antagonist/nukeop/clownop + antag_leader_datum = /datum/antagonist/nukeop/leader/clownop + requirements = list(101,101,101,101,101,101,101,101,101,101) + high_population_requirement = 101 + +/datum/dynamic_ruleset/roundstart/nuclear/clown_ops/pre_execute() + . = ..() + if(.) + for(var/obj/machinery/nuclearbomb/syndicate/S in GLOB.nuke_list) + var/turf/T = get_turf(S) + if(T) + qdel(S) + new /obj/machinery/nuclearbomb/syndicate/bananium(T) + for(var/datum/mind/V in assigned) + V.assigned_role = "Clown Operative" + V.special_role = "Clown Operative" + +////////////////////////////////////////////// +// // +// DEVIL // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/roundstart/devil + name = "Devil" + antag_flag = ROLE_DEVIL + antag_datum = /datum/antagonist/devil + restricted_roles = list("Lawyer", "Curator", "Chaplain", "Head of Security", "Captain", "AI") + required_candidates = 1 + weight = 3 + cost = 0 + requirements = list(101,101,101,101,101,101,101,101,101,101) + high_population_requirement = 101 + var/devil_limit = 4 // Hard limit on devils if scaling is turned off + +/datum/dynamic_ruleset/roundstart/devil/pre_execute() + var/tsc = CONFIG_GET(number/traitor_scaling_coeff) + var/num_devils = 1 + + if(tsc) + num_devils = max(required_candidates, min(round(num_players() / (tsc * 3)) + 2, round(num_players() / (tsc * 1.5)))) + else + num_devils = max(required_candidates, min(num_players(), devil_limit)) + + for(var/j = 0, j < num_devils, j++) + if (!candidates.len) + break + var/mob/devil = pick(candidates) + assigned += devil + candidates -= devil + devil.mind.special_role = ROLE_DEVIL + devil.mind.restricted_roles = restricted_roles + + log_game("[key_name(devil)] has been selected as a devil") + return TRUE + +/datum/dynamic_ruleset/roundstart/devil/execute() + for(var/datum/mind/devil in assigned) + add_devil(devil.current, ascendable = TRUE) + add_devil_objectives(devil,2) + return TRUE + +/datum/dynamic_ruleset/roundstart/devil/proc/add_devil_objectives(datum/mind/devil_mind, quantity) + var/list/validtypes = list(/datum/objective/devil/soulquantity, /datum/objective/devil/soulquality, /datum/objective/devil/sintouch, /datum/objective/devil/buy_target) + var/datum/antagonist/devil/D = devil_mind.has_antag_datum(/datum/antagonist/devil) + for(var/i = 1 to quantity) + var/type = pick(validtypes) + var/datum/objective/devil/objective = new type(null) + objective.owner = devil_mind + D.objectives += objective + if(!istype(objective, /datum/objective/devil/buy_target)) + validtypes -= type + else + objective.find_target() + +////////////////////////////////////////////// +// // +// MONKEY // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/roundstart/monkey + name = "Monkey" + antag_flag = ROLE_MONKEY + antag_datum = /datum/antagonist/monkey/leader + restricted_roles = list("Cyborg", "AI") + required_candidates = 1 + weight = 3 + cost = 0 + requirements = list(101,101,101,101,101,101,101,101,101,101) + high_population_requirement = 101 + var/players_per_carrier = 30 + var/monkeys_to_win = 1 + var/escaped_monkeys = 0 + var/datum/team/monkey/monkey_team + +/datum/dynamic_ruleset/roundstart/monkey/pre_execute() + var/carriers_to_make = max(round(num_players()/players_per_carrier, 1), 1) + + for(var/j = 0, j < carriers_to_make, j++) + if (!candidates.len) + break + var/mob/carrier = pick(candidates) + candidates -= carrier + assigned += carrier.mind + carrier.mind.special_role = "Monkey Leader" + carrier.mind.restricted_roles = restricted_roles + log_game("[key_name(carrier)] has been selected as a Jungle Fever carrier") + return TRUE + +/datum/dynamic_ruleset/roundstart/monkey/execute() + for(var/datum/mind/carrier in assigned) + var/datum/antagonist/monkey/M = add_monkey_leader(carrier) + if(M) + monkey_team = M.monkey_team + return TRUE + +/datum/dynamic_ruleset/roundstart/monkey/proc/check_monkey_victory() + if(SSshuttle.emergency.mode != SHUTTLE_ENDGAME) + return FALSE + var/datum/disease/D = new /datum/disease/transformation/jungle_fever() + for(var/mob/living/carbon/monkey/M in GLOB.alive_mob_list) + if (M.HasDisease(D)) + if(M.onCentCom() || M.onSyndieBase()) + escaped_monkeys++ + if(escaped_monkeys >= monkeys_to_win) + return TRUE + else + return FALSE + +// This does not get called. Look into making it work. +/datum/dynamic_ruleset/roundstart/monkey/round_result() + if(check_monkey_victory()) + SSticker.mode_result = "win - monkey win" + else + SSticker.mode_result = "loss - staff stopped the monkeys" + +////////////////////////////////////////////// +// // +// METEOR // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/roundstart/meteor + name = "Meteor" + persistent = TRUE + required_candidates = 0 + weight = 3 + cost = 0 + requirements = list(101,101,101,101,101,101,101,101,101,101) + high_population_requirement = 101 + var/meteordelay = 2000 + var/nometeors = 0 + var/rampupdelta = 5 + +/datum/dynamic_ruleset/roundstart/meteor/rule_process() + if(nometeors || meteordelay > world.time - SSticker.round_start_time) + return + + var/list/wavetype = GLOB.meteors_normal + var/meteorminutes = (world.time - SSticker.round_start_time - meteordelay) / 10 / 60 + + if (prob(meteorminutes)) + wavetype = GLOB.meteors_threatening + + if (prob(meteorminutes/2)) + wavetype = GLOB.meteors_catastrophic + + var/ramp_up_final = CLAMP(round(meteorminutes/rampupdelta), 1, 10) + + spawn_meteors(ramp_up_final, wavetype) diff --git a/code/game/gamemodes/dynamic/readme.md b/code/game/gamemodes/dynamic/readme.md new file mode 100644 index 0000000000..6bd064cf7c --- /dev/null +++ b/code/game/gamemodes/dynamic/readme.md @@ -0,0 +1,57 @@ +# DYNAMIC + +## ROUNDSTART + +Dynamic rolls threat based on a special sauce formula: +"dynamic_curve_width \* tan((3.1416 \* (rand() - 0.5) \* 57.2957795)) + dynamic_curve_centre" + +Latejoin and midround injection cooldowns are set using exponential distribution between +5 minutes and 25 for latejoin +15 minutes and 35 for midround +this value is then added to world.time and assigned to the injection cooldown variables. + +rigged_roundstart() is called instead if there are forced rules (an admin set the mode) + +can_start() -> pre_setup() -> roundstart() OR rigged_roundstart() -> picking_roundstart_rule(drafted_rules) -> post_setup() + +## PROCESS + +Calls rule_process on every rule which is in the current_rules list. +Every sixty seconds, update_playercounts() +Midround injection time is checked against world.time to see if an injection should happen. +If midround injection time is lower than world.time, it updates playercounts again, then tries to inject and generates a new cooldown regardless of whether a rule is picked. + +## LATEJOIN + +make_antag_chance(newPlayer) -> [For each latespawn rule...] +-> acceptable(living players, threat_level) -> trim_candidates() -> ready(forced=FALSE) +**If true, add to drafted rules +**NOTE that acceptable uses threat_level not threat! +**NOTE Latejoin timer is ONLY reset if at least one rule was drafted. +**NOTE the new_player.dm AttemptLateSpawn() calls OnPostSetup for all roles (unless assigned role is MODE) +[After collecting all draftble rules...] +-> picking_latejoin_ruleset(drafted_rules) -> spend threat -> ruleset.execute() +## MIDROUND +process() -> [For each midround rule...] +-> acceptable(living players, threat_level) -> trim_candidates() -> ready(forced=FALSE) +[After collecting all draftble rules...] +-> picking_midround_ruleset(drafted_rules) -> spend threat -> ruleset.execute() +## FORCED +For latejoin, it simply sets forced_latejoin_rule +make_antag_chance(newPlayer) -> trim_candidates() -> ready(forced=TRUE) **NOTE no acceptable() call +For midround, calls the below proc with forced = TRUE +picking_specific_rule(ruletype,forced) -> forced OR acceptable(living_players, threat_level) -> trim_candidates() -> ready(forced) -> spend threat -> execute() +**NOTE specific rule can be called by RS traitor->MR autotraitor w/ forced=FALSE +**NOTE that due to short circuiting acceptable() need not be called if forced. +## RULESET +acceptable(population,threat) just checks if enough threat_level for population indice. +**NOTE that we currently only send threat_level as the second arg, not threat. +ready(forced) checks if enough candidates and calls the map's map_ruleset(dynamic_ruleset) at the parent level +trim_candidates() varies significantly according to the ruleset type +Roundstart: All candidates are new_player mobs. Check them for standard stuff: connected, desire role, not banned, etc. +**NOTE Roundstart deals with both candidates (trimmed list of valid players) and mode.candidates (everyone readied up). Don't confuse them! +Latejoin: Only one candidate, the latejoiner. Standard checks. +Midround: Instead of building a single list candidates, candidates contains four lists: living, dead, observing, and living antags. Standard checks in trim_list(list). +Midround - Rulesets have additional types +/from_ghosts: execute() -> send_applications() -> review_applications() -> finish_setup(mob/newcharacter, index) -> setup_role(role) +**NOTE: execute() here adds dead players and observers to candidates list diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index d16cbebb2a..f790053863 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -24,6 +24,7 @@ var/list/datum/mind/antag_candidates = list() // List of possible starting antags goes here var/list/restricted_jobs = list() // Jobs it doesn't make sense to be. I.E chaplain or AI cultist var/list/protected_jobs = list() // Jobs that can't be traitors because + var/list/required_jobs = list() // alternative required job groups eg list(list(cap=1),list(hos=1,sec=2)) translates to one captain OR one hos and two secmans var/required_players = 0 var/maximum_players = -1 // -1 is no maximum, positive numbers limit the selection of a mode on overstaffed stations var/required_enemies = 0 @@ -355,7 +356,7 @@ // Ultimate randomizing code right here for(var/mob/dead/new_player/player in GLOB.player_list) - if(player.client && player.ready == PLAYER_READY_TO_PLAY) + if(player.client && player.ready == PLAYER_READY_TO_PLAY && player.check_preferences()) players += player // Shuffling, the players list is now ping-independent!!! @@ -558,3 +559,7 @@ SSticker.news_report = STATION_EVACUATED if(SSshuttle.emergency.is_hijacked()) SSticker.news_report = SHUTTLE_HIJACK + +/// Mode specific admin panel. +/datum/game_mode/proc/admin_panel() + return diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm index 615d55a818..1767d468ec 100644 --- a/code/game/gamemodes/nuclear/nuclear.dm +++ b/code/game/gamemodes/nuclear/nuclear.dm @@ -155,9 +155,9 @@ var/obj/item/U = new uplink_type(H, H.key, tc) H.equip_to_slot_or_del(U, SLOT_IN_BACKPACK) - var/obj/item/implant/weapons_auth/W = new/obj/item/implant/weapons_auth(H) + var/obj/item/implant/weapons_auth/W = new W.implant(H) - var/obj/item/implant/explosive/E = new/obj/item/implant/explosive(H) + var/obj/item/implant/explosive/E = new E.implant(H) H.faction |= ROLE_SYNDICATE H.update_icons() diff --git a/code/game/gamemodes/overthrow/overthrow.dm b/code/game/gamemodes/overthrow/overthrow.dm index 1548556515..dca0c1ade1 100644 --- a/code/game/gamemodes/overthrow/overthrow.dm +++ b/code/game/gamemodes/overthrow/overthrow.dm @@ -3,7 +3,8 @@ name = "overthrow" config_tag = "overthrow" antag_flag = ROLE_OVERTHROW - restricted_jobs = list("Security Officer", "Warden", "Detective", "AI", "Cyborg","Captain", "Head of Personnel", "Head of Security", "Chief Engineer", "Research Director", "Chief Medical Officer") + restricted_jobs = list("AI", "Cyborg") + protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") required_players = 20 // the core idea is of a swift, bloodless coup, so it shouldn't be as chaotic as revs. required_enemies = 2 // minimum two teams, otherwise it's just nerfed revs. recommended_enemies = 4 diff --git a/code/game/gamemodes/revolution/revolution.dm b/code/game/gamemodes/revolution/revolution.dm index 09047b05a9..8459819b5b 100644 --- a/code/game/gamemodes/revolution/revolution.dm +++ b/code/game/gamemodes/revolution/revolution.dm @@ -12,7 +12,8 @@ config_tag = "revolution" antag_flag = ROLE_REV false_report_weight = 10 - restricted_jobs = list("Security Officer", "Warden", "Detective", "AI", "Cyborg","Captain", "Head of Personnel", "Head of Security", "Chief Engineer", "Research Director", "Chief Medical Officer") + restricted_jobs = list("AI", "Cyborg") + protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") required_players = 30 required_enemies = 2 recommended_enemies = 3 diff --git a/code/game/gamemodes/traitor/traitor.dm b/code/game/gamemodes/traitor/traitor.dm index 789737ec0f..4a6e72cf67 100644 --- a/code/game/gamemodes/traitor/traitor.dm +++ b/code/game/gamemodes/traitor/traitor.dm @@ -96,4 +96,4 @@ /datum/game_mode/traitor/generate_report() return "Although more specific threats are commonplace, you should always remain vigilant for Syndicate agents aboard your station. Syndicate communications have implied that many \ - Nanotrasen employees are Syndicate agents with hidden memories that may be activated at a moment's notice, so it's possible that these agents might not even know their positions." \ No newline at end of file + Nanotrasen employees are Syndicate agents with hidden memories that may be activated at a moment's notice, so it's possible that these agents might not even know their positions." diff --git a/code/game/machinery/Sleeper.dm b/code/game/machinery/Sleeper.dm index aa363428fb..513fea4360 100644 --- a/code/game/machinery/Sleeper.dm +++ b/code/game/machinery/Sleeper.dm @@ -88,17 +88,50 @@ return close_machine(target) -/obj/machinery/sleeper/attackby(obj/item/I, mob/user, params) - if(!state_open && !occupant) - if(default_deconstruction_screwdriver(user, "[initial(icon_state)]-o", initial(icon_state), I)) - return +/obj/machinery/sleeper/screwdriver_act(mob/living/user, obj/item/I) + . = TRUE + if(..()) + return + if(occupant) + to_chat(user, "[src] is currently occupied!") + return + if(state_open) + to_chat(user, "[src] must be closed to [panel_open ? "close" : "open"] its maintenance hatch!") + return + if(default_deconstruction_screwdriver(user, "[initial(icon_state)]-o", initial(icon_state), I)) + return + return FALSE + +/obj/machinery/sleeper/wrench_act(mob/living/user, obj/item/I) + . = ..() if(default_change_direction_wrench(user, I)) - return + return TRUE + +/obj/machinery/sleeper/crowbar_act(mob/living/user, obj/item/I) + . = ..() if(default_pry_open(I)) - return + return TRUE if(default_deconstruction_crowbar(I)) + return TRUE + +/obj/machinery/sleeper/default_pry_open(obj/item/I) //wew + . = !(state_open || panel_open || (flags_1 & NODECONSTRUCT_1)) && I.tool_behaviour == TOOL_CROWBAR + if(.) + I.play_tool_sound(src, 50) + visible_message("[usr] pries open [src].", "You pry open [src].") + open_machine() + +/obj/machinery/sleeper/AltClick(mob/user) + if(!user.canUseTopic(src, !issilicon(user))) return - return ..() + if(state_open) + close_machine() + else + open_machine() + +/obj/machinery/sleeper/examine(mob/user) + ..() + to_chat(user, "Alt-click [src] to [state_open ? "close" : "open"] it.") /obj/machinery/sleeper/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state) @@ -146,7 +179,7 @@ data["occupant"]["toxLoss"] = mob_occupant.getToxLoss() data["occupant"]["fireLoss"] = mob_occupant.getFireLoss() data["occupant"]["cloneLoss"] = mob_occupant.getCloneLoss() - data["occupant"]["brainLoss"] = mob_occupant.getBrainLoss() + data["occupant"]["brainLoss"] = mob_occupant.getOrganLoss(ORGAN_SLOT_BRAIN) data["occupant"]["reagents"] = list() if(mob_occupant.reagents && mob_occupant.reagents.reagent_list.len) for(var/datum/reagent/R in mob_occupant.reagents.reagent_list) @@ -190,11 +223,13 @@ if(inject_chem(chem, usr)) . = TRUE if(scrambled_chems && prob(5)) - to_chat(usr, "Chem System Re-route detected, results may not be as expected!") + to_chat(usr, "Chemical system re-route detected, results may not be as expected!") /obj/machinery/sleeper/emag_act(mob/user) + . = ..() scramble_chem_buttons() to_chat(user, "You scramble the sleeper's user interface!") + return TRUE /obj/machinery/sleeper/proc/inject_chem(chem, mob/user) if((chem in available_chems) && chem_allowed(chem)) diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm index b0e4c699d7..667c1f6054 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -113,6 +113,11 @@ Class Procs: var/atom/movable/occupant = null var/speed_process = FALSE // Process as fast as possible? var/obj/item/circuitboard/circuit // Circuit to be created and inserted when the machinery is created + var/obj/item/card/id/inserted_scan_id + var/obj/item/card/id/inserted_modify_id + var/list/region_access = null // For the identification console (card.dm) + var/list/head_subordinates = null // For the identification console (card.dm) + var/authenticated = 0 // For the identification console (card.dm) var/interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN | INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OPEN_SILICON | INTERACT_MACHINE_SET_MACHINE @@ -131,7 +136,7 @@ Class Procs: else START_PROCESSING(SSfastprocess, src) power_change() - AddComponent(/datum/component/redirect, list(COMSIG_ENTER_AREA = CALLBACK(src, .proc/power_change))) + RegisterSignal(src, COMSIG_ENTER_AREA, .proc/power_change) if (occupant_typecache) occupant_typecache = typecacheof(occupant_typecache) @@ -143,6 +148,10 @@ Class Procs: else STOP_PROCESSING(SSfastprocess, src) dropContents() + if(length(component_parts)) + for(var/atom/A in component_parts) + qdel(A) + component_parts.Cut() return ..() /obj/machinery/proc/locate_machinery() @@ -177,14 +186,18 @@ Class Procs: if(isliving(A)) var/mob/living/L = A L.update_canmove() + SEND_SIGNAL(src, COMSIG_MACHINE_EJECT_OCCUPANT, occupant) occupant = null +/obj/machinery/proc/can_be_occupant(atom/movable/am) + return occupant_typecache ? is_type_in_typecache(am, occupant_typecache) : isliving(am) + /obj/machinery/proc/close_machine(atom/movable/target = null) state_open = FALSE density = TRUE if(!target) for(var/am in loc) - if (!(occupant_typecache ? is_type_in_typecache(am, occupant_typecache) : isliving(am))) + if (!(can_be_occupant(am))) continue var/atom/movable/AM = am if(AM.has_buckled_mobs()) @@ -311,6 +324,7 @@ Class Procs: spawn_frame(disassembled) for(var/obj/item/I in component_parts) I.forceMove(loc) + component_parts.Cut() qdel(src) /obj/machinery/proc/spawn_frame(disassembled) @@ -348,8 +362,8 @@ Class Procs: panel_open = FALSE icon_state = icon_state_closed to_chat(user, "You close the maintenance hatch of [src].") - return 1 - return 0 + return TRUE + return FALSE /obj/machinery/proc/default_change_direction_wrench(mob/user, obj/item/I) if(panel_open && I.tool_behaviour == TOOL_WRENCH) @@ -401,7 +415,7 @@ Class Procs: var/obj/item/circuitboard/machine/CB = locate(/obj/item/circuitboard/machine) in component_parts var/P if(W.works_from_distance) - display_parts(user) + to_chat(user, display_parts(user)) for(var/obj/item/A in component_parts) for(var/D in CB.req_components) if(ispath(A.type, D)) @@ -429,34 +443,38 @@ Class Procs: break RefreshParts() else - display_parts(user) + to_chat(user, display_parts(user)) if(shouldplaysound) W.play_rped_sound() return TRUE return FALSE /obj/machinery/proc/display_parts(mob/user) - to_chat(user, "It contains the following parts:") + . = list() + . += "It contains the following parts:" for(var/obj/item/C in component_parts) - to_chat(user, "[icon2html(C, user)] \A [C].") + . += "[icon2html(C, user)] \A [C]." + . = jointext(., "") /obj/machinery/examine(mob/user) - ..() + . = ..() if(stat & BROKEN) - to_chat(user, "It looks broken and non-functional.") + . += "It looks broken and non-functional." if(!(resistance_flags & INDESTRUCTIBLE)) if(resistance_flags & ON_FIRE) - to_chat(user, "It's on fire!") + . += "It's on fire!" var/healthpercent = (obj_integrity/max_integrity) * 100 switch(healthpercent) if(50 to 99) - to_chat(user, "It looks slightly damaged.") + . += "It looks slightly damaged." if(25 to 50) - to_chat(user, "It appears heavily damaged.") + . += "It appears heavily damaged." if(0 to 25) - to_chat(user, "It's falling apart!") + . += "It's falling apart!" if(user.research_scanner && component_parts) - display_parts(user) + . += display_parts(user, TRUE) + if(inserted_scan_id || inserted_modify_id) + . += "Alt-click to eject the ID card." //called on machinery construction (i.e from frame to machinery) but not on initialization /obj/machinery/proc/on_construction() @@ -481,6 +499,7 @@ Class Procs: /obj/machinery/Exited(atom/movable/AM, atom/newloc) . = ..() if (AM == occupant) + SEND_SIGNAL(src, COMSIG_MACHINE_EJECT_OCCUPANT, occupant) occupant = null /obj/machinery/proc/adjust_item_drop_location(atom/movable/AM) // Adjust item drop location to a 3x3 grid inside the tile, returns slot id from 0 to 8 @@ -490,3 +509,73 @@ Class Procs: . = . % 9 AM.pixel_x = -8 + ((.%3)*8) AM.pixel_y = -8 + (round( . / 3)*8) + +/obj/machinery/proc/id_insert_scan(mob/user, obj/item/card/id/I) + I = user.get_active_held_item() + if(istype(I)) + if(inserted_scan_id) + to_chat(user, "There's already an ID card in the console!") + return + if(!user.transferItemToLoc(I, src)) + return + inserted_scan_id = I + user.visible_message("[user] inserts an ID card into the console.", \ + "You insert the ID card into the console.") + playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE) + updateUsrDialog() + +/obj/machinery/proc/id_eject_scan(mob/user) + if(!inserted_scan_id) + to_chat(user, "There's no ID card in the console!") + return + if(inserted_scan_id) + inserted_scan_id.forceMove(drop_location()) + if(!issilicon(user) && Adjacent(user)) + user.put_in_hands(inserted_scan_id) + inserted_scan_id = null + user.visible_message("[user] gets an ID card from the console.", \ + "You get the ID card from the console.") + playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE) + updateUsrDialog() + +/obj/machinery/proc/id_eject_modify(mob/user) + if(inserted_modify_id) + GLOB.data_core.manifest_modify(inserted_modify_id.registered_name, inserted_modify_id.assignment) + inserted_modify_id.update_label() + inserted_modify_id.forceMove(drop_location()) + if(!issilicon(user) && Adjacent(user)) + user.put_in_hands(inserted_modify_id) + user.visible_message("[user] gets an ID card from the console.", \ + "You get the ID card from the console.") + playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE) + inserted_modify_id = null + region_access = null + head_subordinates = null + updateUsrDialog() + +/obj/machinery/proc/id_insert_modify(mob/user) + var/obj/item/card/id/I = user.get_active_held_item() + if(istype(I)) + if(inserted_modify_id) + to_chat(user, "There's already an ID card in the console!") + return + if(!user.transferItemToLoc(I, src)) + return + inserted_modify_id = I + user.visible_message("[user] inserts an ID card into the console.", \ + "You insert the ID card into the console.") + playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE) + updateUsrDialog() + +/obj/machinery/AltClick(mob/user) + . = ..() + if(!user.canUseTopic(src, !issilicon(user)) || !is_operational()) + return + if(inserted_modify_id) + id_eject_modify(user) + authenticated = FALSE + return + if(inserted_scan_id) + id_eject_scan(user) + authenticated = FALSE + return diff --git a/code/game/machinery/announcement_system.dm b/code/game/machinery/announcement_system.dm index 884b818f32..56227cdd53 100644 --- a/code/game/machinery/announcement_system.dm +++ b/code/game/machinery/announcement_system.dm @@ -177,7 +177,9 @@ GLOBAL_LIST_EMPTY(announcement_systems) act_up() /obj/machinery/announcement_system/emag_act() + . = ..() if(obj_flags & EMAGGED) return obj_flags |= EMAGGED act_up() + return TRUE diff --git a/code/game/machinery/buttons.dm b/code/game/machinery/buttons.dm index 879be046c9..968cbe7254 100644 --- a/code/game/machinery/buttons.dm +++ b/code/game/machinery/buttons.dm @@ -101,12 +101,14 @@ return ..() /obj/machinery/button/emag_act(mob/user) + . = ..() if(obj_flags & EMAGGED) return req_access = list() req_one_access = list() playsound(src, "sparks", 100, 1) obj_flags |= EMAGGED + return TRUE /obj/machinery/button/attack_ai(mob/user) if(!panel_open) diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm index 4f04335852..89c5e56b71 100644 --- a/code/game/machinery/cloning.dm +++ b/code/game/machinery/cloning.dm @@ -175,11 +175,12 @@ //Get the clone body ready maim_clone(H) - ADD_TRAIT(H, TRAIT_STABLEHEART, "cloning") - ADD_TRAIT(H, TRAIT_EMOTEMUTE, "cloning") - ADD_TRAIT(H, TRAIT_MUTE, "cloning") - ADD_TRAIT(H, TRAIT_NOBREATH, "cloning") - ADD_TRAIT(H, TRAIT_NOCRITDAMAGE, "cloning") + ADD_TRAIT(H, TRAIT_STABLEHEART, CLONING_POD_TRAIT) + ADD_TRAIT(H, TRAIT_STABLELIVER, CLONING_POD_TRAIT) + ADD_TRAIT(H, TRAIT_EMOTEMUTE, CLONING_POD_TRAIT) + ADD_TRAIT(H, TRAIT_MUTE, CLONING_POD_TRAIT) + ADD_TRAIT(H, TRAIT_NOBREATH, CLONING_POD_TRAIT) + ADD_TRAIT(H, TRAIT_NOCRITDAMAGE, CLONING_POD_TRAIT) H.Unconscious(80) clonemind.transfer_to(H) @@ -241,13 +242,14 @@ var/obj/item/I = pick_n_take(unattached_flesh) if(isorgan(I)) var/obj/item/organ/O = I + O.organ_flags &= ~ORGAN_FROZEN O.Insert(mob_occupant) else if(isbodypart(I)) var/obj/item/bodypart/BP = I BP.attach_limb(mob_occupant) //Premature clones may have brain damage. - mob_occupant.adjustBrainLoss(-((speed_coeff / 2) * dmg_mult)) + mob_occupant.adjustOrganLoss(ORGAN_SLOT_BRAIN, -((speed_coeff / 2) * dmg_mult)) use_power(7500) //This might need tweaking. @@ -261,6 +263,7 @@ for(var/i in unattached_flesh) if(isorgan(i)) var/obj/item/organ/O = i + O.organ_flags &= ~ORGAN_FROZEN O.Insert(mob_occupant) else if(isbodypart(i)) var/obj/item/bodypart/BP = i @@ -320,10 +323,12 @@ return ..() /obj/machinery/clonepod/emag_act(mob/user) + . = ..() if(!occupant) return to_chat(user, "You corrupt the genetic compiler.") malfunction() + return TRUE //Put messages in the connected computer's temp var for display. /obj/machinery/clonepod/proc/connected_message(message) @@ -344,6 +349,9 @@ if(mess) //Clean that mess and dump those gibs! for(var/obj/fl in unattached_flesh) fl.forceMove(T) + if(istype(fl, /obj/item/organ)) + var/obj/item/organ/O = fl + O.organ_flags &= ~ORGAN_FROZEN unattached_flesh.Cut() mess = FALSE new /obj/effect/gibspawner/generic(get_turf(src)) @@ -354,11 +362,12 @@ if(!mob_occupant) return - REMOVE_TRAIT(mob_occupant, TRAIT_STABLEHEART, "cloning") - REMOVE_TRAIT(mob_occupant, TRAIT_EMOTEMUTE, "cloning") - REMOVE_TRAIT(mob_occupant, TRAIT_MUTE, "cloning") - REMOVE_TRAIT(mob_occupant, TRAIT_NOCRITDAMAGE, "cloning") - REMOVE_TRAIT(mob_occupant, TRAIT_NOBREATH, "cloning") + REMOVE_TRAIT(mob_occupant, TRAIT_STABLEHEART, CLONING_POD_TRAIT) + REMOVE_TRAIT(mob_occupant, TRAIT_STABLELIVER, CLONING_POD_TRAIT) + REMOVE_TRAIT(mob_occupant, TRAIT_EMOTEMUTE, CLONING_POD_TRAIT) + REMOVE_TRAIT(mob_occupant, TRAIT_MUTE, CLONING_POD_TRAIT) + REMOVE_TRAIT(mob_occupant, TRAIT_NOCRITDAMAGE, CLONING_POD_TRAIT) + REMOVE_TRAIT(mob_occupant, TRAIT_NOBREATH, CLONING_POD_TRAIT) if(grab_ghost_when == CLONER_MATURE_CLONE) mob_occupant.grab_ghost() @@ -440,7 +449,7 @@ unattached_flesh.Cut() H.setCloneLoss(CLONE_INITIAL_DAMAGE) //Yeah, clones start with very low health, not with random, because why would they start with random health - H.setBrainLoss(CLONE_INITIAL_DAMAGE) + //H.setOrganLoss(ORGAN_SLOT_BRAIN, CLONE_INITIAL_DAMAGE) // In addition to being cellularly damaged and having barely any // brain function, they also have no limbs or internal organs. @@ -456,8 +465,9 @@ for(var/o in H.internal_organs) var/obj/item/organ/organ = o - if(!istype(organ) || organ.vital) + if(!istype(organ) || (organ.organ_flags & ORGAN_VITAL)) continue + organ.organ_flags |= ORGAN_FROZEN organ.Remove(H, special=TRUE) organ.forceMove(src) unattached_flesh += organ diff --git a/code/game/machinery/computer/Operating.dm b/code/game/machinery/computer/Operating.dm index 73fdcd5e8b..c317cbba0d 100644 --- a/code/game/machinery/computer/Operating.dm +++ b/code/game/machinery/computer/Operating.dm @@ -44,7 +44,7 @@ table.computer = src break -/obj/machinery/computer/operating/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) +/obj/machinery/computer/operating/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.not_incapacitated_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) ui = new(user, src, ui_key, "operating_computer", name, 350, 470, master_ui, state) @@ -125,4 +125,4 @@ . = TRUE #undef MENU_OPERATION -#undef MENU_SURGERIES \ No newline at end of file +#undef MENU_SURGERIES diff --git a/code/game/machinery/computer/apc_control.dm b/code/game/machinery/computer/apc_control.dm index e51d623c2f..6d505c8f95 100644 --- a/code/game/machinery/computer/apc_control.dm +++ b/code/game/machinery/computer/apc_control.dm @@ -11,7 +11,6 @@ var/list/result_filters //For sorting the results var/checking_logs = 0 var/list/logs - var/authenticated = 0 var/auth_id = "\[NULL\]" /obj/machinery/computer/apc_control/Initialize() @@ -185,15 +184,19 @@ ui_interact(usr) //Refresh the UI after a filter changes /obj/machinery/computer/apc_control/emag_act(mob/user) + . = ..() if(!authenticated) to_chat(user, "You bypass [src]'s access requirements using your emag.") authenticated = TRUE log_activity("logged in") - else if(!(obj_flags & EMAGGED)) + else + if(obj_flags & EMAGGED) + return user.visible_message("You emag [src], disabling precise logging and allowing you to clear logs.") log_game("[key_name(user)] emagged [src] at [AREACOORD(src)], disabling operator tracking.") obj_flags |= EMAGGED - playsound(src, "sparks", 50, 1) + playsound(src, "sparks", 50, 1) + return TRUE /obj/machinery/computer/apc_control/proc/log_activity(log_text) var/op_string = operator && !(obj_flags & EMAGGED) ? operator : "\[NULL OPERATOR\]" diff --git a/code/game/machinery/computer/arcade.dm b/code/game/machinery/computer/arcade.dm index 8d0cfb95e8..4bce450359 100644 --- a/code/game/machinery/computer/arcade.dm +++ b/code/game/machinery/computer/arcade.dm @@ -45,8 +45,8 @@ /obj/item/gun/ballistic/automatic/toy/pistol/unrestricted = ARCADE_WEIGHT_TRICK, /obj/item/hot_potato/harmless/toy = ARCADE_WEIGHT_RARE, /obj/item/twohanded/dualsaber/toy = ARCADE_WEIGHT_RARE, - /obj/item/twohanded/hypereutactic/toy = ARCADE_WEIGHT_RARE, - /obj/item/twohanded/hypereutactic/toy/rainbow = ARCADE_WEIGHT_RARE, + /obj/item/twohanded/dualsaber/hypereutactic/toy = ARCADE_WEIGHT_RARE, + /obj/item/twohanded/dualsaber/hypereutactic/toy/rainbow = ARCADE_WEIGHT_RARE, /obj/item/storage/box/snappops = ARCADE_WEIGHT_TRICK, /obj/item/clothing/under/syndicate/tacticool = ARCADE_WEIGHT_TRICK, @@ -57,6 +57,7 @@ /obj/item/stack/tile/fakespace/loaded = ARCADE_WEIGHT_TRICK, /obj/item/stack/tile/fakepit/loaded = ARCADE_WEIGHT_TRICK, /obj/item/restraints/handcuffs/fake = ARCADE_WEIGHT_TRICK, + /obj/item/clothing/gloves/rapid/hug = ARCADE_WEIGHT_TRICK, /obj/item/grenade/chem_grenade/glitter/pink = ARCADE_WEIGHT_TRICK, /obj/item/grenade/chem_grenade/glitter/blue = ARCADE_WEIGHT_TRICK, diff --git a/code/game/machinery/computer/arcade/battle.dm b/code/game/machinery/computer/arcade/battle.dm index ded9cf95f6..b906b1afb5 100644 --- a/code/game/machinery/computer/arcade/battle.dm +++ b/code/game/machinery/computer/arcade/battle.dm @@ -186,6 +186,7 @@ /obj/machinery/computer/arcade/battle/emag_act(mob/user) + . = ..() if(obj_flags & EMAGGED) return to_chat(user, "A mesmerizing Rhumba beat starts playing from the arcade machine's speakers!") @@ -202,5 +203,5 @@ enemy_name = "Cuban Pete" name = "Outbomb Cuban Pete" - updateUsrDialog() + return TRUE \ No newline at end of file diff --git a/code/game/machinery/computer/arcade/minesweeper.dm b/code/game/machinery/computer/arcade/minesweeper.dm index e90e05966c..641ef1c9cd 100644 --- a/code/game/machinery/computer/arcade/minesweeper.dm +++ b/code/game/machinery/computer/arcade/minesweeper.dm @@ -284,6 +284,7 @@ return /obj/machinery/computer/arcade/minesweeper/emag_act(mob/user) + . = ..() if(CHECK_BITFIELD(obj_flags, EMAGGED)) return desc = "An arcade machine that generates grids. It's clunking and sparking everywhere, almost as if threatening to explode at any moment!" @@ -298,6 +299,7 @@ to_chat(user, "The machine buzzes and sparks... the game has been reset!") playsound(user, 'sound/machines/buzz-sigh.ogg', 100, 0, extrarange = 3, falloff = 10) //Loud buzz game_status = MINESWEEPER_GAME_MAIN_MENU + return TRUE /obj/machinery/computer/arcade/minesweeper/proc/custom_generation(mob/user) playsound(loc, 'sound/arcade/minesweeper_menuselect.ogg', 50, 0, extrarange = -3, falloff = 10) //Entered into the menu so ping sound diff --git a/code/game/machinery/computer/arcade/orion_trail.dm b/code/game/machinery/computer/arcade/orion_trail.dm index 12941dea35..023b1048ce 100644 --- a/code/game/machinery/computer/arcade/orion_trail.dm +++ b/code/game/machinery/computer/arcade/orion_trail.dm @@ -736,6 +736,7 @@ desc = "Learn how our ancestors got to Orion, and have fun in the process!" /obj/machinery/computer/arcade/orion_trail/emag_act(mob/user) + . = ..() if(obj_flags & EMAGGED) return to_chat(user, "You override the cheat code menu and skip to Cheat #[rand(1, 50)]: Realism Mode.") @@ -743,6 +744,7 @@ desc = "Learn how our ancestors got to Orion, and try not to die in the process!" newgame() obj_flags |= EMAGGED + return TRUE /mob/living/simple_animal/hostile/syndicate/ranged/smg/orion name = "spaceport security" diff --git a/code/game/machinery/computer/card.dm b/code/game/machinery/computer/card.dm index 09bf401e12..886851a6a8 100644 --- a/code/game/machinery/computer/card.dm +++ b/code/game/machinery/computer/card.dm @@ -13,11 +13,8 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0) circuit = /obj/item/circuitboard/computer/card var/obj/item/card/id/scan = null var/obj/item/card/id/modify = null - var/authenticated = 0 var/mode = 0 var/printing = null - var/list/region_access = null - var/list/head_subordinates = null var/target_dept = 0 //Which department this computer has access to. 0=all departments //Cooldown for closing positions in seconds @@ -377,7 +374,6 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0) else if((ACCESS_HOP in scan.access) && ((target_dept==1) || !target_dept)) region_access |= 1 - region_access |= 6 get_subordinates("Head of Personnel") if((ACCESS_HOS in scan.access) && ((target_dept==2) || !target_dept)) region_access |= 2 @@ -391,6 +387,9 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0) if((ACCESS_CE in scan.access) && ((target_dept==5) || !target_dept)) region_access |= 5 get_subordinates("Chief Engineer") + if((ACCESS_QM in scan.access) && ((target_dept==6) || !target_dept)) + region_access |= 6 + get_subordinates("Quartermaster") if(region_access) authenticated = 1 else if ((!( authenticated ) && issilicon(usr)) && (!modify)) @@ -610,7 +609,7 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0) typed_circuit.target_dept = target_dept else target_dept = typed_circuit.target_dept - var/list/dept_list = list("general","security","medical","science","engineering") + var/list/dept_list = list("civilian","security","medical","science","engineering","cargo") name = "[dept_list[target_dept]] department console" /obj/machinery/computer/card/minor/hos @@ -634,3 +633,9 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0) icon_screen = "idce" light_color = LIGHT_COLOR_YELLOW + +/obj/machinery/computer/card/minor/qm + target_dept = 6 + icon_screen = "idqm" + + light_color = LIGHT_COLOR_ORANGE \ No newline at end of file diff --git a/code/game/machinery/computer/cloning.dm b/code/game/machinery/computer/cloning.dm index bfa6b46134..5cbd2d8975 100644 --- a/code/game/machinery/computer/cloning.dm +++ b/code/game/machinery/computer/cloning.dm @@ -1,4 +1,4 @@ -#define AUTOCLONING_MINIMAL_LEVEL 3 +#define AUTOCLONING_MINIMAL_LEVEL 4 /obj/machinery/computer/cloning name = "cloning console" @@ -64,9 +64,6 @@ if(!(scanner && LAZYLEN(pods) && autoprocess)) return - if(scanner.occupant && scanner.scan_level > 2) - scan_occupant(scanner.occupant) - for(var/datum/data/record/R in records) var/obj/machinery/clonepod/pod = GetAvailableEfficientPod(R.fields["mind"]) @@ -162,11 +159,11 @@ if(scanner && HasEfficientPod() && scanner.scan_level >= AUTOCLONING_MINIMAL_LEVEL) if(!autoprocess) - dat += "Autoprocess" + dat += "Autoclone" else - dat += "Stop autoprocess" + dat += "Stop autoclone" else - dat += "Autoprocess" + dat += "Autoclone" dat += "

Cloning Pod Status

" dat += "
[temp] 
" @@ -231,7 +228,7 @@ dat += "

[src.active_record.fields["name"]]

" dat += "Scan ID [src.active_record.fields["id"]] Clone
" - var/obj/item/implant/health/H = locate(src.active_record.fields["imp"]) + var/obj/item/implant/health/H = locate(active_record.fields["imp"]) if ((H) && (istype(H))) dat += "Health Implant Data:
[H.sensehealth()]

" diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index 752765baa1..557f2f0636 100755 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -6,7 +6,6 @@ icon_keyboard = "tech_key" req_access = list(ACCESS_HEADS) circuit = /obj/item/circuitboard/computer/communications - var/authenticated = 0 var/auth_id = "Unknown" //Who is currently logged in? var/list/datum/comm_message/messages = list() var/datum/comm_message/currmsg @@ -432,6 +431,7 @@ return ..() /obj/machinery/computer/communications/emag_act(mob/user) + . = ..() if(obj_flags & EMAGGED) return obj_flags |= EMAGGED @@ -440,6 +440,7 @@ authenticated = 2 to_chat(user, "You scramble the communication routing circuits!") playsound(src, 'sound/machines/terminal_alert.ogg', 50, 0) + return TRUE /obj/machinery/computer/communications/ui_interact(mob/user) . = ..() diff --git a/code/game/machinery/computer/medical.dm b/code/game/machinery/computer/medical.dm index 8af83ae08e..c912586ea3 100644 --- a/code/game/machinery/computer/medical.dm +++ b/code/game/machinery/computer/medical.dm @@ -7,13 +7,10 @@ icon_keyboard = "med_key" req_one_access = list(ACCESS_MEDICAL, ACCESS_FORENSICS_LOCKERS) circuit = /obj/item/circuitboard/computer/med_data - var/obj/item/card/id/scan = null - var/authenticated = null var/rank = null var/screen = null var/datum/data/record/active1 var/datum/data/record/active2 - var/a_id = null var/temp = null var/printing = null //Sorting Variables @@ -25,24 +22,22 @@ /obj/machinery/computer/med_data/syndie icon_keyboard = "syndie_key" -/obj/machinery/computer/med_data/attackby(obj/item/O, mob/user, params) - if(istype(O, /obj/item/card/id) && !scan) - if(!user.transferItemToLoc(O, src)) - return - scan = O - to_chat(user, "You insert [O].") +/obj/machinery/computer/med_data/attackby(obj/item/I, mob/user, params) + if(istype(I, /obj/item/card/id)) + id_insert_scan(user) else return ..() /obj/machinery/computer/med_data/ui_interact(mob/user) . = ..() + if(isliving(user)) + playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) var/dat if(temp) dat = text("[temp]

Clear Screen") else - dat = text("Confirm Identity: []
", (src.scan ? text("[]", src.scan.name) : "----------")) - if(src.authenticated) - switch(src.screen) + if(authenticated) + switch(screen) if(1) dat += {" Search Records @@ -116,7 +111,7 @@ dat += "" dat += "" dat += "ID:[active1.fields["id"]]" - dat += "Sex: [active1.fields["sex"]] " + dat += "Gender: [active1.fields["gender"]] " dat += "Age: [active1.fields["age"]] " dat += "Species: [active1.fields["species"]] " dat += "Fingerprint: [active1.fields["fingerprint"]] " @@ -141,7 +136,7 @@ dat += "
Comments/Log" var/counter = 1 - while(src.active2.fields[text("com_[]", counter)]) + while(active2.fields[text("com_[]", counter)]) dat += "[active2.fields[text("com_[]", counter)]]Delete Entry" counter++ dat += "Add Entry" @@ -169,7 +164,7 @@ dat += "
Medical Robots:" var/bdat = null for(var/mob/living/simple_animal/bot/medbot/M in GLOB.alive_mob_list) - if(M.z != src.z) + if(M.z != z) continue //only find medibots on the same z-level as the computer var/turf/bl = get_turf(M) if(bl) //if it can't find a turf for the medibot, then it probably shouldn't be showing up @@ -189,7 +184,7 @@ dat += "{Log In}" var/datum/browser/popup = new(user, "med_rec", "Medical Records Console", 600, 400) popup.set_content(dat) - popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) + popup.set_title_image(user.browse_rsc_icon(icon, icon_state)) popup.open() /obj/machinery/computer/med_data/Topic(href, href_list) @@ -197,29 +192,20 @@ if(.) return . if(!(active1 in GLOB.data_core.general)) - src.active1 = null + active1 = null if(!(active2 in GLOB.data_core.medical)) - src.active2 = null + active2 = null if(usr.contents.Find(src) || (in_range(src, usr) && isturf(loc)) || issilicon(usr) || IsAdminGhost(usr)) usr.set_machine(src) if(href_list["temp"]) - src.temp = null - if(href_list["scan"]) - if(src.scan) - usr.put_in_hands(scan) - scan = null - else - var/obj/item/I = usr.is_holding_item_of_type(/obj/item/card/id) - if(I) - if(!usr.transferItemToLoc(I, src)) - return - src.scan = I + temp = null else if(href_list["logout"]) - src.authenticated = null - src.screen = null - src.active1 = null - src.active2 = null + authenticated = null + screen = null + active1 = null + active2 = null + playsound(src, 'sound/machines/terminal_off.ogg', 50, FALSE) else if(href_list["choice"]) // SORTING! if(href_list["choice"] == "Sorting") @@ -234,34 +220,37 @@ sortBy = href_list["sort"] order = initial(order) else if(href_list["login"]) - if(issilicon(usr)) - src.active1 = null - src.active2 = null - src.authenticated = 1 - src.rank = "AI" - src.screen = 1 - else if(IsAdminGhost(usr)) - src.active1 = null - src.active2 = null - src.authenticated = 1 - src.rank = "Central Command" - src.screen = 1 - else if(istype(src.scan, /obj/item/card/id)) - src.active1 = null - src.active2 = null - if(src.check_access(src.scan)) - src.authenticated = src.scan.registered_name - src.rank = src.scan.assignment - src.screen = 1 - if(src.authenticated) - + var/mob/M = usr + var/obj/item/card/id/I = M.get_idcard(TRUE) + if(issilicon(M)) + active1 = null + active2 = null + authenticated = 1 + rank = "AI" + screen = 1 + else if(IsAdminGhost(M)) + active1 = null + active2 = null + authenticated = 1 + rank = "Central Command" + screen = 1 + else if(istype(I) && check_access(I)) + active1 = null + active2 = null + authenticated = I.registered_name + rank = I.assignment + screen = 1 + else + to_chat(usr, "Unauthorized access.") + playsound(src, 'sound/machines/terminal_on.ogg', 50, FALSE) + if(authenticated) if(href_list["screen"]) - src.screen = text2num(href_list["screen"]) - if(src.screen < 1) - src.screen = 1 + screen = text2num(href_list["screen"]) + if(screen < 1) + screen = 1 - src.active1 = null - src.active2 = null + active1 = null + active2 = null else if(href_list["vir"]) var/type = href_list["vir"] @@ -269,7 +258,7 @@ var/AfS = "" for(var/mob/M in Dis.viable_mobtypes) AfS += " [initial(M.name)];" - src.temp = {"Name: [Dis.name] + temp = {"Name: [Dis.name]
Number of stages: [Dis.max_stages]
Spread: [Dis.spread_text] Transmission
Possible Cure: [(Dis.cure_text||"none")] @@ -280,110 +269,112 @@
Severity: [Dis.severity]"} else if(href_list["del_all"]) - src.temp = "Are you sure you wish to delete all records?
\n\tYes
\n\tNo
" + temp = "Are you sure you wish to delete all records?
\n\tYes
\n\tNo
" else if(href_list["del_all2"]) investigate_log("[key_name(usr)] has deleted all medical records.", INVESTIGATE_RECORDS) GLOB.data_core.medical.Cut() - src.temp = "All records deleted." + temp = "All records deleted." else if(href_list["field"]) - var/a1 = src.active1 - var/a2 = src.active2 + var/a1 = active1 + var/a2 = active2 switch(href_list["field"]) if("fingerprint") if(active1) - var/t1 = stripped_input("Please input fingerprint hash:", "Med. records", src.active1.fields["fingerprint"], null) + var/t1 = stripped_input("Please input fingerprint hash:", "Med. records", active1.fields["fingerprint"], null) if(!canUseMedicalRecordsConsole(usr, t1, a1)) return - src.active1.fields["fingerprint"] = t1 - if("sex") + active1.fields["fingerprint"] = t1 + if("gender") if(active1) - if(src.active1.fields["sex"] == "Male") - src.active1.fields["sex"] = "Female" + if(active1.fields["gender"] == "Male") + active1.fields["gender"] = "Female" + else if(active1.fields["gender"] == "Female") + active1.fields["gender"] = "Other" else - src.active1.fields["sex"] = "Male" + active1.fields["gender"] = "Male" if("age") if(active1) - var/t1 = input("Please input age:", "Med. records", src.active1.fields["age"], null) as num + var/t1 = input("Please input age:", "Med. records", active1.fields["age"], null) as num if(!canUseMedicalRecordsConsole(usr, t1, a1)) return - src.active1.fields["age"] = t1 + active1.fields["age"] = t1 if("species") if(active1) - var/t1 = stripped_input("Please input species name", "Med. records", src.active1.fields["species"], null) + var/t1 = stripped_input("Please input species name", "Med. records", active1.fields["species"], null) if(!canUseMedicalRecordsConsole(usr, t1, a1)) return active1.fields["species"] = t1 if("mi_dis") if(active2) - var/t1 = stripped_input("Please input minor disabilities list:", "Med. records", src.active2.fields["mi_dis"], null) + var/t1 = stripped_input("Please input minor disabilities list:", "Med. records", active2.fields["mi_dis"], null) if(!canUseMedicalRecordsConsole(usr, t1, null, a2)) return - src.active2.fields["mi_dis"] = t1 + active2.fields["mi_dis"] = t1 if("mi_dis_d") if(active2) - var/t1 = stripped_input("Please summarize minor dis.:", "Med. records", src.active2.fields["mi_dis_d"], null) + var/t1 = stripped_input("Please summarize minor dis.:", "Med. records", active2.fields["mi_dis_d"], null) if(!canUseMedicalRecordsConsole(usr, t1, null, a2)) return - src.active2.fields["mi_dis_d"] = t1 + active2.fields["mi_dis_d"] = t1 if("ma_dis") if(active2) - var/t1 = stripped_input("Please input major disabilities list:", "Med. records", src.active2.fields["ma_dis"], null) + var/t1 = stripped_input("Please input major disabilities list:", "Med. records", active2.fields["ma_dis"], null) if(!canUseMedicalRecordsConsole(usr, t1, null, a2)) return - src.active2.fields["ma_dis"] = t1 + active2.fields["ma_dis"] = t1 if("ma_dis_d") if(active2) - var/t1 = stripped_input("Please summarize major dis.:", "Med. records", src.active2.fields["ma_dis_d"], null) + var/t1 = stripped_input("Please summarize major dis.:", "Med. records", active2.fields["ma_dis_d"], null) if(!canUseMedicalRecordsConsole(usr, t1, null, a2)) return - src.active2.fields["ma_dis_d"] = t1 + active2.fields["ma_dis_d"] = t1 if("alg") if(active2) - var/t1 = stripped_input("Please state allergies:", "Med. records", src.active2.fields["alg"], null) + var/t1 = stripped_input("Please state allergies:", "Med. records", active2.fields["alg"], null) if(!canUseMedicalRecordsConsole(usr, t1, null, a2)) return - src.active2.fields["alg"] = t1 + active2.fields["alg"] = t1 if("alg_d") if(active2) - var/t1 = stripped_input("Please summarize allergies:", "Med. records", src.active2.fields["alg_d"], null) + var/t1 = stripped_input("Please summarize allergies:", "Med. records", active2.fields["alg_d"], null) if(!canUseMedicalRecordsConsole(usr, t1, null, a2)) return - src.active2.fields["alg_d"] = t1 + active2.fields["alg_d"] = t1 if("cdi") if(active2) - var/t1 = stripped_input("Please state diseases:", "Med. records", src.active2.fields["cdi"], null) + var/t1 = stripped_input("Please state diseases:", "Med. records", active2.fields["cdi"], null) if(!canUseMedicalRecordsConsole(usr, t1, null, a2)) return - src.active2.fields["cdi"] = t1 + active2.fields["cdi"] = t1 if("cdi_d") if(active2) - var/t1 = stripped_input("Please summarize diseases:", "Med. records", src.active2.fields["cdi_d"], null) + var/t1 = stripped_input("Please summarize diseases:", "Med. records", active2.fields["cdi_d"], null) if(!canUseMedicalRecordsConsole(usr, t1, null, a2)) return - src.active2.fields["cdi_d"] = t1 + active2.fields["cdi_d"] = t1 if("notes") if(active2) - var/t1 = stripped_input("Please summarize notes:", "Med. records", src.active2.fields["notes"], null) + var/t1 = stripped_input("Please summarize notes:", "Med. records", active2.fields["notes"], null) if(!canUseMedicalRecordsConsole(usr, t1, null, a2)) return - src.active2.fields["notes"] = t1 + active2.fields["notes"] = t1 if("p_stat") if(active1) - src.temp = "Physical Condition:
\n\t*Deceased*
\n\t*Unconscious*
\n\tActive
\n\tPhysically Unfit
" + temp = "Physical Condition:
\n\t*Deceased*
\n\t*Unconscious*
\n\tActive
\n\tPhysically Unfit
" if("m_stat") if(active1) - src.temp = "Mental Condition:
\n\t*Insane*
\n\t*Unstable*
\n\t*Watch*
\n\tStable
" + temp = "Mental Condition:
\n\t*Insane*
\n\t*Unstable*
\n\t*Watch*
\n\tStable
" if("blood_type") if(active2) - src.temp = "Blood Type:
\n\tA- A+
\n\tB- B+
\n\tAB- AB+
\n\tO- O+
" + temp = "Blood Type:
\n\tA- A+
\n\tB- B+
\n\tAB- AB+
\n\tO- O+
" if("b_dna") if(active2) - var/t1 = stripped_input("Please input DNA hash:", "Med. records", src.active2.fields["b_dna"], null) + var/t1 = stripped_input("Please input DNA hash:", "Med. records", active2.fields["b_dna"], null) if(!canUseMedicalRecordsConsole(usr, t1, null, a2)) return - src.active2.fields["b_dna"] = t1 + active2.fields["b_dna"] = t1 if("show_photo_front") if(active1) if(active1.fields["photo_front"]) @@ -402,51 +393,51 @@ if(active1) switch(href_list["p_stat"]) if("deceased") - src.active1.fields["p_stat"] = "*Deceased*" + active1.fields["p_stat"] = "*Deceased*" if("unconscious") - src.active1.fields["p_stat"] = "*Unconscious*" + active1.fields["p_stat"] = "*Unconscious*" if("active") - src.active1.fields["p_stat"] = "Active" + active1.fields["p_stat"] = "Active" if("unfit") - src.active1.fields["p_stat"] = "Physically Unfit" + active1.fields["p_stat"] = "Physically Unfit" else if(href_list["m_stat"]) if(active1) switch(href_list["m_stat"]) if("insane") - src.active1.fields["m_stat"] = "*Insane*" + active1.fields["m_stat"] = "*Insane*" if("unstable") - src.active1.fields["m_stat"] = "*Unstable*" + active1.fields["m_stat"] = "*Unstable*" if("watch") - src.active1.fields["m_stat"] = "*Watch*" + active1.fields["m_stat"] = "*Watch*" if("stable") - src.active1.fields["m_stat"] = "Stable" + active1.fields["m_stat"] = "Stable" else if(href_list["blood_type"]) if(active2) switch(href_list["blood_type"]) if("an") - src.active2.fields["blood_type"] = "A-" + active2.fields["blood_type"] = "A-" if("bn") - src.active2.fields["blood_type"] = "B-" + active2.fields["blood_type"] = "B-" if("abn") - src.active2.fields["blood_type"] = "AB-" + active2.fields["blood_type"] = "AB-" if("on") - src.active2.fields["blood_type"] = "O-" + active2.fields["blood_type"] = "O-" if("ap") - src.active2.fields["blood_type"] = "A+" + active2.fields["blood_type"] = "A+" if("bp") - src.active2.fields["blood_type"] = "B+" + active2.fields["blood_type"] = "B+" if("abp") - src.active2.fields["blood_type"] = "AB+" + active2.fields["blood_type"] = "AB+" if("op") - src.active2.fields["blood_type"] = "O+" + active2.fields["blood_type"] = "O+" else if(href_list["del_r"]) if(active2) - src.temp = "Are you sure you wish to delete the record (Medical Portion Only)?
\n\tYes
\n\tNo
" + temp = "Are you sure you wish to delete the record (Medical Portion Only)?
\n\tYes
\n\tNo
" else if(href_list["del_r2"]) investigate_log("[key_name(usr)] has deleted the medical records for [active1.fields["name"]].", INVESTIGATE_RECORDS) @@ -463,10 +454,10 @@ screen = 4 else if(href_list["new"]) - if((istype(src.active1, /datum/data/record) && !( istype(src.active2, /datum/data/record) ))) + if((istype(active1, /datum/data/record) && !( istype(active2, /datum/data/record) ))) var/datum/data/record/R = new /datum/data/record( ) - R.fields["name"] = src.active1.fields["name"] - R.fields["id"] = src.active1.fields["id"] + R.fields["name"] = active1.fields["name"] + R.fields["id"] = active1.fields["id"] R.name = text("Medical Record #[]", R.fields["id"]) R.fields["blood_type"] = "Unknown" R.fields["b_dna"] = "Unknown" @@ -480,76 +471,77 @@ R.fields["cdi_d"] = "No diseases have been diagnosed at the moment." R.fields["notes"] = "No notes." GLOB.data_core.medical += R - src.active2 = R - src.screen = 4 + active2 = R + screen = 4 else if(href_list["add_c"]) if(!(active2 in GLOB.data_core.medical)) return - var/a2 = src.active2 + var/a2 = active2 var/t1 = stripped_multiline_input("Add Comment:", "Med. records", null, null) if(!canUseMedicalRecordsConsole(usr, t1, null, a2)) return var/counter = 1 - while(src.active2.fields[text("com_[]", counter)]) + while(active2.fields[text("com_[]", counter)]) counter++ - src.active2.fields[text("com_[]", counter)] = text("Made by [] ([]) on [] [], []
[]", src.authenticated, src.rank, STATION_TIME_TIMESTAMP("hh:mm:ss"), time2text(world.realtime, "MMM DD"), GLOB.year_integer+540, t1) + active2.fields[text("com_[]", counter)] = text("Made by [] ([]) on [] [], []
[]", authenticated, rank, STATION_TIME_TIMESTAMP("hh:mm:ss"), time2text(world.realtime, "MMM DD"), GLOB.year_integer+540, t1) else if(href_list["del_c"]) - if((istype(src.active2, /datum/data/record) && src.active2.fields[text("com_[]", href_list["del_c"])])) - src.active2.fields[text("com_[]", href_list["del_c"])] = "Deleted" + if((istype(active2, /datum/data/record) && active2.fields[text("com_[]", href_list["del_c"])])) + active2.fields[text("com_[]", href_list["del_c"])] = "Deleted" else if(href_list["search"]) var/t1 = stripped_input(usr, "Search String: (Name, DNA, or ID)", "Med. records") if(!canUseMedicalRecordsConsole(usr, t1)) return - src.active1 = null - src.active2 = null + active1 = null + active2 = null t1 = lowertext(t1) for(var/datum/data/record/R in GLOB.data_core.medical) if((lowertext(R.fields["name"]) == t1 || t1 == lowertext(R.fields["id"]) || t1 == lowertext(R.fields["b_dna"]))) - src.active2 = R + active2 = R else //Foreach continue //goto(3229) - if(!( src.active2 )) - src.temp = text("Could not locate record [].", sanitize(t1)) + if(!( active2 )) + temp = text("Could not locate record [].", sanitize(t1)) else for(var/datum/data/record/E in GLOB.data_core.general) - if((E.fields["name"] == src.active2.fields["name"] || E.fields["id"] == src.active2.fields["id"])) - src.active1 = E + if((E.fields["name"] == active2.fields["name"] || E.fields["id"] == active2.fields["id"])) + active1 = E else //Foreach continue //goto(3334) - src.screen = 4 + screen = 4 else if(href_list["print_p"]) - if(!( src.printing )) - src.printing = 1 + if(!( printing )) + printing = 1 GLOB.data_core.medicalPrintCount++ playsound(loc, 'sound/items/poster_being_created.ogg', 100, 1) sleep(30) - var/obj/item/paper/P = new /obj/item/paper( src.loc ) + var/obj/item/paper/P = new /obj/item/paper( loc ) P.info = "
Medical Record - (MR-[GLOB.data_core.medicalPrintCount])

" if(active1 in GLOB.data_core.general) - P.info += text("Name: [] ID: []
\nSex: []
\nAge: []
", src.active1.fields["name"], src.active1.fields["id"], src.active1.fields["sex"], src.active1.fields["age"]) + P.info += text("Name: [] ID: []
\nGender: []
\nAge: []
", active1.fields["name"], active1.fields["id"], active1.fields["gender"], active1.fields["age"]) P.info += "\nSpecies: [active1.fields["species"]]
" - P.info += text("\nFingerprint: []
\nPhysical Status: []
\nMental Status: []
", src.active1.fields["fingerprint"], src.active1.fields["p_stat"], src.active1.fields["m_stat"]) + P.info += text("\nFingerprint: []
\nPhysical Status: []
\nMental Status: []
", active1.fields["fingerprint"], active1.fields["p_stat"], active1.fields["m_stat"]) else P.info += "General Record Lost!
" if(active2 in GLOB.data_core.medical) - P.info += text("
\n
Medical Data

\nBlood Type: []
\nDNA: []
\n
\nMinor Disabilities: []
\nDetails: []
\n
\nMajor Disabilities: []
\nDetails: []
\n
\nAllergies: []
\nDetails: []
\n
\nCurrent Diseases: [] (per disease info placed in log/comment section)
\nDetails: []
\n
\nImportant Notes:
\n\t[]
\n
\n
Comments/Log

", src.active2.fields["blood_type"], src.active2.fields["b_dna"], src.active2.fields["mi_dis"], src.active2.fields["mi_dis_d"], src.active2.fields["ma_dis"], src.active2.fields["ma_dis_d"], src.active2.fields["alg"], src.active2.fields["alg_d"], src.active2.fields["cdi"], src.active2.fields["cdi_d"], src.active2.fields["notes"]) + P.info += text("
\n
Medical Data

\nBlood Type: []
\nDNA: []
\n
\nMinor Disabilities: []
\nDetails: []
\n
\nMajor Disabilities: []
\nDetails: []
\n
\nAllergies: []
\nDetails: []
\n
\nCurrent Diseases: [] (per disease info placed in log/comment section)
\nDetails: []
\n
\nImportant Notes:
\n\t[]
\n
\n
Comments/Log

", active2.fields["blood_type"], active2.fields["b_dna"], active2.fields["mi_dis"], active2.fields["mi_dis_d"], active2.fields["ma_dis"], active2.fields["ma_dis_d"], active2.fields["alg"], active2.fields["alg_d"], active2.fields["cdi"], active2.fields["cdi_d"], active2.fields["notes"]) var/counter = 1 - while(src.active2.fields[text("com_[]", counter)]) - P.info += text("[]
", src.active2.fields[text("com_[]", counter)]) + while(active2.fields[text("com_[]", counter)]) + P.info += text("[]
", active2.fields[text("com_[]", counter)]) counter++ - P.name = text("MR-[] '[]'", GLOB.data_core.medicalPrintCount, src.active1.fields["name"]) + P.name = text("MR-[] '[]'", GLOB.data_core.medicalPrintCount, active1.fields["name"]) else P.info += "Medical Record Lost!
" P.name = text("MR-[] '[]'", GLOB.data_core.medicalPrintCount, "Record Lost") P.info += "" - src.printing = null + P.update_icon() + printing = null - src.add_fingerprint(usr) - src.updateUsrDialog() + add_fingerprint(usr) + updateUsrDialog() return /obj/machinery/computer/med_data/emp_act(severity) @@ -560,11 +552,11 @@ switch(rand(1,6)) if(1) if(prob(10)) - R.fields["name"] = random_unique_lizard_name(R.fields["sex"],1) + R.fields["name"] = random_unique_lizard_name(R.fields["gender"],1) else - R.fields["name"] = random_unique_name(R.fields["sex"],1) + R.fields["name"] = random_unique_name(R.fields["gender"],1) if(2) - R.fields["sex"] = pick("Male", "Female") + R.fields["gender"] = pick("Male", "Female", "Other") if(3) R.fields["age"] = rand(AGE_MIN, AGE_MAX) if(4) @@ -583,7 +575,7 @@ if(user) if(message) if(authenticated) - if(user.canUseTopic(src)) + if(user.canUseTopic(src, !issilicon(user))) if(!record1 || record1 == active1) if(!record2 || record2 == active2) return 1 diff --git a/code/game/machinery/computer/prisoner/_prisoner.dm b/code/game/machinery/computer/prisoner/_prisoner.dm new file mode 100644 index 0000000000..d07c351a22 --- /dev/null +++ b/code/game/machinery/computer/prisoner/_prisoner.dm @@ -0,0 +1,52 @@ +/obj/machinery/computer/prisoner + var/obj/item/card/id/prisoner/contained_id + +/obj/machinery/computer/prisoner/Destroy() + if(contained_id) + contained_id.forceMove(get_turf(src)) + return ..() + + +/obj/machinery/computer/prisoner/examine(mob/user) + . = ..() + if(contained_id) + . += "Alt-click to eject the ID card." + + + +/obj/machinery/computer/prisoner/AltClick(mob/user) + id_eject(user) + return ..() + +/obj/machinery/computer/prisoner/proc/id_insert(mob/user, obj/item/card/id/prisoner/P) + if(istype(P)) + if(contained_id) + to_chat(user, "There's already an ID card in the console!") + return + if(!user.transferItemToLoc(P, src)) + return + contained_id = P + user.visible_message("[user] inserts an ID card into the console.", \ + "You insert the ID card into the console.") + playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE) + updateUsrDialog() + +/obj/machinery/computer/prisoner/proc/id_eject(mob/user) + if(!contained_id) + to_chat(user, "There's no ID card in the console!") + return + else + contained_id.forceMove(drop_location()) + if(!issilicon(user) && Adjacent(user)) + user.put_in_hands(contained_id) + contained_id = null + user.visible_message("[user] gets an ID card from the console.", \ + "You get the ID card from the console.") + playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE) + updateUsrDialog() + +/obj/machinery/computer/prisoner/attackby(obj/item/I, mob/user) + if(istype(I, /obj/item/card/id/prisoner)) + id_insert(user, I) + else + return ..() diff --git a/code/game/machinery/computer/prisoner/gulag_teleporter.dm b/code/game/machinery/computer/prisoner/gulag_teleporter.dm new file mode 100644 index 0000000000..f6e164efe9 --- /dev/null +++ b/code/game/machinery/computer/prisoner/gulag_teleporter.dm @@ -0,0 +1,142 @@ +//computer that handle the points and teleports the prisoner +/obj/machinery/computer/prisoner/gulag_teleporter_computer + name = "labor camp teleporter console" + desc = "Used to send criminals to the Labor Camp." + icon_screen = "explosive" + icon_keyboard = "security_key" + req_access = list(ACCESS_ARMORY) + circuit = /obj/item/circuitboard/computer/gulag_teleporter_console + var/default_goal = 200 + var/obj/machinery/gulag_teleporter/teleporter = null + var/obj/structure/gulag_beacon/beacon = null + var/mob/living/carbon/human/prisoner = null + var/datum/data/record/temporary_record = null + + light_color = LIGHT_COLOR_RED + +/obj/machinery/computer/prisoner/gulag_teleporter_computer/Initialize() + . = ..() + scan_machinery() + +/obj/machinery/computer/prisoner/gulag_teleporter_computer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ + datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "gulag_console", name, 455, 440, master_ui, state) + ui.open() + +/obj/machinery/computer/prisoner/gulag_teleporter_computer/ui_data(mob/user) + var/list/data = list() + + var/list/prisoner_list = list() + var/can_teleport = FALSE + + if(teleporter && (teleporter.occupant && ishuman(teleporter.occupant))) + prisoner = teleporter.occupant + prisoner_list["name"] = prisoner.real_name + if(contained_id) + can_teleport = TRUE + if(!isnull(GLOB.data_core.general)) + for(var/r in GLOB.data_core.security) + var/datum/data/record/R = r + if(R.fields["name"] == prisoner_list["name"]) + temporary_record = R + prisoner_list["crimstat"] = temporary_record.fields["criminal"] + + data["prisoner"] = prisoner_list + + if(teleporter) + data["teleporter"] = teleporter + data["teleporter_location"] = "([teleporter.x], [teleporter.y], [teleporter.z])" + data["teleporter_lock"] = teleporter.locked + data["teleporter_state_open"] = teleporter.state_open + if(beacon) + data["beacon"] = beacon + data["beacon_location"] = "([beacon.x], [beacon.y], [beacon.z])" + if(contained_id) + data["id"] = contained_id + data["id_name"] = contained_id.registered_name + data["goal"] = contained_id.goal + data["can_teleport"] = can_teleport + + return data + +/obj/machinery/computer/prisoner/gulag_teleporter_computer/ui_act(action, list/params) + if(isliving(usr)) + playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) + if(..()) + return + if(!allowed(usr)) + to_chat(usr, "Access denied.") + return + switch(action) + if("scan_teleporter") + teleporter = findteleporter() + if("scan_beacon") + beacon = findbeacon() + if("handle_id") + if(contained_id) + id_eject(usr) + else + id_insert(usr) + if("set_goal") + var/new_goal = input("Set the amount of points:", "Points", contained_id.goal) as num|null + if(!isnum(new_goal)) + return + if(!new_goal) + new_goal = default_goal + if (new_goal > 1000) + to_chat(usr, "The entered amount of points is too large. Points have instead been set to the maximum allowed amount.") + contained_id.goal = CLAMP(new_goal, 0, 1000) //maximum 1000 points + if("toggle_open") + if(teleporter.locked) + to_chat(usr, "The teleporter is locked") + return + teleporter.toggle_open() + if("teleporter_lock") + if(teleporter.state_open) + to_chat(usr, "Close the teleporter before locking!") + return + teleporter.locked = !teleporter.locked + if("teleport") + if(!teleporter || !beacon) + return + addtimer(CALLBACK(src, .proc/teleport, usr), 5) + +/obj/machinery/computer/prisoner/gulag_teleporter_computer/proc/scan_machinery() + teleporter = findteleporter() + beacon = findbeacon() + +/obj/machinery/computer/prisoner/gulag_teleporter_computer/proc/findteleporter() + var/obj/machinery/gulag_teleporter/teleporterf = null + + for(var/direction in GLOB.cardinals) + teleporterf = locate(/obj/machinery/gulag_teleporter, get_step(src, direction)) + if(teleporterf && teleporterf.is_operational()) + return teleporterf + +/obj/machinery/computer/prisoner/gulag_teleporter_computer/proc/findbeacon() + return locate(/obj/structure/gulag_beacon) + +/obj/machinery/computer/prisoner/gulag_teleporter_computer/proc/teleport(mob/user) + if(!contained_id) //incase the ID was removed after the transfer timer was set. + say("Warning: Unable to transfer prisoner without a valid Prisoner ID inserted!") + return + var/id_goal_not_set + if(!contained_id.goal) + id_goal_not_set = TRUE + contained_id.goal = default_goal + say("[contained_id]'s ID card goal defaulting to [contained_id.goal] points.") + log_game("[key_name(user)] teleported [key_name(prisoner)] to the Labor Camp [COORD(beacon)] for [id_goal_not_set ? "default goal of ":""][contained_id.goal] points.") + teleporter.handle_prisoner(contained_id, temporary_record) + playsound(src, 'sound/weapons/emitter.ogg', 50, 1) + prisoner.forceMove(get_turf(beacon)) + prisoner.Stun(40) // small travel dizziness + to_chat(prisoner, "The teleportation makes you a little dizzy.") + new /obj/effect/particle_effect/sparks(get_turf(prisoner)) + playsound(src, "sparks", 50, 1) + if(teleporter.locked) + teleporter.locked = FALSE + teleporter.toggle_open() + contained_id = null + temporary_record = null diff --git a/code/game/machinery/computer/prisoner.dm b/code/game/machinery/computer/prisoner/management.dm similarity index 73% rename from code/game/machinery/computer/prisoner.dm rename to code/game/machinery/computer/prisoner/management.dm index 798b0e4c65..653f6bf48b 100644 --- a/code/game/machinery/computer/prisoner.dm +++ b/code/game/machinery/computer/prisoner/management.dm @@ -1,4 +1,5 @@ -/obj/machinery/computer/prisoner + +/obj/machinery/computer/prisoner/management name = "prisoner management console" desc = "Used to manage tracking implants placed inside criminals." icon_screen = "explosive" @@ -10,22 +11,23 @@ var/timeleft = 60 var/stop = 0 var/screen = 0 // 0 - No Access Denied, 1 - Access allowed - var/obj/item/card/id/prisoner/inserted_id circuit = /obj/item/circuitboard/computer/prisoner light_color = LIGHT_COLOR_RED -/obj/machinery/computer/prisoner/ui_interact(mob/user) +/obj/machinery/computer/prisoner/management/ui_interact(mob/user) . = ..() + if(isliving(user)) + playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) var/dat = "" if(screen == 0) - dat += "
Unlock Console" + dat += "
{Log In}" else if(screen == 1) dat += "

Prisoner ID Management

" - if(inserted_id) - dat += text("[inserted_id]
") - dat += text("Collected Points: [inserted_id.points]. Reset.
") - dat += text("Card goal: [inserted_id.goal]. Set
") + if(contained_id) + dat += text("[contained_id]
") + dat += text("Collected Points: [contained_id.points]. Reset.
") + dat += text("Card goal: [contained_id.goal]. Set
") dat += text("Space Law recommends quotas of 100 points per minute they would normally serve in the brig.
") else dat += text("Insert Prisoner ID.
") @@ -33,11 +35,11 @@ dat += "
Chemical Implants
" var/turf/Tr = null for(var/obj/item/implant/chem/C in GLOB.tracked_chem_implants) - Tr = get_turf(C) - if((Tr) && (Tr.z != src.z)) - continue//Out of range if(!C.imp_in) continue + Tr = get_turf(C.imp_in) + if((Tr) && (Tr.z != src.z)) + continue//Out of range dat += "ID: [C.imp_in.name] | Remaining Units: [C.reagents.total_volume]
" dat += "| Inject: " dat += "((1))" @@ -46,9 +48,9 @@ dat += "********************************
" dat += "
Tracking Implants
" for(var/obj/item/implant/tracking/T in GLOB.tracked_implants) - if(!isliving(T.imp_in)) + if(!T.imp_in || !isliving(T.imp_in)) continue - Tr = get_turf(T) + Tr = get_turf(T.imp_in) if((Tr) && (Tr.z != src.z)) continue//Out of range @@ -61,53 +63,47 @@ dat += "ID: [T.imp_in.name] | Location: [loc_display]
" dat += "(Message Holder) |
" dat += "********************************
" - dat += "
Lock Console" + dat += "
{Log Out}" var/datum/browser/popup = new(user, "computer", "Prisoner Management Console", 400, 500) popup.set_content(dat) popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) popup.open() return -/obj/machinery/computer/prisoner/attackby(obj/item/I, mob/user, params) +/obj/machinery/computer/prisoner/management/attackby(obj/item/I, mob/user, params) if(istype(I, /obj/item/card/id)) - return attack_hand(user) + if(screen) + id_insert(user) + else + to_chat(user, "Unauthorized access.") else return ..() -/obj/machinery/computer/prisoner/process() +/obj/machinery/computer/prisoner/management/process() if(!..()) src.updateDialog() return - -/obj/machinery/computer/prisoner/Topic(href, href_list) +/obj/machinery/computer/prisoner/management/Topic(href, href_list) if(..()) return if(usr.contents.Find(src) || (in_range(src, usr) && isturf(loc)) || issilicon(usr)) usr.set_machine(src) if(href_list["id"]) - if(href_list["id"] =="insert" && !inserted_id) - var/obj/item/card/id/prisoner/I = usr.is_holding_item_of_type(/obj/item/card/id/prisoner) - if(I) - if(!usr.transferItemToLoc(I, src)) - return - inserted_id = I - else - to_chat(usr, "No valid ID.") - else if(inserted_id) + if(href_list["id"] =="insert" && !contained_id) + id_insert(usr) + else if(contained_id) switch(href_list["id"]) if("eject") - inserted_id.forceMove(drop_location()) - inserted_id.verb_pickup() - inserted_id = null + id_eject(usr) if("reset") - inserted_id.points = 0 + contained_id.points = 0 if("setgoal") var/num = round(input(usr, "Choose prisoner's goal:", "Input an Integer", null) as num|null) if(num >= 0) num = min(num,1000) //Cap the quota to the equivilent of 10 minutes. - inserted_id.goal = num + contained_id.goal = num else if(href_list["inject1"]) var/obj/item/implant/I = locate(href_list["inject1"]) in GLOB.tracked_chem_implants if(I && istype(I)) @@ -116,17 +112,17 @@ var/obj/item/implant/I = locate(href_list["inject5"]) in GLOB.tracked_chem_implants if(I && istype(I)) I.activate(5) - else if(href_list["inject10"]) var/obj/item/implant/I = locate(href_list["inject10"]) in GLOB.tracked_chem_implants if(I && istype(I)) I.activate(10) else if(href_list["lock"]) - if(src.allowed(usr)) + if(allowed(usr)) screen = !screen + playsound(src, 'sound/machines/terminal_on.ogg', 50, FALSE) else - to_chat(usr, "Unauthorized Access.") + to_chat(usr, "Unauthorized access.") else if(href_list["warn"]) var/warning = copytext(sanitize(input(usr,"Message:","Enter your message here!","")),1,MAX_MESSAGE_LEN) diff --git a/code/game/machinery/computer/security.dm b/code/game/machinery/computer/security.dm index 607f8dbe78..efb1039b8b 100644 --- a/code/game/machinery/computer/security.dm +++ b/code/game/machinery/computer/security.dm @@ -5,13 +5,10 @@ icon_keyboard = "security_key" req_one_access = list(ACCESS_SECURITY, ACCESS_FORENSICS_LOCKERS) circuit = /obj/item/circuitboard/computer/secure_data - var/obj/item/card/id/scan = null - var/authenticated = null var/rank = null var/screen = null var/datum/data/record/active1 = null var/datum/data/record/active2 = null - var/a_id = null var/temp = null var/printing = null var/can_change_id = 0 @@ -23,11 +20,6 @@ light_color = LIGHT_COLOR_RED -/obj/machinery/computer/secure_data/examine(mob/user) - ..() - if(scan) - to_chat(user, "Alt-click to eject the ID card.") - /obj/machinery/computer/secure_data/syndie icon_keyboard = "syndie_key" @@ -40,32 +32,19 @@ clockwork = TRUE //it'd look weird pass_flags = PASSTABLE -/obj/machinery/computer/secure_data/attackby(obj/item/O, mob/user, params) - if(istype(O, /obj/item/card/id)) - if(!scan) - if(!user.transferItemToLoc(O, src)) - return - scan = O - to_chat(user, "You insert [O].") - playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0) - updateUsrDialog() - else - to_chat(user, "There's already an ID card in the console.") - else - return ..() - //Someone needs to break down the dat += into chunks instead of long ass lines. /obj/machinery/computer/secure_data/ui_interact(mob/user) . = ..() + playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) if(src.z > 6) to_chat(user, "Unable to establish a connection: \black You're too far away from the station!") return var/dat if(temp) - dat = text("[]

Clear Screen", temp) + dat = "[temp]

Clear Screen" else - dat = text("Confirm Identity: []
", (scan ? text("[]", scan.name) : "----------")) + dat = "" if(authenticated) switch(screen) if(1) @@ -190,7 +169,7 @@ dat += {"" for(var/j in GLOB.loadout_items[gear_tab]) var/datum/gear/gear = GLOB.loadout_items[gear_tab][j] - var/donoritem - if(gear.ckeywhitelist && gear.ckeywhitelist.len) - donoritem = TRUE - if(!(user.ckey in gear.ckeywhitelist)) - continue + var/donoritem = gear.donoritem + if(donoritem && !gear.donator_ckey_check(user.ckey)) + continue var/class_link = "" if(gear.type in chosen_gear) class_link = "style='white-space:normal;' class='linkOn' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(j)];toggle_gear=0'" @@ -991,9 +1024,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) //The job before the current job. I only use this to get the previous jobs color when I'm filling in blank rows. var/datum/job/lastJob - var/datum/job/overflow = SSjob.GetJob(SSjob.overflow_role) - - for(var/datum/job/job in SSjob.occupations) + for(var/datum/job/job in sortList(SSjob.occupations, /proc/cmp_job_display_asc)) index += 1 if((index >= limit) || (job.title in splitJobs)) @@ -1010,7 +1041,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/rank = job.title lastJob = job if(jobban_isbanned(user, rank)) - HTML += "[rank]" + HTML += "[rank]" continue var/required_playtime_remaining = job.required_playtime_remaining(user.client) if(required_playtime_remaining) @@ -1020,7 +1051,13 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/available_in_days = job.available_in_days(user.client) HTML += "[rank]" continue - if((job_civilian_low & overflow.flag) && (rank != SSjob.overflow_role) && !jobban_isbanned(user, SSjob.overflow_role)) + if(!user.client.prefs.pref_species.qualifies_for_rank(rank, user.client.prefs.features)) + if(user.client.prefs.pref_species.id == "human") + HTML += "[rank]" + else + HTML += "[rank]" + continue + if((job_preferences["[SSjob.overflow_role]"] == JP_LOW) && (rank != SSjob.overflow_role) && !jobban_isbanned(user, SSjob.overflow_role)) HTML += "[rank]" continue if((rank in GLOB.command_positions) || (rank == "AI"))//Bold head jobs @@ -1035,32 +1072,32 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/prefUpperLevel = -1 // level to assign on left click var/prefLowerLevel = -1 // level to assign on right click - if(GetJobDepartment(job, 1) & job.flag) - prefLevelLabel = "High" - prefLevelColor = "slateblue" - prefUpperLevel = 4 - prefLowerLevel = 2 - else if(GetJobDepartment(job, 2) & job.flag) - prefLevelLabel = "Medium" - prefLevelColor = "green" - prefUpperLevel = 1 - prefLowerLevel = 3 - else if(GetJobDepartment(job, 3) & job.flag) - prefLevelLabel = "Low" - prefLevelColor = "orange" - prefUpperLevel = 2 - prefLowerLevel = 4 - else - prefLevelLabel = "NEVER" - prefLevelColor = "red" - prefUpperLevel = 3 - prefLowerLevel = 1 - + switch(job_preferences["[job.title]"]) + if(JP_HIGH) + prefLevelLabel = "High" + prefLevelColor = "slateblue" + prefUpperLevel = 4 + prefLowerLevel = 2 + if(JP_MEDIUM) + prefLevelLabel = "Medium" + prefLevelColor = "green" + prefUpperLevel = 1 + prefLowerLevel = 3 + if(JP_LOW) + prefLevelLabel = "Low" + prefLevelColor = "orange" + prefUpperLevel = 2 + prefLowerLevel = 4 + else + prefLevelLabel = "NEVER" + prefLevelColor = "red" + prefUpperLevel = 3 + prefLowerLevel = 1 HTML += "" if(rank == SSjob.overflow_role)//Overflow is special - if(job_civilian_low & overflow.flag) + if(job_preferences["[SSjob.overflow_role]"] == JP_LOW) HTML += "Yes" else HTML += "No" @@ -1091,61 +1128,17 @@ GLOBAL_LIST_EMPTY(preferences_datums) /datum/preferences/proc/SetJobPreferenceLevel(datum/job/job, level) if (!job) - return 0 + return FALSE - if (level == 1) // to high - // remove any other job(s) set to high - job_civilian_med |= job_civilian_high - job_engsec_med |= job_engsec_high - job_medsci_med |= job_medsci_high - job_civilian_high = 0 - job_engsec_high = 0 - job_medsci_high = 0 + if (level == JP_HIGH) // to high + //Set all other high to medium + for(var/j in job_preferences) + if(job_preferences["[j]"] == JP_HIGH) + job_preferences["[j]"] = JP_MEDIUM + //technically break here - if (job.department_flag == CIVILIAN) - job_civilian_low &= ~job.flag - job_civilian_med &= ~job.flag - job_civilian_high &= ~job.flag - - switch(level) - if (1) - job_civilian_high |= job.flag - if (2) - job_civilian_med |= job.flag - if (3) - job_civilian_low |= job.flag - - return 1 - else if (job.department_flag == ENGSEC) - job_engsec_low &= ~job.flag - job_engsec_med &= ~job.flag - job_engsec_high &= ~job.flag - - switch(level) - if (1) - job_engsec_high |= job.flag - if (2) - job_engsec_med |= job.flag - if (3) - job_engsec_low |= job.flag - - return 1 - else if (job.department_flag == MEDSCI) - job_medsci_low &= ~job.flag - job_medsci_med &= ~job.flag - job_medsci_high &= ~job.flag - - switch(level) - if (1) - job_medsci_high |= job.flag - if (2) - job_medsci_med |= job.flag - if (3) - job_medsci_low |= job.flag - - return 1 - - return 0 + job_preferences["[job.title]"] = level + return TRUE /datum/preferences/proc/UpdateJobPreference(mob/user, role, desiredLvl) if(!SSjob || SSjob.occupations.len <= 0) @@ -1162,64 +1155,29 @@ GLOBAL_LIST_EMPTY(preferences_datums) ShowChoices(user) return - if(role == SSjob.overflow_role) - if(job_civilian_low & job.flag) - job_civilian_low &= ~job.flag - else - job_civilian_low |= job.flag - SetChoices(user) - return 1 + var/jpval = null + switch(desiredLvl) + if(3) + jpval = JP_LOW + if(2) + jpval = JP_MEDIUM + if(1) + jpval = JP_HIGH - SetJobPreferenceLevel(job, desiredLvl) + if(role == SSjob.overflow_role) + if(job_preferences["[job.title]"] == JP_LOW) + jpval = null + else + jpval = JP_LOW + + SetJobPreferenceLevel(job, jpval) SetChoices(user) return 1 /datum/preferences/proc/ResetJobs() - - job_civilian_high = 0 - job_civilian_med = 0 - job_civilian_low = 0 - - job_medsci_high = 0 - job_medsci_med = 0 - job_medsci_low = 0 - - job_engsec_high = 0 - job_engsec_med = 0 - job_engsec_low = 0 - - -/datum/preferences/proc/GetJobDepartment(datum/job/job, level) - if(!job || !level) - return 0 - switch(job.department_flag) - if(CIVILIAN) - switch(level) - if(1) - return job_civilian_high - if(2) - return job_civilian_med - if(3) - return job_civilian_low - if(MEDSCI) - switch(level) - if(1) - return job_medsci_high - if(2) - return job_medsci_med - if(3) - return job_medsci_low - if(ENGSEC) - switch(level) - if(1) - return job_engsec_high - if(2) - return job_engsec_med - if(3) - return job_engsec_low - return 0 + job_preferences = list() /datum/preferences/proc/SetQuirks(mob/user) if(!SSquirks) @@ -1533,7 +1491,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) if("undie_color") var/n_undie_color = input(user, "Choose your underwear's color.", "Character Preference", undie_color) as color|null if(n_undie_color) - undie_color = sanitize_hexcolor(n_undie_color, include_crunch= TRUE) + undie_color = sanitize_hexcolor(n_undie_color) if("undershirt") var/new_undershirt = input(user, "Choose your character's undershirt:", "Character Preference") as null|anything in GLOB.undershirt_list @@ -1543,7 +1501,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) if("shirt_color") var/n_shirt_color = input(user, "Choose your undershirt's color.", "Character Preference", shirt_color) as color|null if(n_shirt_color) - shirt_color = sanitize_hexcolor(n_shirt_color, include_crunch= TRUE) + shirt_color = sanitize_hexcolor(n_shirt_color) if("socks") var/new_socks = input(user, "Choose your character's socks:", "Character Preference") as null|anything in GLOB.socks_list @@ -1553,7 +1511,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) if("socks_color") var/n_socks_color = input(user, "Choose your socks' color.", "Character Preference", socks_color) as color|null if(n_socks_color) - socks_color = sanitize_hexcolor(n_socks_color, include_crunch= TRUE) + socks_color = sanitize_hexcolor(n_socks_color) if("eyes") var/new_eyes = input(user, "Choose your character's eye colour:", "Character Preference","#"+eye_color) as color|null @@ -1561,9 +1519,9 @@ GLOBAL_LIST_EMPTY(preferences_datums) eye_color = sanitize_hexcolor(new_eyes) if("species") - var/result = input(user, "Select a species", "Species Selection") as null|anything in GLOB.roundstart_races + var/result = input(user, "Select a species", "Species Selection") as null|anything in GLOB.roundstart_race_names if(result) - var/newtype = GLOB.species_list[result] + var/newtype = GLOB.species_list[GLOB.roundstart_race_names[result]] pref_species = new newtype() //let's ensure that no weird shit happens on species swapping. custom_species = null @@ -1691,6 +1649,12 @@ GLOBAL_LIST_EMPTY(preferences_datums) features["tail_human"] = "None" features["tail_lizard"] = "None" + if("meats") + var/new_meat + new_meat = input(user, "Choose your character's meat type:", "Character Preference") as null|anything in GLOB.meat_types + if(new_meat) + features["meat_type"] = new_meat + if("snout") var/list/snowflake_snouts_list = list() for(var/path in GLOB.snouts_list) @@ -1726,12 +1690,28 @@ GLOBAL_LIST_EMPTY(preferences_datums) if(new_horns) features["horns"] = new_horns + if("horns_color") + var/new_horn_color = input(user, "Choose your character's horn colour:", "Character Preference","#"+horn_color) as color|null + if(new_horn_color) + if (new_horn_color == "#000000") + horn_color = "#85615A" + else + horn_color = sanitize_hexcolor(new_horn_color) + if("wings") var/new_wings new_wings = input(user, "Choose your character's wings:", "Character Preference") as null|anything in GLOB.r_wings_list if(new_wings) features["wings"] = new_wings + if("wings_color") + var/new_wing_color = input(user, "Choose your character's wing colour:", "Character Preference","#"+wing_color) as color|null + if(new_wing_color) + if (new_wing_color == "#000000") + wing_color = "#FFFFFF" + else + wing_color = sanitize_hexcolor(new_wing_color) + if("frills") var/new_frills new_frills = input(user, "Choose your character's frills:", "Character Preference") as null|anything in GLOB.frills_list @@ -1760,11 +1740,23 @@ GLOBAL_LIST_EMPTY(preferences_datums) features["legs"] = new_legs update_preview_icon() - if("moth_wings") - var/new_moth_wings - new_moth_wings = input(user, "Choose your character's wings:", "Character Preference") as null|anything in GLOB.moth_wings_list - if(new_moth_wings) - features["moth_wings"] = new_moth_wings + if("insect_wings") + var/new_insect_wings + new_insect_wings = input(user, "Choose your character's wings:", "Character Preference") as null|anything in GLOB.insect_wings_list + if(new_insect_wings) + features["insect_wings"] = new_insect_wings + + if("deco_wings") + var/new_deco_wings + new_deco_wings = input(user, "Choose your character's wings:", "Character Preference") as null|anything in GLOB.deco_wings_list + if(new_deco_wings) + features["deco_wings"] = new_deco_wings + + if("insect_fluffs") + var/new_insect_fluff + new_insect_fluff = input(user, "Choose your character's wings:", "Character Preference") as null|anything in GLOB.insect_fluffs_list + if(new_insect_fluff) + features["insect_fluff"] = new_insect_fluff if("s_tone") var/new_s_tone = input(user, "Choose your character's skin-tone:", "Character Preference") as null|anything in GLOB.skin_tones @@ -2037,6 +2029,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) features["genitals_use_skintone"] = !features["genitals_use_skintone"] if("arousable") arousable = !arousable + if("lewdchem") + lewdchem = !lewdchem if("has_cock") features["has_cock"] = !features["has_cock"] if(features["has_cock"] == FALSE) @@ -2053,6 +2047,10 @@ GLOBAL_LIST_EMPTY(preferences_datums) features["eggsack_internal"] = !features["eggsack_internal"] if("has_breasts") features["has_breasts"] = !features["has_breasts"] + if(features["has_breasts"] == FALSE) + features["breasts_producing"] = FALSE + if("breasts_producing") + features["breasts_producing"] = !features["breasts_producing"] if("has_vag") features["has_vag"] = !features["has_vag"] if(features["has_vag"] == FALSE) @@ -2236,7 +2234,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) if(!is_loadout_slot_available(G.category)) to_chat(user, "You cannot take this loadout, as you've already chosen too many of the same category!") return - if(G.ckeywhitelist && G.ckeywhitelist.len && !(user.ckey in G.ckeywhitelist)) + if(G.donoritem && !G.donator_ckey_check(user.ckey)) to_chat(user, "This is an item intended for donator use only. You are not authorized to use this item.") return if(gear_points >= initial(G.cost)) @@ -2278,6 +2276,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) organ_eyes.old_eye_color = eye_color character.hair_color = hair_color character.facial_hair_color = facial_hair_color + character.horn_color = horn_color + character.wing_color = wing_color character.skin_tone = skin_tone character.hair_style = hair_style @@ -2318,7 +2318,10 @@ GLOBAL_LIST_EMPTY(preferences_datums) if("xenotail" in pref_species.default_features) character.dna.species.mutant_bodyparts |= "xenotail" - if(("legs" in character.dna.species.mutant_bodyparts) && character.dna.features["legs"] == "Digitigrade Legs") + if("meat_type" in pref_species.default_features) + character.type_of_meat = GLOB.meat_types[features["meat_type"]] + + if(("legs" in character.dna.species.mutant_bodyparts) && (character.dna.features["legs"] == "Digitigrade" || character.dna.features["legs"] == "Avian")) pref_species.species_traits |= DIGITIGRADE else pref_species.species_traits -= DIGITIGRADE diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index 4ce91ffd94..01a46a44a0 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -5,7 +5,7 @@ // You do not need to raise this if you are adding new values that have sane defaults. // Only raise this value when changing the meaning/format/name/layout of an existing value // where you would want the updater procs below to run -#define SAVEFILE_VERSION_MAX 20 +#define SAVEFILE_VERSION_MAX 23 /* SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Carn @@ -49,6 +49,65 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car pda_style = "mono" if(current_version < 20) pda_color = "#808000" + if((current_version < 21) && features["meat_type"] && (features["meat_type"] == null)) + features["meat_type"] = "Mammalian" + if(current_version < 22) + + job_preferences = list() //It loaded null from nonexistant savefile field. + + var/job_civilian_high = 0 + var/job_civilian_med = 0 + var/job_civilian_low = 0 + + var/job_medsci_high = 0 + var/job_medsci_med = 0 + var/job_medsci_low = 0 + + var/job_engsec_high = 0 + var/job_engsec_med = 0 + var/job_engsec_low = 0 + + S["job_civilian_high"] >> job_civilian_high + S["job_civilian_med"] >> job_civilian_med + S["job_civilian_low"] >> job_civilian_low + S["job_medsci_high"] >> job_medsci_high + S["job_medsci_med"] >> job_medsci_med + S["job_medsci_low"] >> job_medsci_low + S["job_engsec_high"] >> job_engsec_high + S["job_engsec_med"] >> job_engsec_med + S["job_engsec_low"] >> job_engsec_low + + //Can't use SSjob here since this happens right away on login + for(var/job in subtypesof(/datum/job)) + var/datum/job/J = job + var/new_value + var/fval = initial(J.flag) + switch(initial(J.department_flag)) + if(CIVILIAN) + if(job_civilian_high & fval) + new_value = JP_HIGH + else if(job_civilian_med & fval) + new_value = JP_MEDIUM + else if(job_civilian_low & fval) + new_value = JP_LOW + if(MEDSCI) + if(job_medsci_high & fval) + new_value = JP_HIGH + else if(job_medsci_med & fval) + new_value = JP_MEDIUM + else if(job_medsci_low & fval) + new_value = JP_LOW + if(ENGSEC) + if(job_engsec_high & fval) + new_value = JP_HIGH + else if(job_engsec_med & fval) + new_value = JP_MEDIUM + else if(job_engsec_low & fval) + new_value = JP_LOW + if(new_value) + job_preferences["[initial(J.title)]"] = new_value + else if(current_version < 23) // we are fixing a gamebreaking bug. + job_preferences = list() //It loaded null from nonexistant savefile field. /datum/preferences/proc/load_path(ckey,filename="preferences.sav") if(!ckey) @@ -117,6 +176,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car S["widescreenpref"] >> widescreenpref S["autostand"] >> autostand S["cit_toggles"] >> cit_toggles + S["lewdchem"] >> lewdchem //try to fix any outdated data if necessary if(needs_update >= 0) @@ -211,6 +271,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car WRITE_FILE(S["widescreenpref"], widescreenpref) WRITE_FILE(S["autostand"], autostand) WRITE_FILE(S["cit_toggles"], cit_toggles) + WRITE_FILE(S["lewdchem"], lewdchem) return 1 @@ -244,6 +305,11 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car var/species_id S["species"] >> species_id if(species_id) + if(species_id == "avian" || species_id == "aquatic") + species_id = "mammal" + else if(species_id == "moth") + species_id = "insect" + var/newtype = GLOB.species_list[species_id] if(newtype) pref_species = new newtype @@ -251,29 +317,37 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car if(!S["features["mcolor"]"] || S["features["mcolor"]"] == "#000") WRITE_FILE(S["features["mcolor"]"] , "#FFF") + if(!S["features["horn_color"]"] || S["features["horn_color"]"] == "#000") + WRITE_FILE(S["features["horn_color"]"] , "#85615a") + + if(!S["features["wing_color"]"] || S["features["wing_color"]"] == "#000") + WRITE_FILE(S["features["wing_color"]"] , "#FFF") + //Character - S["real_name"] >> real_name - S["nameless"] >> nameless - S["custom_species"] >> custom_species - S["name_is_always_random"] >> be_random_name - S["body_is_always_random"] >> be_random_body - S["gender"] >> gender - S["age"] >> age - S["hair_color"] >> hair_color - S["facial_hair_color"] >> facial_hair_color - S["eye_color"] >> eye_color - S["skin_tone"] >> skin_tone - S["hair_style_name"] >> hair_style - S["facial_style_name"] >> facial_hair_style - S["underwear"] >> underwear - S["undie_color"] >> undie_color - S["undershirt"] >> undershirt - S["shirt_color"] >> shirt_color - S["socks"] >> socks - S["socks_color"] >> socks_color - S["backbag"] >> backbag - S["jumpsuit_style"] >> jumpsuit_style - S["uplink_loc"] >> uplink_spawn_loc + S["real_name"] >> real_name + S["nameless"] >> nameless + S["custom_species"] >> custom_species + S["name_is_always_random"] >> be_random_name + S["body_is_always_random"] >> be_random_body + S["gender"] >> gender + S["age"] >> age + S["hair_color"] >> hair_color + S["facial_hair_color"] >> facial_hair_color + S["eye_color"] >> eye_color + S["skin_tone"] >> skin_tone + S["hair_style_name"] >> hair_style + S["facial_style_name"] >> facial_hair_style + S["underwear"] >> underwear + S["undie_color"] >> undie_color + S["undershirt"] >> undershirt + S["shirt_color"] >> shirt_color + S["socks"] >> socks + S["socks_color"] >> socks_color + S["horn_color"] >> horn_color + S["wing_color"] >> wing_color + S["backbag"] >> backbag + S["jumpsuit_style"] >> jumpsuit_style + S["uplink_loc"] >> uplink_spawn_loc S["feature_mcolor"] >> features["mcolor"] S["feature_lizard_tail"] >> features["tail_lizard"] S["feature_lizard_snout"] >> features["snout"] @@ -282,29 +356,24 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car S["feature_lizard_spines"] >> features["spines"] S["feature_lizard_body_markings"] >> features["body_markings"] S["feature_lizard_legs"] >> features["legs"] - S["feature_moth_wings"] >> features["moth_wings"] S["feature_human_tail"] >> features["tail_human"] S["feature_human_ears"] >> features["ears"] + S["feature_insect_wings"] >> features["insect_wings"] + S["feature_deco_wings"] >> features["deco_wings"] + S["feature_insect_fluff"] >> features["insect_fluff"] //Custom names for(var/custom_name_id in GLOB.preferences_custom_names) var/savefile_slot_name = custom_name_id + "_name" //TODO remove this S[savefile_slot_name] >> custom_names[custom_name_id] - S["preferred_ai_core_display"] >> preferred_ai_core_display - S["prefered_security_department"] >> prefered_security_department + S["preferred_ai_core_display"] >> preferred_ai_core_display + S["prefered_security_department"] >> prefered_security_department //Jobs S["joblessrole"] >> joblessrole - S["job_civilian_high"] >> job_civilian_high - S["job_civilian_med"] >> job_civilian_med - S["job_civilian_low"] >> job_civilian_low - S["job_medsci_high"] >> job_medsci_high - S["job_medsci_med"] >> job_medsci_med - S["job_medsci_low"] >> job_medsci_low - S["job_engsec_high"] >> job_engsec_high - S["job_engsec_med"] >> job_engsec_med - S["job_engsec_low"] >> job_engsec_low + //Load prefs + S["job_preferences"] >> job_preferences //Quirks S["all_quirks"] >> all_quirks @@ -323,6 +392,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car S["feature_mam_tail_animated"] >> features["mam_tail_animated"] S["feature_taur"] >> features["taur"] S["feature_mam_snouts"] >> features["mam_snouts"] + S["feature_meat"] >> features["meat_type"] //Xeno features S["feature_xeno_tail"] >> features["xenotail"] S["feature_xeno_dors"] >> features["xenodorsal"] @@ -347,6 +417,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car S["feature_breasts_shape"] >> features["breasts_shape"] S["feature_breasts_color"] >> features["breasts_color"] S["feature_breasts_fluid"] >> features["breasts_fluid"] + S["feature_breasts_producing"] >> features["breasts_producing"] //vagina features S["feature_has_vag"] >> features["has_vag"] S["feature_vag_shape"] >> features["vag_shape"] @@ -371,11 +442,11 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car //Sanitize - real_name = reject_bad_name(real_name) - gender = sanitize_gender(gender, TRUE, TRUE) + real_name = reject_bad_name(real_name) + gender = sanitize_gender(gender, TRUE, TRUE) if(!real_name) - real_name = random_unique_name(gender) - custom_species = reject_bad_name(custom_species) + real_name = random_unique_name(gender) + custom_species = reject_bad_name(custom_species) for(var/custom_name_id in GLOB.preferences_custom_names) var/namedata = GLOB.preferences_custom_names[custom_name_id] custom_names[custom_name_id] = reject_bad_name(custom_names[custom_name_id],namedata["allow_numbers"]) @@ -385,57 +456,63 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car if(!features["mcolor"] || features["mcolor"] == "#000") features["mcolor"] = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F") - nameless = sanitize_integer(nameless, 0, 1, initial(nameless)) + if(!features["horn_color"] || features["horn_color"] == "#000") + features["horn_color"] = "85615a" + + if(!features["wing_color"] || features["wing_color"] == "#000") + features["wing_color"] = "FFFFFF" + + nameless = sanitize_integer(nameless, 0, 1, initial(nameless)) be_random_name = sanitize_integer(be_random_name, 0, 1, initial(be_random_name)) be_random_body = sanitize_integer(be_random_body, 0, 1, initial(be_random_body)) if(gender == MALE) - hair_style = sanitize_inlist(hair_style, GLOB.hair_styles_male_list) + hair_style = sanitize_inlist(hair_style, GLOB.hair_styles_male_list) facial_hair_style = sanitize_inlist(facial_hair_style, GLOB.facial_hair_styles_male_list) else - hair_style = sanitize_inlist(hair_style, GLOB.hair_styles_female_list) + hair_style = sanitize_inlist(hair_style, GLOB.hair_styles_female_list) facial_hair_style = sanitize_inlist(facial_hair_style, GLOB.facial_hair_styles_female_list) - underwear = sanitize_inlist(underwear, GLOB.underwear_list) - undie_color = sanitize_hexcolor(undie_color, 6, 1, initial(undie_color)) - undershirt = sanitize_inlist(undershirt, GLOB.undershirt_list) - shirt_color = sanitize_hexcolor(shirt_color, 6, 1, initial(shirt_color)) - socks = sanitize_inlist(socks, GLOB.socks_list) - socks_color = sanitize_hexcolor(socks_color, 6, 1, initial(socks_color)) - age = sanitize_integer(age, AGE_MIN, AGE_MAX, initial(age)) - hair_color = sanitize_hexcolor(hair_color, 3, 0) - facial_hair_color = sanitize_hexcolor(facial_hair_color, 3, 0) - eye_color = sanitize_hexcolor(eye_color, 3, 0) - skin_tone = sanitize_inlist(skin_tone, GLOB.skin_tones) - backbag = sanitize_inlist(backbag, GLOB.backbaglist, initial(backbag)) - jumpsuit_style = sanitize_inlist(jumpsuit_style, GLOB.jumpsuitlist, initial(jumpsuit_style)) - uplink_spawn_loc = sanitize_inlist(uplink_spawn_loc, GLOB.uplink_spawn_loc_list, initial(uplink_spawn_loc)) - features["mcolor"] = sanitize_hexcolor(features["mcolor"], 3, 0) - features["tail_lizard"] = sanitize_inlist(features["tail_lizard"], GLOB.tails_list_lizard) - features["tail_human"] = sanitize_inlist(features["tail_human"], GLOB.tails_list_human) - features["snout"] = sanitize_inlist(features["snout"], GLOB.snouts_list) - features["horns"] = sanitize_inlist(features["horns"], GLOB.horns_list) - features["ears"] = sanitize_inlist(features["ears"], GLOB.ears_list) - features["frills"] = sanitize_inlist(features["frills"], GLOB.frills_list) - features["spines"] = sanitize_inlist(features["spines"], GLOB.spines_list) - features["body_markings"] = sanitize_inlist(features["body_markings"], GLOB.body_markings_list) + underwear = sanitize_inlist(underwear, GLOB.underwear_list) + undie_color = sanitize_hexcolor(undie_color, 3, FALSE, initial(undie_color)) + undershirt = sanitize_inlist(undershirt, GLOB.undershirt_list) + shirt_color = sanitize_hexcolor(shirt_color, 3, FALSE, initial(shirt_color)) + socks = sanitize_inlist(socks, GLOB.socks_list) + socks_color = sanitize_hexcolor(socks_color, 3, FALSE, initial(socks_color)) + age = sanitize_integer(age, AGE_MIN, AGE_MAX, initial(age)) + hair_color = sanitize_hexcolor(hair_color, 3, 0) + facial_hair_color = sanitize_hexcolor(facial_hair_color, 3, 0) + eye_color = sanitize_hexcolor(eye_color, 3, 0) + skin_tone = sanitize_inlist(skin_tone, GLOB.skin_tones) + horn_color = sanitize_hexcolor(horn_color, 3, FALSE) + wing_color = sanitize_hexcolor(wing_color, 3, FALSE, "#FFFFFF") + backbag = sanitize_inlist(backbag, GLOB.backbaglist, initial(backbag)) + jumpsuit_style = sanitize_inlist(jumpsuit_style, GLOB.jumpsuitlist, initial(jumpsuit_style)) + uplink_spawn_loc = sanitize_inlist(uplink_spawn_loc, GLOB.uplink_spawn_loc_list, initial(uplink_spawn_loc)) + features["mcolor"] = sanitize_hexcolor(features["mcolor"], 3, 0) + features["tail_lizard"] = sanitize_inlist(features["tail_lizard"], GLOB.tails_list_lizard) + features["tail_human"] = sanitize_inlist(features["tail_human"], GLOB.tails_list_human) + features["snout"] = sanitize_inlist(features["snout"], GLOB.snouts_list) + features["horns"] = sanitize_inlist(features["horns"], GLOB.horns_list) + features["ears"] = sanitize_inlist(features["ears"], GLOB.ears_list) + features["frills"] = sanitize_inlist(features["frills"], GLOB.frills_list) + features["spines"] = sanitize_inlist(features["spines"], GLOB.spines_list) + features["body_markings"] = sanitize_inlist(features["body_markings"], GLOB.body_markings_list) features["feature_lizard_legs"] = sanitize_inlist(features["legs"], GLOB.legs_list) - features["moth_wings"] = sanitize_inlist(features["moth_wings"], GLOB.moth_wings_list) + features["insect_wings"] = sanitize_inlist(features["insect_wings"], GLOB.insect_wings_list) + features["deco_wings"] = sanitize_inlist(features["deco_wings"], GLOB.deco_wings_list, "None") + features["insect_fluff"] = sanitize_inlist(features["insect_fluff"], GLOB.insect_fluffs_list) joblessrole = sanitize_integer(joblessrole, 1, 3, initial(joblessrole)) - job_civilian_high = sanitize_integer(job_civilian_high, 0, 65535, initial(job_civilian_high)) - job_civilian_med = sanitize_integer(job_civilian_med, 0, 65535, initial(job_civilian_med)) - job_civilian_low = sanitize_integer(job_civilian_low, 0, 65535, initial(job_civilian_low)) - job_medsci_high = sanitize_integer(job_medsci_high, 0, 65535, initial(job_medsci_high)) - job_medsci_med = sanitize_integer(job_medsci_med, 0, 65535, initial(job_medsci_med)) - job_medsci_low = sanitize_integer(job_medsci_low, 0, 65535, initial(job_medsci_low)) - job_engsec_high = sanitize_integer(job_engsec_high, 0, 65535, initial(job_engsec_high)) - job_engsec_med = sanitize_integer(job_engsec_med, 0, 65535, initial(job_engsec_med)) - job_engsec_low = sanitize_integer(job_engsec_low, 0, 65535, initial(job_engsec_low)) + //Validate job prefs + for(var/j in job_preferences) + if(job_preferences["[j]"] != JP_LOW && job_preferences["[j]"] != JP_MEDIUM && job_preferences["[j]"] != JP_HIGH) + job_preferences -= j all_quirks = SANITIZE_LIST(all_quirks) + positive_quirks = SANITIZE_LIST(positive_quirks) negative_quirks = SANITIZE_LIST(negative_quirks) - neutral_quirks = SANITIZE_LIST(neutral_quirks) + neutral_quirks = SANITIZE_LIST(neutral_quirks) cit_character_pref_load(S) @@ -457,31 +534,33 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car WRITE_FILE(S["version"] , SAVEFILE_VERSION_MAX) //load_character will sanitize any bad data, so assume up-to-date.) //Character - WRITE_FILE(S["real_name"] , real_name) - WRITE_FILE(S["nameless"] , nameless) - WRITE_FILE(S["custom_species"] , custom_species) - WRITE_FILE(S["name_is_always_random"] , be_random_name) - WRITE_FILE(S["body_is_always_random"] , be_random_body) - WRITE_FILE(S["gender"] , gender) - WRITE_FILE(S["age"] , age) - WRITE_FILE(S["hair_color"] , hair_color) - WRITE_FILE(S["facial_hair_color"] , facial_hair_color) - WRITE_FILE(S["eye_color"] , eye_color) - WRITE_FILE(S["skin_tone"] , skin_tone) - WRITE_FILE(S["hair_style_name"] , hair_style) - WRITE_FILE(S["facial_style_name"] , facial_hair_style) - WRITE_FILE(S["underwear"] , underwear) - WRITE_FILE(S["undie_color"] , undie_color) - WRITE_FILE(S["undershirt"] , undershirt) - WRITE_FILE(S["shirt_color"] , shirt_color) - WRITE_FILE(S["socks"] , socks) - WRITE_FILE(S["socks_color"] , socks_color) - WRITE_FILE(S["backbag"] , backbag) - WRITE_FILE(S["jumpsuit_style"] , jumpsuit_style) - WRITE_FILE(S["uplink_loc"] , uplink_spawn_loc) - WRITE_FILE(S["species"] , pref_species.id) + WRITE_FILE(S["real_name"] , real_name) + WRITE_FILE(S["nameless"] , nameless) + WRITE_FILE(S["custom_species"] , custom_species) + WRITE_FILE(S["name_is_always_random"] , be_random_name) + WRITE_FILE(S["body_is_always_random"] , be_random_body) + WRITE_FILE(S["gender"] , gender) + WRITE_FILE(S["age"] , age) + WRITE_FILE(S["hair_color"] , hair_color) + WRITE_FILE(S["facial_hair_color"] , facial_hair_color) + WRITE_FILE(S["eye_color"] , eye_color) + WRITE_FILE(S["skin_tone"] , skin_tone) + WRITE_FILE(S["hair_style_name"] , hair_style) + WRITE_FILE(S["facial_style_name"] , facial_hair_style) + WRITE_FILE(S["underwear"] , underwear) + WRITE_FILE(S["undie_color"] , undie_color) + WRITE_FILE(S["undershirt"] , undershirt) + WRITE_FILE(S["shirt_color"] , shirt_color) + WRITE_FILE(S["socks"] , socks) + WRITE_FILE(S["socks_color"] , socks_color) + WRITE_FILE(S["horn_color"] , horn_color) + WRITE_FILE(S["wing_color"] , wing_color) + WRITE_FILE(S["backbag"] , backbag) + WRITE_FILE(S["jumpsuit_style"] , jumpsuit_style) + WRITE_FILE(S["uplink_loc"] , uplink_spawn_loc) + WRITE_FILE(S["species"] , pref_species.id) WRITE_FILE(S["feature_mcolor"] , features["mcolor"]) - WRITE_FILE(S["feature_lizard_tail"] , features["tail_lizard"]) + WRITE_FILE(S["feature_lizard_tail"] , features["tail_lizard"]) WRITE_FILE(S["feature_human_tail"] , features["tail_human"]) WRITE_FILE(S["feature_lizard_snout"] , features["snout"]) WRITE_FILE(S["feature_lizard_horns"] , features["horns"]) @@ -489,28 +568,24 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car WRITE_FILE(S["feature_lizard_frills"] , features["frills"]) WRITE_FILE(S["feature_lizard_spines"] , features["spines"]) WRITE_FILE(S["feature_lizard_body_markings"] , features["body_markings"]) - WRITE_FILE(S["feature_lizard_legs"] , features["legs"]) - WRITE_FILE(S["feature_moth_wings"] , features["moth_wings"]) + WRITE_FILE(S["feature_lizard_legs"] , features["legs"]) + WRITE_FILE(S["feature_insect_wings"] , features["insect_wings"]) + WRITE_FILE(S["feature_deco_wings"] , features["deco_wings"]) + WRITE_FILE(S["feature_insect_fluff"] , features["insect_fluff"]) + WRITE_FILE(S["feature_meat"] , features["meat_type"]) //Custom names for(var/custom_name_id in GLOB.preferences_custom_names) var/savefile_slot_name = custom_name_id + "_name" //TODO remove this WRITE_FILE(S[savefile_slot_name],custom_names[custom_name_id]) - WRITE_FILE(S["preferred_ai_core_display"] , preferred_ai_core_display) - WRITE_FILE(S["prefered_security_department"] , prefered_security_department) + WRITE_FILE(S["preferred_ai_core_display"] , preferred_ai_core_display) + WRITE_FILE(S["prefered_security_department"] , prefered_security_department) //Jobs WRITE_FILE(S["joblessrole"] , joblessrole) - WRITE_FILE(S["job_civilian_high"] , job_civilian_high) - WRITE_FILE(S["job_civilian_med"] , job_civilian_med) - WRITE_FILE(S["job_civilian_low"] , job_civilian_low) - WRITE_FILE(S["job_medsci_high"] , job_medsci_high) - WRITE_FILE(S["job_medsci_med"] , job_medsci_med) - WRITE_FILE(S["job_medsci_low"] , job_medsci_low) - WRITE_FILE(S["job_engsec_high"] , job_engsec_high) - WRITE_FILE(S["job_engsec_med"] , job_engsec_med) - WRITE_FILE(S["job_engsec_low"] , job_engsec_low) + //Write prefs + WRITE_FILE(S["job_preferences"] , job_preferences) //Quirks WRITE_FILE(S["all_quirks"] , all_quirks) diff --git a/code/modules/client/verbs/looc.dm b/code/modules/client/verbs/looc.dm index 4049034203..b371372dfe 100644 --- a/code/modules/client/verbs/looc.dm +++ b/code/modules/client/verbs/looc.dm @@ -1,3 +1,6 @@ +GLOBAL_VAR_INIT(LOOC_COLOR, null)//If this is null, use the CSS for OOC. Otherwise, use a custom colour. +GLOBAL_VAR_INIT(normal_looc_colour, "#6699CC") + /client/verb/looc(msg as text) set name = "LOOC" set desc = "Local OOC, seen only by those in view." @@ -59,30 +62,17 @@ continue //Also handled later. if(C.prefs.toggles & CHAT_OOC) -// var/display_name = src.key -// if(holder) -// if(holder.fakekey) -// if(C.holder) -// display_name = "[holder.fakekey]/([src.key])" -// else -// display_name = holder.fakekey - to_chat(C,"LOOC: [src.mob.name]: [msg]") + if(GLOB.LOOC_COLOR) + to_chat(C, "LOOC: [src.mob.name]: [msg]") + else + to_chat(C, "LOOC: [src.mob.name]: [msg]") for(var/client/C in GLOB.admins) if(C.prefs.toggles & CHAT_OOC) var/prefix = "(R)LOOC" if (C.mob in heard) prefix = "LOOC" - to_chat(C,"[ADMIN_FLW(usr)][prefix]: [src.key]/[src.mob.name]: [msg]") - - /*for(var/mob/dead/observer/G in world) - if(!G.client) - continue - var/client/C = G.client - if (C in GLOB.admins) - continue //handled earlier. - if(C.prefs.toggles & CHAT_OOC) - var/prefix = "(G)LOOC" - if (C.mob in heard) - prefix = "LOOC" - to_chat(C,"[prefix]: [src.key]/[src.mob.name]: [msg]")*/ + if(GLOB.LOOC_COLOR) + to_chat(C, "[ADMIN_FLW(usr)] [prefix]: [src.key]/[src.mob.name]: [msg]") + else + to_chat(C, "[ADMIN_FLW(usr)] [prefix]: [src.key]/[src.mob.name]: [msg]") diff --git a/code/modules/clothing/chameleon.dm b/code/modules/clothing/chameleon.dm index 04a8e17b7b..33a83487fc 100644 --- a/code/modules/clothing/chameleon.dm +++ b/code/modules/clothing/chameleon.dm @@ -437,7 +437,7 @@ item_state = "gas_alt" resistance_flags = NONE armor = list("melee" = 5, "bullet" = 5, "laser" = 5, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50) - clothing_flags = BLOCK_GAS_SMOKE_EFFECT | MASKINTERNALS + clothing_flags = BLOCK_GAS_SMOKE_EFFECT | ALLOWINTERNALS flags_inv = HIDEEARS|HIDEEYES|HIDEFACE|HIDEFACIALHAIR gas_transfer_coefficient = 0.01 permeability_coefficient = 0.01 @@ -630,3 +630,27 @@ /obj/item/stamp/chameleon/broken/Initialize() . = ..() chameleon_action.emp_randomise(INFINITY) + +/obj/item/clothing/neck/cloak/chameleon + name = "black tie" + desc = "A neosilk clip-on tie." + icon_state = "blacktie" + item_color = "blacktie" + resistance_flags = NONE + armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50) + +/obj/item/clothing/neck/cloak/chameleon + var/datum/action/item_action/chameleon/change/chameleon_action + +/obj/item/clothing/neck/cloak/chameleon/Initialize() + . = ..() + chameleon_action = new(src) + chameleon_action.chameleon_type = /obj/item/clothing/neck + chameleon_action.chameleon_name = "Cloak" + chameleon_action.initialize_disguises() + +/obj/item/clothing/neck/cloak/chameleon/emp_act(severity) + . = ..() + if(. & EMP_PROTECT_SELF) + return + chameleon_action.emp_randomise() diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index ed3e9f9b89..20a8c518f4 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -41,6 +41,13 @@ var/dynamic_hair_suffix = ""//head > mask for head hair var/dynamic_fhair_suffix = ""//mask > head for facial hair + //basically a restriction list. + var/list/species_restricted = null + //Basically syntax is species_restricted = list("Species Name","Species Name") + //Add a "exclude" string to do the opposite, making it only only species listed that can't wear it. + //You append this to clothing objects. + + /obj/item/clothing/Initialize() . = ..() if(CHECK_BITFIELD(clothing_flags, VOICEBOX_TOGGLABLE)) @@ -338,3 +345,38 @@ BLIND // can't see anything deconstruct(FALSE) else ..() + + +//Species-restricted clothing check. - Thanks Oraclestation, BS13, /vg/station etc. +/obj/item/clothing/mob_can_equip(mob/M, slot, disable_warning = TRUE) + + //if we can't equip the item anyway, don't bother with species_restricted (also cuts down on spam) + if(!..()) + return FALSE + + // Skip species restriction checks on non-equipment slots + if(slot in list(SLOT_IN_BACKPACK, SLOT_L_STORE, SLOT_R_STORE)) + return TRUE + + if(species_restricted && ishuman(M)) + + var/wearable = null + var/exclusive = null + var/mob/living/carbon/human/H = M + + if("exclude" in species_restricted) //TURNS IT INTO A BLACKLIST - AKA ALL MINUS SPECIES LISTED. + exclusive = TRUE + + if(H.dna.species) + if(exclusive) + if(!(H.dna.species.name in species_restricted)) + wearable = TRUE + else + if(H.dna.species.name in species_restricted) + wearable = TRUE + + if(!wearable) + to_chat(M, "Your species cannot wear [src].") + return FALSE + + return TRUE diff --git a/code/modules/clothing/glasses/_glasses.dm b/code/modules/clothing/glasses/_glasses.dm index 097b10cae5..4928de288f 100644 --- a/code/modules/clothing/glasses/_glasses.dm +++ b/code/modules/clothing/glasses/_glasses.dm @@ -281,6 +281,33 @@ ..() user.cure_blind("blindfold_[REF(src)]") +/obj/item/clothing/glasses/sunglasses/blindfold/white + name = "blind personnel blindfold" + desc = "Indicates that the wearer suffers from blindness." + icon_state = "blindfoldwhite" + item_state = "blindfoldwhite" + var/colored_before = FALSE + +/obj/item/clothing/glasses/sunglasses/blindfold/white/equipped(mob/living/carbon/human/user, slot) + if(ishuman(user) && slot == SLOT_GLASSES) + update_icon(user) + user.update_inv_glasses() //Color might have been changed by update_icon. + ..() + +/obj/item/clothing/glasses/sunglasses/blindfold/white/update_icon(mob/living/carbon/human/user) + if(ishuman(user) && !colored_before) + add_atom_colour("#[user.eye_color]", FIXED_COLOUR_PRIORITY) + colored_before = TRUE + +/obj/item/clothing/glasses/sunglasses/blindfold/white/worn_overlays(isinhands = FALSE, file2use) + . = list() + if(!isinhands && ishuman(loc) && !colored_before) + var/mob/living/carbon/human/H = loc + var/mutable_appearance/M = mutable_appearance('icons/mob/eyes.dmi', "blindfoldwhite") + M.appearance_flags |= RESET_COLOR + M.color = "#[H.eye_color]" + . += M + /obj/item/clothing/glasses/sunglasses/big desc = "Strangely ancient technology used to help provide rudimentary eye cover. Larger than average enhanced shielding blocks flashes." icon_state = "bigsunglasses" diff --git a/code/modules/clothing/glasses/hud.dm b/code/modules/clothing/glasses/hud.dm index a87e95e28c..387aa65d20 100644 --- a/code/modules/clothing/glasses/hud.dm +++ b/code/modules/clothing/glasses/hud.dm @@ -24,11 +24,13 @@ desc = "[desc] The display is flickering slightly." /obj/item/clothing/glasses/hud/emag_act(mob/user) + . = ..() if(obj_flags & EMAGGED) return obj_flags |= EMAGGED to_chat(user, "PZZTTPFFFT") desc = "[desc] The display is flickering slightly." + return TRUE /obj/item/clothing/glasses/hud/health name = "health scanner HUD" diff --git a/code/modules/clothing/glasses/vg_glasses.dm b/code/modules/clothing/glasses/vg_glasses.dm index 449b34b22e..a51a03242c 100644 --- a/code/modules/clothing/glasses/vg_glasses.dm +++ b/code/modules/clothing/glasses/vg_glasses.dm @@ -6,21 +6,18 @@ name = "purple sunglasses" icon_state = "sun_purple" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/glasses.dmi' /obj/item/clothing/glasses/sunglasses/star name = "star-shaped sunglasses" desc = "Novelty sunglasses, both lenses are in the shape of a star." icon_state = "sun_star" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/glasses.dmi' /obj/item/clothing/glasses/sunglasses/rockstar name = "red star-shaped sunglasses" desc = "Novelty sunglasses with a fancy silver frame and two red-tinted star-shaped lenses. You should probably stomp on them and get a pair of normal ones." icon_state = "sun_star_silver" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/glasses.dmi' /obj/item/clothing/glasses/gglasses name = "Green Glasses" @@ -28,7 +25,6 @@ icon_state = "gglasses" item_state = "gglasses" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/glasses.dmi' /obj/item/clothing/glasses/welding/superior name = "superior welding goggles" @@ -36,7 +32,6 @@ icon_state = "rwelding-g" item_state = "rwelding-g" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/glasses.dmi' actions_types = list(/datum/action/item_action/toggle) flash_protect = 2 tint = 1 diff --git a/code/modules/clothing/gloves/miscellaneous.dm b/code/modules/clothing/gloves/miscellaneous.dm index bc36353ac5..cc6d65b74d 100644 --- a/code/modules/clothing/gloves/miscellaneous.dm +++ b/code/modules/clothing/gloves/miscellaneous.dm @@ -65,6 +65,9 @@ var/warcry = "AT" /obj/item/clothing/gloves/rapid/Touch(mob/living/target,proximity = TRUE) + if(!istype(target)) + return + var/mob/living/M = loc if(M.a_intent == INTENT_HARM) @@ -72,9 +75,33 @@ M.adjustStaminaLoss(-2) //Restore 2/3 of the stamina used assuming empty stam buffer. With proper stamina buffer management, this results in a net gain of +.5 stamina per click. if(warcry) M.say("[warcry]", ignore_spam = TRUE, forced = "north star warcry") + .= FALSE + /obj/item/clothing/gloves/rapid/attack_self(mob/user) var/input = stripped_input(user,"What do you want your battlecry to be? Max length of 6 characters.", ,"", 7) if(input) warcry = input + +/obj/item/clothing/gloves/rapid/hug + name = "Hugs of the North Star" + desc = "Just looking at these fills you with an urge to hug the shit out of people" + warcry = "owo" //Shouldn't ever come into play + +/obj/item/clothing/gloves/rapid/hug/Touch(mob/living/target,proximity = TRUE) + if(!istype(target)) + return + + var/mob/living/M = loc + + if(M.a_intent == INTENT_HELP) + if(target.health >= 0 && !HAS_TRAIT(target, TRAIT_FAKEDEATH)) //Can't hug people who are dying/dead + if(target.on_fire || target.lying ) //No spamming extinguishing, helping them up, or other non-hugging/patting help interactions + return + else + M.changeNext_move(CLICK_CD_RAPID) + . = FALSE + +/obj/item/clothing/gloves/rapid/hug/attack_self(mob/user) + return FALSE \ No newline at end of file diff --git a/code/modules/clothing/head/beanie.dm b/code/modules/clothing/head/beanie.dm index bbae5b261f..a5fb04d393 100644 --- a/code/modules/clothing/head/beanie.dm +++ b/code/modules/clothing/head/beanie.dm @@ -74,4 +74,13 @@ icon_state = "beaniestripedgreen" item_color = "beaniestripedgreen" +/obj/item/clothing/head/beanie/durathread + name = "durathread beanie" + desc = "A beanie made from durathread, its resilient fibres provide some protection to the wearer." + icon_state = "beaniedurathread" + item_color = null + armor = list("melee" = 25, "bullet" = 10, "laser" = 20,"energy" = 10, "bomb" = 30, "bio" = 15, "rad" = 20, "fire" = 100, "acid" = 50) + + + //No dog fashion sprites yet :( poor Ian can't be dope like the rest of us yet \ No newline at end of file diff --git a/code/modules/clothing/head/cit_hats.dm b/code/modules/clothing/head/cit_hats.dm index 7b0e68264f..df4a21d6c1 100644 --- a/code/modules/clothing/head/cit_hats.dm +++ b/code/modules/clothing/head/cit_hats.dm @@ -4,4 +4,3 @@ icon = 'modular_citadel/icons/obj/clothing/cit_hats.dmi' icon_state = "hunter" item_state = "hunter_worn" - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm index f4b4e4a96d..be6e270e45 100644 --- a/code/modules/clothing/head/helmet.dm +++ b/code/modules/clothing/head/helmet.dm @@ -336,3 +336,11 @@ for(var/X in actions) var/datum/action/A = X A.UpdateButtonIcon() + + +/obj/item/clothing/head/helmet/durathread + name = "makeshift helmet" + desc = "A hardhat with strips of leather and durathread for additional blunt protection." + icon_state = "durathread" + item_state = "durathread" + armor = list("melee" = 25, "bullet" = 10, "laser" = 20,"energy" = 10, "bomb" = 30, "bio" = 15, "rad" = 20, "fire" = 100, "acid" = 50) diff --git a/code/modules/clothing/head/jobs.dm b/code/modules/clothing/head/jobs.dm index 23e1825c3d..298510564c 100644 --- a/code/modules/clothing/head/jobs.dm +++ b/code/modules/clothing/head/jobs.dm @@ -279,6 +279,13 @@ desc = "This headwear shows off your Cargonian leadership" icon_state = "qmberet" +/obj/item/clothing/head/beret/durathread + name = "durathread beret" + desc = "A beret made from durathread, its resilient fibres provide some protection to the wearer." + icon_state = "beretdurathread" + item_color = null + armor = list("melee" = 25, "bullet" = 10, "laser" = 20,"energy" = 10, "bomb" = 30, "bio" = 15, "rad" = 20, "fire" = 100, "acid" = 50) + #undef DRILL_DEFAULT #undef DRILL_SHOUTING #undef DRILL_YELLING diff --git a/code/modules/clothing/head/misc.dm b/code/modules/clothing/head/misc.dm index 73fde5d50f..041f0ba012 100644 --- a/code/modules/clothing/head/misc.dm +++ b/code/modules/clothing/head/misc.dm @@ -312,8 +312,8 @@ /obj/item/clothing/head/pharaoh name = "pharaoh hat" desc = "Walk like an Egyptian." - icon_state = "pharoah_hat" - icon_state = "pharoah_hat" + icon_state = "pharaoh_hat" + icon_state = "pharaoh_hat" /obj/item/clothing/head/jester/alt name = "jester hat" diff --git a/code/modules/clothing/head/soft_caps.dm b/code/modules/clothing/head/soft_caps.dm index 5c7514541d..b14b0575f9 100644 --- a/code/modules/clothing/head/soft_caps.dm +++ b/code/modules/clothing/head/soft_caps.dm @@ -129,3 +129,14 @@ icon_state = "emtsoft" item_color = "emt" dog_fashion = null + +/obj/item/clothing/head/soft/baseball + name = "baseball cap" + desc = "It's a robust baseball hat, this one belongs to syndicate major league team." + icon_state = "baseballsoft" + item_color = "baseballsoft" + item_state = "baseballsoft" + flags_inv = HIDEEYES|HIDEFACE + armor = list("melee" = 35, "bullet" = 35, "laser" = 25, "energy" = 10, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 20, "acid" = 90) + strip_delay = 90 //You dont take a Major Leage cap + dog_fashion = null \ No newline at end of file diff --git a/code/modules/clothing/head/vg_hats.dm b/code/modules/clothing/head/vg_hats.dm index efeb5291db..dc245cd39a 100644 --- a/code/modules/clothing/head/vg_hats.dm +++ b/code/modules/clothing/head/vg_hats.dm @@ -1,4 +1,3 @@ - /obj/item/clothing/head/helmet/dredd name = "Judge Helmet" desc = "Judge, Jury, and Executioner." @@ -12,7 +11,6 @@ max_heat_protection_temperature = SPACE_HELM_MAX_TEMP_PROTECT strip_delay = 80 dog_fashion = null - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' /obj/item/clothing/head/helmet/aviatorhelmet name = "Aviator Helmet" @@ -21,15 +19,12 @@ item_state = "aviator_helmet" icon_state = "aviator_helmet" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' /obj/item/clothing/head/helmet/biker name = "Biker's Helmet" desc = "This helmet should protect you from russians and masked vigilantes." armor = list(melee = 25, bullet = 15, laser = 20, energy = 10, bomb = 10, bio = 0, rad = 0) icon_state = "biker_helmet" - icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR /obj/item/clothing/head/helmet/richard @@ -38,7 +33,6 @@ armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0) icon_state = "richard" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR /obj/item/clothing/head/helmet/megahelmet @@ -47,7 +41,6 @@ icon_state = "megahelmet" item_state = "megahelmet" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' siemens_coefficient = 1 /obj/item/clothing/head/helmet/protohelmet @@ -56,7 +49,6 @@ icon_state = "protohelmet" item_state = "protohelmet" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' siemens_coefficient = 1 /obj/item/clothing/head/helmet/megaxhelmet @@ -65,7 +57,6 @@ icon_state = "megaxhelmet" item_state = "megaxhelmet" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' /obj/item/clothing/head/helmet/joehelmet name = "Sniper Helmet" @@ -74,7 +65,6 @@ flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR item_state = "joehelmet" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' /obj/item/clothing/head/helmet/doomguy name = "Doomguy's helmet" @@ -83,7 +73,6 @@ flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR item_state = "doom" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' armor = list(melee = 50, bullet = 40, laser = 40,energy = 40, bomb = 5, bio = 0, rad = 0) /obj/item/clothing/head/helmet/neorussian @@ -92,8 +81,6 @@ icon_state = "nr_helmet" item_state = "nr_helmet" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' - /obj/item/clothing/head/stalhelm name = "Stalhelm" @@ -101,7 +88,6 @@ icon_state = "stalhelm" item_state = "stalhelm" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' /obj/item/clothing/head/panzer name = "Panzer Cap" @@ -109,7 +95,6 @@ icon_state = "panzercap" item_state = "panzercap" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' /obj/item/clothing/head/naziofficer name = "Officer Cap" @@ -117,8 +102,6 @@ icon_state = "officercap" item_state = "officercap" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' - /obj/item/clothing/head/russobluecamohat name = "russian blue camo beret" @@ -133,7 +116,6 @@ icon_state = "russofurhat" item_state = "russofurhat" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' /obj/item/clothing/head/squatter_hat name = "slav squatter hat" @@ -141,7 +123,6 @@ item_state = "squatter_hat" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' desc = "Cyka blyat." - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' /obj/item/clothing/head/snake name = "snake head" @@ -149,8 +130,6 @@ icon_state = "snakehead" item_state = "snakehead" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' - /obj/item/clothing/head/mummy_rags name = "mummy rags" desc = "Ancient rags taken off from some mummy." @@ -158,7 +137,6 @@ item_state = "mummy" item_color = "mummy" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' flags_inv = HIDEHAIR|HIDEFACE|HIDEEARS /obj/item/clothing/head/clownpiece @@ -167,7 +145,6 @@ icon_state = "clownpiece" item_state = "clownpiece" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' /obj/item/clothing/head/mitre name = "mitre" @@ -175,7 +152,6 @@ icon_state = "mitre" item_state = "mitre" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' /obj/item/clothing/head/tinfoil name = "tinfoil hat" @@ -183,7 +159,6 @@ icon_state = "foilhat" item_state = "paper" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' siemens_coefficient = 2 /obj/item/clothing/head/celtic @@ -192,4 +167,3 @@ icon_state = "celtic_crown" item_state = "celtic_crown" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' diff --git a/code/modules/clothing/masks/breath.dm b/code/modules/clothing/masks/breath.dm index ed0ef27174..947aa048c4 100644 --- a/code/modules/clothing/masks/breath.dm +++ b/code/modules/clothing/masks/breath.dm @@ -4,8 +4,8 @@ icon_state = "breath" item_state = "m_mask" body_parts_covered = 0 - clothing_flags = MASKINTERNALS - visor_flags = MASKINTERNALS + clothing_flags = ALLOWINTERNALS + visor_flags = ALLOWINTERNALS w_class = WEIGHT_CLASS_SMALL gas_transfer_coefficient = 0.1 permeability_coefficient = 0.5 diff --git a/code/modules/clothing/masks/gasmask.dm b/code/modules/clothing/masks/gasmask.dm index bcf3064c49..c613d1a91e 100644 --- a/code/modules/clothing/masks/gasmask.dm +++ b/code/modules/clothing/masks/gasmask.dm @@ -2,7 +2,7 @@ name = "gas mask" desc = "A face-covering mask that can be connected to an air supply. While good for concealing your identity, it isn't good for blocking gas flow." //More accurate icon_state = "gas_alt" - clothing_flags = BLOCK_GAS_SMOKE_EFFECT | MASKINTERNALS + clothing_flags = BLOCK_GAS_SMOKE_EFFECT | ALLOWINTERNALS flags_inv = HIDEEARS|HIDEEYES|HIDEFACE|HIDEFACIALHAIR|HIDESNOUT w_class = WEIGHT_CLASS_NORMAL item_state = "gas_alt" @@ -59,7 +59,7 @@ /obj/item/clothing/mask/gas/clown_hat name = "clown wig and mask" desc = "A true prankster's facial attire. A clown is incomplete without his wig and mask." - clothing_flags = MASKINTERNALS + clothing_flags = ALLOWINTERNALS icon_state = "clown" item_state = "clown_hat" flags_cover = MASKCOVERSEYES @@ -91,7 +91,7 @@ /obj/item/clothing/mask/gas/sexyclown name = "sexy-clown wig and mask" desc = "A feminine clown mask for the dabbling crossdressers or female entertainers." - clothing_flags = MASKINTERNALS + clothing_flags = ALLOWINTERNALS icon_state = "sexyclown" item_state = "sexyclown" flags_cover = MASKCOVERSEYES @@ -100,7 +100,7 @@ /obj/item/clothing/mask/gas/mime name = "mime mask" desc = "The traditional mime's mask. It has an eerie facial posture." - clothing_flags = MASKINTERNALS + clothing_flags = ALLOWINTERNALS icon_state = "mime" item_state = "mime" flags_cover = MASKCOVERSEYES @@ -132,7 +132,7 @@ /obj/item/clothing/mask/gas/monkeymask name = "monkey mask" desc = "A mask used when acting as a monkey." - clothing_flags = MASKINTERNALS + clothing_flags = ALLOWINTERNALS icon_state = "monkeymask" item_state = "monkeymask" flags_cover = MASKCOVERSEYES @@ -141,7 +141,7 @@ /obj/item/clothing/mask/gas/sexymime name = "sexy mime mask" desc = "A traditional female mime's mask." - clothing_flags = MASKINTERNALS + clothing_flags = ALLOWINTERNALS icon_state = "sexymime" item_state = "sexymime" flags_cover = MASKCOVERSEYES @@ -162,7 +162,7 @@ name = "owl mask" desc = "Twoooo!" icon_state = "owl" - clothing_flags = MASKINTERNALS + clothing_flags = ALLOWINTERNALS flags_cover = MASKCOVERSEYES resistance_flags = FLAMMABLE diff --git a/code/modules/clothing/masks/hailer.dm b/code/modules/clothing/masks/hailer.dm index 8860650fbc..086d47e8bf 100644 --- a/code/modules/clothing/masks/hailer.dm +++ b/code/modules/clothing/masks/hailer.dm @@ -7,10 +7,10 @@ actions_types = list(/datum/action/item_action/halt, /datum/action/item_action/adjust) icon_state = "sechailer" item_state = "sechailer" - clothing_flags = BLOCK_GAS_SMOKE_EFFECT | MASKINTERNALS + clothing_flags = BLOCK_GAS_SMOKE_EFFECT | ALLOWINTERNALS flags_inv = HIDEFACIALHAIR|HIDEFACE w_class = WEIGHT_CLASS_SMALL - visor_flags = BLOCK_GAS_SMOKE_EFFECT | MASKINTERNALS + visor_flags = BLOCK_GAS_SMOKE_EFFECT | ALLOWINTERNALS visor_flags_inv = HIDEFACE flags_cover = MASKCOVERSMOUTH visor_flags_cover = MASKCOVERSMOUTH @@ -69,12 +69,14 @@ /obj/item/clothing/mask/gas/sechailer/attack_self() halt() -/obj/item/clothing/mask/gas/sechailer/emag_act(mob/user as mob) - if(safety) - safety = FALSE - to_chat(user, "You silently fry [src]'s vocal circuit with the cryptographic sequencer.") - else + +/obj/item/clothing/mask/gas/sechailer/emag_act(mob/user) + . = ..() + if(!safety) return + safety = FALSE + to_chat(user, "You silently fry [src]'s vocal circuit with the cryptographic sequencer.") + return TRUE /obj/item/clothing/mask/gas/sechailer/verb/halt() set category = "Object" diff --git a/code/modules/clothing/masks/miscellaneous.dm b/code/modules/clothing/masks/miscellaneous.dm index 5dfa7d6047..4b8f16a77f 100644 --- a/code/modules/clothing/masks/miscellaneous.dm +++ b/code/modules/clothing/masks/miscellaneous.dm @@ -313,3 +313,9 @@ message = replacetextEx(message,regex(capitalize(key),"g"), "[capitalize(value)]") message = replacetextEx(message,regex(key,"g"), "[value]") speech_args[SPEECH_MESSAGE] = trim(message) + +/obj/item/clothing/mask/bandana/durathread + name = "durathread bandana" + desc = "A bandana made from durathread, you wish it would provide some protection to its wearer, but it's far too thin..." + icon_state = "banddurathread" + diff --git a/code/modules/clothing/masks/vg_masks.dm b/code/modules/clothing/masks/vg_masks.dm index 7de27fb780..29b65a6b8e 100644 --- a/code/modules/clothing/masks/vg_masks.dm +++ b/code/modules/clothing/masks/vg_masks.dm @@ -3,18 +3,15 @@ desc = "Some pranksters are truly magical." icon_state = "wizzclown" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/masks.dmi' /obj/item/clothing/mask/chapmask name = "venetian mask" desc = "A plain porcelain mask that covers the entire face. Standard attire for particularly unspeakable religions. The eyes are wide shut." icon_state = "chapmask" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/masks.dmi' /obj/item/clothing/mask/neorussian name = "neo-Russian mask" desc = "Somehow, it makes you act and look way more polite than usual." icon_state = "nr_mask" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/masks.dmi' diff --git a/code/modules/clothing/outfits/ert.dm b/code/modules/clothing/outfits/ert.dm index b4310a7f42..88cc7123fd 100644 --- a/code/modules/clothing/outfits/ert.dm +++ b/code/modules/clothing/outfits/ert.dm @@ -10,7 +10,7 @@ if(visualsOnly) return - var/obj/item/implant/mindshield/L = new/obj/item/implant/mindshield(H) + var/obj/item/implant/mindshield/L = new L.implant(H, null, 1) var/obj/item/radio/R = H.ears @@ -45,16 +45,23 @@ R.recalculateChannels() /datum/outfit/ert/commander/alert - name = "ERT Commander - High Alert" + name = "ERT Commander - Amber Alert" suit = /obj/item/clothing/suit/space/hardsuit/ert/alert glasses = /obj/item/clothing/glasses/thermal/eyepatch backpack_contents = list(/obj/item/storage/box/engineer=1,\ /obj/item/melee/baton/loaded=1,\ /obj/item/clothing/mask/gas/sechailer/swat=1,\ - /obj/item/gun/energy/pulse/pistol/loyalpin=1) + /obj/item/gun/energy/e_gun=1) l_pocket = /obj/item/melee/transforming/energy/sword/saber +/datum/outfit/ert/commander/alert/red + name = "ERT Commander - Red Alert" + backpack_contents = list(/obj/item/storage/box/engineer=1,\ + /obj/item/melee/baton/loaded=1,\ + /obj/item/clothing/mask/gas/sechailer/swat=1,\ + /obj/item/gun/energy/pulse/pistol/loyalpin=1) + /datum/outfit/ert/security name = "ERT Security" @@ -80,15 +87,22 @@ R.recalculateChannels() /datum/outfit/ert/security/alert - name = "ERT Security - High Alert" + name = "ERT Security - Amber Alert" suit = /obj/item/clothing/suit/space/hardsuit/ert/alert/sec backpack_contents = list(/obj/item/storage/box/engineer=1,\ /obj/item/storage/box/handcuffs=1,\ /obj/item/clothing/mask/gas/sechailer/swat=1,\ /obj/item/melee/baton/loaded=1,\ - /obj/item/gun/energy/pulse/carbine/loyalpin=1) + /obj/item/gun/energy/e_gun/stun=1) +/datum/outfit/ert/security/alert/red + name = "ERT Security - Red Alert" + backpack_contents = list(/obj/item/storage/box/engineer=1,\ + /obj/item/storage/box/handcuffs=1,\ + /obj/item/clothing/mask/gas/sechailer/swat=1,\ + /obj/item/melee/baton/loaded=1,\ + /obj/item/gun/energy/pulse/carbine/loyalpin=1) /datum/outfit/ert/medic name = "ERT Medic" @@ -117,9 +131,18 @@ R.recalculateChannels() /datum/outfit/ert/medic/alert - name = "ERT Medic - High Alert" + name = "ERT Medic - Amber Alert" suit = /obj/item/clothing/suit/space/hardsuit/ert/alert/med + backpack_contents = list(/obj/item/storage/box/engineer=1,\ + /obj/item/melee/baton/loaded=1,\ + /obj/item/clothing/mask/gas/sechailer/swat=1,\ + /obj/item/gun/energy/e_gun=1,\ + /obj/item/reagent_containers/hypospray/combat/nanites=1,\ + /obj/item/gun/medbeam=1) + +/datum/outfit/ert/medic/alert/red + name = "ERT Medic - Red Alert" backpack_contents = list(/obj/item/storage/box/engineer=1,\ /obj/item/melee/baton/loaded=1,\ /obj/item/clothing/mask/gas/sechailer/swat=1,\ @@ -154,15 +177,51 @@ R.recalculateChannels() /datum/outfit/ert/engineer/alert - name = "ERT Engineer - High Alert" + name = "ERT Engineer - Amber Alert" suit = /obj/item/clothing/suit/space/hardsuit/ert/alert/engi + backpack_contents = list(/obj/item/storage/box/engineer=1,\ + /obj/item/melee/baton/loaded=1,\ + /obj/item/clothing/mask/gas/sechailer/swat=1,\ + /obj/item/gun/energy/e_gun=1,\ + /obj/item/construction/rcd/combat=1) + +/datum/outfit/ert/engineer/alert/red + name = "ERT Engineer - Red Alert" backpack_contents = list(/obj/item/storage/box/engineer=1,\ /obj/item/melee/baton/loaded=1,\ /obj/item/clothing/mask/gas/sechailer/swat=1,\ /obj/item/gun/energy/pulse/pistol/loyalpin=1,\ /obj/item/construction/rcd/combat=1) +/datum/outfit/ert/greybois + name = "Emergency Assistant" + + uniform = /obj/item/clothing/under/color/grey/glorf + shoes = /obj/item/clothing/shoes/sneakers/black + gloves = /obj/item/clothing/gloves/color/fyellow + ears = /obj/item/radio/headset + head = /obj/item/clothing/head/soft/grey + belt = /obj/item/storage/belt/utility/full + back = /obj/item/storage/backpack + mask = /obj/item/clothing/mask/gas + l_pocket = /obj/item/tank/internals/emergency_oxygen + l_hand = /obj/item/storage/toolbox/emergency/old + id = /obj/item/card/id + +/datum/outfit/ert/greybois/greygod + suit = /obj/item/clothing/suit/hazardvest + l_hand = /obj/item/storage/toolbox/plastitanium + gloves = /obj/item/clothing/gloves/color/yellow + +/datum/outfit/ert/greybois/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) + if(visualsOnly) + return + var/obj/item/card/id/W = H.wear_id + W.registered_name = H.real_name + W.assignment = "Assistant" + W.access = list(ACCESS_MAINT_TUNNELS,ACCESS_CENT_GENERAL) + W.update_label(W.registered_name, W.assignment) /datum/outfit/centcom_official name = "CentCom Official" diff --git a/code/modules/clothing/outfits/plasmaman.dm b/code/modules/clothing/outfits/plasmaman.dm new file mode 100644 index 0000000000..20b67891d8 --- /dev/null +++ b/code/modules/clothing/outfits/plasmaman.dm @@ -0,0 +1,164 @@ +/datum/outfit/plasmaman/bar + name = "Bartender Plasmaman" + + head = /obj/item/clothing/head/helmet/space/plasmaman/white + uniform = /obj/item/clothing/under/plasmaman/enviroslacks + +/datum/outfit/plasmaman/chef + name = "Chef Plasmaman" + + head = /obj/item/clothing/head/helmet/space/plasmaman/white + uniform = /obj/item/clothing/under/plasmaman/chef + +/datum/outfit/plasmaman/botany + name = "Botany Plasmaman" + + head = /obj/item/clothing/head/helmet/space/plasmaman/botany + uniform = /obj/item/clothing/under/plasmaman/botany + +/datum/outfit/plasmaman/curator + name = "Curator Plasmaman" + + head = /obj/item/clothing/head/helmet/space/plasmaman/curator + uniform = /obj/item/clothing/under/plasmaman/curator + +/datum/outfit/plasmaman/chaplain + name = "Chaplain Plasmaman" + + head = /obj/item/clothing/head/helmet/space/plasmaman/chaplain + uniform = /obj/item/clothing/under/plasmaman/chaplain + +/datum/outfit/plasmaman/janitor + name = "Janitor Plasmaman" + + head = /obj/item/clothing/head/helmet/space/plasmaman/janitor + uniform = /obj/item/clothing/under/plasmaman/janitor + +/datum/outfit/plasmaman/hop + name = "Head of Personell Plasmaman" + + head = /obj/item/clothing/head/helmet/space/plasmaman/hop + uniform = /obj/item/clothing/under/plasmaman/hop + +/datum/outfit/plasmaman/captain + name = "Captain Plasmaman" + + head = /obj/item/clothing/head/helmet/space/plasmaman/captain + uniform = /obj/item/clothing/under/plasmaman/captain + +/datum/outfit/plasmaman/security + name = "Security Plasmaman" + + head = /obj/item/clothing/head/helmet/space/plasmaman/security + uniform = /obj/item/clothing/under/plasmaman/security + ears = /obj/item/radio/headset/headset_sec + +/datum/outfit/plasmaman/detective + name = "Detective Plasmaman" + + head = /obj/item/clothing/head/helmet/space/plasmaman/white + uniform = /obj/item/clothing/under/plasmaman/enviroslacks + +/datum/outfit/plasmaman/warden + name = "Warden Plasmaman" + + head = /obj/item/clothing/head/helmet/space/plasmaman/security/warden + uniform = /obj/item/clothing/under/plasmaman/security/warden + +/datum/outfit/plasmaman/hos + name = "Head of Security Plasmaman" + + head = /obj/item/clothing/head/helmet/space/plasmaman/security/hos + uniform = /obj/item/clothing/under/plasmaman/security/hos + +/datum/outfit/plasmaman/cargo + name = "Cargo Plasmaman" + + head = /obj/item/clothing/head/helmet/space/plasmaman/cargo + uniform = /obj/item/clothing/under/plasmaman/cargo + +/datum/outfit/plasmaman/mining + name = "Mining Plasmaman" + + head = /obj/item/clothing/head/helmet/space/plasmaman/mining + uniform = /obj/item/clothing/under/plasmaman/mining + +/datum/outfit/plasmaman/medical + name = "Medical Plasmaman" + + head = /obj/item/clothing/head/helmet/space/plasmaman/medical + uniform = /obj/item/clothing/under/plasmaman/medical + +/datum/outfit/plasmaman/cmo + name = "Chief Medical Officer Plasmaman" + + head = /obj/item/clothing/head/helmet/space/plasmaman/cmo + uniform = /obj/item/clothing/under/plasmaman/cmo + +/datum/outfit/plasmaman/viro + name = "Virology Plasmaman" + + head = /obj/item/clothing/head/helmet/space/plasmaman/viro + uniform = /obj/item/clothing/under/plasmaman/viro + +/datum/outfit/plasmaman/chemist + name = "Chemist Plasmaman" + + head = /obj/item/clothing/head/helmet/space/plasmaman/chemist + uniform = /obj/item/clothing/under/plasmaman/chemist + +/datum/outfit/plasmaman/genetics + name = "Genetics Plasmaman" + + head = /obj/item/clothing/head/helmet/space/plasmaman/genetics + uniform = /obj/item/clothing/under/plasmaman/genetics + +/datum/outfit/plasmaman/science + name = "Science Plasmaman" + + head = /obj/item/clothing/head/helmet/space/plasmaman/science + uniform = /obj/item/clothing/under/plasmaman/science + +/datum/outfit/plasmaman/rd + name = "Research Director Plasmaman" + + head = /obj/item/clothing/head/helmet/space/plasmaman/rd + uniform = /obj/item/clothing/under/plasmaman/rd + +/datum/outfit/plasmaman/robotics + name = "Robotics Plasmaman" + + head = /obj/item/clothing/head/helmet/space/plasmaman/robotics + uniform = /obj/item/clothing/under/plasmaman/robotics + +/datum/outfit/plasmaman/engineering + name = "Engineering Plasmaman" + + head = /obj/item/clothing/head/helmet/space/plasmaman/engineering + uniform = /obj/item/clothing/under/plasmaman/engineering + +/datum/outfit/plasmaman/ce + name = "Chief Engineer Plasmaman" + + head = /obj/item/clothing/head/helmet/space/plasmaman/engineering/ce + uniform = /obj/item/clothing/under/plasmaman/engineering/ce + +/datum/outfit/plasmaman/atmospherics + name = "Atmospherics Plasmaman" + + head = /obj/item/clothing/head/helmet/space/plasmaman/atmospherics + uniform = /obj/item/clothing/under/plasmaman/atmospherics + +/datum/outfit/plasmaman/mime + name = "Plasmamime" + + head = /obj/item/clothing/head/helmet/space/plasmaman/mime + uniform = /obj/item/clothing/under/plasmaman/mime + mask = /obj/item/clothing/mask/gas/mime + +/datum/outfit/plasmaman/clown + name = "Plasmaclown" + + head = /obj/item/clothing/head/helmet/space/plasmaman/clown + uniform = /obj/item/clothing/under/plasmaman/clown + mask = /obj/item/clothing/mask/gas/clown_hat \ No newline at end of file diff --git a/code/modules/clothing/outfits/standard.dm b/code/modules/clothing/outfits/standard.dm index 325c124867..6c961dc250 100644 --- a/code/modules/clothing/outfits/standard.dm +++ b/code/modules/clothing/outfits/standard.dm @@ -399,7 +399,7 @@ R.set_frequency(FREQ_CENTCOM) R.freqlock = TRUE - var/obj/item/implant/mindshield/L = new/obj/item/implant/mindshield(H)//Here you go Deuryn + var/obj/item/implant/mindshield/L = new //Here you go Deuryn L.implant(H, null, 1) @@ -426,7 +426,7 @@ /datum/outfit/debug //Debug objs plus hardsuit name = "Debug outfit" - uniform = /obj/item/clothing/under/patriotsuit + uniform = /obj/item/clothing/under/patriotsuit suit = /obj/item/clothing/suit/space/hardsuit/syndi/elite shoes = /obj/item/clothing/shoes/magboots/advance suit_store = /obj/item/tank/internals/oxygen diff --git a/code/modules/clothing/outfits/vr.dm b/code/modules/clothing/outfits/vr.dm index cd8930641f..cd8115ac7d 100644 --- a/code/modules/clothing/outfits/vr.dm +++ b/code/modules/clothing/outfits/vr.dm @@ -29,9 +29,9 @@ . = ..() var/obj/item/uplink/U = new /obj/item/uplink/nuclear_restricted(H, H.key, 80) H.equip_to_slot_or_del(U, SLOT_IN_BACKPACK) - var/obj/item/implant/weapons_auth/W = new/obj/item/implant/weapons_auth(H) + var/obj/item/implant/weapons_auth/W = new W.implant(H) - var/obj/item/implant/explosive/E = new/obj/item/implant/explosive(H) + var/obj/item/implant/explosive/E = new E.implant(H) H.faction |= ROLE_SYNDICATE H.update_icons() diff --git a/code/modules/clothing/shoes/miscellaneous.dm b/code/modules/clothing/shoes/miscellaneous.dm index e6554f6125..080d9281cf 100644 --- a/code/modules/clothing/shoes/miscellaneous.dm +++ b/code/modules/clothing/shoes/miscellaneous.dm @@ -62,6 +62,16 @@ desc = "A pair of orange rubber boots, designed to prevent slipping on wet surfaces while also drying them." icon_state = "galoshes_dry" +/obj/item/clothing/shoes/sneakers/noslip + desc = "A pair of black shoes, they have the soles of galoshes making them unable to be slipped on a wet surface." + name = "black shoes" + icon_state = "black" + permeability_coefficient = 0.30 + clothing_flags = NOSLIP + strip_delay = 50 + equip_delay_other = 50 + resistance_flags = NONE + /obj/item/clothing/shoes/galoshes/dry/step_action() var/turf/open/t_loc = get_turf(src) SEND_SIGNAL(t_loc, COMSIG_TURF_MAKE_DRY, TURF_WET_WATER, TRUE, INFINITY) @@ -69,10 +79,8 @@ /obj/item/clothing/shoes/clown_shoes desc = "The prankster's standard-issue clowning shoes. Damn, they're huge!" name = "clown shoes" - icon_state = "clown" - item_state = "clown_shoes" + icon_state = "clown_shoes" slowdown = SHOES_SLOWDOWN+1 - item_color = "clown" pocket_storage_component_path = /datum/component/storage/concrete/pockets/shoes/clown /obj/item/clothing/shoes/clown_shoes/Initialize() @@ -98,7 +106,6 @@ name = "jackboots" desc = "Nanotrasen-issue Security combat boots for combat scenarios or combat situations. All combat, all the time." icon_state = "jackboots" - item_state = "jackboots" lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi' item_color = "hosred" @@ -115,7 +122,6 @@ name = "winter boots" desc = "Boots lined with 'synthetic' animal fur." icon_state = "winterboots" - item_state = "winterboots" permeability_coefficient = 0.15 cold_protection = FEET|LEGS min_cold_protection_temperature = SHOES_MIN_TEMP_PROTECT @@ -127,7 +133,6 @@ name = "work boots" desc = "Nanotrasen-issue Engineering lace-up work boots for the especially blue-collar." icon_state = "workboots" - item_state = "jackboots" lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi' permeability_coefficient = 0.15 @@ -145,7 +150,6 @@ name = "\improper Nar'Sien invoker boots" desc = "A pair of boots worn by the followers of Nar'Sie." icon_state = "cult" - item_state = "cult" item_color = "cult" cold_protection = FEET min_cold_protection_temperature = SHOES_MIN_TEMP_PROTECT @@ -178,7 +182,6 @@ name = "roman sandals" desc = "Sandals with buckled leather straps on it." icon_state = "roman" - item_state = "roman" strip_delay = 100 equip_delay_other = 100 permeability_coefficient = 0.9 @@ -187,14 +190,12 @@ name = "griffon boots" desc = "A pair of costume boots fashioned after bird talons." icon_state = "griffinboots" - item_state = "griffinboots" pocket_storage_component_path = /datum/component/storage/concrete/pockets/shoes /obj/item/clothing/shoes/bhop name = "jump boots" desc = "A specialized pair of combat boots with a built-in propulsion system for rapid foward movement." icon_state = "jetboots" - item_state = "jetboots" item_color = "hosred" resistance_flags = FIRE_PROOF pocket_storage_component_path = /datum/component/storage/concrete/pockets/shoes @@ -219,17 +220,13 @@ var/atom/target = get_edge_target_turf(user, user.dir) //gets the user's direction - if (user.throw_at(target, jumpdistance, jumpspeed, spin = FALSE, diagonals_first = TRUE, callback = CALLBACK(src, .proc/hop_end))) - jumping = TRUE + if (user.throw_at(target, jumpdistance, jumpspeed, spin = FALSE, diagonals_first = TRUE)) playsound(src, 'sound/effects/stealthoff.ogg', 50, 1, 1) + recharging_time = world.time + recharging_rate user.visible_message("[usr] dashes forward into the air!") else to_chat(user, "Something prevents you from dashing forward!") -/obj/item/clothing/shoes/bhop/proc/hop_end() - jumping = FALSE - recharging_time = world.time + recharging_rate - /obj/item/clothing/shoes/singery name = "yellow performer's boots" desc = "These boots were made for dancing." @@ -256,7 +253,6 @@ name = "Wheely-Heels" desc = "Uses patented retractable wheel technology. Never sacrifice speed for style - not that this provides much of either." //Thanks Fel icon_state = "wheelys" - item_state = "wheelys" actions_types = list(/datum/action/item_action/wheelys) var/wheelToggle = FALSE //False means wheels are not popped out var/obj/vehicle/ridden/scooter/wheelys/W @@ -295,7 +291,6 @@ name = "Kindle Kicks" desc = "They'll sure kindle something in you, and it's not childhood nostalgia..." icon_state = "kindleKicks" - item_state = "kindleKicks" actions_types = list(/datum/action/item_action/kindleKicks) var/lightCycle = 0 var/active = FALSE @@ -316,3 +311,25 @@ set_light(0) lightCycle = 0 active = FALSE + +// kevin is into feet +/obj/item/clothing/shoes/wraps + name = "gilded leg wraps" + desc = "Ankle coverings. These ones have a golden design." + icon_state = "gildedcuffs" + body_parts_covered = FALSE + +/obj/item/clothing/shoes/wraps/silver + name = "silver leg wraps" + desc = "Ankle coverings. Not made of real silver." + icon_state = "silvergildedcuffs" + +/obj/item/clothing/shoes/wraps/red + name = "red leg wraps" + desc = "Ankle coverings. Show off your style with these shiny red ones!" + icon_state = "redcuffs" + +/obj/item/clothing/shoes/wraps/blue + name = "blue leg wraps" + desc = "Ankle coverings. Hang ten, brother." + icon_state = "bluecuffs" \ No newline at end of file diff --git a/code/modules/clothing/shoes/vg_shoes.dm b/code/modules/clothing/shoes/vg_shoes.dm index 931c25b823..627a061181 100644 --- a/code/modules/clothing/shoes/vg_shoes.dm +++ b/code/modules/clothing/shoes/vg_shoes.dm @@ -5,7 +5,6 @@ icon_state = "leather" item_color = "leather" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/shoes/magboots/deathsquad @@ -14,7 +13,6 @@ icon_state = "DS-magboots0" magboot_state = "DS-magboots" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF mutantrace_variation = NO_MUTANTRACE_VARIATION @@ -23,7 +21,6 @@ name = "atmospherics magboots" icon_state = "atmosmagboots0" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' magboot_state = "atmosmagboots" resistance_flags = FIRE_PROOF mutantrace_variation = NO_MUTANTRACE_VARIATION @@ -33,7 +30,6 @@ desc = "Simon's Shoes." icon_state = "simonshoes" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/shoes/kneesocks @@ -41,7 +37,6 @@ desc = "A pair of girly knee-high socks." icon_state = "kneesock" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/shoes/jestershoes @@ -49,7 +44,6 @@ desc = "As worn by the clowns of old." icon_state = "jestershoes" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/shoes/aviatorboots @@ -57,7 +51,6 @@ desc = "Boots suitable for just about any occasion." icon_state = "aviator_boots" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/shoes/libertyshoes @@ -65,7 +58,6 @@ desc = "Freedom isn't free, neither were these shoes." icon_state = "libertyshoes" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/shoes/megaboots @@ -73,7 +65,6 @@ desc = "Large armored boots, very weak to large spikes." icon_state = "megaboots" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/shoes/protoboots @@ -81,7 +72,6 @@ desc = "Functionally identical to the DRN-001 model's boots, but in red." icon_state = "protoboots" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/shoes/megaxboots @@ -89,7 +79,6 @@ desc = "Regardless of how much stronger these boots are than the DRN-001 model's, they're still extremely easy to pierce with a large spike." icon_state = "megaxboots" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/shoes/joeboots @@ -97,7 +86,6 @@ desc = "Nearly identical to the Prototype's boots, except in black." icon_state = "joeboots" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/shoes/doomguy @@ -105,7 +93,6 @@ desc = "If you look closely, you might see skull fragments still buried in these boots." icon_state = "doom" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/shoes/rottenshoes @@ -113,7 +100,6 @@ desc = "These shoes seem perfect for sneaking around." icon_state = "rottenshoes" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/shoes/sandal/slippers @@ -121,7 +107,6 @@ icon_state = "slippers" desc = "For the wizard that puts comfort first. Who's going to laugh?" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/shoes/slippers_worn @@ -129,7 +114,6 @@ desc = "Fluffy..." icon_state = "slippers_worn" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/shoes/jackboots/neorussian @@ -137,5 +121,4 @@ desc = "Tovarish, no one will realize you stepped on a pile of shit if your pair already looks like shit." icon_state = "nr_boots" icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' - alternate_worn_icon = 'modular_citadel/icons/mob/citadel/head.dmi' mutantrace_variation = NO_MUTANTRACE_VARIATION \ No newline at end of file diff --git a/code/modules/clothing/spacesuits/_spacesuits.dm b/code/modules/clothing/spacesuits/_spacesuits.dm index 9d3918ed84..57866b5131 100644 --- a/code/modules/clothing/spacesuits/_spacesuits.dm +++ b/code/modules/clothing/spacesuits/_spacesuits.dm @@ -4,7 +4,7 @@ name = "space helmet" icon_state = "spaceold" desc = "A special helmet with solar UV shielding to protect your eyes from harmful rays." - clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL + clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL | BLOCK_GAS_SMOKE_EFFECT | ALLOWINTERNALS item_state = "spaceold" permeability_coefficient = 0.01 armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 100, "rad" = 50, "fire" = 80, "acid" = 70) @@ -22,6 +22,7 @@ resistance_flags = NONE dog_fashion = null mutantrace_variation = MUTANTRACE_VARIATION + rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE /obj/item/clothing/suit/space name = "space suit" @@ -44,4 +45,5 @@ strip_delay = 80 equip_delay_other = 80 resistance_flags = NONE + rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE //rated for cosmic radation :honk: tauric = TRUE //Citadel Add for tauric hardsuits diff --git a/code/modules/clothing/spacesuits/hardsuit.dm b/code/modules/clothing/spacesuits/hardsuit.dm index 85503c720a..2694497579 100644 --- a/code/modules/clothing/spacesuits/hardsuit.dm +++ b/code/modules/clothing/spacesuits/hardsuit.dm @@ -624,19 +624,19 @@ desc = "The Multi-Augmented Severe Operations Networked Resource Integration Gear is an man-portable tank designed for extreme environmental situations. It is excessively bulky, but rated for all but the most atomic of hazards. The specialized armor is surprisingly weak to conventional weaponry. The exo slot can attach most storge bags on to the suit." icon_state = "hardsuit-ancient" item_state = "anc_hardsuit" - armor = list("melee" = 10, "bullet" = 5, "laser" = 5, "energy" = 500, "bomb" = 500, "bio" = 500, "rad" = 500, "fire" = 500, "acid" = 500) + armor = list("melee" = 20, "bullet" = 15, "laser" = 15, "energy" = 45, "bomb" = 100, "bio" = 100, "rad" = 100, "fire" = 100, "acid" = 100) slowdown = 6 //Slow allowed = list(/obj/item/flashlight, /obj/item/tank/internals, /obj/item/storage, /obj/item/construction/rcd, /obj/item/pipe_dispenser) helmettype = /obj/item/clothing/head/helmet/space/hardsuit/ancient/mason max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT - resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF + resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF /obj/item/clothing/head/helmet/space/hardsuit/ancient/mason name = "M.A.S.O.N RIG helmet" desc = "The M.A.S.O.N RIG helmet is complimentary to the rest of the armor. It features a very large, high powered flood lamp and robust flash protection." icon_state = "hardsuit0-ancient" item_state = "anc_helm" - armor = list("melee" = 10, "bullet" = 5, "laser" = 5, "energy" = 500, "bomb" = 500, "bio" = 500, "rad" = 500, "fire" = 500, "acid" = 500) + armor = list("melee" = 20, "bullet" = 15, "laser" = 15, "energy" = 45, "bomb" = 100, "bio" = 100, "rad" = 100, "fire" = 100, "acid" = 100) item_color = "ancient" brightness_on = 16 scan_reagents = TRUE @@ -644,7 +644,7 @@ tint = 1 var/obj/machinery/doppler_array/integrated/bomb_radar max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT - resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF + resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF /obj/item/clothing/head/helmet/space/hardsuit/ancient/mason/Initialize() . = ..() diff --git a/code/modules/clothing/spacesuits/plasmamen.dm b/code/modules/clothing/spacesuits/plasmamen.dm index d1ee88d5a8..0b07aafa5d 100644 --- a/code/modules/clothing/spacesuits/plasmamen.dm +++ b/code/modules/clothing/spacesuits/plasmamen.dm @@ -12,7 +12,7 @@ var/next_extinguish = 0 var/extinguish_cooldown = 100 var/extinguishes_left = 10 - + mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/suit/space/eva/plasmaman/examine(mob/user) ..() @@ -45,12 +45,18 @@ resistance_flags = FIRE_PROOF var/brightness_on = 4 //luminosity when the light is on var/on = FALSE + var/light_overlay = "envirohelm-light" actions_types = list(/datum/action/item_action/toggle_helmet_light) + mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/head/helmet/space/plasmaman/attack_self(mob/user) + if(!light_overlay) + return on = !on - icon_state = "[initial(icon_state)][on ? "-light":""]" - item_state = icon_state + if(!on) + cut_overlay(light_overlay) + else + add_overlay(light_overlay) user.update_inv_head() //So the mob overlay updates if(on) @@ -61,3 +67,166 @@ for(var/X in actions) var/datum/action/A=X A.UpdateButtonIcon() + +/obj/item/clothing/head/helmet/space/plasmaman/worn_overlays(isinhands, icon_file) + . = ..() + if(!isinhands && on) + . += mutable_appearance(icon_file, light_overlay) + +/obj/item/clothing/head/helmet/space/plasmaman/security + name = "security plasma envirosuit helmet" + desc = "A plasmaman containment helmet designed for security officers, protecting them from being flashed and burning alive, along-side other undesirables." + icon_state = "security_envirohelm" + item_state = "security_envirohelm" + armor = list("melee" = 10, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 100, "rad" = 0, "fire" = 100, "acid" = 75) + +/obj/item/clothing/head/helmet/space/plasmaman/security/warden + name = "warden's plasma envirosuit helmet" + desc = "A plasmaman containment helmet designed for the warden, a pair of white stripes being added to differeciate them from other members of security." + icon_state = "warden_envirohelm" + item_state = "warden_envirohelm" + +/obj/item/clothing/head/helmet/space/plasmaman/security/hos + name = "head of security's plasma envirosuit helmet" + desc = "A plasmaman containment helmet designed for the head of security, manacing black with red stripes, to differenciate them from other members of security." + icon_state = "hos_envirohelm" + item_state = "hos_envirohelm" + +/obj/item/clothing/head/helmet/space/plasmaman/medical + name = "medical's plasma envirosuit helmet" + desc = "An envriohelmet designed for plasmaman medical doctors, having two stripes down it's length to denote as much." + icon_state = "doctor_envirohelm" + item_state = "doctor_envirohelm" + +/obj/item/clothing/head/helmet/space/plasmaman/cmo + name = "chief medical officer's plasma envirosuit helmet" + desc = "A blue and white envriohelmet designed for the chief medical officer." + icon_state = "cmo_envirohelm" + item_state = "cmo_envirohelm" + +/obj/item/clothing/head/helmet/space/plasmaman/genetics + name = "geneticist's plasma envirosuit helmet" + desc = "A plasmaman envirohelmet designed for geneticists." + icon_state = "geneticist_envirohelm" + item_state = "geneticist_envirohelm" + +/obj/item/clothing/head/helmet/space/plasmaman/viro + name = "virology plasma envirosuit helmet" + desc = "The helmet worn by the safest people on the station, those who are completely immune to the monstrosities they create." + icon_state = "virologist_envirohelm" + item_state = "virologist_envirohelm" + +/obj/item/clothing/head/helmet/space/plasmaman/chemist + name = "chemistry plasma envirosuit helmet" + desc = "A plasmaman envirosuit designed for chemists, two orange stripes going down it's face." + icon_state = "chemist_envirohelm" + item_state = "chemist_envirohelm" + +/obj/item/clothing/head/helmet/space/plasmaman/science + name = "science plasma envirosuit helmet" + desc = "A plasmaman envirohelmet designed for scientists." + icon_state = "scientist_envirohelm" + item_state = "scientist_envirohelm" + +/obj/item/clothing/head/helmet/space/plasmaman/rd + name = "research director's plasma envirosuit helmet" + desc = "A sturdier plasmaman envirohelmet designed for research directors." + icon_state = "rd_envirohelm" + item_state = "rd_envirohelm" + armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 10, "bio" = 100, "rad" = 0, "fire" = 100, "acid" = 75) + +/obj/item/clothing/head/helmet/space/plasmaman/robotics + name = "robotics plasma envirosuit helmet" + desc = "A plasmaman envirohelmet designed for roboticists." + icon_state = "roboticist_envirohelm" + item_state = "roboticist_envirohelm" + +/obj/item/clothing/head/helmet/space/plasmaman/engineering + name = "engineering plasma envirosuit helmet" + desc = "A space-worthy helmet specially designed for engineer plasmamen, the usual purple stripes being replaced by engineering's orange." + icon_state = "engineer_envirohelm" + item_state = "engineer_envirohelm" + armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 100, "rad" = 10, "fire" = 100, "acid" = 75) + +/obj/item/clothing/head/helmet/space/plasmaman/engineering/ce + name = "chief engineer's plasma envirosuit helmet" + desc = "A space-worthy helmet specially designed for the chief engineer, white with gold stripes designed for high visibility." + icon_state = "ce_envirohelm" + item_state = "ce_envirohelm" + +/obj/item/clothing/head/helmet/space/plasmaman/atmospherics + name = "atmospherics plasma envirosuit helmet" + desc = "A space-worthy helmet specially designed for atmos technician plasmamen, the usual purple stripes being replaced by engineering's blue." + icon_state = "atmos_envirohelm" + item_state = "atmos_envirohelm" + +/obj/item/clothing/head/helmet/space/plasmaman/cargo + name = "cargo plasma envirosuit helmet" + desc = "An plasmaman envirohelmet designed for cargo techs and quartermasters." + icon_state = "cargo_envirohelm" + item_state = "cargo_envirohelm" + +/obj/item/clothing/head/helmet/space/plasmaman/mining + name = "mining plasma envirosuit helmet" + desc = "A khaki helmet given to plasmamen miners operating on lavaland." + icon_state = "explorer_envirohelm" + item_state = "explorer_envirohelm" + +/obj/item/clothing/head/helmet/space/plasmaman/chaplain + name = "chaplain's plasma envirosuit helmet" + desc = "An envirohelmet specially designed for only the most pious of plasmamen." + icon_state = "chap_envirohelm" + item_state = "chap_envirohelm" + +/obj/item/clothing/head/helmet/space/plasmaman/white + name = "white plasma envirosuit helmet" + desc = "A generic white envirohelm." + icon_state = "white_envirohelm" + item_state = "white_envirohelm" + +/obj/item/clothing/head/helmet/space/plasmaman/hop + name = "head of personell's plasma envirosuit helmet" + desc = "A finely tailored azure envirohelm designed for head of personell." + icon_state = "hop_envirohelm" + item_state = "hop_envirohelm" + +/obj/item/clothing/head/helmet/space/plasmaman/captain + name = "captain's plasma envirosuit helmet" + desc = "A blue and gold envirohelm designed for the station's captain, nonetheless. Made of superior materials to protect them from the station hazards and more." + icon_state = "captain_envirohelm" + item_state = "captain_envirohelm" + armor = list("melee" = 10, "bullet" = 10, "laser" = 10, "energy" = 10, "bomb" = 10, "bio" = 100, "rad" = 10, "fire" = 100, "acid" = 85) + +/obj/item/clothing/head/helmet/space/plasmaman/curator + name = "curator's plasma envirosuit helmet" + desc = "A slight modification on a tradiational voidsuit helmet, this helmet was Nano-Trasen's first solution to the *logistical problems* that come with employing plasmamen. Despite their limitations, these helmets still see use by historian and old-styled plasmamen alike." + icon_state = "prototype_envirohelm" + item_state = "prototype_envirohelm" + light_overlay = null + actions_types = list() + +/obj/item/clothing/head/helmet/space/plasmaman/botany + name = "botany plasma envirosuit helmet" + desc = "A green and blue envirohelmet designating it's wearer as a botanist. While not specially designed for it, it would protect against minor planet-related injuries." + icon_state = "botany_envirohelm" + item_state = "botany_envirohelm" + +/obj/item/clothing/head/helmet/space/plasmaman/janitor + name = "janitor's plasma envirosuit helmet" + desc = "A grey helmet bearing a pair of purple stripes, designating the wearer as a janitor." + icon_state = "janitor_envirohelm" + item_state = "janitor_envirohelm" + +/obj/item/clothing/head/helmet/space/plasmaman/mime + name = "mime envirosuit helmet" + desc = "The make-up is painted on, it's a miracle it doesn't chip. It's not very colourful." + icon_state = "mime_envirohelm" + item_state = "mime_envirohelm" + light_overlay = "mime_envirohelm-light" + +/obj/item/clothing/head/helmet/space/plasmaman/clown + name = "clown envirosuit helmet" + desc = "The make-up is painted on, it's a miracle it doesn't chip. 'HONK!'" + icon_state = "clown_envirohelm" + item_state = "clown_envirohelm" + light_overlay = "clown_envirohelm-light" diff --git a/code/modules/clothing/suits/_suits.dm b/code/modules/clothing/suits/_suits.dm index cf411ef367..342429e480 100644 --- a/code/modules/clothing/suits/_suits.dm +++ b/code/modules/clothing/suits/_suits.dm @@ -5,6 +5,7 @@ allowed = list(/obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman) armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0) slot_flags = ITEM_SLOT_OCLOTHING + body_parts_covered = CHEST var/blood_overlay_type = "suit" var/togglename = null var/suittoggled = FALSE @@ -54,7 +55,7 @@ if(damaged_clothes) . += mutable_appearance('icons/effects/item_damage.dmi', "damaged[blood_overlay_type]") IF_HAS_BLOOD_DNA(src) - if(taurmode >= SNEK_TAURIC) + if(tauric) . += mutable_appearance('modular_citadel/icons/mob/64x32_effects.dmi', "[blood_overlay_type]blood") else . += mutable_appearance('icons/effects/blood.dmi', "[blood_overlay_type]blood") diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm index 5eec159462..19050dc36f 100644 --- a/code/modules/clothing/suits/armor.dm +++ b/code/modules/clothing/suits/armor.dm @@ -1,6 +1,5 @@ /obj/item/clothing/suit/armor allowed = null - body_parts_covered = CHEST cold_protection = CHEST|GROIN min_cold_protection_temperature = ARMOR_MIN_TEMP_PROTECT heat_protection = CHEST|GROIN @@ -238,3 +237,14 @@ /obj/item/clothing/suit/armor/riot/knight/red icon_state = "knight_red" item_state = "knight_red" + +/obj/item/clothing/suit/armor/vest/durathread + name = "makeshift vest" + desc = "A vest made of durathread with strips of leather acting as trauma plates." + icon_state = "durathread" + item_state = "durathread" + strip_delay = 60 + equip_delay_other = 40 + max_integrity = 200 + resistance_flags = FLAMMABLE + armor = list("melee" = 20, "bullet" = 10, "laser" = 30, "energy" = 5, "bomb" = 15, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 50) diff --git a/code/modules/clothing/suits/cloaks.dm b/code/modules/clothing/suits/cloaks.dm index c3276213e1..b8287c7f4c 100644 --- a/code/modules/clothing/suits/cloaks.dm +++ b/code/modules/clothing/suits/cloaks.dm @@ -7,7 +7,7 @@ icon_state = "qmcloak" item_state = "qmcloak" w_class = WEIGHT_CLASS_SMALL - body_parts_covered = CHEST|GROIN|LEGS|ARMS + body_parts_covered = CHEST|LEGS|ARMS /obj/item/clothing/head/cloakhood name = "cloak hood" @@ -62,7 +62,7 @@ allowed = list(/obj/item/flashlight, /obj/item/tank/internals, /obj/item/pickaxe, /obj/item/twohanded/spear, /obj/item/twohanded/bonespear, /obj/item/organ/regenerative_core/legion, /obj/item/kitchen/knife/combat/bone, /obj/item/kitchen/knife/combat/survival) armor = list("melee" = 35, "bullet" = 10, "laser" = 25, "energy" = 10, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 60, "acid" = 60) //a fair alternative to bone armor, requiring alternative materials and gaining a suit slot hoodtype = /obj/item/clothing/head/hooded/cloakhood/goliath - body_parts_covered = CHEST|GROIN|ARMS + body_parts_covered = CHEST|ARMS|LEGS /obj/item/clothing/head/hooded/cloakhood/goliath name = "goliath cloak hood" diff --git a/code/modules/clothing/suits/jobs.dm b/code/modules/clothing/suits/jobs.dm index bf11d40caf..4318839845 100644 --- a/code/modules/clothing/suits/jobs.dm +++ b/code/modules/clothing/suits/jobs.dm @@ -23,30 +23,48 @@ allowed = list(/obj/item/disk, /obj/item/stamp, /obj/item/reagent_containers/food/drinks/flask, /obj/item/melee, /obj/item/storage/lockbox/medal, /obj/item/assembly/flash/handheld, /obj/item/storage/box/matches, /obj/item/lighter, /obj/item/clothing/mask/cigarette, /obj/item/storage/fancy/cigarettes, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman) //Chaplain -/obj/item/clothing/suit/nun +/obj/item/clothing/suit/chaplain + name = "chaplain suit" + desc = "A piece of clothing adorned by the gods of Coding. Should never exist in this mortal realm." + allowed = list(/obj/item/storage/book/bible, HOLY_WEAPONS, /obj/item/reagent_containers/food/drinks/bottle/holywater, /obj/item/storage/fancy/candle_box, /obj/item/candle, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman) + +/obj/item/clothing/suit/chaplain/nun name = "nun robe" desc = "Maximum piety in this star system." icon_state = "nun" item_state = "nun" body_parts_covered = CHEST|GROIN|LEGS|ARMS|HANDS flags_inv = HIDESHOES|HIDEJUMPSUIT - allowed = list(/obj/item/storage/book/bible, /obj/item/nullrod, /obj/item/reagent_containers/food/drinks/bottle/holywater, /obj/item/storage/fancy/candle_box, /obj/item/candle, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman) -/obj/item/clothing/suit/studentuni +/obj/item/clothing/suit/chaplain/studentuni name = "student robe" desc = "The uniform of a bygone institute of learning." icon_state = "studentuni" item_state = "studentuni" body_parts_covered = ARMS|CHEST - allowed = list(/obj/item/storage/book/bible, /obj/item/nullrod, /obj/item/reagent_containers/food/drinks/bottle/holywater, /obj/item/storage/fancy/candle_box, /obj/item/candle, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman) -/obj/item/clothing/suit/witchhunter +/obj/item/clothing/suit/chaplain/witchhunter name = "witchunter garb" desc = "This worn outfit saw much use back in the day." icon_state = "witchhunter" item_state = "witchhunter" body_parts_covered = CHEST|GROIN|LEGS|ARMS - allowed = list(/obj/item/storage/book/bible, /obj/item/nullrod, /obj/item/reagent_containers/food/drinks/bottle/holywater, /obj/item/storage/fancy/candle_box, /obj/item/candle, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman) + +/obj/item/clothing/suit/chaplain/pharaoh + name = "pharaoh tunic" + desc = "Lavish space tomb not included." + icon_state = "pharaoh" + icon_state = "pharaoh" + body_parts_covered = CHEST|GROIN + +/obj/item/clothing/suit/chaplain/holidaypriest + name = "holiday priest" + desc = "This is a nice holiday, my son." + icon_state = "holidaypriest" + item_state = "w_suit" + body_parts_covered = CHEST|GROIN|LEGS|ARMS + flags_inv = HIDEJUMPSUIT + //Chef /obj/item/clothing/suit/toggle/chef @@ -135,6 +153,7 @@ icon = 'icons/obj/clothing/belts.dmi' icon_state = "suspenders" blood_overlay_type = "armor" //it's the less thing that I can put here + body_parts_covered = NONE //Security /obj/item/clothing/suit/security/officer @@ -177,3 +196,24 @@ armor = list("melee" = 25, "bullet" = 10, "laser" = 25, "energy" = 10, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 45) cold_protection = CHEST|ARMS heat_protection = CHEST|ARMS + + +//Robotocist + +/obj/item/clothing/suit/hooded/techpriest + name = "techpriest robes" + desc = "For those who REALLY love their toasters." + icon_state = "techpriest" + item_state = "techpriest" + body_parts_covered = CHEST|GROIN|LEGS|ARMS + hoodtype = /obj/item/clothing/head/hooded/techpriest + mutantrace_variation = NO_MUTANTRACE_VARIATION + +/obj/item/clothing/head/hooded/techpriest + name = "techpriest's hood" + desc = "A hood for those who REALLY love their toasters." + icon_state = "techpriesthood" + item_state = "techpriesthood" + body_parts_covered = HEAD + flags_inv = HIDEHAIR|HIDEEARS + mutantrace_variation = MUTANTRACE_VARIATION diff --git a/code/modules/clothing/suits/miscellaneous.dm b/code/modules/clothing/suits/miscellaneous.dm index dc1b2b6dc3..bc885868c5 100644 --- a/code/modules/clothing/suits/miscellaneous.dm +++ b/code/modules/clothing/suits/miscellaneous.dm @@ -67,6 +67,7 @@ item_state = "death" flags_1 = CONDUCT_1 fire_resist = T0C+5200 + body_parts_covered = CHEST|GROIN|LEGS|ARMS|HANDS|FEET flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT @@ -75,6 +76,7 @@ desc = "this pretty much looks ridiculous" //Needs no fixing icon_state = "justice" item_state = "justice" + body_parts_covered = CHEST|GROIN|LEGS|ARMS|HANDS|FEET flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT @@ -100,14 +102,14 @@ desc = "A fancy purple apron for a stylish person." icon_state = "purplebartenderapron" item_state = "purplebartenderapron" - body_parts_covered = CHEST|GROIN|LEGS + body_parts_covered = CHEST /obj/item/clothing/suit/syndicatefake name = "black and red space suit replica" icon_state = "syndicate-black-red" item_state = "syndicate-black-red" desc = "A plastic replica of the Syndicate space suit. You'll look just like a real murderous Syndicate agent in this! This is a toy, it is not made for use in space!" - w_class = WEIGHT_CLASS_NORMAL + body_parts_covered = CHEST|ARMS|GROIN|LEGS|FEET|HANDS allowed = list(/obj/item/flashlight, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman, /obj/item/toy) flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT resistance_flags = NONE @@ -154,7 +156,7 @@ icon_state = "owl_wings" item_state = "owl_wings" togglename = "wings" - body_parts_covered = ARMS|CHEST + body_parts_covered = ARMS actions_types = list(/datum/action/item_action/toggle_wings) /obj/item/clothing/suit/toggle/owlwings/Initialize() @@ -167,16 +169,6 @@ icon_state = "griffin_wings" item_state = "griffin_wings" - -/obj/item/clothing/suit/holidaypriest - name = "holiday priest" - desc = "This is a nice holiday, my son." - icon_state = "holidaypriest" - item_state = "w_suit" - body_parts_covered = CHEST|GROIN|LEGS|ARMS - flags_inv = HIDEJUMPSUIT - allowed = list(/obj/item/storage/book/bible, /obj/item/nullrod, /obj/item/reagent_containers/food/drinks/bottle/holywater, /obj/item/storage/fancy/candle_box, /obj/item/candle, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman) - /obj/item/clothing/suit/cardborg name = "cardborg suit" desc = "An ordinary cardboard box with holes cut in the sides." @@ -219,6 +211,7 @@ desc = "Your classic, non-racist poncho." icon_state = "classicponcho" item_state = "classicponcho" + body_parts_covered = CHEST|GROIN /obj/item/clothing/suit/poncho/green name = "green poncho" @@ -255,7 +248,7 @@ desc = "A costume made from 'synthetic' carp scales, it smells." icon_state = "carp_casual" item_state = "labcoat" - body_parts_covered = CHEST|GROIN|ARMS + body_parts_covered = CHEST|GROIN|ARMS|LEGS|FEET cold_protection = CHEST|GROIN|ARMS min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT //Space carp like space, so you should too allowed = list(/obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman, /obj/item/gun/ballistic/automatic/speargun) @@ -275,9 +268,7 @@ desc = "A costume that looks like someone made a human-like corgi, it won't guarantee belly rubs." icon_state = "ian" item_state = "labcoat" - body_parts_covered = CHEST|GROIN|ARMS - //cold_protection = CHEST|GROIN|ARMS - //min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT + body_parts_covered = CHEST|GROIN|ARMS|LEGS|FEET allowed = list() hoodtype = /obj/item/clothing/head/hooded/ian_hood dog_fashion = /datum/dog_fashion/back @@ -287,8 +278,6 @@ desc = "A hood that looks just like a corgi's head, it won't guarantee dog biscuits." icon_state = "ian" body_parts_covered = HEAD - //cold_protection = HEAD - //min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT flags_inv = HIDEHAIR|HIDEEARS /obj/item/clothing/suit/hooded/bee_costume // It's Hip! @@ -314,7 +303,7 @@ desc = "A horribly bloated suit made from human skins." icon_state = "lingspacesuit" item_state = "labcoat" - body_parts_covered = CHEST|GROIN|ARMS + body_parts_covered = CHEST|GROIN|ARMS|LEGS|FEET|HANDS allowed = list() actions_types = list(/datum/action/item_action/toggle_human_head) hoodtype = /obj/item/clothing/head/hooded/human_head @@ -335,6 +324,23 @@ item_state = "officertanjacket" body_parts_covered = CHEST|ARMS +/obj/item/clothing/suit/ran + name = "Shikigami costume" + desc = "A costume that looks like a certain shikigami, is super fluffy." + icon_state = "ran_suit" + item_state = "ran_suit" + body_parts_covered = CHEST|GROIN|LEGS + flags_inv = HIDEJUMPSUIT|HIDETAUR + heat_protection = CHEST|GROIN|LEGS //fluffy tails! +//2061 + +/obj/item/clothing/head/ran + name = "Shikigami hat" + desc = "A hat that looks like it keeps any fluffy ears contained super warm, has little charms over it." + icon_state = "ran_hat" + item_state = "ran_hat" + flags_inv = HIDEEARS + /* * Misc */ @@ -355,18 +361,21 @@ desc = "A worn out, curiously comfortable t-shirt with a picture of Ian. You wouldn't go so far as to say it feels like being hugged when you wear it, but it's pretty close. Good for sleeping in." icon_state = "ianshirt" item_state = "ianshirt" + body_parts_covered = CHEST|GROIN /obj/item/clothing/suit/nerdshirt name = "gamer shirt" desc = "A baggy shirt with vintage game character Phanic the Weasel. Why would anyone wear this?" icon_state = "nerdshirt" item_state = "nerdshirt" + body_parts_covered = CHEST|GROIN /obj/item/clothing/suit/vapeshirt //wearing this is asking to get beat. name = "Vape Naysh shirt" desc = "A cheap white T-shirt with a big tacky \"VN\" on the front, Why would you wear this unironically?" icon_state = "vapeshirt" item_state = "vapeshirt" + body_parts_covered = CHEST|GROIN /obj/item/clothing/suit/jacket name = "bomber jacket" @@ -374,7 +383,7 @@ icon_state = "bomberjacket" item_state = "brownjsuit" allowed = list(/obj/item/flashlight, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman, /obj/item/toy, /obj/item/storage/fancy/cigarettes, /obj/item/lighter, /obj/item/radio) - body_parts_covered = CHEST|GROIN|ARMS + body_parts_covered = CHEST|ARMS cold_protection = CHEST|GROIN|ARMS min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT @@ -399,6 +408,7 @@ desc = "A thick jacket with a rubbery, water-resistant shell." icon_state = "pufferjacket" item_state = "hostrench" + body_parts_covered = CHEST|GROIN|ARMS armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 50, "rad" = 0, "fire" = 0, "acid" = 0) /obj/item/clothing/suit/jacket/puffer/vest @@ -446,18 +456,21 @@ desc = "Looks like this belongs in a very old movie set." icon_state = "draculacoat" item_state = "draculacoat" + body_parts_covered = CHEST|ARMS /obj/item/clothing/suit/drfreeze_coat name = "doctor freeze's labcoat" desc = "A labcoat imbued with the power of features and freezes." icon_state = "drfreeze_coat" item_state = "drfreeze_coat" + body_parts_covered = CHEST|GROIN|ARMS /obj/item/clothing/suit/gothcoat name = "gothic coat" desc = "Perfect for those who want stalk in a corner of a bar." icon_state = "gothcoat" item_state = "gothcoat" + body_parts_covered = CHEST|ARMS|HAND_LEFT //peculiar /obj/item/clothing/suit/xenos name = "xenos suit" @@ -468,13 +481,6 @@ flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT allowed = list(/obj/item/clothing/mask/facehugger/toy) -/obj/item/clothing/suit/nemes - name = "pharoah tunic" - desc = "Lavish space tomb not included." - icon_state = "pharoah" - icon_state = "pharoah" - body_parts_covered = CHEST|GROIN - // WINTER COATS @@ -603,6 +609,7 @@ name = "spooky ghost" desc = "This is obviously just a bedsheet, but maybe try it on?" icon_state = "bedsheet" + body_parts_covered = CHEST|GROIN|LEGS|ARMS|HANDS|HEAD user_vars_to_edit = list("name" = "Spooky Ghost", "real_name" = "Spooky Ghost" , "incorporeal_move" = INCORPOREAL_MOVE_BASIC, "appearance_flags" = KEEP_TOGETHER|TILE_BOUND, "alpha" = 150) alternate_worn_layer = ABOVE_BODY_FRONT_LAYER //so the bedsheet goes over everything but fire @@ -611,6 +618,7 @@ desc = "A big and clanky suit made of bronze that offers no protection and looks very unfashionable. Nice." icon = 'icons/obj/clothing/clockwork_garb.dmi' icon_state = "clockwork_cuirass_old" + body_parts_covered = CHEST|GROIN|LEGS armor = list("melee" = 5, "bullet" = 0, "laser" = -5, "energy" = 0, "bomb" = 10, "bio" = 0, "rad" = 0, "fire" = 20, "acid" = 20) /obj/item/clothing/suit/ghost_sheet @@ -623,4 +631,5 @@ throw_range = 2 w_class = WEIGHT_CLASS_TINY flags_inv = HIDEGLOVES|HIDEEARS|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR + body_parts_covered = CHEST|GROIN|LEGS|ARMS|HANDS|HEAD alternate_worn_layer = UNDER_HEAD_LAYER diff --git a/code/modules/clothing/suits/utility.dm b/code/modules/clothing/suits/utility.dm index d003a20167..fbdca6ddbc 100644 --- a/code/modules/clothing/suits/utility.dm +++ b/code/modules/clothing/suits/utility.dm @@ -130,7 +130,7 @@ equip_delay_other = 60 flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH resistance_flags = NONE - rad_flags = RAD_PROTECT_CONTENTS + rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE mutantrace_variation = MUTANTRACE_VARIATION /obj/item/clothing/suit/radiation @@ -150,5 +150,5 @@ equip_delay_other = 60 flags_inv = HIDEJUMPSUIT|HIDETAUR resistance_flags = NONE - rad_flags = RAD_PROTECT_CONTENTS + rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE tauric = TRUE //Citadel Add for tauric hardsuits diff --git a/code/modules/clothing/under/accessories.dm b/code/modules/clothing/under/accessories.dm index 396bcb4766..6dd6164d79 100644 --- a/code/modules/clothing/under/accessories.dm +++ b/code/modules/clothing/under/accessories.dm @@ -1,4 +1,4 @@ -/obj/item/clothing/accessory //Ties moved to neck slot items, but as there are still things like medals and armbands, this accessory system is being kept as-is +/obj/item/clothing/accessory //Ties moved to neck slot items, but as there are still things like medals, pokadots, and armbands, this accessory system is being kept as-is name = "Accessory" desc = "Something has gone wrong!" icon = 'icons/obj/clothing/accessories.dmi' @@ -354,3 +354,68 @@ item_color = "skull" above_suit = TRUE armor = list("melee" = 5, "bullet" = 5, "laser" = 5, "energy" = 5, "bomb" = 20, "bio" = 20, "rad" = 5, "fire" = 0, "acid" = 25) + +/obj/item/clothing/accessory/skullcodpiece/fake + name = "false codpiece" + desc = "A plastic ornament, intended to protect the important things in life. It's not very good at it." + icon_state = "skull" + item_color = "skull" + above_suit = TRUE + armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0) + +///////////////////// +//Synda Accessories// +///////////////////// + +/obj/item/clothing/accessory/padding + name = "soft padding" + desc = "Some long sheets of padding to help soften the blows of a physical attacks." + icon_state = "padding" + item_color = "nothing" + armor = list("melee" = 15, "bullet" = 10, "laser" = 0, "energy" = 0, "bomb" = 5, "bio" = 0, "rad" = 0, "fire" = -20, "acid" = 45) + +/obj/item/clothing/accessory/kevlar + name = "kevlar sheets" + desc = "Long thin sheets of kevlar to help resist bullets and some physical attacks." + icon_state = "padding" + item_color = "nothing" + armor = list("melee" = 10, "bullet" = 20, "laser" = 0, "energy" = 0, "bomb" = 10, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 25) + +/obj/item/clothing/accessory/plastics + name = "underling plastic sheet" + desc = "A full body sheet of white plastic to help defuse lasers and energy based weapons." + icon_state = "plastics" + item_color = "nothing" + armor = list("melee" = 0, "bullet" = 0, "laser" = 20, "energy" = 10, "bomb" = 0, "bio" = 30, "rad" = 0, "fire" = 0, "acid" = -40) + +///////////////////// +//Pokadots On Pants// +///////////////////// + +/obj/item/clothing/accessory/attrocious_pokadots + name = "atrocious pokadots" + desc = "They look like something out of a thrift store. Attaches to clothing not to be worn by itself." + icon_state = "attrocious_pokadots" + item_color = "attrocious_pokadots" + attack_verb = list("horrifed", "eye bleeded") + +/obj/item/clothing/accessory/black_white_pokadots + name = "checkered pokadots" + desc = "You can play a game of chess on these! Attaches to clothing not to be worn by itself." + icon_state = "black_white_pokadots" + item_color = "black_white_pokadots" + attack_verb = list("check", "mate") + +/obj/item/clothing/accessory/nt_pokadots + name = "blue and white pokadots" + desc = "To show your pride in your workplace, in the most annoying possable way. Attaches to clothing not to be worn by itself." + icon_state = "nt_pokadots" + item_color = "nt_pokadots" + attack_verb = list("eye bleeded", "annoyed") + +/obj/item/clothing/accessory/syndi_pokadots + name = "black and red pokadots" + desc = "King me. Attaches to clothing not to be worn by itself." //checkers! + icon_state = "syndi_pokadots" + item_color = "syndi_pokadots" + attack_verb = list("jumped", "taken") \ No newline at end of file diff --git a/code/modules/clothing/under/jobs/Plasmaman/civilian_service.dm b/code/modules/clothing/under/jobs/Plasmaman/civilian_service.dm new file mode 100644 index 0000000000..74181b05eb --- /dev/null +++ b/code/modules/clothing/under/jobs/Plasmaman/civilian_service.dm @@ -0,0 +1,100 @@ +/obj/item/clothing/under/plasmaman/cargo + name = "cargo plasma envirosuit" + desc = "A joint envirosuit used by plasmamen quartermasters and cargo techs alike, due to the logistical problems of differenciating the two with the length of their pant legs." + icon_state = "cargo_envirosuit" + item_state = "cargo_envirosuit" + item_color = "cargo_envirosuit" + +/obj/item/clothing/under/plasmaman/mining + name = "mining plasma envirosuit" + desc = "An air-tight khaki suit designed for operations on lavaland by plasmamen." + icon_state = "explorer_envirosuit" + item_state = "explorer_envirosuit" + item_color = "explorer_envirosuit" + + +/obj/item/clothing/under/plasmaman/chef + name = "chef's plasma envirosuit" + desc = "A white plasmaman envirosuit designed for cullinary practices. One might question why a member of a species that doesn't need to eat would become a chef." + icon_state = "chef_envirosuit" + item_state = "chef_envirosuit" + item_color = "chef_envirosuit" + +/obj/item/clothing/under/plasmaman/enviroslacks + name = "enviroslacks" + desc = "The pet project of a particularly posh plasmaman, this custom suit was quickly appropriated by Nano-Trasen for it's detectives, lawyers, and bar-tenders alike." + icon_state = "enviroslacks" + item_state = "enviroslacks" + item_color = "enviroslacks" + +/obj/item/clothing/under/plasmaman/chaplain + name = "chaplain's plasma envirosuit" + desc = "An envirosuit specially designed for only the most pious of plasmamen." + icon_state = "chap_envirosuit" + item_state = "chap_envirosuit" + item_color = "chap_envirosuit" + +/obj/item/clothing/under/plasmaman/curator + name = "curator's plasma envirosuit" + desc = "Made out of a modified voidsuit, this suit was Nano-Trasen's first solution to the *logistical problems* that come with employing plasmamen. Due to the modifications, the suit is no longer space-worthy. Despite their limitations, these suits are still in used by historian and old-styled plasmamen alike." + icon_state = "prototype_envirosuit" + item_state = "prototype_envirosuit" + item_color = "prototype_envirosuit" + +/obj/item/clothing/under/plasmaman/janitor + name = "janitor's plasma envirosuit" + desc = "A grey and purple envirosuit designated for plasmamen janitors." + icon_state = "janitor_envirosuit" + item_state = "janitor_envirosuit" + item_color = "janitor_envirosuit" + +/obj/item/clothing/under/plasmaman/botany + name = "botany envirosuit" + desc = "A green and blue envirosuit designed to protect plasmamen from minor plant-related injuries." + icon_state = "botany_envirosuit" + item_state = "botany_envirosuit" + item_color = "botany_envirosuit" + +/obj/item/clothing/under/plasmaman/hop + name = "head of personell's envirosuit" + desc = "A prestigious azure envirosuit designed for head of personell." + icon_state = "hop_envirosuit" + item_state = "hop_envirosuit" + item_color = "hop_envirosuit" + +/obj/item/clothing/under/plasmaman/captain + name = "captain's envirosuit" + desc = "An expensive piece of plasmaman envirosuit fashion. guaranteed to keep you cool while the station goes down in fierceful fires." + icon_state = "captain_envirosuit" + item_state = "captain_envirosuit" + item_color = "captain_envirosuit" + armor = list("melee" = 10, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 100, "rad" = 0, "fire" = 95, "acid" = 95) + +/obj/item/clothing/under/plasmaman/mime + name = "mime envirosuit" + desc = "It's not very colourful." + icon_state = "mime_envirosuit" + item_state = "mime_envirosuit" + item_color = "mime_envirosuit" + +/obj/item/clothing/under/plasmaman/clown + name = "clown envirosuit" + desc = "'HONK!'" + icon_state = "clown_envirosuit" + item_state = "clown_envirosuit" + item_color = "clown_envirosuit" + +/obj/item/clothing/under/plasmaman/clown/Extinguish(mob/living/carbon/human/H) + if(!istype(H)) + return + + if(H.on_fire) + if(extinguishes_left) + if(next_extinguish > world.time) + return + next_extinguish = world.time + extinguish_cooldown + extinguishes_left-- + H.visible_message("[H]'s suit spews out a tonne of space lube!","Your suit spews out a tonne of space lube!") + H.ExtinguishMob() + new /obj/effect/particle_effect/foam(loc) //Truely terrifying. + return FALSE \ No newline at end of file diff --git a/code/modules/clothing/under/jobs/Plasmaman/engineering.dm b/code/modules/clothing/under/jobs/Plasmaman/engineering.dm new file mode 100644 index 0000000000..1f381df4cf --- /dev/null +++ b/code/modules/clothing/under/jobs/Plasmaman/engineering.dm @@ -0,0 +1,21 @@ +/obj/item/clothing/under/plasmaman/engineering + name = "engineering plasma envirosuit" + desc = "An air-tight suit designed to be used by plasmamen exployed as engineers, the usual purple stripes being replaced by engineer's orange. It protects the user from fire and acid damage." + icon_state = "engineer_envirosuit" + item_state = "engineer_envirosuit" + item_color = "engineer_envirosuit" + armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 100, "rad" = 10, "fire" = 95, "acid" = 95) + +/obj/item/clothing/under/plasmaman/engineering/ce + name = "chief engineer's plasma envirosuit" + desc = "An advanced air-tight suit designed to be used by plasmamen chief engineers, complete with ornamental widgets and gizmo. It protects the user from fire and acid damage." + icon_state = "ce_envirosuit" + item_state = "ce_envirosuit" + item_color = "ce_envirosuit" + +/obj/item/clothing/under/plasmaman/atmospherics + name = "atmospherics plasma envirosuit" + desc = "An air-tight suit designed to be used by plasmamen exployed as atmos technicians, the usual purple stripes being replaced by atmos's blue." + icon_state = "atmos_envirosuit" + item_state = "atmos_envirosuit" + item_color = "atmos_envirosuit" diff --git a/code/modules/clothing/under/jobs/Plasmaman/medsci.dm b/code/modules/clothing/under/jobs/Plasmaman/medsci.dm new file mode 100644 index 0000000000..6106d785a9 --- /dev/null +++ b/code/modules/clothing/under/jobs/Plasmaman/medsci.dm @@ -0,0 +1,56 @@ +/obj/item/clothing/under/plasmaman/medical + name = "medical plasma envirosuit" + desc = "A suit designed for the station's more plasma-based doctors." + icon_state = "doctor_envirosuit" + item_state = "doctor_envirosuit" + item_color = "doctor_envirosuit" + +/obj/item/clothing/under/plasmaman/cmo + name = "chief medical officer's plasma envirosuit" + desc = "A suit designed for the station's most plasma-based chief medical officer, but not for their cat." + icon_state = "cmo_envirosuit" + item_state = "cmo_envirosuit" + item_color = "cmo_envirosuit" + +/obj/item/clothing/under/plasmaman/science + name = "science plasma envirosuit" + desc = "A plasmaman envirosuit designed for scientists." + icon_state = "scientist_envirosuit" + item_state = "scientist_envirosuit" + item_color = "scientist_envirosuit" + +/obj/item/clothing/under/plasmaman/rd + name = "research direactor's plasma envirosuit" + desc = "A plasmaman envirosuit designed for the research director to aid them in their job of directing research into the right direction." + icon_state = "rd_envirosuit" + item_state = "rd_envirosuit" + item_color = "rd_envirosuit" + armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 10, "bio" = 100, "rad" = 0, "fire" = 95, "acid" = 95) + +/obj/item/clothing/under/plasmaman/robotics + name = "robotics plasma envirosuit" + desc = "A plasmaman envirosuit designed for roboticists." + icon_state = "roboticist_envirosuit" + item_state = "roboticist_envirosuit" + item_color = "roboticist_envirosuit" + +/obj/item/clothing/under/plasmaman/viro + name = "virology plasma envirosuit" + desc = "The suit worn by the safest people on the station, those who are completely immune to the monstrosities they create." + icon_state = "virologist_envirosuit" + item_state = "virologist_envirosuit" + item_color = "virologist_envirosuit" + +/obj/item/clothing/under/plasmaman/genetics + name = "genetics plasma envirosuit" + desc = "A plasmaman envirosuit designed for geneticists." + icon_state = "geneticist_envirosuit" + item_state = "geneticist_envirosuit" + item_color = "geneticist_envirosuit" + +/obj/item/clothing/under/plasmaman/chemist + name = "chemistry plasma envirosuit" + desc = "A plasmaman envirosuit designed for chemists." + icon_state = "chemist_envirosuit" + item_state = "chemist_envirosuit" + item_color = "chemist_envirosuit" diff --git a/code/modules/clothing/under/jobs/Plasmaman/security.dm b/code/modules/clothing/under/jobs/Plasmaman/security.dm new file mode 100644 index 0000000000..ff756e09fd --- /dev/null +++ b/code/modules/clothing/under/jobs/Plasmaman/security.dm @@ -0,0 +1,21 @@ +/obj/item/clothing/under/plasmaman/security + name = "security plasma envirosuit" + desc = "A plasmaman containment suit designed for security officers, offering a limited amount of extra protection." + icon_state = "security_envirosuit" + item_state = "security_envirosuit" + item_color = "security_envirosuit" + armor = list("melee" = 10, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 100, "rad" = 0, "fire" = 95, "acid" = 95) + +/obj/item/clothing/under/plasmaman/security/warden + name = "warden plasma envirosuit" + desc = "A plasmaman containment suit designed for the warden, white stripes being added to differeciate them from other members of security." + icon_state = "warden_envirosuit" + item_state = "warden_envirosuit" + item_color = "warden_envirosuit" + +/obj/item/clothing/under/plasmaman/security/hos + name = "security plasma envirosuit" + desc = "A slick black and red plasmaman containment suit designed for the head of security, also called the LAW." + icon_state = "hos_envirosuit" + item_state = "hos_envirosuit" + item_color = "hos_envirosuit" diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm index abc157fa71..ec39f20b0b 100644 --- a/code/modules/clothing/under/miscellaneous.dm +++ b/code/modules/clothing/under/miscellaneous.dm @@ -589,6 +589,7 @@ item_state = "b_suit" item_color = "sailor" can_adjust = FALSE + /obj/item/clothing/under/plasmaman name = "plasma envirosuit" desc = "A special containment suit that allows plasma-based lifeforms to exist safely in an oxygenated environment, and automatically extinguishes them in a crisis. Despite being airtight, it's not spaceworthy." @@ -596,12 +597,15 @@ item_state = "plasmaman" item_color = "plasmaman" armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 100, "rad" = 0, "fire" = 95, "acid" = 95) + slowdown = 1 body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS + mutantrace_variation = NO_MUTANTRACE_VARIATION can_adjust = FALSE strip_delay = 80 var/next_extinguish = 0 var/extinguish_cooldown = 100 var/extinguishes_left = 5 + /obj/item/clothing/under/plasmaman/examine(mob/user) ..() to_chat(user, "There are [extinguishes_left] extinguisher charges left in this suit.") @@ -618,6 +622,7 @@ H.ExtinguishMob() new /obj/effect/particle_effect/water(get_turf(H)) return 0 + /obj/item/clothing/under/plasmaman/attackby(obj/item/E, mob/user, params) ..() if (istype(E, /obj/item/extinguisher_refill)) @@ -631,11 +636,13 @@ return return return + /obj/item/extinguisher_refill name = "envirosuit extinguisher cartridge" desc = "A cartridge loaded with a compressed extinguisher mix, used to refill the automatic extinguisher on plasma envirosuits." icon_state = "plasmarefill" icon = 'icons/obj/device.dmi' + /obj/item/clothing/under/rank/security/navyblue/russian name = "\improper Russian officer's uniform" desc = "The latest in fashionable russian outfits." @@ -703,14 +710,6 @@ fitted = NO_FEMALE_UNIFORM can_adjust = FALSE resistance_flags = NONE -/obj/item/clothing/under/durathread - name = "durathread jumpsuit" - desc = "A jumpsuit made from durathread, its resilient fibres provide some protection to the wearer." - icon_state = "durathread" - item_state = "durathread" - item_color = "durathread" - can_adjust = FALSE - armor = list("melee" = 10, "laser" = 10, "fire" = 40, "acid" = 10, "bomb" = 5) /obj/item/clothing/under/gear_harness name = "gear harness" @@ -718,3 +717,22 @@ icon_state = "gear_harness" item_state = "gear_harness" //We dont use golem do to being a item, item without faces making it default to error suit sprites. body_parts_covered = CHEST|GROIN + +/obj/item/clothing/under/durathread + name = "durathread jumpsuit" + desc = "A jumpsuit made from durathread, its resilient fibres provide some protection to the wearer." + icon_state = "durathread" + item_state = "durathread" + item_color = "durathread" + can_adjust = TRUE + armor = list("melee" = 10, "laser" = 10, "fire" = 40, "acid" = 10, "bomb" = 5) + +/obj/item/clothing/under/duraskirt + name = "durathread jumpskirt" + desc = "A jumpsuit made from durathread, its resilient fibres provide some protection to the wearer. Being a short skirt, it naturally doesn't protect the legs." + icon_state = "duraskirt" + item_state = "duraskirt" + item_color = "durathread" + can_adjust = FALSE + body_parts_covered = CHEST|GROIN|ARMS + armor = list("melee" = 10, "laser" = 10, "fire" = 40, "acid" = 10, "bomb" = 5) \ No newline at end of file diff --git a/code/modules/clothing/under/syndicate.dm b/code/modules/clothing/under/syndicate.dm index 9893edf248..4e3e1aa0cc 100644 --- a/code/modules/clothing/under/syndicate.dm +++ b/code/modules/clothing/under/syndicate.dm @@ -67,3 +67,14 @@ icon_state = "syndicate_combat" item_color = "syndicate_combat" can_adjust = FALSE + +/obj/item/clothing/under/syndicate/baseball + name = "major league, number unknown" + desc = "A major league outfit with the number faded number on the back. Seems rather robust for just a game" + icon_state = "syndicatebaseball" + item_state = "syndicatebaseball" + item_color = "syndicatebaseball" + has_sensor = NO_SENSORS + armor = list("melee" = 15, "bullet" = 5, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 40) + alt_covers_chest = TRUE + diff --git a/code/modules/crafting/recipes.dm b/code/modules/crafting/recipes.dm index 025b4af578..f86691c067 100644 --- a/code/modules/crafting/recipes.dm +++ b/code/modules/crafting/recipes.dm @@ -211,6 +211,12 @@ time = 40 category = CAT_ROBOT +/datum/crafting_recipe/potatos + name = "Potat-OS" + reqs = list(/obj/item/stack/cable_coil = 1, /obj/item/stack/rods = 1, /obj/item/reagent_containers/food/snacks/grown/potato = 1, /obj/item/aicard = 1 ) + result = /obj/item/aicard/potato + category = CAT_ROBOT + /datum/crafting_recipe/improvised_pneumatic_cannon //Pretty easy to obtain but name = "Pneumatic Cannon" result = /obj/item/pneumatic_cannon/ghetto @@ -353,6 +359,7 @@ reqs = list(/obj/item/restraints/handcuffs/cable = 1, /obj/item/shard = 1, /obj/item/stack/rods = 1) + parts = list(/obj/item/shard = 1) time = 40 category = CAT_WEAPONRY subcategory = CAT_WEAPON @@ -455,6 +462,12 @@ /obj/item/bikehorn = 1) category = CAT_MISC +/datum/crafting_recipe/toyneb + name = "Non-Euplastic Blade" + reqs = list(/obj/item/light/tube = 1, /obj/item/stack/cable_coil = 1, /obj/item/stack/sheet/plastic = 4) + result = /obj/item/toy/sword/cx + category = CAT_MISC + /datum/crafting_recipe/chemical_payload name = "Chemical Payload (C4)" result = /obj/item/bombcore/chemical @@ -663,12 +676,12 @@ /datum/crafting_recipe/femur_breaker name = "Femur Breaker" result = /obj/structure/femur_breaker - time = 150 + time = 150 reqs = list(/obj/item/stack/sheet/metal = 20, /obj/item/stack/cable_coil = 30) tools = list(TOOL_SCREWDRIVER, TOOL_WRENCH, TOOL_WELDER) category = CAT_MISC - + /datum/crafting_recipe/lizardhat name = "Lizard Cloche Hat" result = /obj/item/clothing/head/lizard @@ -874,12 +887,66 @@ /datum/crafting_recipe/smartdartgun name = "Smart dartgun" result = /obj/item/gun/syringe/dart - reqs = list(/obj/item/stack/sheet/metal = 15, - /obj/item/stack/sheet/glass = 10, + reqs = list(/obj/item/stack/sheet/metal = 10, + /obj/item/stack/sheet/glass = 5, /obj/item/tank/internals = 1, /obj/item/reagent_containers/glass/beaker = 1, - /obj/item/stack/sheet/plastic = 10, - /obj/item/stack/cable_coil = 2) + /obj/item/stack/sheet/plastic = 5, + /obj/item/stack/cable_coil = 1) time = 150 //It's a gun category = CAT_WEAPONRY subcategory = CAT_WEAPON + +/datum/crafting_recipe/rapiddartgun + name = "Rapid Smart dartgun" + result = /obj/item/gun/syringe/dart/rapiddart + reqs = list( + /obj/item/gun/syringe/dart = 1, + /obj/item/stack/sheet/plastic = 5, + /obj/item/stack/cable_coil = 1, + /obj/item/reagent_containers/glass/beaker = 1 + ) + parts = list(/obj/item/reagent_containers/glass/beaker = 1) + time = 120 //Modifying your gun + category = CAT_WEAPONRY + subcategory = CAT_WEAPON + +/datum/crafting_recipe/durathread_duffelbag + name = "Durathread Dufflebag" + result = /obj/item/storage/backpack/duffelbag/durathread + reqs = list(/obj/item/stack/sheet/durathread = 7, + /obj/item/stack/sheet/leather = 3) + time = 70 + category = CAT_CLOTHING + +/datum/crafting_recipe/durathread_toolbelt + name = "Durathread Toolbelt" + result = /obj/item/storage/belt/durathread + reqs = list(/obj/item/stack/sheet/durathread = 5, + /obj/item/stack/sheet/leather = 1) + time = 30 + category = CAT_CLOTHING + +/datum/crafting_recipe/durathread_bandolier + name = "Durathread Bandolier" + result = /obj/item/storage/belt/bandolier/durathread + reqs = list(/obj/item/stack/sheet/durathread = 6, + /obj/item/stack/sheet/leather = 2) + time = 50 + category = CAT_CLOTHING + + /datum/crafting_recipe/durathread_helmet + name = "Makeshift Durathread Helmet" + result = /obj/item/clothing/head/helmet/durathread + reqs = list(/obj/item/stack/sheet/durathread = 4, + /obj/item/stack/sheet/leather = 2) + time = 30 + category = CAT_CLOTHING + +/datum/crafting_recipe/durathread_vest + name = "Makeshift Durathread Armour" + result = /obj/item/clothing/suit/armor/vest/durathread + reqs = list(/obj/item/stack/sheet/durathread = 6, + /obj/item/stack/sheet/leather = 3) + time = 50 + category = CAT_CLOTHING diff --git a/code/modules/events/holiday/halloween.dm b/code/modules/events/holiday/halloween.dm index 9b72020047..66495d833d 100644 --- a/code/modules/events/holiday/halloween.dm +++ b/code/modules/events/holiday/halloween.dm @@ -19,6 +19,7 @@ new /mob/living/simple_animal/parrot/Poly/ghost(Poly.loc) qdel(Poly) + /datum/round_event/spooky/announce(fake) priority_announce(pick("RATTLE ME BONES!","THE RIDE NEVER ENDS!", "A SKELETON POPS OUT!", "SPOOKY SCARY SKELETONS!", "CREWMEMBERS BEWARE, YOU'RE IN FOR A SCARE!") , "THE CALL IS COMING FROM INSIDE THE HOUSE") diff --git a/code/modules/events/holiday/vday.dm b/code/modules/events/holiday/vday.dm index a4e8b276b5..8f77af58eb 100644 --- a/code/modules/events/holiday/vday.dm +++ b/code/modules/events/holiday/vday.dm @@ -41,11 +41,16 @@ else L.mind.add_antag_datum(/datum/antagonist/heartbreaker) -/proc/forge_valentines_objective(mob/living/lover,mob/living/date) +/proc/forge_valentines_objective(mob/living/lover,mob/living/date,var/chemLove = FALSE) lover.mind.special_role = "valentine" - var/datum/antagonist/valentine/V = new - V.date = date.mind - lover.mind.add_antag_datum(V) //These really should be teams but i can't be assed to incorporate third wheels right now + if (chemLove == TRUE) + var/datum/antagonist/valentine/chem/V = new //Changes text and EOG check basically. + V.date = date.mind + lover.mind.add_antag_datum(V) + else + var/datum/antagonist/valentine/V = new + V.date = date.mind + lover.mind.add_antag_datum(V) //These really should be teams but i can't be assed to incorporate third wheels right now /datum/round_event/valentines/announce(fake) priority_announce("It's Valentine's Day! Give a valentine to that special someone!") diff --git a/code/modules/events/holiday/xmas.dm b/code/modules/events/holiday/xmas.dm index a76c75dd43..5f9873c387 100644 --- a/code/modules/events/holiday/xmas.dm +++ b/code/modules/events/holiday/xmas.dm @@ -77,7 +77,7 @@ if(LAZYLEN(candidates)) var/mob/dead/observer/C = pick(candidates) santa = new /mob/living/carbon/human(pick(GLOB.blobstart)) - santa.key = C.key + C.transfer_ckey(santa, FALSE) santa.equipOutfit(/datum/outfit/santa) santa.update_icons() diff --git a/code/modules/events/meteor_wave.dm b/code/modules/events/meteor_wave.dm index 798bcf82dd..604e203cd6 100644 --- a/code/modules/events/meteor_wave.dm +++ b/code/modules/events/meteor_wave.dm @@ -1,5 +1,8 @@ // Normal strength +#define SINGULO_BEACON_DISTURBANCE 0.2 //singularity beacon also improve the odds of meteor waves and speed them up a little. +#define SINGULO_BEACON_MAX_DISTURBANCE 0.6 //maximum cap due to how meteor waves can be potentially round ending. + /datum/round_event_control/meteor_wave name = "Meteor Wave: Normal" typepath = /datum/round_event/meteor_wave @@ -15,14 +18,20 @@ var/list/wave_type var/wave_name = "normal" +/datum/round_event/meteor_wave/setup() + announceWhen = 1 + startWhen = rand(300, 600) //Yeah for SOME REASON this is measured in seconds and not deciseconds??? + if(GLOB.singularity_counter) + startWhen *= 1 - min(GLOB.singularity_counter * SINGULO_BEACON_DISTURBANCE, SINGULO_BEACON_MAX_DISTURBANCE) + endWhen = startWhen + 60 + + /datum/round_event/meteor_wave/New() ..() if(!wave_type) determine_wave_type() /datum/round_event/meteor_wave/proc/determine_wave_type() - if(SSevents.holidays && SSevents.holidays[HALLOWEEN]) - wave_name = "halloween" if(!wave_name) wave_name = pickweight(list( "normal" = 50, @@ -34,7 +43,10 @@ if("threatening") wave_type = GLOB.meteors_threatening if("catastrophic") - wave_type = GLOB.meteors_catastrophic + if(SSevents.holidays && SSevents.holidays[HALLOWEEN]) + wave_type = GLOB.meteorsSPOOKY + else + wave_type = GLOB.meteors_catastrophic if("meaty") wave_type = GLOB.meteorsB if("space dust") @@ -46,7 +58,7 @@ kill() /datum/round_event/meteor_wave/announce(fake) - priority_announce("Meteors have been detected on collision course with the station.", "Meteor Alert", 'sound/ai/meteors.ogg') + priority_announce("Meteors have been detected on collision course with the station. Estimated time until impact: [round(startWhen/60)] minutes.[GLOB.singularity_counter ? " Warning: Anomalous gravity pulse detected, Syndicate technology interference likely." : ""]", "Meteor Alert", 'sound/ai/meteors.ogg') /datum/round_event/meteor_wave/tick() if(ISMULTIPLE(activeFor, 3)) @@ -73,3 +85,6 @@ /datum/round_event/meteor_wave/catastrophic wave_name = "catastrophic" + +#undef SINGULO_BEACON_DISTURBANCE +#undef SINGULO_BEACON_MAX_DISTURBANCE diff --git a/code/modules/events/sentience.dm b/code/modules/events/sentience.dm index 55d8ce8b14..96b6cded58 100644 --- a/code/modules/events/sentience.dm +++ b/code/modules/events/sentience.dm @@ -48,7 +48,7 @@ spawned_animals++ - SA.key = SG.key + SG.transfer_ckey(SA, FALSE) SA.grant_all_languages(TRUE) diff --git a/code/modules/events/wizard/imposter.dm b/code/modules/events/wizard/imposter.dm index 1c8ef95baa..29704168e9 100644 --- a/code/modules/events/wizard/imposter.dm +++ b/code/modules/events/wizard/imposter.dm @@ -23,7 +23,7 @@ I.name = I.dna.real_name I.updateappearance(mutcolor_update=1) I.domutcheck() - I.key = C.key + C.transfer_ckey(I, FALSE) var/datum/antagonist/wizard/master = M.has_antag_datum(/datum/antagonist/wizard) if(!master.wiz_team) master.create_wiz_team() diff --git a/code/modules/flufftext/Hallucination.dm b/code/modules/flufftext/Hallucination.dm index 88f72d27c3..bac2e0bb65 100644 --- a/code/modules/flufftext/Hallucination.dm +++ b/code/modules/flufftext/Hallucination.dm @@ -771,7 +771,7 @@ GLOBAL_LIST_INIT(hallucination_list, list( ..() var/turf/source = random_far_turf() if(!sound_type) - sound_type = pick("airlock","airlock pry","console","explosion","far explosion","mech","glass","alarm","beepsky","mech","wall decon","door hack") + sound_type = pick("airlock","airlock pry","console","flash","explosion","far explosion","mech","glass","alarm","beepsky","mech","wall decon","door hack") feedback_details += "Type: [sound_type]" //Strange audio switch(sound_type) @@ -788,6 +788,8 @@ GLOBAL_LIST_INIT(hallucination_list, list( target.playsound_local(source,'sound/effects/explosion1.ogg', 50, 1) else target.playsound_local(source, 'sound/effects/explosion2.ogg', 50, 1) + if("flash") + target.playsound_local(source, 'sound/weapons/flash.ogg', 50, 1) if("far explosion") target.playsound_local(source, 'sound/effects/explosionfar.ogg', 50, 1) if("glass") @@ -1291,4 +1293,4 @@ GLOBAL_LIST_INIT(hallucination_list, list( H.hal_target = target H.preparePixelProjectile(target, start) H.fire() - qdel(src) \ No newline at end of file + qdel(src) diff --git a/code/modules/food_and_drinks/drinks/drinks/bottle.dm b/code/modules/food_and_drinks/drinks/drinks/bottle.dm index 0794d274b6..e72b624ae5 100644 --- a/code/modules/food_and_drinks/drinks/drinks/bottle.dm +++ b/code/modules/food_and_drinks/drinks/drinks/bottle.dm @@ -7,11 +7,12 @@ /obj/item/reagent_containers/food/drinks/bottle amount_per_transfer_from_this = 10 volume = 100 + force = 15 throwforce = 15 item_state = "broken_beer" //Generic held-item sprite until unique ones are made. lefthand_file = 'icons/mob/inhands/misc/food_lefthand.dmi' righthand_file = 'icons/mob/inhands/misc/food_righthand.dmi' - var/const/duration = 13 //Directly relates to the 'knockdown' duration. Lowered by armor (i.e. helmets) + var/knockdown_duration = 13 //Directly relates to the 'knockdown' duration. Lowered by armor (i.e. helmets) isGlass = TRUE foodtype = ALCOHOL @@ -61,46 +62,30 @@ to_chat(user, "You don't want to harm [target]!") return - force = 15 //Smashing bottles over someoen's head hurts. - var/obj/item/bodypart/affecting = user.zone_selected //Find what the player is aiming at - var/armor_block = 0 //Get the target's armor values for normal attack damage. - var/armor_duration = 0 //The more force the bottle has, the longer the duration. + var/headarmor = 0 // Target's head armor + var/armor_block = min(90, target.run_armor_check(affecting, "melee", null, null,armour_penetration)) // For normal attack damage - //Calculating duration and calculating damage. - if(ishuman(target)) + //If they have a hat/helmet and the user is targeting their head. + if(affecting == BODY_ZONE_HEAD) + var/obj/item/I = target.get_item_by_slot(SLOT_HEAD) + if(I) + headarmor = I.armor.melee - var/mob/living/carbon/human/H = target - var/headarmor = 0 // Target's head armor - armor_block = H.run_armor_check(affecting, "melee", null, null,armour_penetration) // For normal attack damage - - //If they have a hat/helmet and the user is targeting their head. - if(istype(H.head, /obj/item/clothing/head) && affecting == BODY_ZONE_HEAD) - headarmor = H.head.armor.melee - else - headarmor = 0 - - //Calculate the knockdown duration for the target. - armor_duration = (duration - headarmor) + force - - else - //Only humans can have armor, right? - armor_block = target.run_armor_check(affecting, "melee") - if(affecting == BODY_ZONE_HEAD) - armor_duration = duration + force + //Calculate the knockdown duration for the target. + var/armor_duration = (knockdown_duration - headarmor) + force //Apply the damage! - armor_block = min(90,armor_block) target.apply_damage(force, BRUTE, affecting, armor_block) // You are going to knock someone out for longer if they are not wearing a helmet. var/head_attack_message = "" - if(affecting == BODY_ZONE_HEAD && istype(target, /mob/living/carbon/)) + if(affecting == BODY_ZONE_HEAD && iscarbon(target)) head_attack_message = " on the head" //Knockdown the target for the duration that we calculated and divide it by 5. if(armor_duration) - target.apply_effect(min(armor_duration, 200) , EFFECT_KNOCKDOWN) // Never knockdown more than a flash! + target.Knockdown(min(armor_duration, 200)) // Never knockdown more than a flash! //Display an attack message. if(target != user) @@ -202,17 +187,18 @@ desc = "A flask of holy water...it's been sitting in the Necropolis a while though." list_reagents = list("hell_water" = 100) -/obj/item/reagent_containers/food/drinks/holyoil +/obj/item/reagent_containers/food/drinks/bottle/holyoil name = "flask of zelus oil" desc = "A brass flask of Zelus oil, a viscous fluid scenting of brass. Can be thrown to deal damage from afar." icon_state = "zelusflask" - list_reagents = list("holyoil" = 30) //Powerfull + list_reagents = list("holyoil" = 30) volume = 30 foodtype = NONE - force = 12 //Same as a toolbox + force = 18 throwforce = 18 + knockdown_duration = 18 -/obj/item/reagent_containers/food/drinks/holyoil/null +/obj/item/reagent_containers/food/drinks/bottle/holyoil/empty list_reagents = list("holyoil" = 0) /obj/item/reagent_containers/food/drinks/bottle/vermouth diff --git a/code/modules/food_and_drinks/food/condiment.dm b/code/modules/food_and_drinks/food/condiment.dm index 31e99535d1..1d0b626d98 100644 --- a/code/modules/food_and_drinks/food/condiment.dm +++ b/code/modules/food_and_drinks/food/condiment.dm @@ -16,6 +16,7 @@ //Possible_states has the reagent id as key and a list of, in order, the icon_state, the name and the desc as values. Used in the on_reagent_change(changetype) to change names, descs and sprites. var/list/possible_states = list( "ketchup" = list("ketchup", "ketchup bottle", "You feel more American already."), + "mustard" = list("mustard", "mustard bottle", "A spice mixed with enzymes and water."), "capsaicin" = list("hotsauce", "hotsauce bottle", "You can almost TASTE the stomach ulcers now!"), "enzyme" = list("enzyme", "universal enzyme bottle", "Used in cooking various dishes"), "soysauce" = list("soysauce", "soy sauce bottle", "A salty soy-based flavoring"), @@ -282,6 +283,12 @@ originalname = "ketchup" list_reagents = list("ketchup" = 10) +//Mustard +/obj/item/reagent_containers/food/condiment/pack/mustard + name = "mustard pack" + originalname = "mustard" + list_reagents = list("mustard" = 10) + //Hot sauce /obj/item/reagent_containers/food/condiment/pack/hotsauce name = "hotsauce pack" diff --git a/code/modules/food_and_drinks/food/snacks/meat.dm b/code/modules/food_and_drinks/food/snacks/meat.dm index 1a82d1b406..ee169e9861 100644 --- a/code/modules/food_and_drinks/food/snacks/meat.dm +++ b/code/modules/food_and_drinks/food/snacks/meat.dm @@ -108,7 +108,7 @@ tastes = list("maggots" = 1, "the inside of a reactor" = 1) foodtype = MEAT | RAW | GROSS -/obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/moth +/obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/insect icon_state = "mothmeat" desc = "Unpleasantly powdery and dry. Kind of pretty, though." filling_color = "#BF896B" diff --git a/code/modules/food_and_drinks/food/snacks_cake.dm b/code/modules/food_and_drinks/food/snacks_cake.dm index d66cfdd667..98f80331a7 100644 --- a/code/modules/food_and_drinks/food/snacks_cake.dm +++ b/code/modules/food_and_drinks/food/snacks_cake.dm @@ -335,7 +335,7 @@ obj/item/reagent_containers/food/snacks/store/cake/pound_cake icon_state = "vanillacake" slice_path = /obj/item/reagent_containers/food/snacks/cakeslice/vanilla_slice bonus_reagents = list("sugar" = 15, "vanilla" = 15) - tastes = list("caje" = 1, "sugar" = 1, "vanilla" = 10) + tastes = list("cake" = 1, "sugar" = 1, "vanilla" = 10) foodtype = GRAIN | SUGAR | DAIRY /obj/item/reagent_containers/food/snacks/cakeslice/vanilla_slice @@ -361,4 +361,21 @@ obj/item/reagent_containers/food/snacks/store/cake/pound_cake icon_state = "clowncake_slice" filling_color = "#00FFFF" tastes = list("cake" = 1, "sugar" = 1, "joy" = 10) - foodtype = GRAIN | SUGAR | DAIRY \ No newline at end of file + foodtype = GRAIN | SUGAR | DAIRY + +/obj/item/reagent_containers/food/snacks/store/cake/peach_cake + name = "peach cake" + desc = "A peach filled cake." + icon_state = "peachcake" + slice_path = /obj/item/reagent_containers/food/snacks/cakeslice/peach_slice + bonus_reagents = list("sugar" = 5, "peachjuice" = 15) + tastes = list("cake" = 1, "sugar" = 1, "peachjuice" = 10) + foodtype = GRAIN | SUGAR | DAIRY + +/obj/item/reagent_containers/food/snacks/cakeslice/peach_slice + name = "peach cake slice" + desc = "A slice of peach cake." + icon_state = "peach_slice" + filling_color = "#00FFFF" + tastes = list("cake" = 1, "sugar" = 1, "peachjuice" = 10) + foodtype = GRAIN | SUGAR | DAIRY diff --git a/code/modules/food_and_drinks/food/snacks_frozen.dm b/code/modules/food_and_drinks/food/snacks_frozen.dm index c4f8ccf76b..3988909b30 100644 --- a/code/modules/food_and_drinks/food/snacks_frozen.dm +++ b/code/modules/food_and_drinks/food/snacks_frozen.dm @@ -28,6 +28,50 @@ tastes = list("ice cream" = 1, "banana" = 1, "a bad joke" = 1) foodtype = FRUIT | DAIRY | SUGAR +/obj/item/reagent_containers/food/snacks/banana_split + name = "banana split" + trash = /obj/item/reagent_containers/food/drinks/drinkingglass + desc = "A long glass dish filled with ice-cream, chocolate and a banana down the middle. A timeless classic by any standards." + icon_state = "banana_split" + bonus_reagents = list("nutriment" = 5, "vitamin" = 3) + list_reagents = list("nutriment" = 3, "banana" = 10, "vitamin" = 2) + filling_color = "#FFFACD" + tastes = list("ice cream" = 1, "banana" = 1, "charries" = 1) + foodtype = FRUIT | DAIRY | SUGAR + +/obj/item/reagent_containers/food/snacks/cola_float + name = "Root Beer Float" + trash = /obj/item/reagent_containers/food/drinks/drinkingglass + desc = "A glass filled with cream, soda and ice-cream with a cherry on top." + icon_state = "cola_float" + bonus_reagents = list("nutriment" = 3, "vitamin" = 1) + list_reagents = list("nutriment" = 3, "vitamin" = 2) + filling_color = "#FFFACD" + tastes = list("ice cream" = 1, "space coal" = 1, "cherries" = 1) + foodtype = FRUIT | DAIRY | SUGAR + +/obj/item/reagent_containers/food/snacks/charrie_float + name = "Cherry Shake" + trash = /obj/item/reagent_containers/food/drinks/drinkingglass + desc = "Cherries mixed with ice-cream, known for its filling tastes" + icon_state = "cherryshake" + bonus_reagents = list("nutriment" = 3, "vitamin" = 1) + list_reagents = list("nutriment" = 3, "vitamin" = 2, "cherryshake" = 15) + filling_color = "#FFFACD" + tastes = list("ice cream" = 1, "charries" = 1) + foodtype = FRUIT | DAIRY | SUGAR + +/obj/item/reagent_containers/food/snacks/bluecharrie_float + name = "Blue Cherry Shake" + trash = /obj/item/reagent_containers/food/drinks/drinkingglass + desc = "Cherries mixed with ice-cream, known for its filling tastes. This one is a exotic blue!" + icon_state = "bluecherryshake" + bonus_reagents = list("nutriment" = 3, "vitamin" = 1) + list_reagents = list("nutriment" = 3, "vitamin" = 2, "bluecherryshake" = 10) + filling_color = "#FFFACD" + tastes = list("ice cream" = 1, "blue cherries" = 1) + foodtype = FRUIT | DAIRY | SUGAR + /obj/item/reagent_containers/food/snacks/spacefreezy name = "space freezy" desc = "The best icecream in space." @@ -126,6 +170,22 @@ tastes = list("ice" = 1, "water" = 1, "berries" = 5) foodtype = FRUIT +/obj/item/reagent_containers/food/snacks/snowcones/peach + name = "peach flavored snowcone" + desc = "A peach flavord snowball in a paper cup." + icon_state = "peach_sc" + list_reagents = list("nutriment" = 1, "peachjuice" = 10) + tastes = list("ice" = 1, "water" = 1, " peach" = 5) + foodtype = FRUIT + +/obj/item/reagent_containers/food/snacks/snowcones/strawberry + name = "strawberry flavored snowcone" + desc = "A strawberry flavord snowball in a paper cup." + icon_state = "blue_sc" + list_reagents = list("nutriment" = 1, "berryjuice" = 10) + tastes = list("ice" = 1, "water" = 1, " strawberry" = 5) + foodtype = FRUIT + /obj/item/reagent_containers/food/snacks/snowcones/fruitsalad name = "mixed fruit flavored snowcone" desc = "A mix of different flavors dizzled on a snowball in a paper cup." diff --git a/code/modules/food_and_drinks/food/snacks_meat.dm b/code/modules/food_and_drinks/food/snacks_meat.dm index cf99bd78d9..0b53ec8822 100644 --- a/code/modules/food_and_drinks/food/snacks_meat.dm +++ b/code/modules/food_and_drinks/food/snacks_meat.dm @@ -322,6 +322,14 @@ filling_color = "#800000" tastes = list("meat" = 1, "butter" = 1) +/obj/item/reagent_containers/food/snacks/corndog + name = "corndog plate" + desc = "A plate with two small corn dogs, with two dimples of ketchup and mustard to dip them in." + icon_state = "dorndog" + trash = /obj/item/trash/plate/alt + tastes = list("hotdog" = 2, "mustard and ketchup" = 1, "fryed bread" = 1) + bonus_reagents = list("nutriment" = 6, "vitamin" = 2, "mustard" = 5, "ketchup" = 5) + /obj/item/reagent_containers/food/snacks/kebab/rat name = "rat-kebab" desc = "Not so delicious rat meat, on a stick." diff --git a/code/modules/food_and_drinks/food/snacks_other.dm b/code/modules/food_and_drinks/food/snacks_other.dm index e36efe750b..ad0824dd79 100644 --- a/code/modules/food_and_drinks/food/snacks_other.dm +++ b/code/modules/food_and_drinks/food/snacks_other.dm @@ -573,4 +573,22 @@ name = "Maintenance Peaches" desc = "I have a mouth and I must eat." icon_state = "peachcanmaint" - tastes = list("peaches" = 1, "tin" = 7) \ No newline at end of file + tastes = list("peaches" = 1, "tin" = 7) + +/obj/item/reagent_containers/food/snacks/chocolatestrawberry + name = "Chocolate dipped strawberries" + desc = "A strawberry dipped in a bit of chocolate." + icon_state = "chocolatestrawberry" + list_reagents = list("sugar" = 5, "nutriment" = 2) + filling_color = "#ffdf26" + tastes = list("strawberries" = 5, "chocolate" = 3) + foodtype = FRUIT | SUGAR + +/obj/item/reagent_containers/food/snacks/chocolatebanana + name = "Chocolate dipped banana" + desc = "A banana dipped in a bit of chocolate and held on a stick." + icon_state = "banana_coco" + list_reagents = list("sugar" = 5, "nutriment" = 3, "vitamin" = 1) + filling_color = "#ffdf26" + tastes = list("banana" = 5, "chocolate" = 3) + foodtype = FRUIT | SUGAR \ No newline at end of file diff --git a/code/modules/food_and_drinks/food/snacks_pastry.dm b/code/modules/food_and_drinks/food/snacks_pastry.dm index 238bb4f86a..9b87002738 100644 --- a/code/modules/food_and_drinks/food/snacks_pastry.dm +++ b/code/modules/food_and_drinks/food/snacks_pastry.dm @@ -308,7 +308,6 @@ tastes = list("bread" = 1, "egg" = 1, "cheese" = 1) foodtype = GRAIN | MEAT | DAIRY - /obj/item/reagent_containers/food/snacks/sugarcookie name = "sugar cookie" desc = "Just like your little sister used to make." @@ -369,6 +368,16 @@ tastes = list("cake" = 3, "blue cherry" = 1) foodtype = GRAIN | FRUIT | SUGAR +/obj/item/reagent_containers/food/snacks/strawberrycupcake + name = "Strawberry cupcake" + desc = "Strawberry inside a delicious cupcake." + icon_state = "strawberrycupcake" + bonus_reagents = list("nutriment" = 1, "vitamin" = 3) + list_reagents = list("nutriment" = 5, "vitamin" = 1) + filling_color = "#F0E68C" + tastes = list("cake" = 2, "strawberry" = 1) + foodtype = GRAIN | FRUIT | SUGAR + /obj/item/reagent_containers/food/snacks/honeybun name = "honey bun" desc = "A sticky pastry bun glazed with honey." diff --git a/code/modules/food_and_drinks/food/snacks_pie.dm b/code/modules/food_and_drinks/food/snacks_pie.dm index 20313fd1b7..bc66d353e1 100644 --- a/code/modules/food_and_drinks/food/snacks_pie.dm +++ b/code/modules/food_and_drinks/food/snacks_pie.dm @@ -315,4 +315,20 @@ filling_color = "#1E90FF" list_reagents = list("nutriment" = 2, "vitamin" = 4) tastes = list("nuts" = 1, "pie" = 1) - foodtype = GRAIN \ No newline at end of file + foodtype = GRAIN + +/obj/item/reagent_containers/food/snacks/pie/strawberrypie + name = "strawberry pie" + desc = "A strawberry pie." + icon_state = "strawberrypie" + bonus_reagents = list("nutriment" = 6, "vitamin" = 6) + tastes = list("strawberry" = 1, "pie" = 1) + foodtype = GRAIN | FRUIT | SUGAR + +/obj/item/reagent_containers/food/snacks/pie/peachpie + name = "peach pie" + desc = "A pie with peach filling." + icon_state = "strawberrypie" + bonus_reagents = list("nutriment" = 5, "vitamin" = 6, "peachjuice" = 15) + tastes = list("peach" = 1, "pie" = 1) + foodtype = GRAIN | FRUIT diff --git a/code/modules/food_and_drinks/food/snacks_vend.dm b/code/modules/food_and_drinks/food/snacks_vend.dm index 317a434040..8f661b868e 100644 --- a/code/modules/food_and_drinks/food/snacks_vend.dm +++ b/code/modules/food_and_drinks/food/snacks_vend.dm @@ -7,7 +7,7 @@ desc = "Nougat love it or hate it." icon_state = "candy" trash = /obj/item/trash/candy - list_reagents = list("nutriment" = 1, "sugar" = 3) + list_reagents = list("nutriment" = 1, "sugar" = 3, "cocoa" = 3) junkiness = 25 filling_color = "#D2691E" tastes = list("candy" = 1) diff --git a/code/modules/food_and_drinks/kitchen_machinery/icecream_vat.dm b/code/modules/food_and_drinks/kitchen_machinery/icecream_vat.dm index 58d3ef69bb..0f901f2412 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/icecream_vat.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/icecream_vat.dm @@ -1,9 +1,13 @@ #define ICECREAM_VANILLA 1 #define ICECREAM_CHOCOLATE 2 #define ICECREAM_STRAWBERRY 3 -#define ICECREAM_BLUE 4 -#define CONE_WAFFLE 5 -#define CONE_CHOC 6 +#define ICECREAM_PEACH 4 +#define ICECREAM_GRAPE 5 +#define ICECREAM_BLUE 6 +#define CONE_WAFFLE 7 +#define CONE_CHOC 8 + + /obj/machinery/icecream_vat name = "ice cream vat" @@ -26,7 +30,9 @@ "cocoa" = 5, "vanilla" = 5, "berryjuice" = 5, - "singulo" = 5) + "singulo" = 5, + "peachjuice" = 5, + "grapejuice" = 5) /obj/machinery/icecream_vat/proc/get_ingredient_list(type) switch(type) @@ -34,6 +40,10 @@ return list("milk", "ice", "cocoa") if(ICECREAM_STRAWBERRY) return list("milk", "ice", "berryjuice") + if(ICECREAM_PEACH) + return list("milk", "ice", "peachjuice") + if(ICECREAM_GRAPE) + return list("milk", "ice", "grapejuice") if(ICECREAM_BLUE) return list("milk", "ice", "singulo") if(CONE_WAFFLE) @@ -50,6 +60,10 @@ return "chocolate" if(ICECREAM_STRAWBERRY) return "strawberry" + if(ICECREAM_PEACH) + return "peach" + if(ICECREAM_GRAPE) + return "grape" if(ICECREAM_BLUE) return "blue" if(CONE_WAFFLE) @@ -62,7 +76,7 @@ /obj/machinery/icecream_vat/Initialize() . = ..() - while(product_types.len < 6) + while(product_types.len < 8) product_types.Add(5) create_reagents(100, OPENCONTAINER | NO_REACT) for(var/reagent in icecream_vat_reagents) @@ -76,6 +90,8 @@ dat += "Vanilla ice cream: SelectMakex5 [product_types[ICECREAM_VANILLA]] scoops left. (Ingredients: milk, ice)
" dat += "Strawberry ice cream:SelectMakex5 [product_types[ICECREAM_STRAWBERRY]] dollops left. (Ingredients: milk, ice, berry juice)
" dat += "Chocolate ice cream:SelectMakex5 [product_types[ICECREAM_CHOCOLATE]] dollops left. (Ingredients: milk, ice, coco powder)
" + dat += "Peach ice cream:SelectMakex5 [product_types[ICECREAM_PEACH]] dollops left. (Ingredients: milk, ice, peach juice)
" + dat += "Grape ice cream:SelectMakex5 [product_types[ICECREAM_GRAPE]] dollops left. (Ingredients: milk, ice, grape juice)
" dat += "Blue ice cream:SelectMakex5 [product_types[ICECREAM_BLUE]] dollops left. (Ingredients: milk, ice, singulo)
" dat += "
CONES
" dat += "Waffle cones: Dispense Make x5 [product_types[CONE_WAFFLE]] cones left. (Ingredients: flour, sugar)
" @@ -207,6 +223,12 @@ if ("strawberry") desc = "A delicious [cone_type] cone filled with strawberry ice cream. Definitely not made with real strawberries." reagents.add_reagent("berryjuice", 2) + if ("peach") + desc = "A delicious [cone_type] cone filled with peach ice cream. Definitely made with real peaches!" + reagents.add_reagent("peachjuice", 2) + if ("grape") + desc = "A delicious [cone_type] cone filled with grape ice cream. Surprisingly, made with real pink grape, likely not real sugarcanes used." + reagents.add_reagent("grapejuice", 2) if ("blue") desc = "A delicious [cone_type] cone filled with blue ice cream. Made with real... blue?" reagents.add_reagent("singulo", 2) @@ -228,6 +250,8 @@ #undef ICECREAM_VANILLA #undef ICECREAM_CHOCOLATE #undef ICECREAM_STRAWBERRY +#undef ICECREAM_PEACH +#undef ICECREAM_GRAPE #undef ICECREAM_BLUE #undef CONE_WAFFLE #undef CONE_CHOC diff --git a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm index 483055cb0d..ceb7a01ede 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm @@ -144,6 +144,13 @@ else O.forceMove(src) return TRUE + +///Really simple proc, just moves the object "O" into the hands of mob "M" if able, done so I could modify the proc a little for the organ fridge +/obj/machinery/smartfridge/proc/dispense(obj/item/O, var/mob/M) + if(!M.put_in_hands(O)) + O.forceMove(drop_location()) + adjust_item_drop_location(O) + /obj/machinery/smartfridge/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) @@ -197,9 +204,7 @@ if(desired == 1 && Adjacent(usr) && !issilicon(usr)) for(var/obj/item/O in src) if(O.name == params["name"]) - if(!usr.put_in_hands(O)) - O.forceMove(drop_location()) - adjust_item_drop_location(O) + dispense(O, usr) break if (visible_contents) update_icon() @@ -209,8 +214,7 @@ if(desired <= 0) break if(O.name == params["name"]) - O.forceMove(drop_location()) - adjust_item_drop_location(O) + dispense(O, usr) desired-- if (visible_contents) update_icon() @@ -378,6 +382,44 @@ /obj/machinery/smartfridge/extract/preloaded initial_contents = list(/obj/item/slime_scanner = 2) +// ------------------------- You think you're better than Chem, huh? +// Organ Surgery Smartfridge +// ------------------------- Just wait till Tamiorgans +/obj/machinery/smartfridge/organ + name = "smart organ storage" + desc = "A refrigerated storage unit for organ storage." + max_n_of_items = 20 //vastly lower to prevent processing too long + var/repair_rate = 0 + +/obj/machinery/smartfridge/organ/accept_check(obj/item/O) + if(istype(O, /obj/item/organ)) + return TRUE + return FALSE + +/obj/machinery/smartfridge/organ/load(obj/item/O) + . = ..() + if(!.) //if the item loads, clear can_decompose + return + var/obj/item/organ/organ = O + organ.organ_flags |= ORGAN_FROZEN + +/obj/machinery/smartfridge/organ/RefreshParts() + for(var/obj/item/stock_parts/matter_bin/B in component_parts) + max_n_of_items = 20 * B.rating + repair_rate = max(0, STANDARD_ORGAN_HEALING * (B.rating - 1)) + +/obj/machinery/smartfridge/organ/process() + for(var/organ in contents) + var/obj/item/organ/O = organ + if(!istype(O)) + return + O.applyOrganDamage(-repair_rate) + +/obj/machinery/smartfridge/organ/Exited(obj/item/organ/AM, atom/newLoc) + . = ..() + if(istype(AM)) + AM.organ_flags &= ~ORGAN_FROZEN + // ----------------------------- // Chemistry Medical Smartfridge // ----------------------------- diff --git a/code/modules/food_and_drinks/recipes/drinks_recipes.dm b/code/modules/food_and_drinks/recipes/drinks_recipes.dm index 7c44857b1d..c83048e4b1 100644 --- a/code/modules/food_and_drinks/recipes/drinks_recipes.dm +++ b/code/modules/food_and_drinks/recipes/drinks_recipes.dm @@ -381,6 +381,36 @@ id = "neurotoxin" results = list("neurotoxin" = 2) required_reagents = list("gargleblaster" = 1, "morphine" = 1) + //FermiChem vars: Easy to make, but hard to make potent + OptimalTempMin = 200 // Lower area of bell curve for determining heat based rate reactions + OptimalTempMax = 950 // Upper end for above + ExplodeTemp = 999 //Temperature at which reaction explodes + OptimalpHMin = 4.6 // Lowest value of pH determining pH a 1 value for pH based rate reactions (Plateu phase) + OptimalpHMax = 5.2 // Higest value for above + ReactpHLim = 5 // How far out pH wil react, giving impurity place (Exponential phase) + CatalystFact = 0 // How much the catalyst affects the reaction (0 = no catalyst) + CurveSharpT = 2 // How sharp the temperature exponential curve is (to the power of value) + CurveSharppH = 4 // How sharp the pH exponential curve is (to the power of value) + ThermicConstant = 10 //Temperature change per 1u produced + HIonRelease = 0.02 //pH change per 1u reaction + RateUpLim = 5 //Optimal/max rate possible if all conditions are perfect + FermiChem = TRUE//If the chemical uses the Fermichem reaction mechanics + FermiExplode = FALSE //If the chemical explodes in a special way + PurityMin = 0 //The minimum purity something has to be above, otherwise it explodes. + clear_conversion = REACTION_CLEAR_INVERSE + +/* +/datum/chemical_reaction/neurotoxin/FermiFinish(datum/reagents/holder, var/atom/my_atom) + var/datum/reagent/consumable/ethanol/neurotoxin/Nt = locate(/datum/reagent/consumable/ethanol/neurotoxin) in my_atom.reagents.reagent_list + var/cached_volume = Nt.volume + if(Nt.purity < 0.5) + holder.remove_reagent(src.id, cached_volume) + holder.add_reagent("neuroweak", cached_volume) +*/ + +/datum/chemical_reaction/neurotoxin/FermiExplode(datum/reagents, var/atom/my_atom, volume, temp, pH)//reduced size + volume = volume/10 + ..() /datum/chemical_reaction/snowwhite name = "Snow White" @@ -454,18 +484,6 @@ results = list("vanillapudding" = 20) required_reagents = list("vanilla" = 5, "milk" = 5, "eggyolk" = 5) -/datum/chemical_reaction/cherryshake - name = "Cherry Shake" - id = "cherryshake" - results = list("cherryshake" = 3) - required_reagents = list("cherryjelly" = 1, "ice" = 1, "cream" = 1) - -/datum/chemical_reaction/bluecherryshake - name = "Blue Cherry Shake" - id = "bluecherryshake" - results = list("bluecherryshake" = 3) - required_reagents = list("bluecherryjelly" = 1, "ice" = 1, "cream" = 1) - /datum/chemical_reaction/drunkenblumpkin name = "Drunken Blumpkin" id = "drunkenblumpkin" @@ -794,4 +812,17 @@ name = "Red Queen" id = "red_queen" results = list("red_queen" = 10) - required_reagents = list("tea" = 6, "mercury" = 2, "blackpepper" = 1, "growthserum" = 1) \ No newline at end of file + required_reagents = list("tea" = 6, "mercury" = 2, "blackpepper" = 1, "growthserum" = 1) + +/datum/chemical_reaction/catnip_tea + name = "Catnip Tea" + id = "catnip_tea" + results = list("catnip_tea" = 3) + required_reagents = list("tea" = 5, "catnip" = 2) + +/datum/chemical_reaction/commander_and_chief + name = "Commander and Chief" + id = "commander_and_chief" + results = list("commander_and_chief" = 50) + required_reagents = list("alliescocktail" = 50, "champagne" = 20, "doctorsdelight" = 10, "quintuple_sec" = 10, "screwdrivercocktail" = 10) + mix_message = "When your powers combine, I am Captain Pl-..." diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_cake.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_cake.dm index e26d15dbd3..284affe2ec 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_cake.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_cake.dm @@ -169,6 +169,15 @@ result = /obj/item/reagent_containers/food/snacks/store/cake/vanilla_cake subcategory = CAT_CAKE +/datum/crafting_recipe/food/peachcake + name = "Peach cake" + reqs = list( + /obj/item/reagent_containers/food/snacks/store/cake/plain = 1, + /obj/item/reagent_containers/food/snacks/grown/peach = 5 + ) + result = /obj/item/reagent_containers/food/snacks/store/cake/peach_cake + subcategory = CAT_CAKE + /datum/crafting_recipe/food/cak name = "Living cat/cake hybrid" reqs = list( diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_frozen.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_frozen.dm index 73b09df68d..8f4c5d05f1 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_frozen.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_frozen.dm @@ -42,6 +42,52 @@ result = /obj/item/reagent_containers/food/snacks/honkdae subcategory = CAT_ICE +/datum/crafting_recipe/food/banana_split + name = "Banana Split" + always_availible = FALSE + reqs = list( + /obj/item/reagent_containers/food/snacks/icecream = 3, + /obj/item/reagent_containers/food/snacks/grown/banana = 1, + /obj/item/reagent_containers/food/snacks/grown/cherries = 1, + /obj/item/reagent_containers/food/snacks/chocolatebar = 1 + ) + result = /obj/item/reagent_containers/food/snacks/banana_split + subcategory = CAT_ICE + +/datum/crafting_recipe/food/root_float + name = "Cola Float" + always_availible = FALSE + reqs = list( + /obj/item/reagent_containers/food/snacks/icecream = 1, + /obj/item/reagent_containers/food/snacks/grown/cherries = 1, + /datum/reagent/consumable/space_cola = 10, + /obj/item/reagent_containers/food/drinks/drinkingglass = 1 + ) + result = /obj/item/reagent_containers/food/snacks/cola_float + subcategory = CAT_ICE + +/datum/crafting_recipe/food/charrie_float + name = "Cherry Shake" + always_availible = FALSE + reqs = list( + /obj/item/reagent_containers/food/snacks/icecream = 1, + /obj/item/reagent_containers/food/snacks/grown/cherries = 3, + /obj/item/reagent_containers/food/drinks/drinkingglass = 1 + ) + result = /obj/item/reagent_containers/food/snacks/charrie_float + subcategory = CAT_ICE + +/datum/crafting_recipe/food/bluecharrie_float + name = "Blue Cherry Shake" + always_availible = FALSE + reqs = list( + /obj/item/reagent_containers/food/snacks/icecream = 1, + /obj/item/reagent_containers/food/snacks/grown/bluecherries = 3, + /obj/item/reagent_containers/food/drinks/drinkingglass = 1 + ) + result = /obj/item/reagent_containers/food/snacks/bluecharrie_float + subcategory = CAT_ICE + //////////////////////////SNOW CONES/////////////////////// /datum/crafting_recipe/food/flaverless_sc @@ -232,6 +278,28 @@ result = /obj/item/reagent_containers/food/snacks/snowcones/honey subcategory = CAT_ICE +/datum/crafting_recipe/food/peach_sc + name = "Peach snowcone" + reqs = list( + /obj/item/reagent_containers/food/drinks/sillycup = 1, + /datum/reagent/water = 5, + /datum/reagent/consumable/ice = 15, + /obj/item/reagent_containers/food/snacks/grown/peach = 1 + ) + result = /obj/item/reagent_containers/food/snacks/snowcones/peach + subcategory = CAT_ICE + +/datum/crafting_recipe/food/strawberry_sc + name = "Strawberry snowcone" + reqs = list( + /obj/item/reagent_containers/food/drinks/sillycup = 1, + /datum/reagent/water = 5, + /datum/reagent/consumable/ice = 15, + /obj/item/reagent_containers/food/snacks/grown/strawberry = 2 + ) + result = /obj/item/reagent_containers/food/snacks/snowcones/strawberry + subcategory = CAT_ICE + /datum/crafting_recipe/food/honey_sc name = "Rainbow snowcone" reqs = list( diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_meat.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_meat.dm index 7eff2820c5..d17ccf585e 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_meat.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_meat.dm @@ -128,6 +128,18 @@ result = /obj/item/reagent_containers/food/snacks/pigblanket subcategory = CAT_MEAT +/datum/crafting_recipe/food/corndog + name = "Corndog meal" + reqs = list( + /obj/item/stack/rods = 1, + /obj/item/reagent_containers/food/snacks/meat/cutlet = 1, + /obj/item/reagent_containers/food/snacks/bun = 1, + /datum/reagent/consumable/mustard = 5, + /datum/reagent/consumable/ketchup = 5 + ) + result = /obj/item/reagent_containers/food/snacks/corndog + subcategory = CAT_MEAT + /datum/crafting_recipe/food/ratkebab name = "Rat Kebab" reqs = list( diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_misc.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_misc.dm index ce33cbef77..9cf5ea31a0 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_misc.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_misc.dm @@ -332,3 +332,12 @@ ) result = /obj/item/reagent_containers/food/snacks/riceball subcategory = CAT_MISCFOOD + +/datum/crafting_recipe/food/chocolatestrawberry + name = "Chocolate Strawberry" + reqs = list( + /obj/item/reagent_containers/food/snacks/chocolatebar = 1, + /obj/item/reagent_containers/food/snacks/grown/strawberry = 1 + ) + result = /obj/item/reagent_containers/food/snacks/chocolatestrawberry + subcategory = CAT_MISCFOOD \ No newline at end of file diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm index 2246d12df4..365cf499bb 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm @@ -23,7 +23,7 @@ result = /obj/item/reagent_containers/food/snacks/donut subcategory = CAT_PASTRY -/datum/crafting_recipe/food/donut +/datum/crafting_recipe/food/donut/semen time = 15 name = "Semen donut" reqs = list( @@ -325,6 +325,15 @@ datum/crafting_recipe/food/donut/meat result = /obj/item/reagent_containers/food/snacks/bluecherrycupcake subcategory = CAT_PASTRY +/datum/crafting_recipe/food/strawberrycupcake + name = "Strawberry cherry cupcake" + reqs = list( + /obj/item/reagent_containers/food/snacks/pastrybase = 1, + /obj/item/reagent_containers/food/snacks/grown/strawberry = 1 + ) + result = /obj/item/reagent_containers/food/snacks/strawberrycupcake + subcategory = CAT_PASTRY + /datum/crafting_recipe/food/honeybun name = "Honey bun" reqs = list( diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pie.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pie.dm index 39eb4ce05e..30c265e237 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pie.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pie.dm @@ -160,6 +160,15 @@ result = /obj/item/reagent_containers/food/snacks/pie/frostypie subcategory = CAT_PIE +/datum/crafting_recipe/food/strawberrypie + name = "Strawberry pie" + reqs = list( + /obj/item/reagent_containers/food/snacks/pie/plain = 1, + /obj/item/reagent_containers/food/snacks/grown/strawberry = 1 + ) + result = /obj/item/reagent_containers/food/snacks/pie/strawberrypie + subcategory = CAT_PIE + /datum/crafting_recipe/food/baklava name = "Baklava pie" reqs = list( @@ -205,4 +214,13 @@ /obj/item/slime_extract = 1 ) result = /obj/item/reagent_containers/food/snacks/pie/cocolavatart + subcategory = CAT_PIE + +/datum/crafting_recipe/food/peachpie + name = "Peach Pie" + reqs = list( + /obj/item/reagent_containers/food/snacks/pie/plain = 1, + /obj/item/reagent_containers/food/snacks/grown/peach = 3 + ) + result = /obj/item/reagent_containers/food/snacks/pie/peachpie subcategory = CAT_PIE \ No newline at end of file diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm index 082f20f524..c273690571 100644 --- a/code/modules/goonchat/browserOutput.dm +++ b/code/modules/goonchat/browserOutput.dm @@ -82,11 +82,13 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico if("setMusicVolume") data = setMusicVolume(arglist(params)) - if("swaptodarkmode") - swaptodarkmode() + if("colorPresetPost") //User just swapped color presets in their goonchat preferences. Do we do anything else? + switch(href_list["preset"]) + if("light") + owner.force_white_theme() + if("dark" || "normal") + owner.force_dark_theme() - if("swaptolightmode") - swaptolightmode() if(data) ehjax_send(data = data) @@ -160,7 +162,7 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico var/list/row = src.connectionHistory[i] if (!row || row.len < 3 || (!row["ckey"] || !row["compid"] || !row["ip"])) //Passed malformed history object return - if (world.IsBanned(row["ckey"], row["compid"], row["ip"], real_bans_only=TRUE)) + if (world.IsBanned(row["ckey"], row["ip"], row["compid"], real_bans_only=TRUE)) found = row break @@ -181,8 +183,8 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico log_world("\[[time2text(world.realtime, "YYYY-MM-DD hh:mm:ss")]\] Client: [(src.owner.key ? src.owner.key : src.owner)] triggered JS error: [error]") //Global chat procs -/proc/to_chat(target, message, handle_whitespace=TRUE) - if(!target) +/proc/to_chat_immediate(target, message, handle_whitespace=TRUE) + if(!target || !message) return //Ok so I did my best but I accept that some calls to this will be for shit like sound and images @@ -204,7 +206,7 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico message = replacetext(message, "\proper", "") if(handle_whitespace) message = replacetext(message, "\n", "
") - message = replacetext(message, "\t", "[GLOB.TAB][GLOB.TAB]") + message = replacetext(message, "\t", "[FOURSPACES][FOURSPACES]") if(islist(target)) // Do the double-encoding outside the loop to save nanoseconds @@ -247,6 +249,11 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico // url_encode it TWICE, this way any UTF-8 characters are able to be decoded by the Javascript. C << output(url_encode(url_encode(message)), "browseroutput:output") +/proc/to_chat(target, message, handle_whitespace = TRUE) + if(Master.current_runlevel == RUNLEVEL_INIT || !SSchat?.initialized) + to_chat_immediate(target, message, handle_whitespace) + return + SSchat.queue(target, message, handle_whitespace) /datum/chatOutput/proc/swaptolightmode() //Dark mode light mode stuff. Yell at KMC if this breaks! (See darkmode.dm for documentation) owner.force_white_theme() diff --git a/code/modules/goonchat/browserassets/css/browserOutput.css b/code/modules/goonchat/browserassets/css/browserOutput.css index b6db020df0..796d630693 100644 --- a/code/modules/goonchat/browserassets/css/browserOutput.css +++ b/code/modules/goonchat/browserassets/css/browserOutput.css @@ -7,20 +7,16 @@ html, body { padding: 0; margin: 0; height: 100%; - color: #f0f0f0; + color: #000000; } body { - background: #171717; + background: #E0E0E0; /*CIT CHANGE - darkens chatbox a lil*/ font-family: Verdana, sans-serif; font-size: 9pt; - font-color: #f0f0f0; line-height: 1.2; overflow-x: hidden; overflow-y: scroll; - word-wrap: break-word; - scrollbar-face-color:#1A1A1A; - scrollbar-track-color:#171717; - scrollbar-highlight-color:#171717; + word-wrap: break-word; } em { @@ -60,9 +56,9 @@ img.icon { border-radius: 10px; } -a {color: #397ea5;} -a.visited {color: #7c00e6;} -a:visited {color: #7c00e6;} +a {color: #0000ff;} +a.visited {color: #ff00ff;} +a:visited {color: #ff00ff;} a.popt {text-decoration: none;} /***************************************** @@ -93,21 +89,21 @@ a.popt {text-decoration: none;} bottom: 0; right: 0; padding: 8px; - background: #202020; + background: #d0d0d0; text-decoration: none; font-variant: small-caps; font-size: 1.1em; font-weight: bold; - color: #a4bad6; + color: #333; } -#newMessages:hover {background: #171717;} +#newMessages:hover {background: #ccc;} #newMessages i {vertical-align: middle; padding-left: 3px;} #ping { position: fixed; top: 0; right: 115px; width: 45px; - background: #202020; + background: #d0d0d0; height: 30px; padding: 8px 0 2px 0; } @@ -124,19 +120,19 @@ a.popt {text-decoration: none;} right: 0; } #userBar .subCell { - background: #202020; + background: #d0d0d0; height: 30px; padding: 5px 0; display: block; - color: #a4bad6; + color: #333; text-decoration: none; line-height: 28px; - border-top: 1px solid #171717; + border-top: 1px solid #b4b4b4; } -#userBar .subCell:hover {background: #202020;} +#userBar .subCell:hover {background: #ccc;} #userBar .toggle { width: 40px; - background: #202020; + background: #ccc; border-top: 0; float: right; text-align: center; @@ -172,7 +168,7 @@ a.popt {text-decoration: none;} position: fixed; top: 50%; left: 50%; - background: #ddd; + background: #d0d0d0; } .popup .close { position: absolute; @@ -189,7 +185,7 @@ a.popt {text-decoration: none;} .popup .close:hover {background: #999;} .popup .head { background: #999; - color: #ddd; + color: #d0d0d0; padding: 0 10px; height: 30px; line-height: 30px; @@ -200,7 +196,7 @@ a.popt {text-decoration: none;} } .popup input {border: 1px solid #999; background: #fff; margin: 0; padding: 5px; outline: none; color: #333;} .popup input[type=text]:hover, .popup input[type=text]:active, .popup input[type=text]:focus {border-color: green;} -.popup input[type=submit] {padding: 5px 10px; background: #999; color: #ddd; text-transform: uppercase; font-size: 0.9em; font-weight: bold;} +.popup input[type=submit] {padding: 5px 10px; background: #999; color: #d0d0d0; text-transform: uppercase; font-size: 0.9em; font-weight: bold;} .popup input[type=submit]:hover, .popup input[type=submit]:focus, .popup input[type=submit]:active {background: #aaa; cursor: pointer;} .changeFont {padding: 10px;} @@ -214,7 +210,7 @@ a.popt {text-decoration: none;} /* ADMIN CONTEXT MENU */ .contextMenu { - background-color: #ddd; + background-color: #d0d0d0; position: fixed; margin: 2px; width: 150px; @@ -246,9 +242,9 @@ a.popt {text-decoration: none;} ******************************************/ /* MOTD */ -.motd {color: #a4bad6; font-family: Verdana, sans-serif;} -.motd h1, .motd h2, .motd h3, .motd h4, .motd h5, .motd h6 {color: #a4bad6; text-decoration: underline;} -.motd a, .motd a:link, .motd a:visited, .motd a:active, .motd a:hover {color: #a4bad6;} +.motd {color: #638500; font-family: Verdana, sans-serif;} +.motd h1, .motd h2, .motd h3, .motd h4, .motd h5, .motd h6 {color: #638500; text-decoration: underline;} +.motd a, .motd a:link, .motd a:visited, .motd a:active, .motd a:hover {color: #638500;} /* ADD HERE FOR BOLD */ .bold, .name, .prefix, .ooc, .looc, .adminooc, .admin, .medal, .yell {font-weight: bold;} @@ -259,90 +255,91 @@ a.popt {text-decoration: none;} /* OUTPUT COLORS */ .highlight {background: yellow;} -h1, h2, h3, h4, h5, h6 {color: #a4bad6;font-family: Georgia, Verdana, sans-serif;} -h1.alert, h2.alert {color: #a4bad6;} +h1, h2, h3, h4, h5, h6 {color: #0000ff;font-family: Georgia, Verdana, sans-serif;} +h1.alert, h2.alert {color: #000000;} em {font-style: normal; font-weight: bold;} -.ooc {color: #cca300; font-weight: bold;} -.antagooc {color: #ce254f; font-weight: bold;} +.ooc {color: #002eb8; font-weight: bold;} +.looc {color: #6699CC; font-weight: bold;} +.antagooc {color: #b8002e; font-weight: bold;} .adminobserverooc {color: #0099cc; font-weight: bold;} -.adminooc {color: #3d5bc3; font-weight: bold;} +.adminooc {color: #700038; font-weight: bold;} -.adminsay {color: #ff4500; font-weight: bold;} -.admin {color: #5975da; font-weight: bold;} +.adminsay {color: #FF4500} +.admin {color: #386aff; font-weight: bold;} .name { font-weight: bold;} .say {} -.deadsay {color: #e2c1ff;} +.deadsay {color: #5c00e6;} .binarysay {color: #20c20e; background-color: #000000; display: block;} .binarysay a {color: #00ff00;} .binarysay a:active, .binarysay a:visited {color: #88ff88;} -.radio {color: #1ecc43;} -.sciradio {color: #c68cfa;} -.comradio {color: #5177ff;} -.secradio {color: #dd3535;} -.medradio {color: #57b8f0;} -.engradio {color: #f37746;} -.suppradio {color: #b88646;} -.servradio {color: #6ca729;} -.syndradio {color: #8f4a4b;} -.centcomradio {color: #2681a5;} -.aiprivradio {color: #d65d95;} -.redteamradio {color: #ff4444;} -.blueteamradio {color: #3434fd;} +.radio {color: #008000;} +.sciradio {color: #993399;} +.comradio {color: #948f02;} +.secradio {color: #a30000;} +.medradio {color: #337296;} +.engradio {color: #fb5613;} +.suppradio {color: #a8732b;} +.servradio {color: #6eaa2c;} +.syndradio {color: #6d3f40;} +.centcomradio {color: #686868;} +.aiprivradio {color: #ff00ff;} +.redteamradio {color: #ff0000;} +.blueteamradio {color: #0000ff;} .yell { font-weight: bold;} -.alert {color: #d82020;} -h1.alert, h2.alert {color: #99aab5;} +.alert {color: #ff0000;} +h1.alert, h2.alert {color: #000000;} .emote { font-style: italic;} .selecteddna {color: #ffffff; background-color: #001B1B} -.attack {color: #e01c1c;} -.disarm {color: #b42525;} -.passive {color: #a00f0f;} +.attack {color: #ff0000;} +.disarm {color: #990000;} +.passive {color: #660000;} -.userdanger {color: #c51e1e; font-weight: bold; font-size: 24px;} -.danger {color: #c51e1e;} -.warning {color: #c51e1e; font-style: italic;} +.userdanger {color: #ff0000; font-weight: bold; font-size: 24px;} +.danger {color: #ff0000;} +.warning {color: #ff0000; font-style: italic;} .alertwarning {color: #FF0000; font-weight: bold} -.boldwarning {color: #c51e1e; font-style: italic; font-weight: bold} -.announce {color: #c51e1e; font-weight: bold;} -.boldannounce {color: #c51e1e; font-weight: bold;} -.greenannounce {color: #059223; font-weight: bold;} +.boldwarning {color: #ff0000; font-style: italic; font-weight: bold} +.announce {color: #228b22; font-weight: bold;} +.boldannounce {color: #ff0000; font-weight: bold;} +.greenannounce {color: #00ff00; font-weight: bold;} .rose {color: #ff5050;} -.info {color: #6685f5;} -.notice {color: #6685f5;} -.boldnotice {color: #6685f5; font-weight: bold;} -.adminnotice {color: #6685f5;} +.info {color: #0000CC;} +.notice {color: #000099;} +.boldnotice {color: #000099; font-weight: bold;} +.adminnotice {color: #0000ff;} .adminhelp {color: #ff0000; font-weight: bold;} -.unconscious {color: #a4bad6; font-weight: bold;} +.unconscious {color: #0000ff; font-weight: bold;} .suicide {color: #ff5050; font-style: italic;} -.red {color: #FF0000} -.pink {color: #ff70c1;} -.blue {color: #215cff} -.green {color: #059223;} -.nicegreen {color: #059223;} +.green {color: #03ff39;} +.red {color: #FF0000;} +.pink {color: #FF69Bf;} +.blue {color: #0000FF;} +.nicegreen {color: #14a833;} .userlove {color: #FF1493; font-style: italic; font-weight: bold; text-shadow: 0 0 6px #ff6dbc;} .love {color: #ff006a; font-style: italic; text-shadow: 0 0 6px #ff6d6d;} -.shadowling {color: #8e8a99;} -.cult {color: #aa1c1c;} +.shadowling {color: #3b2769;} +.cult {color: #960000;} -.cultitalic {color: #aa1c1c; font-style: italic;} -.cultbold {color: #aa1c1c; font-style: italic; font-weight: bold;} -.cultboldtalic {color: #aa1c1c; font-weight: bold; font-size: 24px;} +.cultitalic {color: #960000; font-style: italic;} +.cultbold {color: #960000; font-style: italic; font-weight: bold;} +.cultboldtalic {color: #960000; font-weight: bold; font-size: 24px;} -.cultlarge {color: #aa1c1c; font-weight: bold; font-size: 24px;} -.narsie {color: #aa1c1c; font-weight: bold; font-size: 120px;} -.narsiesmall {color: #aa1c1c; font-weight: bold; font-size: 48px;} +.cultlarge {color: #960000; font-weight: bold; font-size: 24px;} +.narsie {color: #960000; font-weight: bold; font-size: 120px;} +.narsiesmall {color: #960000; font-weight: bold; font-size: 48px;} .colossus {color: #7F282A; font-size: 40px;} -.hierophant {color: #b441ee; font-weight: bold; font-style: italic;} -.hierophant_warning {color: #c56bf1; font-style: italic;} -.purple {color: #9956d3;} -.holoparasite {color: #88809c;} +.hierophant {color: #660099; font-weight: bold; font-style: italic;} +.hierophant_warning {color: #660099; font-style: italic;} +.purple {color: #5e2d79;} +.holoparasite {color: #35333a;} .revennotice {color: #1d2953;} .revenboldnotice {color: #1d2953; font-weight: bold;} @@ -350,11 +347,11 @@ h1.alert, h2.alert {color: #99aab5;} .revenminor {color: #823abb} .revenwarning {color: #760fbb; font-style: italic;} .revendanger {color: #760fbb; font-weight: bold; font-size: 24px;} -.umbra {color: #7c00e6;} -.umbra_emphasis {color: #7c00e6; font-weight: bold; font-style: italic;} -.umbra_large {color: #7c00e6; font-size: 24px; font-weight: bold; font-style: italic;} +.umbra {color: #5000A0;} +.umbra_emphasis {color: #5000A0; font-weight: bold; font-style: italic;} +.umbra_large {color: #5000A0; font-size: 24px; font-weight: bold; font-style: italic;} -.deconversion_message {color: #a947ff; font-size: 24px; font-style: italic;} +.deconversion_message {color: #5000A0; font-size: 24px; font-style: italic;} .brass {color: #BE8700;} .heavy_brass {color: #BE8700; font-weight: bold; font-style: italic;} @@ -379,17 +376,17 @@ h1.alert, h2.alert {color: #99aab5;} .neovgre {color: #6E001A; font-weight: bold; font-style: italic;} .neovgre_small {color: #6E001A;} -.newscaster {color: #c05d5d;} -.ghostalert {color: #6600ff; font-style: italic; font-weight: bold;} +.newscaster {color: #800000;} +.ghostalert {color: #5c00e6; font-style: italic; font-weight: bold;} -.alien {color: #855d85;} -.noticealien {color: #059223;} -.alertalien {color: #059223; font-weight: bold;} -.changeling {color: #059223; font-style: italic;} +.alien {color: #543354;} +.noticealien {color: #00c000;} +.alertalien {color: #00c000; font-weight: bold;} +.changeling {color: #800080; font-style: italic;} -.spider {color: #8800ff;} +.spider {color: #4d004d;} -.interface {color: #750e75;} +.interface {color: #330033;} .sans {font-family: "Comic Sans MS", cursive, sans-serif;} .papyrus {font-family: "Papyrus", cursive, sans-serif;} @@ -400,29 +397,55 @@ h1.alert, h2.alert {color: #99aab5;} .big {font-size: 24px;} .reallybig {font-size: 32px;} .extremelybig {font-size: 40px;} -.greentext {color: #059223; font-size: 24px;} -.redtext {color: #c51e1e; font-size: 24px;} -.clown {color: #ff70c1; font-size: 24px; font-family: "Comic Sans MS", cursive, sans-serif; font-weight: bold;} +.greentext {color: #00FF00; font-size: 24px;} +.redtext {color: #FF0000; font-size: 24px;} +.clown {color: #FF69Bf; font-size: 24px; font-family: "Comic Sans MS", cursive, sans-serif; font-weight: bold;} .his_grace {color: #15D512; font-family: "Courier New", cursive, sans-serif; font-style: italic;} +.spooky {color: #FF6100;} +.velvet {color: #660015; font-weight: bold; animation: velvet 5000ms infinite;} +@keyframes velvet { + 0% { color: #400020; } + 40% { color: #FF0000; } + 50% { color: #FF8888; } + 60% { color: #FF0000; } + 100% { color: #400020; } +} + +.hypnophrase {color: #202020; font-weight: bold; animation: hypnocolor 1500ms infinite;} +@keyframes hypnocolor { + 0% { color: #202020; } + 25% { color: #4b02ac; } + 50% { color: #9f41f1; } + 75% { color: #541c9c; } + 100% { color: #7adbf3; } +} + +.phobia {color: #dd0000; font-weight: bold; animation: phobia 750ms infinite;} +@keyframes phobia { + 0% { color: #f75a5a; } + 50% { color: #dd0000; } + 100% { color: #f75a5a; } +} + .icon {height: 1em; width: auto;} .memo {color: #638500; text-align: center;} .memoedit {text-align: center; font-size: 16px;} -.abductor {color: #c204c2; font-style: italic;} -.mind_control {color: #df3da9; font-size: 3; font-weight: bold; font-style: italic;} +.abductor {color: #800080; font-style: italic;} +.mind_control {color: #A00D6F; font-size: 3; font-weight: bold; font-style: italic;} .slime {color: #00CED1;} .drone {color: #848482;} .monkey {color: #975032;} .swarmer {color: #2C75FF;} .resonate {color: #298F85;} -.monkeyhive {color: #a56408;} -.monkeylead {color: #af6805; font-size: 2;} +.monkeyhive {color: #774704;} +.monkeylead {color: #774704; font-size: 2;} .connectionClosed, .fatalError {background: red; color: white; padding: 5px;} .connectionClosed.restored {background: green;} -.internal.boldnshit {color: #3d5bc3; font-weight: bold;} +.internal.boldnshit {color: #000099; font-weight: bold;} /* HELPER CLASSES */ .text-normal {font-weight: normal; font-style: normal;} diff --git a/code/modules/goonchat/browserassets/css/browserOutput_dark.css b/code/modules/goonchat/browserassets/css/browserOutput_dark.css new file mode 100644 index 0000000000..2e1fe8cdec --- /dev/null +++ b/code/modules/goonchat/browserassets/css/browserOutput_dark.css @@ -0,0 +1,159 @@ +html, body {color: #E0E0E0;} +body { + background: #171717; + font-color: #E0E0E0; + scrollbar-face-color:#1A1A1A; + scrollbar-track-color:#171717; + scrollbar-highlight-color:#171717; +} + +a {color: #397ea5;} +a.visited {color: #7c00e6;} +a:visited {color: #7c00e6;} + +#newMessages { + background: #242424; + color: #E0E0E0; +} +#newMessages:hover {background: #272727;} + +#ping {background: #272727;} + +#userBar .subCell { + background: #272727; + color: #E0E0E0; + border-top: 1px solid #171717; +} +#userBar .subCell:hover {background: #272727;} +#userBar .toggle {background: #272727;} + +/* MOTD */ +.motd {color: #E0E0E0; font-family: Verdana, sans-serif;} +.motd h1, .motd h2, .motd h3, .motd h4, .motd h5, .motd h6 {color: #E0E0E0; text-decoration: underline;} +.motd a, .motd a:link, .motd a:visited, .motd a:active, .motd a:hover {color: #E0E0E0;} + +h1, h2, h3, h4, h5, h6 {color: #E0E0E0;font-family: Georgia, Verdana, sans-serif;} +h1.alert, h2.alert {color: #E0E0E0;} + +.ooc {color: #cca300; font-weight: bold;} +.looc {color: #d8b555; font-weight: bold;} +.antagooc {color: #ce254f; font-weight: bold;} +.adminobserverooc {color: #0099cc; font-weight: bold;} +.adminooc {color: #3d5bc3; font-weight: bold;} + +.admin {color: #5975da; font-weight: bold;} + +.deadsay {color: #e2c1ff;} +.radio {color: #1ecc43;} +.sciradio {color: #c68cfa;} +.comradio {color: #5177ff;} +.secradio {color: #dd3535;} +.medradio {color: #57b8f0;} +.engradio {color: #f37746;} +.suppradio {color: #b88646;} +.servradio {color: #6ca729;} +.syndradio {color: #8f4a4b;} +.centcomradio {color: #2681a5;} +.aiprivradio {color: #d65d95;} +.redteamradio {color: #ff4444;} +.blueteamradio {color: #3434fd;} + +.alert {color: #d82020;} +h1.alert, h2.alert {color: #99aab5;} + +.attack {color: #e01c1c;} +.disarm {color: #b42525;} +.passive {color: #a00f0f;} + +.userdanger {color: #c51e1e; font-weight: bold; font-size: 24px;} +.danger {color: #c51e1e;} +.warning {color: #c51e1e; font-style: italic;} +.alertwarning {color: #c51e1e; font-weight: bold} +.boldwarning {color: #c51e1e; font-style: italic; font-weight: bold} +.announce {color: #c51e1e; font-weight: bold;} +.boldannounce {color: #c51e1e; font-weight: bold;} +.greenannounce {color: #059223; font-weight: bold;} +.info {color: #6685f5;} +.notice {color: #6685f5;} +.boldnotice {color: #6685f5; font-weight: bold;} +.adminnotice {color: #6685f5;} +.adminhelp {color: #ff0000; font-weight: bold;} +.unconscious {color: #E0E0E0; font-weight: bold;} +.red {color: #FF0000} +.pink {color: #ff70c1;} +.blue {color: #215cff} +.green {color: #059223;} +.nicegreen {color: #059223;} +.userlove {color: #ff42a6; font-style: italic; font-weight: bold; text-shadow: 0 0 6px #82365e;} +.love {color: #ff4591; font-style: italic; text-shadow: 0 0 6px #994449;} +.shadowling {color: #8e8a99;} +.cult {color: #aa1c1c;} + +.cultitalic {color: #aa1c1c; font-style: italic;} +.cultbold {color: #aa1c1c; font-style: italic; font-weight: bold;} +.cultboldtalic {color: #aa1c1c; font-weight: bold; font-size: 24px;} + +.cultlarge {color: #aa1c1c; font-weight: bold; font-size: 24px;} +.narsie {color: #aa1c1c; font-weight: bold; font-size: 120px;} +.narsiesmall {color: #aa1c1c; font-weight: bold; font-size: 48px;} +.hierophant {color: #b441ee; font-weight: bold; font-style: italic;} +.hierophant_warning {color: #c56bf1; font-style: italic;} +.purple {color: #9956d3;} +.holoparasite {color: #88809c;} + +.revennotice {color: #3645aa;} +.revenboldnotice {color: #3645aa; font-weight: bold;} +.revenbignotice {color: #3645aa; font-weight: bold; font-size: 24px;} +.revenminor {color: #823ddd} +.revenwarning {color: #8911d9; font-style: italic;} +.revendanger {color: #8911d9; font-weight: bold; font-size: 24px;} +.umbra {color: #7c00e6;} +.umbra_emphasis {color: #7c00e6; font-weight: bold; font-style: italic;} +.umbra_large {color: #7c00e6; font-size: 24px; font-weight: bold; font-style: italic;} + +.deconversion_message {color: #a947ff; font-size: 24px; font-style: italic;} + +.alloy {color: #545b64;} +.heavy_alloy {color: #545b64; font-weight: bold; font-style: italic;} +.nezbere_large {color: #545b64; font-size: 24px; font-weight: bold; font-style: italic;} +.nezbere {color: #545b64; font-weight: bold; font-style: italic;} +.nezbere_small {color: #545b64;} +.inathneq_large {color: #1d7dc7; font-size: 24px; font-weight: bold; font-style: italic;} +.inathneq {color: #1d7dc7; font-weight: bold; font-style: italic;} +.inathneq_small {color: #1d7dc7;} +.neovgre_large {color: #7c0622; font-size: 24px; font-weight: bold; font-style: italic;} +.neovgre {color: #7c0622; font-weight: bold; font-style: italic;} +.neovgre_small {color: #7c0622;} + +.newscaster {color: #c05d5d;} +.ghostalert {color: #6600ff; font-style: italic; font-weight: bold;} + +.alien {color: #855d85;} +.noticealien {color: #059223;} +.alertalien {color: #059223; font-weight: bold;} +.changeling {color: #059223; font-style: italic;} + +.spider {color: #8800ff;} + +.interface {color: #750e75;} + +.greentext {color: #059223; font-size: 24px;} +.redtext {color: #c51e1e; font-size: 24px;} +.clown {color: #ff70c1; font-size: 24px; font-family: "Comic Sans MS", cursive, sans-serif; font-weight: bold;} +.velvet {color: #660015; font-weight: bold; animation: velvet 5000ms infinite;} +@keyframes velvet { + 0% { color: #890020; } + 40% { color: #c51e1e; } + 50% { color: #FF8888; } + 60% { color: #c51e1e; } + 100% { color: #890020; } +} + +.abductor {color: #c204c2; font-style: italic;} +.mind_control {color: #df3da9; font-size: 3; font-weight: bold; font-style: italic;} +.drone {color: #979795;} + +.monkeyhive {color: #a56408;} +.monkeylead {color: #af6805; font-size: 2;} + +.internal.boldnshit {color: #3d5bc3; font-weight: bold;} diff --git a/code/modules/goonchat/browserassets/css/browserOutput_white.css b/code/modules/goonchat/browserassets/css/browserOutput_light.css similarity index 58% rename from code/modules/goonchat/browserassets/css/browserOutput_white.css rename to code/modules/goonchat/browserassets/css/browserOutput_light.css index e21185449b..098bd25367 100644 --- a/code/modules/goonchat/browserassets/css/browserOutput_white.css +++ b/code/modules/goonchat/browserassets/css/browserOutput_light.css @@ -1,236 +1,18 @@ -/***************************************** -* -* GLOBAL STYLES -* -******************************************/ -html, body { - padding: 0; - margin: 0; - height: 100%; - color: #000000; -} -body { - background: #fff; - font-family: Verdana, sans-serif; - font-size: 9pt; - line-height: 1.2; - overflow-x: hidden; - overflow-y: scroll; - word-wrap: break-word; -} +body {background: #F1F1F1;} -em { - font-style: normal; - font-weight: bold; -} +#newMessages {background: #ddd;} +#ping {background: #ddd;} -img { - margin: 0; - padding: 0; - line-height: 1; - -ms-interpolation-mode: nearest-neighbor; - image-rendering: pixelated; -} -img.icon { - height: 1em; - min-height: 16px; - width: auto; - vertical-align: bottom; -} - - -.r:before { /* "repeated" badge class for combined messages */ - content: 'x'; -} -.r { - display: inline-block; - min-width: 0.5em; - font-size: 0.7em; - padding: 0.2em 0.3em; - line-height: 1; - color: white; - text-align: center; - white-space: nowrap; - vertical-align: middle; - background-color: crimson; - border-radius: 10px; -} - -a {color: #0000ff;} -a.visited {color: #ff00ff;} -a:visited {color: #ff00ff;} -a.popt {text-decoration: none;} - -/***************************************** -* -* OUTPUT NOT RELATED TO ACTUAL MESSAGES -* -******************************************/ -#loading { - position: fixed; - width: 300px; - height: 150px; - text-align: center; - left: 50%; - top: 50%; - margin: -75px 0 0 -150px; -} -#loading i {display: block; padding-bottom: 3px;} - -#messages { - font-size: 13px; - padding: 3px; - margin: 0; - word-wrap: break-word; -} -#newMessages { - position: fixed; - display: block; - bottom: 0; - right: 0; - padding: 8px; - background: #ddd; - text-decoration: none; - font-variant: small-caps; - font-size: 1.1em; - font-weight: bold; - color: #333; -} -#newMessages:hover {background: #ccc;} -#newMessages i {vertical-align: middle; padding-left: 3px;} -#ping { - position: fixed; - top: 0; - right: 115px; - width: 45px; - background: #ddd; - height: 30px; - padding: 8px 0 2px 0; -} -#ping i {display: block; text-align: center;} -#ping .ms { - display: block; - text-align: center; - font-size: 8pt; - padding-top: 2px; -} -#userBar { - position: fixed; - top: 0; - right: 0; -} -#userBar .subCell { - background: #ddd; - height: 30px; - padding: 5px 0; - display: block; - color: #333; - text-decoration: none; - line-height: 28px; - border-top: 1px solid #b4b4b4; -} -#userBar .subCell:hover {background: #ccc;} -#userBar .toggle { - width: 40px; - background: #ccc; - border-top: 0; - float: right; - text-align: center; -} -#userBar .sub {clear: both; display: none; width: 160px;} -#userBar .sub.scroll {overflow-y: scroll;} -#userBar .sub.subCell {padding: 3px 0 3px 8px; line-height: 30px; font-size: 0.9em; clear: both;} -#userBar .sub span { - display: block; - line-height: 30px; - float: left; -} -#userBar .sub i { - display: block; - padding: 0 5px; - font-size: 1.1em; - width: 22px; - text-align: center; - line-height: 30px; - float: right; -} -#userBar .sub input { - position: absolute; - padding: 7px 5px; - width: 121px; - line-height: 30px; - float: left; -} -#userBar .topCell {border-top: 0;} +#userBar .subCell {background: #ddd;} /* POPUPS */ -.popup { - position: fixed; - top: 50%; - left: 50%; - background: #ddd; -} -.popup .close { - position: absolute; - background: #aaa; - top: 0; - right: 0; - color: #333; - text-decoration: none; - z-index: 2; - padding: 0 10px; - height: 30px; - line-height: 30px; -} -.popup .close:hover {background: #999;} -.popup .head { - background: #999; - color: #ddd; - padding: 0 10px; - height: 30px; - line-height: 30px; - text-transform: uppercase; - font-size: 0.9em; - font-weight: bold; - border-bottom: 2px solid green; -} -.popup input {border: 1px solid #999; background: #fff; margin: 0; padding: 5px; outline: none; color: #333;} -.popup input[type=text]:hover, .popup input[type=text]:active, .popup input[type=text]:focus {border-color: green;} -.popup input[type=submit] {padding: 5px 10px; background: #999; color: #ddd; text-transform: uppercase; font-size: 0.9em; font-weight: bold;} -.popup input[type=submit]:hover, .popup input[type=submit]:focus, .popup input[type=submit]:active {background: #aaa; cursor: pointer;} - -.changeFont {padding: 10px;} -.changeFont a {display: block; text-decoration: none; padding: 3px; color: #333;} -.changeFont a:hover {background: #ccc;} - -.highlightPopup {padding: 10px; text-align: center;} -.highlightPopup input[type=text] {display: block; width: 215px; text-align: left; margin-top: 5px;} -.highlightPopup input.highlightColor {background-color: #FFFF00;} -.highlightPopup input.highlightTermSubmit {margin-top: 5px;} +.popup {background: #ddd;} +.popup .head {color: #ddd;} +.popup input[type=submit] {color: #ddd;} /* ADMIN CONTEXT MENU */ -.contextMenu { - background-color: #ddd; - position: fixed; - margin: 2px; - width: 150px; -} -.contextMenu a { - display: block; - padding: 2px 5px; - text-decoration: none; - color: #333; -} +.contextMenu {background-color: #ddd;} -.contextMenu a:hover { - background-color: #ccc; -} - -/* ADMIN FILTER MESSAGES MENU */ -.filterMessages {padding: 5px;} -.filterMessages div {padding: 2px 0;} -.filterMessages input {} -.filterMessages label {} .icon-stack {height: 1em; line-height: 1em; width: 1em; vertical-align: middle; margin-top: -2px;} @@ -261,12 +43,13 @@ h1.alert, h2.alert {color: #000000;} em {font-style: normal; font-weight: bold;} .ooc {color: #002eb8; font-weight: bold;} +.looc {color: #6699CC; font-weight: bold;} .antagooc {color: #b8002e; font-weight: bold;} .adminobserverooc {color: #0099cc; font-weight: bold;} .adminooc {color: #700038; font-weight: bold;} -.adminsay {color: #ff4500; font-weight: bold;} -.admin {color: #4473ff; font-weight: bold;} +.adminsay {color: #FF4500} +.admin {color: #386aff; font-weight: bold;} .name { font-weight: bold;} @@ -304,7 +87,7 @@ h1.alert, h2.alert {color: #000000;} .userdanger {color: #ff0000; font-weight: bold; font-size: 24px;} .danger {color: #ff0000;} .warning {color: #ff0000; font-style: italic;} -.alertwarning {color: #FF0000; font-weight: bold} +.alertwarning {color: #FF0000; font-weight: bold} .boldwarning {color: #ff0000; font-style: italic; font-weight: bold} .announce {color: #228b22; font-weight: bold;} .boldannounce {color: #ff0000; font-weight: bold;} @@ -317,10 +100,10 @@ h1.alert, h2.alert {color: #000000;} .adminhelp {color: #ff0000; font-weight: bold;} .unconscious {color: #0000ff; font-weight: bold;} .suicide {color: #ff5050; font-style: italic;} -.green {color: #03ff39;} -.red {color: #FF0000} +.green {color: #03ff39;} +.red {color: #FF0000;} .pink {color: #FF69Bf;} -.blue {color: #0000FF} +.blue {color: #0000FF;} .nicegreen {color: #14a833;} .userlove {color: #FF1493; font-style: italic; font-weight: bold; text-shadow: 0 0 6px #ff6dbc;} .love {color: #ff006a; font-style: italic; text-shadow: 0 0 6px #ff6d6d;} @@ -329,7 +112,7 @@ h1.alert, h2.alert {color: #000000;} .cultitalic {color: #960000; font-style: italic;} .cultbold {color: #960000; font-style: italic; font-weight: bold;} -.cultboldtalic {color: #960000; font-weight: bold; font-size: 24px;} +.cultboldtalic {color: #960000; font-weight: bold; font-size: 24px;} .cultlarge {color: #960000; font-weight: bold; font-size: 24px;} .narsie {color: #960000; font-weight: bold; font-size: 120px;} @@ -400,13 +183,38 @@ h1.alert, h2.alert {color: #000000;} .redtext {color: #FF0000; font-size: 24px;} .clown {color: #FF69Bf; font-size: 24px; font-family: "Comic Sans MS", cursive, sans-serif; font-weight: bold;} .his_grace {color: #15D512; font-family: "Courier New", cursive, sans-serif; font-style: italic;} +.velvet {color: #660015; font-weight: bold; animation: velvet 5000ms infinite;} +@keyframes velvet { + 0% { color: #400020; } + 40% { color: #FF0000; } + 50% { color: #FF8888; } + 60% { color: #FF0000; } + 100% { color: #400020; } +} + +.hypnophrase {color: #202020; font-weight: bold; animation: hypnocolor 1500ms infinite;} +@keyframes hypnocolor { + 0% { color: #202020; } + 25% { color: #4b02ac; } + 50% { color: #9f41f1; } + 75% { color: #541c9c; } + 100% { color: #7adbf3; } +} + +.phobia {color: #dd0000; font-weight: bold; animation: phobia 750ms infinite;} +@keyframes phobia { + 0% { color: #f75a5a; } + 50% { color: #dd0000; } + 100% { color: #f75a5a; } +} + .icon {height: 1em; width: auto;} .memo {color: #638500; text-align: center;} .memoedit {text-align: center; font-size: 16px;} .abductor {color: #800080; font-style: italic;} -.mind_control {color: #A00D6F; font-size: 3; font-weight: bold; font-style: italic;} +.mind_control {color: #A00D6F; font-size: 3; font-weight: bold; font-style: italic;} .slime {color: #00CED1;} .drone {color: #848482;} .monkey {color: #975032;} @@ -418,9 +226,8 @@ h1.alert, h2.alert {color: #000000;} .connectionClosed, .fatalError {background: red; color: white; padding: 5px;} .connectionClosed.restored {background: green;} -.internal.boldnshit {color: blue; font-weight: bold;} +.internal.boldnshit {color: #000099; font-weight: bold;} /* HELPER CLASSES */ .text-normal {font-weight: normal; font-style: normal;} .hidden {display: none; visibility: hidden;} - diff --git a/code/modules/goonchat/browserassets/html/browserOutput.html b/code/modules/goonchat/browserassets/html/browserOutput.html index 9c6d462a85..68da251702 100644 --- a/code/modules/goonchat/browserassets/html/browserOutput.html +++ b/code/modules/goonchat/browserassets/html/browserOutput.html @@ -5,8 +5,9 @@ - + + @@ -29,7 +30,7 @@ --ms
- +
diff --git a/code/modules/goonchat/browserassets/js/browserOutput.js b/code/modules/goonchat/browserassets/js/browserOutput.js index 93a498fd06..abd05d29ed 100644 --- a/code/modules/goonchat/browserassets/js/browserOutput.js +++ b/code/modules/goonchat/browserassets/js/browserOutput.js @@ -35,7 +35,7 @@ var opts = { 'wasd': false, //Is the user in wasd mode? 'priorChatHeight': 0, //Thing for height-resizing detection 'restarting': false, //Is the round restarting? - 'darkmode':false, //Are we using darkmode? If not WHY ARE YOU LIVING IN 2009??? + 'colorPreset': 0, // index in the color presets list. //Options menu 'selectedSubLoop': null, //Contains the interval loop for closing the selected sub menu @@ -73,6 +73,14 @@ var opts = { }; +// Array of names for chat display color presets. +// If not set to normal, a CSS file `browserOutput_${name}.css` will be added to the head. +var colorPresets = [ + 'normal', + 'light', + 'dark' +] + function clamp(val, min, max) { return Math.max(min, Math.min(val, max)) } @@ -96,6 +104,12 @@ if (typeof String.prototype.trim !== 'function') { }; } +function updateColorPreset() { + var el = $("#colorPresetLink")[0]; + el.href = "browserOutput_"+colorPresets[opts.colorPreset]+".css"; + runByond('?_src_=chat&proc=colorPresetPost&preset='+colorPresets[opts.colorPreset]); +} + // Linkify the contents of a node, within its parent. function linkify(parent, insertBefore, text) { var start = 0; @@ -395,19 +409,6 @@ function toHex(n) { return "0123456789ABCDEF".charAt((n-n%16)/16) + "0123456789ABCDEF".charAt(n%16); } -function swap() { //Swap to darkmode - if (opts.darkmode){ - document.getElementById("sheetofstyles").href = "browserOutput_white.css"; - opts.darkmode = false; - runByond('?_src_=chat&proc=swaptolightmode'); - } else { - document.getElementById("sheetofstyles").href = "browserOutput.css"; - opts.darkmode = true; - runByond('?_src_=chat&proc=swaptodarkmode'); - } - setCookie('darkmode', (opts.darkmode ? 'true' : 'false'), 365); -} - function handleClientData(ckey, ip, compid) { //byond sends player info to here var currentData = {'ckey': ckey, 'ip': ip, 'compid': compid}; @@ -615,7 +616,7 @@ $(function() { 'shighlightColor': getCookie('highlightcolor'), 'smusicVolume': getCookie('musicVolume'), 'smessagecombining': getCookie('messagecombining'), - 'sdarkmode': getCookie('darkmode'), + 'scolorPreset': getCookie('colorpreset'), }; if (savedConfig.sfontSize) { @@ -626,9 +627,6 @@ $(function() { $("body").css('line-height', savedConfig.slineHeight); internalOutput('Loaded line height setting of: '+savedConfig.slineHeight+'', 'internal'); } - if(savedConfig.sdarkmode == 'true'){ - swap(); - } if (savedConfig.spingDisabled) { if (savedConfig.spingDisabled == 'true') { opts.pingDisabled = true; @@ -654,6 +652,13 @@ $(function() { opts.highlightColor = savedConfig.shighlightColor; internalOutput('Loaded highlight color of: '+savedConfig.shighlightColor+'', 'internal'); } + + if (savedConfig.scolorPreset) { + opts.colorPreset = Number(savedConfig.scolorPreset); + updateColorPreset(); + internalOutput('Loaded color preset of: '+colorPresets[opts.colorPreset]+'', 'internal'); + } + if (savedConfig.smusicVolume) { var newVolume = clamp(savedConfig.smusicVolume, 0, 100); $('#adminMusic').prop('volume', newVolume / 100); @@ -839,9 +844,6 @@ $(function() { $('#toggleOptions').click(function(e) { handleToggleClick($subOptions, $(this)); }); - $('#darkmodetoggle').click(function(e) { - swap(); - }); $('#toggleAudio').click(function(e) { handleToggleClick($subAudio, $(this)); }); @@ -913,7 +915,7 @@ $(function() { $.ajax({ type: 'GET', - url: 'browserOutput_white.css', + url: 'browserOutput.css', success: function(styleData) { var blob = new Blob(['Chat Log', $messages.html(), '']); @@ -992,6 +994,13 @@ $(function() { opts.messageCount = 0; }); + $('#changeColorPreset').click(function() { + opts.colorPreset = (opts.colorPreset+1) % colorPresets.length; + updateColorPreset(); + setCookie('colorpreset', opts.colorPreset, 365); + internalOutput('Changed color preset to: '+colorPresets[opts.colorPreset]); + }); + $('#musicVolumeSpan').hover(function() { $('#musicVolumeText').addClass('hidden'); $('#musicVolume').removeClass('hidden'); diff --git a/code/modules/holiday/halloween/bartholomew.dm b/code/modules/holiday/halloween/bartholomew.dm new file mode 100644 index 0000000000..129f4e29b6 --- /dev/null +++ b/code/modules/holiday/halloween/bartholomew.dm @@ -0,0 +1,148 @@ +/obj/effect/landmark/barthpot + name = "barthpot" + +/obj/item/barthpot + name = "Bartholomew" + icon = 'icons/obj/halloween_items.dmi' + icon_state = "barthpot" + anchored = TRUE + var/items_list = list() + speech_span = "spooky" + var/active = TRUE + +/obj/item/barthpot/Destroy() + var/obj/item/barthpot/n = new src(loc) + n.items_list = items_list + ..() + + +/obj/item/barthpot/attackby(obj/item/I, mob/user, params) + if(!active) + say("Meow!") + return + for(var/I2 in items_list) + if(istype(I, I2)) + qdel(I) + new /obj/item/reagent_containers/food/snacks/special_candy(loc) + to_chat(user, "You add the [I.name] to the pot and watch as it melts into the mixture, a candy crystalising in it's wake.") + say("Hooray! Thank you!") + items_list -= I2 + return + say("It doesn't seem like that's magical enough!") + +/obj/item/barthpot/attack_hand(mob/user) + if(!active) + say("Meow!") + return + say("Hello there, I'm Bartholomew, Jacqueline's Familiar.") + sleep(20) + say("I'm currently seeking items to put into my pot, if we get the right items, it should crystalise into a magic candy!") + if(!iscarbon(user)) + say("Though... I'm not sure you can help me.") + + var/message = "From what I can tell, " + if(LAZYLEN(items_list) < 5) + generate_items() + for(var/I2 in items_list) + if(!I2) + items_list -= I2 + continue + var/obj/item/I3 = new I2 + message += "a [I3.name], " + message += "currently seem to have the most magic potential." + sleep(15) + say("[message]") + +/obj/item/barthpot/proc/generate_items() + var/length = LAZYLEN(items_list) + var/rand_items = list(/obj/item/bodybag = 1, + /obj/item/clothing/glasses/meson = 2, + /obj/item/clothing/glasses/sunglasses = 1, + /obj/item/clothing/gloves/color/fyellow = 1, + /obj/item/clothing/head/hardhat = 1, + /obj/item/clothing/head/hardhat/red = 1, + /obj/item/clothing/head/that = 1, + /obj/item/clothing/head/ushanka = 1, + /obj/item/clothing/head/welding = 1, + /obj/item/clothing/mask/gas = 15, + /obj/item/clothing/suit/hazardvest = 1, + /obj/item/clothing/under/rank/vice = 1, + /obj/item/clothing/suit/hooded/flashsuit = 2, + /obj/item/clothing/accessory/medal/greytide = 1, + /obj/item/assembly/prox_sensor = 4, + /obj/item/assembly/timer = 3, + /obj/item/flashlight = 4, + /obj/item/flashlight/pen = 1, + /obj/effect/spawner/lootdrop/glowstick = 4, + /obj/effect/spawner/lootdrop/mre = 3, + /obj/item/multitool = 2, + /obj/item/radio/off = 2, + /obj/item/t_scanner = 5, + /obj/item/airlock_painter = 1, + /obj/item/stack/cable_coil/ = 4, + /obj/item/stack/medical/bruise_pack = 1, + /obj/item/stack/rods = 3, + /obj/item/stack/sheet/cardboard = 2, + /obj/item/stack/sheet/metal = 1, + /obj/item/stack/sheet/mineral/plasma = 1, + /obj/item/stack/sheet/rglass = 1, + /obj/item/book/manual/wiki/engineering_construction = 1, + /obj/item/book/manual/wiki/engineering_hacking = 1, + /obj/item/clothing/head/cone = 1, + /obj/item/coin/silver = 1, + /obj/item/coin/twoheaded = 1, + /obj/item/poster/random_contraband = 1, + /obj/item/poster/random_official = 1, + /obj/item/crowbar = 1, + /obj/item/crowbar/red = 1, + /obj/item/extinguisher = 11, + /obj/item/hand_labeler = 1, + /obj/item/paper/crumpled = 1, + /obj/item/pen = 1, + /obj/item/reagent_containers/spray/pestspray = 1, + /obj/item/reagent_containers/rag = 3, + /obj/item/stock_parts/cell = 3, + /obj/item/storage/belt/utility = 2, + /obj/item/storage/box = 2, + /obj/item/storage/box/cups = 1, + /obj/item/storage/box/donkpockets = 1, + /obj/item/storage/box/lights/mixed = 3, + /obj/item/storage/box/hug/medical = 1, + /obj/item/storage/fancy/cigarettes/dromedaryco = 1, + /obj/item/storage/toolbox/mechanical = 1, + /obj/item/screwdriver = 3, + /obj/item/tank/internals/emergency_oxygen = 2, + /obj/item/vending_refill/cola = 1, + /obj/item/weldingtool = 3, + /obj/item/wirecutters = 1, + /obj/item/wrench = 4, + /obj/item/relic = 3, + /obj/item/weaponcrafting/receiver = 2, + /obj/item/clothing/head/cone = 2, + /obj/item/grenade/smokebomb = 2, + /obj/item/geiger_counter = 3, + /obj/item/reagent_containers/food/snacks/grown/citrus/orange = 1, + /obj/item/radio/headset = 1, + /obj/item/assembly/infra = 1, + /obj/item/assembly/igniter = 2, + /obj/item/assembly/signaler = 2, + /obj/item/assembly/mousetrap = 2, + /obj/item/reagent_containers/syringe = 2, + /obj/item/clothing/gloves = 8, + /obj/item/clothing/shoes/laceup = 1, + /obj/item/storage/secure/briefcase = 3, + /obj/item/storage/toolbox/artistic = 2, + /obj/item/toy/eightball = 1, + /obj/item/reagent_containers/pill/floorpill = 1, + /obj/item/reagent_containers/food/snacks/cannedpeaches/maint = 2, + /obj/item/clothing/shoes = 2) + if(length == 5) + return TRUE + //var/metalist = pickweight(GLOB.maintenance_loot) + for(var/i = length, i <= 5, i+=1) + var/obj/item = pickweight(rand_items) + if(!item) + i-=1 + continue + items_list += item + return TRUE diff --git a/code/modules/holiday/halloween.dm b/code/modules/holiday/halloween/halloween.dm similarity index 92% rename from code/modules/holiday/halloween.dm rename to code/modules/holiday/halloween/halloween.dm index a27db8dd38..5635994a7a 100644 --- a/code/modules/holiday/halloween.dm +++ b/code/modules/holiday/halloween/halloween.dm @@ -5,19 +5,27 @@ //spooky recipes -/datum/recipe/sugarcookie/spookyskull - reagents = list("flour" = 5, "sugar" = 5, "milk" = 5) - items = list( - /obj/item/reagent_containers/food/snacks/egg, +/datum/crafting_recipe/food/sugarcookie/spookyskull + time = 15 + name = "Sugar cookie" + reqs = list( + /datum/reagent/consumable/sugar = 5, + /obj/item/reagent_containers/food/snacks/pastrybase = 1 ) result = /obj/item/reagent_containers/food/snacks/sugarcookie/spookyskull + subcategory = CAT_PASTRY -/datum/recipe/sugarcookie/spookycoffin - reagents = list("flour" = 5, "sugar" = 5, "coffee" = 5) - items = list( - /obj/item/reagent_containers/food/snacks/egg, +/datum/crafting_recipe/food/sugarcookie/spookycoffin + time = 15 + name = "Sugar cookie" + reqs = list( + /datum/reagent/consumable/sugar = 5, + /datum/reagent/consumable/coffee = 5, + /obj/item/reagent_containers/food/snacks/pastrybase = 1 ) result = /obj/item/reagent_containers/food/snacks/sugarcookie/spookycoffin + subcategory = CAT_PASTRY + ////////////////////////////// //Spookoween trapped closets// @@ -34,12 +42,12 @@ var/trapped = 0 var/mob/trapped_mob -/obj/structure/closet/initialize() +/obj/structure/closet/Initialize() ..() if(prob(30)) set_spooky_trap() -/obj/structure/closet/dump_contents() +/obj/structure/closet/dump_contents(var/override = TRUE) ..() trigger_spooky_trap() @@ -256,6 +264,7 @@ desc = "A standard miniature energy crossbow that uses a hard-light projector to transform bolts into candy corn. Happy Halloween!" category = "Holiday" item = /obj/item/gun/energy/kinetic_accelerator/crossbow/halloween + cost = 12 surplus = 0 /datum/uplink_item/device_tools/emag/hack_o_lantern diff --git a/code/modules/holiday/halloween/jacqueen.dm b/code/modules/holiday/halloween/jacqueen.dm new file mode 100644 index 0000000000..b2f69df2e4 --- /dev/null +++ b/code/modules/holiday/halloween/jacqueen.dm @@ -0,0 +1,442 @@ +//Conversation +#define JACQ_HELLO (1<<0) +#define JACQ_CANDIES (1<<1) +#define JACQ_HEAD (1<<2) +#define JACQ_FAR (1<<3) +#define JACQ_WITCH (1<<4) +#define JACQ_EXPELL (1<<5) +#define JACQ_DATE (1<<6) + +/////// EVENT +/datum/round_event_control/jacqueen + name = "Jacqueline's visit" + holidayID = "jacqueen" + typepath = /datum/round_event/jacqueen + weight = -1 //forces it to be called, regardless of weight + max_occurrences = 1 + earliest_start = 0 MINUTES + +/datum/round_event/jacqueen/start() + ..() + + for(var/mob/living/carbon/human/H in GLOB.carbon_list) + playsound(H, 'sound/spookoween/ahaha.ogg', 100, 0.25) + + for(var/obj/effect/landmark/barthpot/bp in GLOB.landmarks_list) + new /obj/item/barthpot(bp.loc) + new /mob/living/simple_animal/jacq(bp.loc) + +/////// MOBS + +//Whacha doing in here like? Yae wan tae ruin ta magicks? +/mob/living/simple_animal/jacq + name = "Jacqueline the Pumpqueen" + real_name = "Jacqueline" + icon = 'icons/obj/halloween_items.dmi' + icon_state = "jacqueline" + maxHealth = 25 + health = 25 + density = FALSE + speech_span = "spooky" + friendly = "pets" + response_help = "chats with" + var/last_poof + var/progression = list() //Keep track of where people are in the story. + var/active = TRUE //Turn this to false to keep normal mob behavour + +/mob/living/simple_animal/jacq/Initialize() + ..() + poof() + +/mob/living/simple_animal/jacq/Life() + ..() + if(!ckey) + if((last_poof+4 MINUTES) < world.realtime) + poof() + +/mob/living/simple_animal/jacq/Destroy() //I.e invincible + visible_message("[src] cackles, \"You'll nae get rid a me that easily!\"") + playsound(loc, 'sound/spookoween/ahaha.ogg', 100, 0.25) + var/mob/living/simple_animal/jacq/Jacq = new src.type(loc) + Jacq.progression = progression + ..() + +/mob/living/simple_animal/jacq/death() //What is alive may never die + visible_message("[src] cackles, \"You'll nae get rid a me that easily!\"") + playsound(loc, 'sound/spookoween/ahaha.ogg', 100, 0.25) + health = 20 + poof() + +/mob/living/simple_animal/jacq/attack_hand(mob/living/carbon/human/M) + if(!active) + say("Hello there [gender_check(M)]!") + return ..() + if(!ckey) + canmove = FALSE + chit_chat(M) + canmove = TRUE + ..() + +/mob/living/simple_animal/jacq/attack_paw(mob/living/carbon/monkey/M) + if(!active) + say("Hello there [gender_check(M)]!") + return ..() + if(!ckey) + canmove = FALSE + chit_chat(M) + canmove = TRUE + ..() + +/mob/living/simple_animal/jacq/proc/poof() + last_poof = world.realtime + var/datum/reagents/R = new/datum/reagents(100)//Hey, just in case. + var/datum/effect_system/smoke_spread/chem/s = new() + R.add_reagent("secretcatchem", (10)) + s.set_up(R, 0, loc) + s.start() + visible_message("[src] disappears in a puff of smoke!") + canmove = TRUE + + var/hp_list = list() + for(var/obj/machinery/holopad/hp in world) + hp_list += hp + + var/obj/machinery/holopad/hp = pick(hp_list) + if(forceMove(pick(hp.loc))) + return TRUE + + return FALSE + +/mob/living/simple_animal/jacq/proc/gender_check(mob/living/carbon/C) + var/gender = "lamb" + if(C) + if(C.gender == MALE) + gender = "laddie" + if(C.gender == FEMALE) + gender = "lassie" + return gender + +//Ye wee bugger, gerrout of it. Ye've nae tae enjoy reading the code fer mae secrets like. +/mob/living/simple_animal/jacq/proc/chit_chat(mob/living/carbon/C) + //Very important + var/gender = gender_check(C) + if(C) + if(C.gender == MALE) + gender = "laddie" + if(C.gender == FEMALE) + gender = "lassie" + + if(!progression["[C.real_name]"] || !(progression["[C.real_name]"] & JACQ_HELLO)) + visible_message("[src] smiles ominously at [C], \"Well halo there [gender]! Ah'm Jacqueline, tae great Pumpqueen, great tae meet ye.\"") + sleep(20) + visible_message("[src] continues, says, \"Ah'm sure yae well stunned, but ah've got nae taem fer that. Ah'm after the candies around this station. If yae get mae enoof o the wee buggers, Ah'll give ye a treat, or if yae feeling bold, Ah ken trick ye instead.\" giving [C] a wide grin.") + if(!progression["[C.real_name]"]) + progression["[C.real_name]"] = NONE //TO MAKE SURE THAT THE LIST ENTRY EXISTS. + + progression["[C.real_name]"] = progression["[C.real_name]"] | JACQ_HELLO + + var/choices = list("Trick", "Treat", "How do I get candies?") + var/choice = input(C, "Trick or Treat?", "Trick or Treat?") in choices + switch(choice) + if("Trick") + trick(C) + return + if("Treat") + if(check_candies(C)) + treat(C, gender) + else + visible_message("[src] raises an eyebrow, \"You've nae got any candies Ah want! They're the orange round ones, now bugger off an go get em first.\"") + return + if("How do I get candies?") + visible_message("[src] says, \"Gae find my familiar; Bartholomew. Ee's tendin the cauldron which ken bring oot t' magic energy in items scattered aroond. Knowing him, ee's probably gone tae somewhere with books.\"") + return + +/mob/living/simple_animal/jacq/proc/treat(mob/living/carbon/C, gender) + visible_message("[src] gives off a glowing smile, \"What ken Ah offer ye? I can magic up an object, a potion or a plushie fer ye.\"") + var/choices_reward = list("Object - 3 candies", "Potion - 2 candies", "Plushie - 1 candy", "Can I ask you a question instead?") + var/choice_reward = input(usr, "Trick or Treat?", "Trick or Treat?") in choices_reward + + //rewards + switch(choice_reward) + if("Object - 3 candies") + if(!take_candies(C, 3)) + visible_message("[src] raises an eyebrown, \"It's 3 candies per trinket [gender]! Thems the rules!\"") + return + + var/new_obj = pick(subtypesof(/obj)) + //for(var/item in blacklist) + // if(new_obj == item) + // panic() + var/reward = new new_obj(C.loc) + C.put_in_hands(reward) + visible_message("[src] waves her hands, magicing up a [reward] from thin air, \"There ye are [gender], enjoy! \"") + sleep(20) + poof() + return + if("Potion - 2 candies") + if(!take_candies(C, 2)) + visible_message("[src] raises an eyebrow, \"It's 2 candies per potion [gender]! Thems the rules!\"") + return + + var/reward = new /obj/item/reagent_containers/potion_container(C.loc) + C.put_in_hands(reward) + visible_message("[src] waves her hands, magicing up a [reward] from thin air, \"There ye are [gender], enjoy! \"") + sleep(20) + poof() + return + if("Plushie - 1 candy") + if(!take_candies(C, 1)) + visible_message("[src] raises an eyebrow, \"It's 1 candy per plushie [gender]! Thems the rules!\"") + return + + new /obj/item/toy/plush/random(C.loc) + visible_message("[src] waves her hands, magicing up a plushie from thin air, \"There ye are [gender], enjoy! \"") + sleep(20) + poof() + return + + //chitchats! + if("Can I ask you a question instead?") + var/choices = list() + //Figure out where the C is in the story + if(!progression["[C.real_name]"]) //I really don't want to get here withoot a hello, but just to be safe + progression["[C.real_name]"] = NONE + if(!(progression["[C.real_name]"] & JACQ_FAR)) + if(progression["[C.real_name]"] & JACQ_CANDIES) + choices += "You really came all this way for candy?" + else + choices += "Why do you want the candies?" + if(!(progression["[C.real_name]"] & JACQ_HEAD)) + choices += "What is that on your head?" + if(!(progression["[C.real_name]"] & JACQ_EXPELL)) + if(progression["[C.real_name]"] & JACQ_WITCH) + choices += "So you got ex-spell-ed?" + else + choices += "Are you a witch?" + + //for Kepler, delete this, or just delete the whole story aspect if you want. + //If fully completed + /* + if(progression["[C.real_name]"] & JACQ_FAR)//Damnit this is a pain + if(progression["[C.real_name]"] & JACQ_EXPELL) //I give up + if(progression["[C.real_name]"] & JACQ_HEAD) //This is only an event thing + choices += "Can I take you out on a date?" + */ + if(progression["[C.real_name]"] == 63)//Damnit this is a pain + choices += "Can I take you out on a date?" + + //If you've nothing to ask + if(!LAZYLEN(choices)) + visible_message("[src] sighs, \"Ah'm all questioned oot fer noo, [gender].\"") + return + //Otherwise, lets go! + visible_message("[src] says, \"A question? Sure, it'll cost you a candy though!\"") + choices += "Nevermind" + //Candies for chitchats + var/choice = input(C, "What do you want to ask?", "What do you want to ask?") in choices + if(!take_candies(C, 1)) + visible_message("[src] raises an eyebrow, \"It's a candy per question [gender]! Thems the rules!\"") + return + //Talking + switch(choice) + if("Why do you want the candies?") + visible_message("[src] says, \"Ave ye tried them? They're full of all sorts of reagents. Ah'm after them so ah ken magic em up an hopefully find rare stuff fer me brews. Honestly it's a lot easier magicking up tatt fer ye lot than runnin aroond on me own like. I'd ask me familiars but most a my familiars are funny fellows 'n constantly bugger off on adventures when given simple objectives like; Go grab me a tea cake or watch over me cauldron. Ah mean, ye might run into Bartholomew my cat. Ee's supposed tae be tending my cauldron, but I've nae idea where ee's got tae.\"") + progression["[C.real_name]"] = progression["[C.real_name]"] | JACQ_CANDIES + sleep(30) + poof() + + if("You really came all this way for candy?") + visible_message("[src] looks tae the side sheepishly, \"Aye, well, tae be honest, Ah'm here tae see me sis, but dunnae let her knew that. She's an alchemist too like, but she dunnae use a caldron like mae, she buggered off like tae her posh ivory tower tae learn bloody chemistry instead!\" [src] scowls, \"She's tae black sheep o' the family too, so we dunnae see eye tae eye sometimes on alchemy. Ah mean, she puts moles in her brews! Ye dunnae put moles in yer brews! Yae threw your brews at tae wee bastards an blew em up!\" [src] sighs, \"But she's a heart o gold so.. Ah wanted tae see her an check up oon her, make sure she's okay.\"") + progression["[C.real_name]"] = progression["[C.real_name]"] | JACQ_FAR + sleep(30) + poof() + + if("What is that on your head?") + visible_message("[src] pats the pumpkin atop her head, \"This thing? This ain't nae ordinary pumpkin! Me Ma grew this monster ooer a year o love, dedication an hard work. Honestly it felt like she loved this thing more than any of us, which Ah knew ain't true an it's not like she was hartless or anything but.. well, we had a falling oot when Ah got back home with all me stuff in tow. An all she had done is sent me owl after owl over t' last year aboot this bloody pumpkin and ah had enough. So ah took it, an put it on me head. You know, as ye do. Ah am the great Pumpqueen after all, Ah deserve this.\"") + progression["[C.real_name]"] = progression["[C.real_name]"] | JACQ_HEAD + sleep(30) + poof() + + if("Are you a witch?") + visible_message("[src] grumbles, \"If ye must know, Ah got kicked oot of the witch academy fer being too much of a \"loose cannon\". A bloody loose cannon? Nae they were just pissed off Ah had the brass tae proclaim myself as the Pumpqueen! And also maybe the time Ah went and blew up one of the towers by trying tae make a huge batch of astrogen might've had something tae do with it. Ah mean it would've worked fine if the cauldrons weren't so shite and were actually upgraded by the faculty. So technically no, I'm not a witch.\"") + progression["[C.real_name]"] = progression["[C.real_name]"] | JACQ_WITCH + sleep(30) + poof() + + if("So you got ex-spell-ed?") + visible_message("[src] Gives you a blank look at the pun, before continuing, \"Not quite, Ah know Ah ken get back into the academy, it's only an explosion, they happen all the time, but, tae be fair it's my fault that things came tae their explosive climax. You don't know what it's like when you're after a witch doctorate, everyone else is doing well, everyone's making new spells and the like, and I'm just good at making explosions really, or fireworks. So, Ah did something Ah knew was dangerous, because Ah had tae do something tae stand oot, but Ah know this life ain't fer me, Ah don't want tae be locked up in dusty towers, grinding reagent after reagent together, trying tae find new reactions, some of the wizards in there haven't left fer years. Ah want tae live, Ah want tae fly around on a broom, turn people into cats fer a day and disappear cackling! That's what got me into witchcraft!\" she throws her arms up in the arm, spinning the pumpkin upon her head slightly. She carefully spins it back to face you, giving oot a soft sigh, \"Ah know my mother's obsession with this dumb thing on my head is just her trying tae fill the void of me and my sis moving oot, and it really shouldn't be on my head. And Ah know that I'm really here tae get help from my sis.. She's the sensible one, and she gives good hugs.\"") + sleep(30) + visible_message("[src] says, \"Thanks [C], Ah guess Ah didn't realise Ah needed someone tae talk tae but, I'm glad ye spent all your candies talking tae me. Funny how things seem much worse in yer head.\"") + progression["[C.real_name]"] = progression["[C.real_name]"] | JACQ_EXPELL + sleep(30) + poof() + + if("Can I take you out on a date?") + visible_message("[src] blushes, \"...You want tae ask me oot on a date? Me? After all that nonsense Ah just said? It seems a waste of a candy honestly.\"") + progression["[C.real_name]"] = progression["[C.real_name]"] | JACQ_DATE + visible_message("[src] looks to the side, deep in thought.") + dating_start(C, gender) + + if("Nevermind") + visible_message("[src] shrugs, \"Suit yerself then, here's your candy back.\"") + new /obj/item/reagent_containers/food/snacks/special_candy(loc) + + +/mob/living/simple_animal/jacq/proc/trick(mob/living/carbon/C, gender) + var/option + if(ishuman(C)) + option = rand(1,7) + else + option = rand(1,6) + switch(option) + if(1) + visible_message("[src] waves their arms around, \"Hocus pocus, making friends is now your focus!\"") + var/datum/objective/brainwashing/objective = pick("Make a tasty sandwich for", "Compose a poem for", "Aquire a nice outfit to give to", "Strike up a conversation about pumpkins with", "Write a letter and deliver it to", "Give a nice hat to") + var/mob/living/L2 = pick(GLOB.player_list) + objective += " [L2.name]." + brainwash(C, objective) + if(2) + visible_message("[src] waves their arms around, \"Off comes your head, a pumpkin taking it's stead!\"") + C.reagents.add_reagent("pumpkinmutationtoxin", 5) + if(3) + visible_message("[src] waves their arms around, \"If only you had a better upbringing, your ears are now full of my singing!\"") + var/client/C2 = C.client + C2.chatOutput.sendMusic("https://a.uguu.se/rQ8FxxUQ1Xzc_SpOwOkyOwOkyPumpkinSong-PFrPrIxluWk.mp4", 1)//I hope this works! + if(4) + visible_message("[src] waves their arms around, \"You're cute little bumpkin, On your head is a pumpkin!\"") + if(C.head) + var/obj/item/W = C.head + C.dropItemToGround(W, TRUE) + var/jaqc_latern = new /obj/item/clothing/head/hardhat/pumpkinhead/jaqc + C.equip_to_slot(jaqc_latern, SLOT_HEAD, 1, 1) + if(5) + visible_message("[src] waves their arms around, \"In your body there's something amiss, you'll find it's a chem made by my sis!\"") + C.reagents.add_reagent("eigenstate", 30) + if(6) + visible_message("[src] waves their arms around, \"A new familiar for me, and you'll see it's thee!\"") + C.reagents.add_reagent("secretcatchem", 30) + if(7) + visible_message("[src] waves their arms around, \"While you may not be a ghost, for this sheet you'll always be it's host.\"") + var/mob/living/carbon/human/H = C + if(H.wear_suit) + var/obj/item/W = H.wear_suit + H.dropItemToGround(W, TRUE) + var/ghost = new /obj/item/clothing/suit/ghost_sheet/sticky + H.equip_to_slot(ghost, SLOT_WEAR_SUIT, 1, 1) + poof() + +//Blame Fel +/mob/living/simple_animal/jacq/proc/dating_start(mob/living/carbon/C, gender) + var/candies = pollGhostCandidates("Do you want to go on a date with [C] as Jacqueline the great pumpqueen?") + //sleep(30) //If the poll doesn't autopause. + if(candies) + candies = shuffle(candies)//Shake those ghosts up! + for(var/mob/dead/observer/C2 in candies) + if(C2.key && C2) + key = C2.key + message_admins("[C2]/[C2.key] has agreed to go on a date with [C] as Jacqueline.") + log_game("HALLOWEEN: [C2]/[C2.key] has agreed to go on a date with [C] as Jacqueline") + to_chat(src, "You are Jacqueline the great pumpqueen, witch Extraordinaire! You're a very Scottish lass with a kind heart, but also a little crazy. You also blew up the wizarding school and you're suspended for a while, so you visited the station before heading home. On your head lies the prize pumpkin of your Mother's pumpkin patch. You're currently on a date with [C] and well, I didn't think anyone would get this far. Please be good so I can do events like this in the future. ") + return + else + candies =- C2 + visible_message("[src] looks to the side, \"Look, Ah like ye but, Ah don't think Ah can right now. If ye can't tell, the stations covered in volatile candies, I've a few other laddies and lassies running after me treats, and tae top it all off, I've the gods breathing down me neck, watching every treat Ah make fer the lot of yous.\" she sighs, \"But that's not a no, right? That's.. just a nae right noo.\"") + sleep(20) + visible_message("[src] takes off the pumpkin on her head, a rich blush on her cheeks. She leans over planting a kiss upon your forehead quickly befere popping the pumpkin back on her head.") + sleep(10) + visible_message("[src] waves their arms around, \"There, that aught tae be worth a candy.\"") + sleep(20) + poof() + +/obj/item/clothing/head/hardhat/pumpkinhead/jaqc + name = "Jacq o' latern" + desc = "A jacqueline o' lantern! You can't seem to get rid of it." + icon_state = "hardhat0_pumpkin_j" + item_state = "hardhat0_pumpkin_j" + item_color = "pumpkin_j" + brightness_on = 4 + +/obj/item/clothing/head/hardhat/pumpkinhead/jaqc/Initialize() + . = ..() + ADD_TRAIT(src, TRAIT_NODROP, GLUED_ITEM_TRAIT) + +/obj/item/clothing/suit/ghost_sheet/sticky + +/obj/item/clothing/suit/ghost_sheet/sticky/Initialize() + . = ..() + ADD_TRAIT(src, TRAIT_NODROP, GLUED_ITEM_TRAIT) + +/obj/item/clothing/suit/ghost_sheet/sticky/attack_hand(mob/user) + if(iscarbon(user)) + to_chat(user, "Boooooo~!") + return + else + ..() + +/obj/item/clothing/suit/ghost_sheet/sticky/attack_hand(mob/user) + if(iscarbon(user)) + to_chat(user, "Boooooo~!") + return + else + ..() + +/datum/reagent/mutationtoxin/pumpkinhead + name = "Pumpkin head mutation toxin" + id = "pumpkinmutationtoxin" + race = /datum/species/dullahan/pumpkin + mutationtext = "The pain subsides. You feel your head roll off your shoulders... and you smell pumpkin." + //I couldn't get the replace head sprite with a pumpkin to work so, it is what it is. + +/mob/living/simple_animal/jacq/proc/check_candies(mob/living/carbon/C) + var/invs = C.get_contents() + var/candy_count = 0 + for(var/item in invs) + if(istype(item, /obj/item/reagent_containers/food/snacks/special_candy)) + candy_count++ + return candy_count + +/mob/living/simple_animal/jacq/proc/take_candies(mob/living/carbon/C, candy_amount = 1) + var/inv = C.get_contents() + var/candies = list() + for(var/item in inv) + if(istype(item, /obj/item/reagent_containers/food/snacks/special_candy)) + candies += item + if(LAZYLEN(candies) == candy_amount) + break + if(LAZYLEN(candies) == candy_amount) //I know it's a double check but eh, to be safe. + for(var/candy in candies) + qdel(candy) + return TRUE + return FALSE + +//Potions +/obj/item/reagent_containers/potion_container + name = "potion" + icon = 'icons/obj/halloween_items.dmi' + icon_state = "jacq_potion" + desc = "A potion with a strange concoction within. Be careful, as if it's thrown it explodes in a puff of smoke like Jacqueline." + +/obj/item/reagent_containers/potion_container/Initialize() + .=..() + var/R = get_random_reagent_id() + reagents.add_reagent(R, 30) + name = "[R] Potion" + +/obj/item/reagent_containers/potion_container/throw_impact(atom/target) + ..() + sleep(20) + var/datum/effect_system/smoke_spread/chem/s = new() + s.set_up(src.reagents, 3, src.loc) + s.start() + qdel(src) + +//Candies +/obj/item/reagent_containers/food/snacks/special_candy + name = "Magic candy" + icon = 'icons/obj/halloween_items.dmi' + icon_state = "jacq_candy" + desc = "A candy with strange magic within. Be careful, as the magic isn't always helpful." + +/obj/item/reagent_containers/food/snacks/special_candy/Initialize() + .=..() + reagents.add_reagent(get_random_reagent_id(), 5) diff --git a/code/modules/holiday/holidays.dm b/code/modules/holiday/holidays.dm index 7d1e25235d..9d075857a7 100644 --- a/code/modules/holiday/holidays.dm +++ b/code/modules/holiday/holidays.dm @@ -333,6 +333,16 @@ /datum/holiday/halloween/getStationPrefix() return pick("Bone-Rattling","Mr. Bones' Own","2SPOOKY","Spooky","Scary","Skeletons") +/datum/holiday/jacqueen //Subset of halloween + name = "jacqueen" + begin_day = 27 + begin_month = OCTOBER + end_day = 2 + end_month = NOVEMBER + +/datum/holiday/jacqueen/greet() + return "Jacqueline the great Pumpqueen has come to visit!" + /datum/holiday/vegan name = "Vegan Day" begin_day = 1 diff --git a/code/modules/holodeck/computer.dm b/code/modules/holodeck/computer.dm index 4ffc10f9c2..889706744a 100644 --- a/code/modules/holodeck/computer.dm +++ b/code/modules/holodeck/computer.dm @@ -111,6 +111,11 @@ if(A) load_program(A) if("safety") + if(!issilicon(usr) && !IsAdminGhost(usr)) + var/msg = "[key_name(usr)] attempted to emag the holodeck using a href they shouldn't have!" + message_admins(msg) + log_admin(msg) + return obj_flags ^= EMAGGED if((obj_flags & EMAGGED) && program && emag_programs[program.name]) emergency_shutdown() @@ -149,6 +154,7 @@ active_power_usage = 50 + spawned.len * 3 + effects.len * 5 /obj/machinery/computer/holodeck/emag_act(mob/user) + . = ..() if(obj_flags & EMAGGED) return if(!LAZYLEN(emag_programs)) @@ -160,6 +166,7 @@ to_chat(user, "Warning. Automatic shutoff and derezing protocols have been corrupted. Please call Nanotrasen maintenance and do not use the simulator.") log_game("[key_name(user)] emagged the Holodeck Control Console") nerf(!(obj_flags & EMAGGED)) + return TRUE /obj/machinery/computer/holodeck/emp_act(severity) . = ..() diff --git a/code/modules/holodeck/holo_effect.dm b/code/modules/holodeck/holo_effect.dm index fee0b2b7c9..308cec1cbd 100644 --- a/code/modules/holodeck/holo_effect.dm +++ b/code/modules/holodeck/holo_effect.dm @@ -78,6 +78,12 @@ // these vars are not really standardized but all would theoretically create stuff on death for(var/v in list("butcher_results","corpse","weapon1","weapon2","blood_volume") & mob.vars) mob.vars[v] = null + ENABLE_BITFIELD(mob.flags_1, HOLOGRAM_1) + if(isliving(mob)) + var/mob/living/L = mob + L.feeding = FALSE + L.devourable = FALSE + L.digestable = FALSE return mob /obj/effect/holodeck_effect/mobspawner/deactivate(var/obj/machinery/computer/holodeck/HC) @@ -100,7 +106,7 @@ /obj/effect/holodeck_effect/mobspawner/penguin mobtype = /mob/living/simple_animal/pet/penguin/emperor - + /obj/effect/holodeck_effect/mobspawner/penguin/Initialize() if(prob(1)) mobtype = /mob/living/simple_animal/pet/penguin/emperor/shamebrero diff --git a/code/modules/hydroponics/gene_modder.dm b/code/modules/hydroponics/gene_modder.dm index d6eacfe0e1..79a23014b0 100644 --- a/code/modules/hydroponics/gene_modder.dm +++ b/code/modules/hydroponics/gene_modder.dm @@ -69,6 +69,8 @@ if(default_deconstruction_screwdriver(user, "dnamod", "dnamod", I)) update_icon() return + else if(default_unfasten_wrench(user, I)) + return if(default_deconstruction_crowbar(I)) return if(iscyborg(user)) diff --git a/code/modules/hydroponics/grown/berries.dm b/code/modules/hydroponics/grown/berries.dm index 19abdacf3a..ef019387e8 100644 --- a/code/modules/hydroponics/grown/berries.dm +++ b/code/modules/hydroponics/grown/berries.dm @@ -215,3 +215,26 @@ filling_color = "#7FFF00" tastes = list("green grape" = 1) distill_reagent = "cognac" + +// Strawberry +/obj/item/seeds/strawberry + name = "pack of strawberry seeds" + desc = "These seeds grow into strawberry vines." + icon_state = "seed-strawberry" + species = "strawberry" + plantname = "Strawberry Vine" + product = /obj/item/reagent_containers/food/snacks/grown/strawberry + growthstages = 6 + growing_icon = 'icons/obj/hydroponics/growing_fruits.dmi' + icon_grow = "strawberry-grow" + icon_dead = "berry-dead" + reagents_add = list("vitamin" = 0.07, "nutriment" = 0.1, "sugar" = 0.2) + mutatelist = list() + +/obj/item/reagent_containers/food/snacks/grown/strawberry + seed = /obj/item/seeds/strawberry + name = "strawberry" + icon_state = "strawberry" + filling_color = "#7FFF00" + tastes = list("strawberries" = 1) + wine_power = 20 diff --git a/code/modules/hydroponics/grown/cotton.dm b/code/modules/hydroponics/grown/cotton.dm new file mode 100644 index 0000000000..045839d0de --- /dev/null +++ b/code/modules/hydroponics/grown/cotton.dm @@ -0,0 +1,79 @@ +/obj/item/seeds/cotton + name = "pack of cotton seeds" + desc = "A pack of seeds that'll grow into a cotton plant. Assistants make good free labor if neccesary." + icon_state = "seed-cotton" + species = "cotton" + plantname = "Cotton" + icon_harvest = "cotton-harvest" + product = /obj/item/grown/cotton + lifespan = 35 + endurance = 25 + maturation = 15 + production = 1 + yield = 2 + potency = 50 + growthstages = 3 + growing_icon = 'icons/obj/hydroponics/growing.dmi' + icon_dead = "cotton-dead" + mutatelist = list(/obj/item/seeds/cotton/durathread) + +/obj/item/grown/cotton + seed = /obj/item/seeds/cotton + name = "cotton bundle" + desc = "A fluffy bundle of cotton." + icon_state = "cotton" + force = 0 + throwforce = 0 + w_class = WEIGHT_CLASS_TINY + throw_speed = 2 + throw_range = 3 + attack_verb = list("pomfed") + var/cotton_type = /obj/item/stack/sheet/cotton + var/cotton_name = "raw cotton" + +/obj/item/grown/cotton/attack_self(mob/user) + user.show_message("You pull some [cotton_name] out of the [name]!", 1) + var/seed_modifier = 0 + if(seed) + seed_modifier = round(seed.potency / 25) + var/obj/item/stack/cotton = new cotton_type(user.loc, 1 + seed_modifier) + var/old_cotton_amount = cotton.amount + for(var/obj/item/stack/ST in user.loc) + if(ST != cotton && istype(ST, cotton_type) && ST.amount < ST.max_amount) + ST.attackby(cotton, user) + if(cotton.amount > old_cotton_amount) + to_chat(user, "You add the newly-formed [cotton_name] to the stack. It now contains [cotton.amount] [cotton_name].") + qdel(src) + +//reinforced mutated variant +/obj/item/seeds/cotton/durathread + name = "pack of durathread seeds" + desc = "A pack of seeds that'll grow into an extremely durable thread that could easily rival plasteel if woven properly." + icon_state = "seed-durathread" + species = "durathread" + plantname = "Durathread" + icon_harvest = "durathread-harvest" + product = /obj/item/grown/cotton/durathread + lifespan = 80 + endurance = 50 + maturation = 15 + production = 1 + yield = 2 + potency = 50 + growthstages = 3 + growing_icon = 'icons/obj/hydroponics/growing.dmi' + icon_dead = "cotton-dead" + +/obj/item/grown/cotton/durathread + seed = /obj/item/seeds/cotton/durathread + name = "durathread bundle" + desc = "A tough bundle of durathread, good luck unraveling this." + icon_state = "durathread" + force = 5 + throwforce = 5 + w_class = WEIGHT_CLASS_NORMAL + throw_speed = 2 + throw_range = 3 + attack_verb = list("bashed", "battered", "bludgeoned", "whacked") + cotton_type = /obj/item/stack/sheet/cotton/durathread + cotton_name = "raw durathread" \ No newline at end of file diff --git a/code/modules/hydroponics/grown/flowers.dm b/code/modules/hydroponics/grown/flowers.dm index 4e1718f853..af5919969c 100644 --- a/code/modules/hydroponics/grown/flowers.dm +++ b/code/modules/hydroponics/grown/flowers.dm @@ -25,6 +25,7 @@ slot_flags = ITEM_SLOT_HEAD filling_color = "#FF6347" bitesize_mod = 3 + tastes = list("sesame seeds" = 1) foodtype = VEGETABLES | GROSS distill_reagent = "vermouth" @@ -36,13 +37,14 @@ species = "lily" plantname = "Lily Plants" product = /obj/item/reagent_containers/food/snacks/grown/poppy/lily - mutatelist = list() + mutatelist = list(/obj/item/seeds/bee_balm) /obj/item/reagent_containers/food/snacks/grown/poppy/lily seed = /obj/item/seeds/poppy/lily name = "lily" desc = "A beautiful orange flower." icon_state = "lily" + tastes = list("pelts " = 1) filling_color = "#FFA500" // Geranium @@ -61,6 +63,7 @@ desc = "A beautiful blue flower." icon_state = "geranium" filling_color = "#008B8B" + tastes = list("pelts " = 1) // Harebell /obj/item/seeds/harebell @@ -86,6 +89,7 @@ name = "harebell" desc = "\"I'll sweeten thy sad grave: thou shalt not lack the flower that's like thy face, pale primrose, nor the azured hare-bell, like thy veins; no, nor the leaf of eglantine, whom not to slander, out-sweeten'd not thy breath.\"" icon_state = "harebell" + tastes = list("salt" = 1) slot_flags = ITEM_SLOT_HEAD filling_color = "#E6E6FA" bitesize_mod = 3 @@ -123,6 +127,7 @@ w_class = WEIGHT_CLASS_TINY throw_speed = 1 throw_range = 3 + tastes = list("seeds" = 1) /obj/item/grown/sunflower/attack(mob/M, mob/user) to_chat(M, " [user] smacks you with a sunflower!FLOWER POWER") @@ -153,6 +158,7 @@ filling_color = "#E6E6FA" bitesize_mod = 2 distill_reagent = "absinthe" //It's made from flowers. + tastes = list("glowbugs" = 1) // Novaflower /obj/item/seeds/sunflower/novaflower @@ -184,6 +190,7 @@ throw_range = 3 attack_verb = list("roasted", "scorched", "burned") grind_results = list("capsaicin" = 0, "condensedcapsaicin" = 0) + tastes = list("cooked sunflower" = 1) /obj/item/grown/novaflower/add_juice() ..() @@ -214,3 +221,61 @@ if(!user.gloves) to_chat(user, "The [name] burns your bare hand!") user.adjustFireLoss(rand(1, 5)) + +// Beebalm +/obj/item/seeds/bee_balm + name = "pack of Bee Balm seeds" + desc = "These seeds grow into Bee Balms." + icon_state = "seed-bee_balm" + species = "bee_balm" + plantname = "Bee Balm Buds" + product = /obj/item/reagent_containers/food/snacks/grown/bee_balm + endurance = 10 + maturation = 8 + yield = 3 + potency = 30 + growthstages = 3 + growing_icon = 'icons/obj/hydroponics/growing_flowers.dmi' + icon_grow = "bee_balm-grow" + icon_dead = "bee_balm-dead" + mutatelist = list(/obj/item/seeds/poppy/geranium, /obj/item/seeds/bee_balm/honey) //Lower odds of becoming honey + reagents_add = list("spaceacillin" = 0.1, "sterilizine" = 0.05) + +/obj/item/reagent_containers/food/snacks/grown/bee_balm + seed = /obj/item/seeds/bee_balm + name = "bee balm" + desc = "A flower used for medical antiseptic in history." + icon_state = "bee_balm" + filling_color = "#FF6347" + bitesize_mod = 8 + tastes = list("strong antiseptic " = 1) + foodtype = GROSS + +// Beebalm +/obj/item/seeds/bee_balm/honey + name = "pack of Honey Balm seeds" + desc = "These seeds grow into Honey Balms." + icon_state = "seed-bee_balmalt" + species = "seed-bee_balm_alt" + plantname = "Honey Balm Pods" + product = /obj/item/reagent_containers/food/snacks/grown/bee_balm/honey + endurance = 1 + maturation = 10 + yield = 1 + potency = 1 + growthstages = 3 + growing_icon = 'icons/obj/hydroponics/growing_flowers.dmi' + icon_grow = "bee_balmalt-grow" + icon_dead = "bee_balmalt-dead" + reagents_add = list("honey" = 0.1, "lye" = 0.3) //To make wax + rarity = 30 + +/obj/item/reagent_containers/food/snacks/grown/bee_balm/honey + seed = /obj/item/seeds/bee_balm/honey + name = "honey balm" + desc = "A large honey filled pod of a flower." + icon_state = "bee_balmalt" + filling_color = "#FF6347" + bitesize_mod = 8 + tastes = list("wax" = 1) + foodtype = SUGAR \ No newline at end of file diff --git a/code/modules/hydroponics/grown/melon.dm b/code/modules/hydroponics/grown/melon.dm index 29691c3289..eb463e5f6d 100644 --- a/code/modules/hydroponics/grown/melon.dm +++ b/code/modules/hydroponics/grown/melon.dm @@ -58,6 +58,7 @@ wine_power = 70 //Water to wine, baby. wine_flavor = "divinity" -/obj/item/reagent_containers/food/snacks/grown/holymelon/Initialize() - . = ..() - AddComponent(/datum/component/anti_magic, TRUE, TRUE) //deliver us from evil o melon god + +// /obj/item/reagent_containers/food/snacks/grown/holymelon/Initialize() +// . = ..() +// AddComponent(/datum/component/anti_magic, TRUE, TRUE) //deliver us from evil o melon god diff --git a/code/modules/hydroponics/grown/misc.dm b/code/modules/hydroponics/grown/misc.dm index 107a6a94f9..0902052a11 100644 --- a/code/modules/hydroponics/grown/misc.dm +++ b/code/modules/hydroponics/grown/misc.dm @@ -1,7 +1,7 @@ // Starthistle /obj/item/seeds/starthistle name = "pack of starthistle seeds" - desc = "A robust species of weed that often springs up in-between the cracks of spaceship parking lots." + desc = "A robust species of weed that often springs up in-between the cracks of spaceship parking lots. Grind down these seeds for a substitution for mustardgrind." icon_state = "seed-starthistle" species = "starthistle" plantname = "Starthistle" @@ -9,9 +9,10 @@ endurance = 50 // damm pesky weeds maturation = 5 production = 1 - yield = 2 + yield = 6 potency = 10 growthstages = 3 + grind_results = list("mustardgrind" = 1) growing_icon = 'icons/obj/hydroponics/growing_flowers.dmi' genes = list(/datum/plant_gene/trait/plant_type/weed_hardy) mutatelist = list(/obj/item/seeds/harebell) diff --git a/code/modules/hydroponics/grown/peach.dm b/code/modules/hydroponics/grown/peach.dm new file mode 100644 index 0000000000..6fbf933bd1 --- /dev/null +++ b/code/modules/hydroponics/grown/peach.dm @@ -0,0 +1,27 @@ +// Peach +/obj/item/seeds/peach + name = "pack of peach seeds" + desc = "These seeds grow into peach trees." + icon_state = "seed-peach" + species = "peach" + plantname = "Peach Tree" + product = /obj/item/reagent_containers/food/snacks/grown/peach + lifespan = 65 + endurance = 40 + yield = 3 + growing_icon = 'icons/obj/hydroponics/growing_fruits.dmi' + icon_grow = "peach-grow" + icon_dead = "peach-dead" + genes = list(/datum/plant_gene/trait/repeated_harvest) + reagents_add = list("vitamin" = 0.04, "nutriment" = 0.1) + +/obj/item/reagent_containers/food/snacks/grown/peach + seed = /obj/item/seeds/peach + name = "peach" + desc = "It's fuzzy!" + icon_state = "peach" + filling_color = "#FF4500" + bitesize = 25 + foodtype = FRUIT + juice_results = list("peachjuice" = 0) + tastes = list("peach" = 1) diff --git a/code/modules/hydroponics/grown/tea_coffee.dm b/code/modules/hydroponics/grown/tea_coffee.dm index fc84617ed8..06cbb1df0c 100644 --- a/code/modules/hydroponics/grown/tea_coffee.dm +++ b/code/modules/hydroponics/grown/tea_coffee.dm @@ -14,6 +14,7 @@ icon_dead = "tea-dead" genes = list(/datum/plant_gene/trait/repeated_harvest) mutatelist = list(/obj/item/seeds/tea/astra) + reagents_add = list("teapowder" = 0.1) /obj/item/reagent_containers/food/snacks/grown/tea seed = /obj/item/seeds/tea @@ -32,7 +33,7 @@ species = "teaastra" plantname = "Tea Astra Plant" product = /obj/item/reagent_containers/food/snacks/grown/tea/astra - mutatelist = list() + mutatelist = list(/obj/item/seeds/tea/catnip) reagents_add = list("synaptizine" = 0.1, "vitamin" = 0.04, "teapowder" = 0.1) rarity = 20 @@ -43,6 +44,24 @@ filling_color = "#4582B4" grind_results = list("teapowder" = 0, "salglu_solution" = 0) +// Kitty drugs +/obj/item/seeds/tea/catnip + name = "pack of catnip seeds" + icon_state = "seed-catnip" + desc = "Long stocks with flowering tips that has a chemical to make feline attracted to it." + species = "catnip" + plantname = "Catnip Plant" + growthstages = 3 + product = /obj/item/reagent_containers/food/snacks/grown/tea/catnip + reagents_add = list("catnip" = 0.1, "vitamin" = 0.06, "teapowder" = 0.3) + rarity = 50 + +/obj/item/reagent_containers/food/snacks/grown/tea/catnip + seed = /obj/item/seeds/tea/catnip + name = "Catnip buds" + icon_state = "catnip_leaves" + filling_color = "#4582B4" + grind_results = list("catnp" = 2, "water" = 1) // Coffee /obj/item/seeds/coffee diff --git a/code/modules/hydroponics/growninedible.dm b/code/modules/hydroponics/growninedible.dm index 5aeef19b1a..c0e3beaf79 100644 --- a/code/modules/hydroponics/growninedible.dm +++ b/code/modules/hydroponics/growninedible.dm @@ -7,6 +7,7 @@ icon = 'icons/obj/hydroponics/harvest.dmi' resistance_flags = FLAMMABLE var/obj/item/seeds/seed = null // type path, gets converted to item on New(). It's safe to assume it's always a seed item. + var/tastes = list("indescribable" = 1) //Stops runtimes. Grown are un-eatable anyways so if you do then its a bug /obj/item/grown/Initialize(newloc, obj/item/seeds/new_seed) . = ..() diff --git a/code/modules/integrated_electronics/core/printer.dm b/code/modules/integrated_electronics/core/printer.dm index de3ade389f..f0aa10f2da 100644 --- a/code/modules/integrated_electronics/core/printer.dm +++ b/code/modules/integrated_electronics/core/printer.dm @@ -193,7 +193,7 @@ else if(ispath(build_type, /obj/item/integrated_circuit)) var/obj/item/integrated_circuit/IC = SScircuit.cached_components[build_type] cost = IC.materials[MAT_METAL] - else if(!build_type in SScircuit.circuit_fabricator_recipe_list["Tools"]) + else if(!(build_type in SScircuit.circuit_fabricator_recipe_list["Tools"])) return var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) diff --git a/code/modules/jobs/access.dm b/code/modules/jobs/access.dm index e88a80514a..1ffdff2347 100644 --- a/code/modules/jobs/access.dm +++ b/code/modules/jobs/access.dm @@ -121,7 +121,7 @@ return list(ACCESS_CENT_GENERAL, ACCESS_CENT_LIVING, ACCESS_CENT_BAR) /proc/get_all_accesses() - return list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_FORENSICS_LOCKERS, ACCESS_COURT, + return list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_FORENSICS_LOCKERS, ACCESS_COURT, ACCESS_ENTER_GENPOP, ACCESS_LEAVE_GENPOP, ACCESS_MEDICAL, ACCESS_GENETICS, ACCESS_MORGUE, ACCESS_RD, ACCESS_TOX, ACCESS_TOX_STORAGE, ACCESS_CHEMISTRY, ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_MAINT_TUNNELS, ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CHANGE_IDS, ACCESS_AI_UPLOAD, @@ -157,7 +157,7 @@ if(1) //station general return list(ACCESS_KITCHEN,ACCESS_BAR, ACCESS_HYDROPONICS, ACCESS_JANITOR, ACCESS_CHAPEL_OFFICE, ACCESS_CREMATORIUM, ACCESS_LIBRARY, ACCESS_THEATRE, ACCESS_LAWYER) if(2) //security - return list(ACCESS_SEC_DOORS, ACCESS_WEAPONS, ACCESS_SECURITY, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_FORENSICS_LOCKERS, ACCESS_COURT, ACCESS_HOS) + return list(ACCESS_SEC_DOORS, ACCESS_WEAPONS, ACCESS_SECURITY, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_FORENSICS_LOCKERS, ACCESS_COURT, ACCESS_HOS, ACCESS_ENTER_GENPOP, ACCESS_LEAVE_GENPOP,) if(3) //medbay return list(ACCESS_MEDICAL, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_MORGUE, ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_SURGERY, ACCESS_CMO) if(4) //research @@ -312,6 +312,10 @@ return "Gateway" if(ACCESS_SEC_DOORS) return "Brig" + if(ACCESS_ENTER_GENPOP) + return "Prison Turnstile Entrance" + if(ACCESS_LEAVE_GENPOP) + return "Prison Turnstile Exit" if(ACCESS_MINERAL_STOREROOM) return "Mineral Storage" if(ACCESS_MINISAT) diff --git a/code/modules/jobs/job_exp.dm b/code/modules/jobs/job_exp.dm index 4b7b175240..f99bf65071 100644 --- a/code/modules/jobs/job_exp.dm +++ b/code/modules/jobs/job_exp.dm @@ -8,6 +8,8 @@ GLOBAL_PROTECT(exp_to_update) return 0 if(!CONFIG_GET(flag/use_exp_tracking)) return 0 + if(!SSdbcore.Connect()) + return 0 if(!exp_requirements || !exp_type) return 0 if(!job_is_xp_locked(src.title)) diff --git a/code/modules/jobs/job_types/job.dm b/code/modules/jobs/job_types/_job.dm similarity index 87% rename from code/modules/jobs/job_types/job.dm rename to code/modules/jobs/job_types/_job.dm index f03696e5da..2eeffa8b7a 100644 --- a/code/modules/jobs/job_types/job.dm +++ b/code/modules/jobs/job_types/_job.dm @@ -1,238 +1,245 @@ -/datum/job - //The name of the job - var/title = "NOPE" - - //Job access. The use of minimal_access or access is determined by a config setting: config.jobs_have_minimal_access - var/list/minimal_access = list() //Useful for servers which prefer to only have access given to the places a job absolutely needs (Larger server population) - var/list/access = list() //Useful for servers which either have fewer players, so each person needs to fill more than one role, or servers which like to give more access, so players can't hide forever in their super secure departments (I'm looking at you, chemistry!) - - //Determines who can demote this position - var/department_head = list() - - //Tells the given channels that the given mob is the new department head. See communications.dm for valid channels. - var/list/head_announce = null - - //Bitflags for the job - var/flag = 0 - var/department_flag = 0 - - //Players will be allowed to spawn in as jobs that are set to "Station" - var/faction = "None" - - //How many players can be this job - var/total_positions = 0 - - //How many players can spawn in as this job - var/spawn_positions = 0 - - //How many players have this job - var/current_positions = 0 - - //Supervisors, who this person answers to directly - var/supervisors = "" - - //Sellection screen color - var/selection_color = "#ffffff" - - - //If this is set to 1, a text is printed to the player when jobs are assigned, telling him that he should let admins know that he has to disconnect. - var/req_admin_notify - - var/custom_spawn_text - - //If you have the use_age_restriction_for_jobs config option enabled and the database set up, this option will add a requirement for players to be at least minimal_player_age days old. (meaning they first signed in at least that many days before.) - var/minimal_player_age = 0 - - var/outfit = null - - var/exp_requirements = 0 - - var/exp_type = "" - var/exp_type_department = "" - - //The amount of good boy points playing this role will earn you towards a higher chance to roll antagonist next round - //can be overridden by antag_rep.txt config - var/antag_rep = 10 - - var/list/mind_traits // Traits added to the mind of the mob assigned this job - -//Only override this proc -//H is usually a human unless an /equip override transformed it -/datum/job/proc/after_spawn(mob/living/H, mob/M, latejoin = FALSE) - //do actions on H but send messages to M as the key may not have been transferred_yet - if(mind_traits) - for(var/t in mind_traits) - ADD_TRAIT(H.mind, t, JOB_TRAIT) - -/datum/job/proc/announce(mob/living/carbon/human/H) - if(head_announce) - announce_head(H, head_announce) - -/datum/job/proc/override_latejoin_spawn(mob/living/carbon/human/H) //Return TRUE to force latejoining to not automatically place the person in latejoin shuttle/whatever. - return FALSE - -//Used for a special check of whether to allow a client to latejoin as this job. -/datum/job/proc/special_check_latejoin(client/C) - return TRUE - -/datum/job/proc/GetAntagRep() - . = CONFIG_GET(keyed_list/antag_rep)[lowertext(title)] - if(. == null) - return antag_rep - -//Don't override this unless the job transforms into a non-human (Silicons do this for example) -/datum/job/proc/equip(mob/living/carbon/human/H, visualsOnly = FALSE, announce = TRUE, latejoin = FALSE, datum/outfit/outfit_override = null) - if(!H) - return FALSE - - if(CONFIG_GET(flag/enforce_human_authority) && (title in GLOB.command_positions)) - if(H.dna.species.id != "human") - H.set_species(/datum/species/human) - H.apply_pref_name("human", H.client) - - //Equip the rest of the gear - H.dna.species.before_equip_job(src, H, visualsOnly) - - if(outfit_override || outfit) - H.equipOutfit(outfit_override ? outfit_override : outfit, visualsOnly) - - H.dna.species.after_equip_job(src, H, visualsOnly) - - if(!visualsOnly && announce) - announce(H) - -/datum/job/proc/get_access() - if(!config) //Needed for robots. - return src.minimal_access.Copy() - - . = list() - - if(CONFIG_GET(flag/jobs_have_minimal_access)) - . = src.minimal_access.Copy() - else - . = src.access.Copy() - - if(CONFIG_GET(flag/everyone_has_maint_access)) //Config has global maint access set - . |= list(ACCESS_MAINT_TUNNELS) - -/datum/job/proc/announce_head(var/mob/living/carbon/human/H, var/channels) //tells the given channel that the given mob is the new department head. See communications.dm for valid channels. - if(H && GLOB.announcement_systems.len) - //timer because these should come after the captain announcement - SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/addtimer, CALLBACK(pick(GLOB.announcement_systems), /obj/machinery/announcement_system/proc/announce, "NEWHEAD", H.real_name, H.job, channels), 1)) - -//If the configuration option is set to require players to be logged as old enough to play certain jobs, then this proc checks that they are, otherwise it just returns 1 -/datum/job/proc/player_old_enough(client/C) - if(available_in_days(C) == 0) - return TRUE //Available in 0 days = available right now = player is old enough to play. - return FALSE - - -/datum/job/proc/available_in_days(client/C) - if(!C) - return 0 - if(!CONFIG_GET(flag/use_age_restriction_for_jobs)) - return 0 - if(C.prefs.db_flags & DB_FLAG_EXEMPT) - return 0 - if(!isnum(C.player_age)) - return 0 //This is only a number if the db connection is established, otherwise it is text: "Requires database", meaning these restrictions cannot be enforced - if(!isnum(minimal_player_age)) - return 0 - - return max(0, minimal_player_age - C.player_age) - -/datum/job/proc/config_check() - return TRUE - -/datum/job/proc/map_check() - return TRUE - - -/datum/outfit/job - name = "Standard Gear" - - var/jobtype = null - - uniform = /obj/item/clothing/under/color/grey - id = /obj/item/card/id - ears = /obj/item/radio/headset - belt = /obj/item/pda - back = /obj/item/storage/backpack - shoes = /obj/item/clothing/shoes/sneakers/black - - var/backpack = /obj/item/storage/backpack - var/satchel = /obj/item/storage/backpack/satchel - var/duffelbag = /obj/item/storage/backpack/duffelbag - var/box = /obj/item/storage/box/survival - - var/pda_slot = SLOT_BELT - -/datum/outfit/job/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE) - switch(H.backbag) - if(GBACKPACK) - back = /obj/item/storage/backpack //Grey backpack - if(GSATCHEL) - back = /obj/item/storage/backpack/satchel //Grey satchel - if(GDUFFELBAG) - back = /obj/item/storage/backpack/duffelbag //Grey Duffel bag - if(LSATCHEL) - back = /obj/item/storage/backpack/satchel/leather //Leather Satchel - if(DSATCHEL) - back = satchel //Department satchel - if(DDUFFELBAG) - back = duffelbag //Department duffel bag - else - back = backpack //Department backpack - - if(box) - if(!backpack_contents) - backpack_contents = list() - backpack_contents.Insert(1, box) // Box always takes a first slot in backpack - backpack_contents[box] = 1 - - //converts the uniform string into the path we'll wear, whether it's the skirt or regular variant - var/holder - if(H.jumpsuit_style == PREF_SKIRT) - holder = "[uniform]/skirt" - if(!text2path(holder)) - holder = "[uniform]" - else - holder = "[uniform]" - uniform = text2path(holder) - -/datum/outfit/job/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) - if(visualsOnly) - return - - var/datum/job/J = SSjob.GetJobType(jobtype) - if(!J) - J = SSjob.GetJob(H.job) - - if(H.nameless && J.dresscodecompliant) - if(J.title in GLOB.command_positions) - H.real_name = J.title - else - H.real_name = "[J.title] #[rand(10000, 99999)]" - - var/obj/item/card/id/C = H.wear_id - if(istype(C)) - C.access = J.get_access() - shuffle_inplace(C.access) // Shuffle access list to make NTNet passkeys less predictable - C.registered_name = H.real_name - C.assignment = J.title - C.update_label() - H.sec_hud_set_ID() - - var/obj/item/pda/PDA = H.get_item_by_slot(pda_slot) - if(istype(PDA)) - PDA.owner = H.real_name - PDA.ownjob = J.title - PDA.update_label() - -/datum/outfit/job/get_chameleon_disguise_info() - var/list/types = ..() - types -= /obj/item/storage/backpack //otherwise this will override the actual backpacks - types += backpack - types += satchel - types += duffelbag - return types +/datum/job + //The name of the job , used for preferences, bans and more. Make sure you know what you're doing before changing this. + var/title = "NOPE" + + //Job access. The use of minimal_access or access is determined by a config setting: config.jobs_have_minimal_access + var/list/minimal_access = list() //Useful for servers which prefer to only have access given to the places a job absolutely needs (Larger server population) + var/list/access = list() //Useful for servers which either have fewer players, so each person needs to fill more than one role, or servers which like to give more access, so players can't hide forever in their super secure departments (I'm looking at you, chemistry!) + + //Determines who can demote this position + var/department_head = list() + + //Tells the given channels that the given mob is the new department head. See communications.dm for valid channels. + var/list/head_announce = null + + //Bitflags for the job + var/flag = NONE //Deprecated + var/department_flag = NONE //Deprecated +// var/auto_deadmin_role_flags = NONE + + //Players will be allowed to spawn in as jobs that are set to "Station" + var/faction = "None" + + //How many players can be this job + var/total_positions = 0 + + //How many players can spawn in as this job + var/spawn_positions = 0 + + //How many players have this job + var/current_positions = 0 + + //Supervisors, who this person answers to directly + var/supervisors = "" + + //Sellection screen color + var/selection_color = "#ffffff" + + + //If this is set to 1, a text is printed to the player when jobs are assigned, telling him that he should let admins know that he has to disconnect. + var/req_admin_notify + + // This is for Citadel specific tweaks to job notices. + var/custom_spawn_text + + //If you have the use_age_restriction_for_jobs config option enabled and the database set up, this option will add a requirement for players to be at least minimal_player_age days old. (meaning they first signed in at least that many days before.) + var/minimal_player_age = 0 + + var/outfit = null + + var/exp_requirements = 0 + + var/exp_type = "" + var/exp_type_department = "" + + //The amount of good boy points playing this role will earn you towards a higher chance to roll antagonist next round + //can be overridden by antag_rep.txt config + var/antag_rep = 10 + + var/list/mind_traits // Traits added to the mind of the mob assigned this job + var/list/blacklisted_quirks //list of quirk typepaths blacklisted. + + var/display_order = JOB_DISPLAY_ORDER_DEFAULT + +//Only override this proc +//H is usually a human unless an /equip override transformed it +/datum/job/proc/after_spawn(mob/living/H, mob/M, latejoin = FALSE) + //do actions on H but send messages to M as the key may not have been transferred_yet + if(mind_traits) + for(var/t in mind_traits) + ADD_TRAIT(H.mind, t, JOB_TRAIT) + +/datum/job/proc/announce(mob/living/carbon/human/H) + if(head_announce) + announce_head(H, head_announce) + +/datum/job/proc/override_latejoin_spawn(mob/living/carbon/human/H) //Return TRUE to force latejoining to not automatically place the person in latejoin shuttle/whatever. + return FALSE + +//Used for a special check of whether to allow a client to latejoin as this job. +/datum/job/proc/special_check_latejoin(client/C) + return TRUE + +/datum/job/proc/GetAntagRep() + . = CONFIG_GET(keyed_list/antag_rep)[lowertext(title)] + if(. == null) + return antag_rep + +//Don't override this unless the job transforms into a non-human (Silicons do this for example) +/datum/job/proc/equip(mob/living/carbon/human/H, visualsOnly = FALSE, announce = TRUE, latejoin = FALSE, datum/outfit/outfit_override = null, client/preference_source) + if(!H) + return FALSE + + if(CONFIG_GET(flag/enforce_human_authority) && (title in GLOB.command_positions)) + if(H.dna.species.id != "human") + H.set_species(/datum/species/human) + H.apply_pref_name("human", preference_source) + + //Equip the rest of the gear + H.dna.species.before_equip_job(src, H, visualsOnly) + + if(outfit_override || outfit) + H.equipOutfit(outfit_override ? outfit_override : outfit, visualsOnly) + + H.dna.species.after_equip_job(src, H, visualsOnly) + + if(!visualsOnly && announce) + announce(H) + +/datum/job/proc/get_access() + if(!config) //Needed for robots. + return src.minimal_access.Copy() + + . = list() + + if(CONFIG_GET(flag/jobs_have_minimal_access)) + . = src.minimal_access.Copy() + else + . = src.access.Copy() + + if(CONFIG_GET(flag/everyone_has_maint_access)) //Config has global maint access set + . |= list(ACCESS_MAINT_TUNNELS) + +/datum/job/proc/announce_head(var/mob/living/carbon/human/H, var/channels) //tells the given channel that the given mob is the new department head. See communications.dm for valid channels. + if(H && GLOB.announcement_systems.len) + //timer because these should come after the captain announcement + SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/addtimer, CALLBACK(pick(GLOB.announcement_systems), /obj/machinery/announcement_system/proc/announce, "NEWHEAD", H.real_name, H.job, channels), 1)) + +//If the configuration option is set to require players to be logged as old enough to play certain jobs, then this proc checks that they are, otherwise it just returns 1 +/datum/job/proc/player_old_enough(client/C) + if(available_in_days(C) == 0) + return TRUE //Available in 0 days = available right now = player is old enough to play. + return FALSE + + +/datum/job/proc/available_in_days(client/C) + if(!C) + return 0 + if(!CONFIG_GET(flag/use_age_restriction_for_jobs)) + return 0 + if(!SSdbcore.Connect()) + return 0 //Without a database connection we can't get a player's age so we'll assume they're old enough for all jobs + if(C.prefs.db_flags & DB_FLAG_EXEMPT) + return 0 + if(!isnum(minimal_player_age)) + return 0 + + return max(0, minimal_player_age - C.player_age) + +/datum/job/proc/config_check() + return TRUE + +/datum/job/proc/map_check() + return TRUE + +/datum/job/proc/radio_help_message(mob/M) + to_chat(M, "Prefix your message with :h to speak on your department's radio. To see other prefixes, look closely at your headset.") + +/datum/outfit/job + name = "Standard Gear" + + var/jobtype = null + + uniform = /obj/item/clothing/under/color/grey + id = /obj/item/card/id + ears = /obj/item/radio/headset + belt = /obj/item/pda + back = /obj/item/storage/backpack + shoes = /obj/item/clothing/shoes/sneakers/black + box = /obj/item/storage/box/survival + + var/backpack = /obj/item/storage/backpack + var/satchel = /obj/item/storage/backpack/satchel + var/duffelbag = /obj/item/storage/backpack/duffelbag + + var/pda_slot = SLOT_BELT + +/datum/outfit/job/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE) + switch(H.backbag) + if(GBACKPACK) + back = /obj/item/storage/backpack //Grey backpack + if(GSATCHEL) + back = /obj/item/storage/backpack/satchel //Grey satchel + if(GDUFFELBAG) + back = /obj/item/storage/backpack/duffelbag //Grey Duffel bag + if(LSATCHEL) + back = /obj/item/storage/backpack/satchel/leather //Leather Satchel + if(DSATCHEL) + back = satchel //Department satchel + if(DDUFFELBAG) + back = duffelbag //Department duffel bag + else + back = backpack //Department backpack + + //converts the uniform string into the path we'll wear, whether it's the skirt or regular variant + var/holder + if(H.jumpsuit_style == PREF_SKIRT) + holder = "[uniform]/skirt" + if(!text2path(holder)) + holder = "[uniform]" + else + holder = "[uniform]" + uniform = text2path(holder) + +/datum/outfit/job/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) + if(visualsOnly) + return + + var/datum/job/J = SSjob.GetJobType(jobtype) + if(!J) + J = SSjob.GetJob(H.job) + + if(H.nameless && J.dresscodecompliant) + if(J.title in GLOB.command_positions) + H.real_name = J.title + else + H.real_name = "[J.title] #[rand(10000, 99999)]" + + var/obj/item/card/id/C = H.wear_id + if(istype(C)) + C.access = J.get_access() + shuffle_inplace(C.access) // Shuffle access list to make NTNet passkeys less predictable + C.registered_name = H.real_name + C.assignment = J.title + C.update_label() + H.sec_hud_set_ID() + + var/obj/item/pda/PDA = H.get_item_by_slot(pda_slot) + if(istype(PDA)) + PDA.owner = H.real_name + PDA.ownjob = J.title + PDA.update_label() + +/datum/outfit/job/get_chameleon_disguise_info() + var/list/types = ..() + types -= /obj/item/storage/backpack //otherwise this will override the actual backpacks + types += backpack + types += satchel + types += duffelbag + return types + +//Warden and regular officers add this result to their get_access() +/datum/job/proc/check_config_for_sec_maint() + if(CONFIG_GET(flag/security_has_maint_access)) + return list(ACCESS_MAINT_TUNNELS) + return list() diff --git a/code/modules/jobs/job_types/silicon.dm b/code/modules/jobs/job_types/ai.dm similarity index 71% rename from code/modules/jobs/job_types/silicon.dm rename to code/modules/jobs/job_types/ai.dm index ab963eb8f3..4bcfab5836 100644 --- a/code/modules/jobs/job_types/silicon.dm +++ b/code/modules/jobs/job_types/ai.dm @@ -1,90 +1,69 @@ -/* -AI -*/ -/datum/job/ai - title = "AI" - flag = AI_JF - department_flag = ENGSEC - faction = "Station" - total_positions = 1 - spawn_positions = 1 - selection_color = "#ccffcc" - supervisors = "your laws" - req_admin_notify = TRUE - minimal_player_age = 30 - exp_requirements = 180 - exp_type = EXP_TYPE_CREW - exp_type_department = EXP_TYPE_SILICON - var/do_special_check = TRUE - -/datum/job/ai/equip(mob/living/carbon/human/H, visualsOnly, announce, latejoin, outfit_override) - . = H.AIize(latejoin) - -/datum/job/ai/after_spawn(mob/H, mob/M, latejoin) - . = ..() - if(latejoin) - var/obj/structure/AIcore/latejoin_inactive/lateJoinCore - for(var/obj/structure/AIcore/latejoin_inactive/P in GLOB.latejoin_ai_cores) - if(P.is_available()) - lateJoinCore = P - GLOB.latejoin_ai_cores -= P - break - if(lateJoinCore) - lateJoinCore.available = FALSE - H.forceMove(lateJoinCore.loc) - qdel(lateJoinCore) - var/mob/living/silicon/ai/AI = H - AI.apply_pref_name("ai", M.client) //If this runtimes oh well jobcode is fucked. - AI.set_core_display_icon(null, M.client) - - //we may have been created after our borg - if(SSticker.current_state == GAME_STATE_SETTING_UP) - for(var/mob/living/silicon/robot/R in GLOB.silicon_mobs) - if(!R.connected_ai) - R.TryConnectToAI() - - if(latejoin) - announce(AI) - -/datum/job/ai/override_latejoin_spawn() - return TRUE - -/datum/job/ai/special_check_latejoin(client/C) - if(!do_special_check) - return TRUE - for(var/i in GLOB.latejoin_ai_cores) - var/obj/structure/AIcore/latejoin_inactive/LAI = i - if(istype(LAI)) - if(LAI.is_available()) - return TRUE - return FALSE - -/datum/job/ai/announce(mob/living/silicon/ai/AI) - . = ..() - SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/minor_announce, "[AI] has been downloaded to an empty bluespace-networked AI core at [AREACOORD(AI)].")) - -/datum/job/ai/config_check() - return CONFIG_GET(flag/allow_ai) - -/* -Cyborg -*/ -/datum/job/cyborg - title = "Cyborg" - flag = CYBORG - department_flag = ENGSEC - faction = "Station" - total_positions = 0 - spawn_positions = 1 - supervisors = "your laws and the AI" //Nodrak - selection_color = "#ddffdd" - minimal_player_age = 21 - exp_requirements = 120 - exp_type = EXP_TYPE_CREW - -/datum/job/cyborg/equip(mob/living/carbon/human/H, visualsOnly = FALSE, announce = TRUE, latejoin = FALSE, outfit_override = null) - return H.Robotize(FALSE, latejoin) - -/datum/job/cyborg/after_spawn(mob/living/silicon/robot/R, mob/M) - R.updatename(M.client) - R.gender = NEUTER +/datum/job/ai + title = "AI" + flag = AI_JF +// auto_deadmin_role_flags = DEADMIN_POSITION_SILICON + department_flag = ENGSEC + faction = "Station" + total_positions = 1 + spawn_positions = 1 + selection_color = "#ccffcc" + supervisors = "your laws" + req_admin_notify = TRUE + minimal_player_age = 30 + exp_requirements = 180 + exp_type = EXP_TYPE_CREW + exp_type_department = EXP_TYPE_SILICON + display_order = JOB_DISPLAY_ORDER_AI + var/do_special_check = TRUE + +/datum/job/ai/equip(mob/living/carbon/human/H, visualsOnly, announce, latejoin, datum/outfit/outfit_override, client/preference_source = null) + if(visualsOnly) + CRASH("dynamic preview is unsupported") + . = H.AIize(latejoin,preference_source) + +/datum/job/ai/after_spawn(mob/H, mob/M, latejoin) + . = ..() + if(latejoin) + var/obj/structure/AIcore/latejoin_inactive/lateJoinCore + for(var/obj/structure/AIcore/latejoin_inactive/P in GLOB.latejoin_ai_cores) + if(P.is_available()) + lateJoinCore = P + GLOB.latejoin_ai_cores -= P + break + if(lateJoinCore) + lateJoinCore.available = FALSE + H.forceMove(lateJoinCore.loc) + qdel(lateJoinCore) + var/mob/living/silicon/ai/AI = H + AI.apply_pref_name("ai", M.client) //If this runtimes oh well jobcode is fucked. + AI.set_core_display_icon(null, M.client) + + //we may have been created after our borg + if(SSticker.current_state == GAME_STATE_SETTING_UP) + for(var/mob/living/silicon/robot/R in GLOB.silicon_mobs) + if(!R.connected_ai) + R.TryConnectToAI() + + if(latejoin) + announce(AI) + +/datum/job/ai/override_latejoin_spawn() + return TRUE + +/datum/job/ai/special_check_latejoin(client/C) + if(!do_special_check) + return TRUE + for(var/i in GLOB.latejoin_ai_cores) + var/obj/structure/AIcore/latejoin_inactive/LAI = i + if(istype(LAI)) + if(LAI.is_available()) + return TRUE + return FALSE + +/datum/job/ai/announce(mob/living/silicon/ai/AI) + . = ..() + SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/minor_announce, "[AI] has been downloaded to an empty bluespace-networked AI core at [AREACOORD(AI)].")) + +/datum/job/ai/config_check() + return CONFIG_GET(flag/allow_ai) + diff --git a/code/modules/jobs/job_types/assistant.dm b/code/modules/jobs/job_types/assistant.dm index ce6eea97b0..c04560f849 100644 --- a/code/modules/jobs/job_types/assistant.dm +++ b/code/modules/jobs/job_types/assistant.dm @@ -14,7 +14,7 @@ Assistant minimal_access = list() //See /datum/job/assistant/get_access() outfit = /datum/outfit/job/assistant antag_rep = 7 - + display_order = JOB_DISPLAY_ORDER_ASSISTANT /datum/job/assistant/get_access() if(CONFIG_GET(flag/assistants_have_maint_access) || !CONFIG_GET(flag/jobs_have_minimal_access)) //Config has assistant maint access set diff --git a/code/modules/jobs/job_types/atmospheric_technician.dm b/code/modules/jobs/job_types/atmospheric_technician.dm new file mode 100644 index 0000000000..93775beca9 --- /dev/null +++ b/code/modules/jobs/job_types/atmospheric_technician.dm @@ -0,0 +1,44 @@ +/datum/job/atmos + title = "Atmospheric Technician" + flag = ATMOSTECH + department_head = list("Chief Engineer") + department_flag = ENGSEC + faction = "Station" + total_positions = 3 + spawn_positions = 2 + supervisors = "the chief engineer" + selection_color = "#ff9b3d" + exp_requirements = 60 + exp_type = EXP_TYPE_CREW + + outfit = /datum/outfit/job/atmos + + access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS, + ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_ATMOSPHERICS, ACCESS_MINERAL_STOREROOM) + minimal_access = list(ACCESS_ATMOSPHERICS, ACCESS_MAINT_TUNNELS, ACCESS_CONSTRUCTION, ACCESS_MINERAL_STOREROOM) + display_order = JOB_DISPLAY_ORDER_ATMOSPHERIC_TECHNICIAN + +/datum/outfit/job/atmos + name = "Atmospheric Technician" + jobtype = /datum/job/atmos + + belt = /obj/item/storage/belt/utility/atmostech + l_pocket = /obj/item/pda/atmos + ears = /obj/item/radio/headset/headset_eng + uniform = /obj/item/clothing/under/rank/atmospheric_technician + r_pocket = /obj/item/analyzer + + backpack = /obj/item/storage/backpack/industrial + satchel = /obj/item/storage/backpack/satchel/eng + duffelbag = /obj/item/storage/backpack/duffelbag/engineering + box = /obj/item/storage/box/engineer + pda_slot = SLOT_L_STORE + backpack_contents = list(/obj/item/modular_computer/tablet/preset/advanced=1) + +/datum/outfit/job/atmos/rig + name = "Atmospheric Technician (Hardsuit)" + + mask = /obj/item/clothing/mask/gas + suit = /obj/item/clothing/suit/space/hardsuit/engine/atmos + suit_store = /obj/item/tank/internals/oxygen + internals_slot = SLOT_S_STORE diff --git a/code/modules/jobs/job_types/bartender.dm b/code/modules/jobs/job_types/bartender.dm new file mode 100644 index 0000000000..0ace449757 --- /dev/null +++ b/code/modules/jobs/job_types/bartender.dm @@ -0,0 +1,30 @@ +/datum/job/bartender + title = "Bartender" + flag = BARTENDER + department_head = list("Head of Personnel") + department_flag = CIVILIAN + faction = "Station" + total_positions = 1 + spawn_positions = 1 + supervisors = "the head of personnel" + selection_color = "#bbe291" + exp_type_department = EXP_TYPE_SERVICE // This is so the jobs menu can work properly + + outfit = /datum/outfit/job/bartender + + access = list(ACCESS_HYDROPONICS, ACCESS_BAR, ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM) + minimal_access = list(ACCESS_BAR, ACCESS_MINERAL_STOREROOM) + display_order = JOB_DISPLAY_ORDER_BARTENDER + +/datum/outfit/job/bartender + name = "Bartender" + jobtype = /datum/job/bartender + + glasses = /obj/item/clothing/glasses/sunglasses/reagent + belt = /obj/item/pda/bar + ears = /obj/item/radio/headset/headset_srv + uniform = /obj/item/clothing/under/rank/bartender + suit = /obj/item/clothing/suit/armor/vest + backpack_contents = list(/obj/item/storage/box/beanbag=1,/obj/item/book/granter/action/drink_fling=1) + shoes = /obj/item/clothing/shoes/laceup + diff --git a/code/modules/jobs/job_types/botanist.dm b/code/modules/jobs/job_types/botanist.dm new file mode 100644 index 0000000000..e6338d9b0a --- /dev/null +++ b/code/modules/jobs/job_types/botanist.dm @@ -0,0 +1,32 @@ +/datum/job/hydro + title = "Botanist" + flag = BOTANIST + department_head = list("Head of Personnel") + department_flag = CIVILIAN + faction = "Station" + total_positions = 3 + spawn_positions = 2 + supervisors = "the head of personnel" + selection_color = "#bbe291" + + outfit = /datum/outfit/job/botanist + + access = list(ACCESS_HYDROPONICS, ACCESS_BAR, ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM) + minimal_access = list(ACCESS_HYDROPONICS, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM) + display_order = JOB_DISPLAY_ORDER_BOTANIST + +/datum/outfit/job/botanist + name = "Botanist" + jobtype = /datum/job/hydro + + belt = /obj/item/pda/botanist + ears = /obj/item/radio/headset/headset_srv + uniform = /obj/item/clothing/under/rank/hydroponics + suit = /obj/item/clothing/suit/apron + gloves =/obj/item/clothing/gloves/botanic_leather + suit_store = /obj/item/plant_analyzer + + backpack = /obj/item/storage/backpack/botany + satchel = /obj/item/storage/backpack/satchel/hyd + + diff --git a/code/modules/jobs/job_types/captain.dm b/code/modules/jobs/job_types/captain.dm old mode 100755 new mode 100644 index 80c78220e6..fea8557b40 --- a/code/modules/jobs/job_types/captain.dm +++ b/code/modules/jobs/job_types/captain.dm @@ -1,111 +1,66 @@ -/* -Captain -*/ -/datum/job/captain - title = "Captain" - flag = CAPTAIN - department_head = list("CentCom") - department_flag = ENGSEC - faction = "Station" - total_positions = 1 - spawn_positions = 1 - supervisors = "Nanotrasen officials and Space law" - selection_color = "#ccccff" - req_admin_notify = 1 - minimal_player_age = 14 - exp_requirements = 180 - exp_type = EXP_TYPE_CREW - - outfit = /datum/outfit/job/captain - - access = list() //See get_access() - minimal_access = list() //See get_access() - -/datum/job/captain/get_access() - return get_all_accesses() - -/datum/job/captain/announce(mob/living/carbon/human/H) - ..() - SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/minor_announce, "Captain [H.nameless ? "" : "[H.real_name] "]on deck!")) - -/datum/outfit/job/captain - name = "Captain" - jobtype = /datum/job/captain - - id = /obj/item/card/id/gold - belt = /obj/item/pda/captain - glasses = /obj/item/clothing/glasses/sunglasses - ears = /obj/item/radio/headset/heads/captain/alt - gloves = /obj/item/clothing/gloves/color/captain - uniform = /obj/item/clothing/under/rank/captain - suit = /obj/item/clothing/suit/armor/vest/capcarapace - shoes = /obj/item/clothing/shoes/sneakers/brown - head = /obj/item/clothing/head/caphat - backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1, /obj/item/station_charter=1) - - backpack = /obj/item/storage/backpack/captain - satchel = /obj/item/storage/backpack/satchel/cap - duffelbag = /obj/item/storage/backpack/duffelbag/captain - - implants = list(/obj/item/implant/mindshield) - accessory = /obj/item/clothing/accessory/medal/gold/captain - - chameleon_extras = list(/obj/item/gun/energy/e_gun, /obj/item/stamp/captain) - -/datum/outfit/job/captain/hardsuit - name = "Captain (Hardsuit)" - - mask = /obj/item/clothing/mask/gas/sechailer - suit = /obj/item/clothing/suit/space/hardsuit/captain - suit_store = /obj/item/tank/internals/oxygen - -/* -Head of Personnel -*/ -/datum/job/hop - title = "Head of Personnel" - flag = HOP - department_head = list("Captain") - department_flag = CIVILIAN - head_announce = list(RADIO_CHANNEL_SERVICE) - faction = "Station" - total_positions = 1 - spawn_positions = 1 - supervisors = "the captain" - selection_color = "#ddddff" - req_admin_notify = 1 - minimal_player_age = 10 - exp_requirements = 180 - exp_type = EXP_TYPE_CREW - exp_type_department = EXP_TYPE_SUPPLY - - outfit = /datum/outfit/job/hop - - access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_COURT, ACCESS_WEAPONS, - ACCESS_MEDICAL, ACCESS_ENGINE, ACCESS_CHANGE_IDS, ACCESS_AI_UPLOAD, ACCESS_EVA, ACCESS_HEADS, - ACCESS_ALL_PERSONAL_LOCKERS, ACCESS_MAINT_TUNNELS, ACCESS_BAR, ACCESS_JANITOR, ACCESS_CONSTRUCTION, ACCESS_MORGUE, - ACCESS_CREMATORIUM, ACCESS_KITCHEN, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_MAILSORTING, ACCESS_QM, ACCESS_HYDROPONICS, ACCESS_LAWYER, - ACCESS_THEATRE, ACCESS_CHAPEL_OFFICE, ACCESS_LIBRARY, ACCESS_RESEARCH, ACCESS_MINING, ACCESS_VAULT, ACCESS_MINING_STATION, - ACCESS_HOP, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MINERAL_STOREROOM) - minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_COURT, ACCESS_WEAPONS, - ACCESS_MEDICAL, ACCESS_ENGINE, ACCESS_CHANGE_IDS, ACCESS_AI_UPLOAD, ACCESS_EVA, ACCESS_HEADS, - ACCESS_ALL_PERSONAL_LOCKERS, ACCESS_MAINT_TUNNELS, ACCESS_BAR, ACCESS_JANITOR, ACCESS_CONSTRUCTION, ACCESS_MORGUE, - ACCESS_CREMATORIUM, ACCESS_KITCHEN, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_MAILSORTING, ACCESS_QM, ACCESS_HYDROPONICS, ACCESS_LAWYER, - ACCESS_THEATRE, ACCESS_CHAPEL_OFFICE, ACCESS_LIBRARY, ACCESS_RESEARCH, ACCESS_MINING, ACCESS_VAULT, ACCESS_MINING_STATION, - ACCESS_HOP, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MINERAL_STOREROOM) - - -/datum/outfit/job/hop - name = "Head of Personnel" - jobtype = /datum/job/hop - - id = /obj/item/card/id/silver - belt = /obj/item/pda/heads/hop - ears = /obj/item/radio/headset/heads/hop - uniform = /obj/item/clothing/under/rank/head_of_personnel - shoes = /obj/item/clothing/shoes/sneakers/brown - head = /obj/item/clothing/head/hopcap - backpack_contents = list(/obj/item/storage/box/ids=1,\ - /obj/item/melee/classic_baton/telescopic=1, /obj/item/modular_computer/tablet/preset/advanced = 1) - - chameleon_extras = list(/obj/item/gun/energy/e_gun, /obj/item/stamp/hop) +/datum/job/captain + title = "Captain" + flag = CAPTAIN +// auto_deadmin_role_flags = DEADMIN_POSITION_HEAD|DEADMIN_POSITION_SECURITY //:eyes: + department_head = list("CentCom") + department_flag = ENGSEC + faction = "Station" + total_positions = 1 + spawn_positions = 1 + supervisors = "Nanotrasen officials and Space law" + selection_color = "#aac1ee" + req_admin_notify = 1 + minimal_player_age = 14 + exp_requirements = 180 + exp_type = EXP_TYPE_CREW + exp_type_department = EXP_TYPE_COMMAND + + outfit = /datum/outfit/job/captain + + access = list() //See get_access() + minimal_access = list() //See get_access() + + mind_traits = list(TRAIT_CAPTAIN_METABOLISM) +// mind_traits = list(TRAIT_DISK_VERIFIER) + + display_order = JOB_DISPLAY_ORDER_CAPTAIN + + blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/insanity) + +/datum/job/captain/get_access() + return get_all_accesses() + +/datum/job/captain/announce(mob/living/carbon/human/H) + ..() + SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/minor_announce, "Captain [H.nameless ? "" : "[H.real_name] "]on deck!")) + +/datum/outfit/job/captain + name = "Captain" + jobtype = /datum/job/captain + + id = /obj/item/card/id/gold + belt = /obj/item/pda/captain + glasses = /obj/item/clothing/glasses/sunglasses + ears = /obj/item/radio/headset/heads/captain/alt + gloves = /obj/item/clothing/gloves/color/captain + uniform = /obj/item/clothing/under/rank/captain + suit = /obj/item/clothing/suit/armor/vest/capcarapace + shoes = /obj/item/clothing/shoes/sneakers/brown + head = /obj/item/clothing/head/caphat + backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1, /obj/item/station_charter=1) + + backpack = /obj/item/storage/backpack/captain + satchel = /obj/item/storage/backpack/satchel/cap + duffelbag = /obj/item/storage/backpack/duffelbag/captain + + implants = list(/obj/item/implant/mindshield) + accessory = /obj/item/clothing/accessory/medal/gold/captain + + chameleon_extras = list(/obj/item/gun/energy/e_gun, /obj/item/stamp/captain) + +/datum/outfit/job/captain/hardsuit + name = "Captain (Hardsuit)" + + mask = /obj/item/clothing/mask/gas/sechailer + suit = /obj/item/clothing/suit/space/hardsuit/captain + suit_store = /obj/item/tank/internals/oxygen \ No newline at end of file diff --git a/code/modules/jobs/job_types/cargo_service.dm b/code/modules/jobs/job_types/cargo_service.dm deleted file mode 100644 index 175b7e8263..0000000000 --- a/code/modules/jobs/job_types/cargo_service.dm +++ /dev/null @@ -1,291 +0,0 @@ -/* -Quartermaster -*/ -/datum/job/qm - title = "Quartermaster" - flag = QUARTERMASTER - department_head = list("Head of Personnel") - department_flag = CIVILIAN - head_announce = list(RADIO_CHANNEL_SUPPLY) - faction = "Station" - total_positions = 1 - spawn_positions = 1 - supervisors = "the head of personnel" - selection_color = "#d7b088" - - outfit = /datum/outfit/job/quartermaster - - access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_QM, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM, ACCESS_VAULT) - minimal_access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_QM, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM, ACCESS_VAULT) - -/datum/outfit/job/quartermaster - name = "Quartermaster" - jobtype = /datum/job/qm - - belt = /obj/item/pda/quartermaster - ears = /obj/item/radio/headset/headset_cargo - uniform = /obj/item/clothing/under/rank/cargo - shoes = /obj/item/clothing/shoes/sneakers/brown - glasses = /obj/item/clothing/glasses/sunglasses - l_hand = /obj/item/clipboard - - chameleon_extras = /obj/item/stamp/qm - -/* -Cargo Technician -*/ -/datum/job/cargo_tech - title = "Cargo Technician" - flag = CARGOTECH - department_head = list("Head of Personnel") - department_flag = CIVILIAN - faction = "Station" - total_positions = 3 - spawn_positions = 2 - supervisors = "the quartermaster and the head of personnel" - selection_color = "#dcba97" - - outfit = /datum/outfit/job/cargo_tech - - access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_QM, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM) - minimal_access = list(ACCESS_MAINT_TUNNELS, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_MAILSORTING, ACCESS_MINERAL_STOREROOM) - -/datum/outfit/job/cargo_tech - name = "Cargo Technician" - jobtype = /datum/job/cargo_tech - - belt = /obj/item/pda/cargo - ears = /obj/item/radio/headset/headset_cargo - uniform = /obj/item/clothing/under/rank/cargotech - l_hand = /obj/item/export_scanner - -/* -Shaft Miner -*/ -/datum/job/mining - title = "Shaft Miner" - flag = MINER - department_head = list("Head of Personnel") - department_flag = CIVILIAN - faction = "Station" - total_positions = 3 - spawn_positions = 3 - supervisors = "the quartermaster and the head of personnel" - selection_color = "#dcba97" - custom_spawn_text = "Remember, you are a miner, not a hunter. Hunting monsters is not a requirement of your job, the only requirement of your job is to provide materials for the station. Don't be afraid to run away if you're inexperienced with fighting the mining area's locals." - - outfit = /datum/outfit/job/miner - - access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_QM, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM) - minimal_access = list(ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MAILSORTING, ACCESS_MINERAL_STOREROOM) - -/datum/outfit/job/miner - name = "Shaft Miner (Lavaland)" - jobtype = /datum/job/mining - - belt = /obj/item/pda/shaftminer - ears = /obj/item/radio/headset/headset_cargo/mining - shoes = /obj/item/clothing/shoes/workboots/mining - gloves = /obj/item/clothing/gloves/color/black - uniform = /obj/item/clothing/under/rank/miner/lavaland - l_pocket = /obj/item/reagent_containers/hypospray/medipen/survival - r_pocket = /obj/item/storage/bag/ore //causes issues if spawned in backpack - backpack_contents = list( - /obj/item/flashlight/seclite=1,\ - /obj/item/kitchen/knife/combat/survival=1,\ - /obj/item/mining_voucher=1,\ - /obj/item/suit_voucher=1,\ - /obj/item/stack/marker_beacon/ten=1) - - backpack = /obj/item/storage/backpack/explorer - satchel = /obj/item/storage/backpack/satchel/explorer - duffelbag = /obj/item/storage/backpack/duffelbag - box = /obj/item/storage/box/survival_mining - - chameleon_extras = /obj/item/gun/energy/kinetic_accelerator - -/datum/outfit/job/miner/asteroid - name = "Shaft Miner (Asteroid)" - uniform = /obj/item/clothing/under/rank/miner - shoes = /obj/item/clothing/shoes/workboots - -/datum/outfit/job/miner/equipped - name = "Shaft Miner (Lavaland + Equipment)" - suit = /obj/item/clothing/suit/hooded/explorer/standard - mask = /obj/item/clothing/mask/gas/explorer - glasses = /obj/item/clothing/glasses/meson - suit_store = /obj/item/tank/internals/oxygen - internals_slot = SLOT_S_STORE - backpack_contents = list( - /obj/item/flashlight/seclite=1,\ - /obj/item/kitchen/knife/combat/survival=1, - /obj/item/mining_voucher=1, - /obj/item/t_scanner/adv_mining_scanner/lesser=1, - /obj/item/gun/energy/kinetic_accelerator=1,\ - /obj/item/stack/marker_beacon/ten=1) - -/datum/outfit/job/miner/equipped/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) - ..() - if(visualsOnly) - return - if(istype(H.wear_suit, /obj/item/clothing/suit/hooded)) - var/obj/item/clothing/suit/hooded/S = H.wear_suit - S.ToggleHood() - -/datum/outfit/job/miner/equipped/hardsuit - name = "Shaft Miner (Equipment + Hardsuit)" - suit = /obj/item/clothing/suit/space/hardsuit/mining - mask = /obj/item/clothing/mask/breath - - -/* -Bartender -*/ -/datum/job/bartender - title = "Bartender" - flag = BARTENDER - department_head = list("Head of Personnel") - department_flag = CIVILIAN - faction = "Station" - total_positions = 1 - spawn_positions = 1 - supervisors = "the head of personnel" - selection_color = "#bbe291" - - outfit = /datum/outfit/job/bartender - - access = list(ACCESS_HYDROPONICS, ACCESS_BAR, ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM) - minimal_access = list(ACCESS_BAR, ACCESS_MINERAL_STOREROOM) - - -/datum/outfit/job/bartender - name = "Bartender" - jobtype = /datum/job/bartender - - glasses = /obj/item/clothing/glasses/sunglasses/reagent - belt = /obj/item/pda/bar - ears = /obj/item/radio/headset/headset_srv - uniform = /obj/item/clothing/under/rank/bartender - suit = /obj/item/clothing/suit/armor/vest - backpack_contents = list(/obj/item/storage/box/beanbag=1,/obj/item/book/granter/action/drink_fling=1) - shoes = /obj/item/clothing/shoes/laceup - -/* -Cook -*/ -/datum/job/cook - title = "Cook" - flag = COOK - department_head = list("Head of Personnel") - department_flag = CIVILIAN - faction = "Station" - total_positions = 2 - spawn_positions = 1 - supervisors = "the head of personnel" - selection_color = "#bbe291" - var/cooks = 0 //Counts cooks amount - - outfit = /datum/outfit/job/cook - - access = list(ACCESS_HYDROPONICS, ACCESS_BAR, ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM) - minimal_access = list(ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM) - -/datum/outfit/job/cook - name = "Cook" - jobtype = /datum/job/cook - - belt = /obj/item/pda/cook - ears = /obj/item/radio/headset/headset_srv - uniform = /obj/item/clothing/under/rank/chef - suit = /obj/item/clothing/suit/toggle/chef - head = /obj/item/clothing/head/chefhat - mask = /obj/item/clothing/mask/fakemoustache/italian - backpack_contents = list(/obj/item/sharpener = 1) - -/datum/outfit/job/cook/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE) - ..() - var/datum/job/cook/J = SSjob.GetJobType(jobtype) - if(J) // Fix for runtime caused by invalid job being passed - if(J.cooks>0)//Cooks - suit = /obj/item/clothing/suit/apron/chef - head = /obj/item/clothing/head/soft/mime - if(!visualsOnly) - J.cooks++ - -/datum/outfit/job/cook/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) - ..() - if(visualsOnly) - return - var/list/possible_boxes = subtypesof(/obj/item/storage/box/ingredients) - var/chosen_box = pick(possible_boxes) - var/obj/item/storage/box/I = new chosen_box(src) - H.equip_to_slot_or_del(I,SLOT_IN_BACKPACK) - var/datum/martial_art/cqc/under_siege/justacook = new - justacook.teach(H) - -/* -Botanist -*/ -/datum/job/hydro - title = "Botanist" - flag = BOTANIST - department_head = list("Head of Personnel") - department_flag = CIVILIAN - faction = "Station" - total_positions = 3 - spawn_positions = 2 - supervisors = "the head of personnel" - selection_color = "#bbe291" - - outfit = /datum/outfit/job/botanist - - access = list(ACCESS_HYDROPONICS, ACCESS_BAR, ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM) - minimal_access = list(ACCESS_HYDROPONICS, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM) - // Removed tox and chem access because STOP PISSING OFF THE CHEMIST GUYS - // Removed medical access because WHAT THE FUCK YOU AREN'T A DOCTOR YOU GROW WHEAT - // Given Morgue access because they have a viable means of cloning. - - -/datum/outfit/job/botanist - name = "Botanist" - jobtype = /datum/job/hydro - - belt = /obj/item/pda/botanist - ears = /obj/item/radio/headset/headset_srv - uniform = /obj/item/clothing/under/rank/hydroponics - suit = /obj/item/clothing/suit/apron - gloves =/obj/item/clothing/gloves/botanic_leather - suit_store = /obj/item/plant_analyzer - - backpack = /obj/item/storage/backpack/botany - satchel = /obj/item/storage/backpack/satchel/hyd - - -/* -Janitor -*/ -/datum/job/janitor - title = "Janitor" - flag = JANITOR - department_head = list("Head of Personnel") - department_flag = CIVILIAN - faction = "Station" - total_positions = 2 - spawn_positions = 1 - supervisors = "the head of personnel" - selection_color = "#bbe291" - var/global/janitors = 0 - - outfit = /datum/outfit/job/janitor - - access = list(ACCESS_JANITOR, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM) - minimal_access = list(ACCESS_JANITOR, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM) - -/datum/outfit/job/janitor - name = "Janitor" - jobtype = /datum/job/janitor - - belt = /obj/item/pda/janitor - ears = /obj/item/radio/headset/headset_srv - uniform = /obj/item/clothing/under/rank/janitor - backpack_contents = list(/obj/item/modular_computer/tablet/preset/advanced=1) diff --git a/code/modules/jobs/job_types/cargo_technician.dm b/code/modules/jobs/job_types/cargo_technician.dm new file mode 100644 index 0000000000..3ceb29bae2 --- /dev/null +++ b/code/modules/jobs/job_types/cargo_technician.dm @@ -0,0 +1,27 @@ +/datum/job/cargo_tech + title = "Cargo Technician" + flag = CARGOTECH + department_head = list("Quartermaster") + department_flag = CIVILIAN + faction = "Station" + total_positions = 3 + spawn_positions = 2 + supervisors = "the quartermaster" + selection_color = "#ca8f55" + + outfit = /datum/outfit/job/cargo_tech + + access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_QM, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM) + minimal_access = list(ACCESS_MAINT_TUNNELS, ACCESS_CARGO, ACCESS_MAILSORTING, ACCESS_MINERAL_STOREROOM) + + display_order = JOB_DISPLAY_ORDER_CARGO_TECHNICIAN + +/datum/outfit/job/cargo_tech + name = "Cargo Technician" + jobtype = /datum/job/cargo_tech + + belt = /obj/item/pda/cargo + ears = /obj/item/radio/headset/headset_cargo + uniform = /obj/item/clothing/under/rank/cargotech + l_hand = /obj/item/export_scanner + diff --git a/code/modules/jobs/job_types/civilian_chaplain.dm b/code/modules/jobs/job_types/chaplain.dm similarity index 65% rename from code/modules/jobs/job_types/civilian_chaplain.dm rename to code/modules/jobs/job_types/chaplain.dm index 2d190cfe60..97b1edc8c2 100644 --- a/code/modules/jobs/job_types/civilian_chaplain.dm +++ b/code/modules/jobs/job_types/chaplain.dm @@ -1,95 +1,121 @@ -//Due to how large this one is it gets its own file -/* -Chaplain -*/ -/datum/job/chaplain - title = "Chaplain" - flag = CHAPLAIN - department_head = list("Head of Personnel") - department_flag = CIVILIAN - faction = "Station" - total_positions = 1 - spawn_positions = 1 - supervisors = "the head of personnel" - selection_color = "#dddddd" - - outfit = /datum/outfit/job/chaplain - - access = list(ACCESS_MORGUE, ACCESS_CHAPEL_OFFICE, ACCESS_CREMATORIUM, ACCESS_THEATRE) - minimal_access = list(ACCESS_MORGUE, ACCESS_CHAPEL_OFFICE, ACCESS_CREMATORIUM, ACCESS_THEATRE) - -/datum/job/chaplain/after_spawn(mob/living/H, mob/M) - . = ..() - if(H.mind) - H.mind.isholy = TRUE - - var/obj/item/storage/book/bible/booze/B = new - - if(GLOB.religion) - B.deity_name = GLOB.deity - B.name = GLOB.bible_name - B.icon_state = GLOB.bible_icon_state - B.item_state = GLOB.bible_item_state - to_chat(H, "There is already an established religion onboard the station. You are an acolyte of [GLOB.deity]. Defer to the Chaplain.") - H.equip_to_slot_or_del(B, SLOT_IN_BACKPACK) - var/nrt = GLOB.holy_weapon_type || /obj/item/nullrod - var/obj/item/nullrod/N = new nrt(H) - H.put_in_hands(N) - return - - var/new_religion = "Christianity" - if(M.client && M.client.prefs.custom_names["religion"]) - new_religion = M.client.prefs.custom_names["religion"] - - var/new_deity = "Space Jesus" - if(M.client && M.client.prefs.custom_names["deity"]) - new_deity = M.client.prefs.custom_names["deity"] - - B.deity_name = new_deity - - - switch(lowertext(new_religion)) - if("christianity") - B.name = pick("The Holy Bible","The Dead Sea Scrolls") - if("satanism") - B.name = "The Unholy Bible" - if("cthulhu") - B.name = "The Necronomicon" - if("islam") - B.name = "Quran" - if("scientology") - B.name = pick("The Biography of L. Ron Hubbard","Dianetics") - if("chaos") - B.name = "The Book of Lorgar" - if("imperium") - B.name = "Uplifting Primer" - if("toolboxia") - B.name = "Toolbox Manifesto" - if("homosexuality") - B.name = "Guys Gone Wild" - if("lol", "wtf", "gay", "penis", "ass", "poo", "badmin", "shitmin", "deadmin", "cock", "cocks", "meme", "memes") - B.name = pick("Woodys Got Wood: The Aftermath", "War of the Cocks", "Sweet Bro and Hella Jef: Expanded Edition") - H.adjustBrainLoss(100) // starts off retarded as fuck - if("science") - B.name = pick("Principle of Relativity", "Quantum Enigma: Physics Encounters Consciousness", "Programming the Universe", "Quantum Physics and Theology", "String Theory for Dummies", "How To: Build Your Own Warp Drive", "The Mysteries of Bluespace", "Playing God: Collector's Edition") - else - B.name = "The Holy Book of [new_religion]" - - GLOB.religion = new_religion - GLOB.bible_name = B.name - GLOB.deity = B.deity_name - - H.equip_to_slot_or_del(B, SLOT_IN_BACKPACK) - - SSblackbox.record_feedback("text", "religion_name", 1, "[new_religion]", 1) - SSblackbox.record_feedback("text", "religion_deity", 1, "[new_deity]", 1) - -/datum/outfit/job/chaplain - name = "Chaplain" - jobtype = /datum/job/chaplain - - belt = /obj/item/pda/chaplain - uniform = /obj/item/clothing/under/rank/chaplain - backpack_contents = list(/obj/item/camera/spooky = 1) - backpack = /obj/item/storage/backpack/cultpack - satchel = /obj/item/storage/backpack/cultpack +/datum/job/chaplain + title = "Chaplain" + flag = CHAPLAIN + department_head = list("Head of Personnel") + department_flag = CIVILIAN + faction = "Station" + total_positions = 1 + spawn_positions = 1 + supervisors = "the head of personnel" + selection_color = "#dddddd" + + outfit = /datum/outfit/job/chaplain + + access = list(ACCESS_MORGUE, ACCESS_CHAPEL_OFFICE, ACCESS_CREMATORIUM, ACCESS_THEATRE) + minimal_access = list(ACCESS_MORGUE, ACCESS_CHAPEL_OFFICE, ACCESS_CREMATORIUM, ACCESS_THEATRE) + + display_order = JOB_DISPLAY_ORDER_CHAPLAIN + + +/datum/job/chaplain/after_spawn(mob/living/H, mob/M) + . = ..() + if(H.mind) + H.mind.isholy = TRUE + + var/obj/item/storage/book/bible/booze/B = new + + if(GLOB.religion) + B.deity_name = GLOB.deity + B.name = GLOB.bible_name + B.icon_state = GLOB.bible_icon_state + B.item_state = GLOB.bible_item_state + to_chat(H, "There is already an established religion onboard the station. You are an acolyte of [GLOB.deity]. Defer to the Chaplain.") + H.equip_to_slot_or_del(B, SLOT_IN_BACKPACK) + var/nrt = GLOB.holy_weapon_type || /obj/item/nullrod + var/obj/item/nullrod/N = new nrt(H) + H.put_in_hands(N) + return + + var/new_religion = DEFAULT_RELIGION + if(M.client && M.client.prefs.custom_names["religion"]) + new_religion = M.client.prefs.custom_names["religion"] + + var/new_deity = DEFAULT_DEITY + if(M.client && M.client.prefs.custom_names["deity"]) + new_deity = M.client.prefs.custom_names["deity"] + + B.deity_name = new_deity + + + switch(lowertext(new_religion)) + if("christianity") // DEFAULT_RELIGION + B.name = pick("The Holy Bible","The Dead Sea Scrolls") + if("buddhism") + B.name = "The Sutras" + if("clownism","honkmother","honk","honkism","comedy") + B.name = pick("The Holy Joke Book", "Just a Prank", "Hymns to the Honkmother") + if("chaos") + B.name = "The Book of Lorgar" + if("cthulhu") + B.name = "The Necronomicon" + if("hinduism") + B.name = "The Vedas" + if("homosexuality") + B.name = pick("Guys Gone Wild","Coming Out of The Closet") + if("imperium") + B.name = "Uplifting Primer" + if("islam") + B.name = "Quran" + if("judaism") + B.name = "The Torah" + if("lampism") + B.name = "Fluorescent Incandescence" + if("lol", "wtf", "gay", "penis", "ass", "poo", "badmin", "shitmin", "deadmin", "cock", "cocks", "meme", "memes") + B.name = pick("Woodys Got Wood: The Aftermath", "War of the Cocks", "Sweet Bro and Hella Jef: Expanded Edition","F.A.T.A.L. Rulebook") + H.adjustOrganLoss(ORGAN_SLOT_BRAIN, 100) // starts off retarded as fuck + if("monkeyism","apism","gorillism","primatism") + B.name = pick("Going Bananas", "Bananas Out For Harambe") + if("mormonism") + B.name = "The Book of Mormon" + if("pastafarianism") + B.name = "The Gospel of the Flying Spaghetti Monster" + if("rastafarianism","rasta") + B.name = "The Holy Piby" + if("satanism") + B.name = "The Unholy Bible" + if("science") + B.name = pick("Principle of Relativity", "Quantum Enigma: Physics Encounters Consciousness", "Programming the Universe", "Quantum Physics and Theology", "String Theory for Dummies", "How To: Build Your Own Warp Drive", "The Mysteries of Bluespace", "Playing God: Collector's Edition") + if("scientology") + B.name = pick("The Biography of L. Ron Hubbard","Dianetics") + if("servicianism", "partying") + B.name = "The Tenets of Servicia" + B.deity_name = pick("Servicia", "Space Bacchus", "Space Dionysus") + B.desc = "Happy, Full, Clean. Live it and give it." + if("subgenius") + B.name = "Book of the SubGenius" + if("toolboxia","greytide") + B.name = pick("Toolbox Manifesto","iGlove Assistants") + if("weeaboo","kawaii") + B.name = pick("Fanfiction Compendium","Japanese for Dummies","The Manganomicon","Establishing Your O.T.P") + else + B.name = "The Holy Book of [new_religion]" + + GLOB.religion = new_religion + GLOB.bible_name = B.name + GLOB.deity = B.deity_name + + H.equip_to_slot_or_del(B, SLOT_IN_BACKPACK) + + SSblackbox.record_feedback("text", "religion_name", 1, "[new_religion]", 1) + SSblackbox.record_feedback("text", "religion_deity", 1, "[new_deity]", 1) + +/datum/outfit/job/chaplain + name = "Chaplain" + jobtype = /datum/job/chaplain + + belt = /obj/item/pda/chaplain + ears = /obj/item/radio/headset/headset_srv + uniform = /obj/item/clothing/under/rank/chaplain + backpack_contents = list(/obj/item/camera/spooky = 1) + backpack = /obj/item/storage/backpack/cultpack + satchel = /obj/item/storage/backpack/cultpack diff --git a/code/modules/jobs/job_types/chemist.dm b/code/modules/jobs/job_types/chemist.dm new file mode 100644 index 0000000000..a915d261ed --- /dev/null +++ b/code/modules/jobs/job_types/chemist.dm @@ -0,0 +1,36 @@ +/datum/job/chemist + title = "Chemist" + flag = CHEMIST + department_head = list("Chief Medical Officer") + department_flag = MEDSCI + faction = "Station" + total_positions = 2 + spawn_positions = 2 + supervisors = "the chief medical officer" + selection_color = "#74b5e0" + exp_type = EXP_TYPE_CREW + exp_requirements = 60 + + outfit = /datum/outfit/job/chemist + + access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_MINERAL_STOREROOM) + minimal_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_CHEMISTRY, ACCESS_MINERAL_STOREROOM) + + display_order = JOB_DISPLAY_ORDER_CHEMIST + +/datum/outfit/job/chemist + name = "Chemist" + jobtype = /datum/job/chemist + + glasses = /obj/item/clothing/glasses/science + belt = /obj/item/pda/chemist + ears = /obj/item/radio/headset/headset_med + uniform = /obj/item/clothing/under/rank/chemist + shoes = /obj/item/clothing/shoes/sneakers/white + suit = /obj/item/clothing/suit/toggle/labcoat/chemist + backpack = /obj/item/storage/backpack/chemistry + satchel = /obj/item/storage/backpack/satchel/chem + duffelbag = /obj/item/storage/backpack/duffelbag/med + + chameleon_extras = /obj/item/gun/syringe + diff --git a/code/modules/jobs/job_types/chief_engineer.dm b/code/modules/jobs/job_types/chief_engineer.dm new file mode 100644 index 0000000000..da3f281267 --- /dev/null +++ b/code/modules/jobs/job_types/chief_engineer.dm @@ -0,0 +1,64 @@ +/datum/job/chief_engineer + title = "Chief Engineer" + flag = CHIEF +// auto_deadmin_role_flags = DEADMIN_POSITION_HEAD + department_head = list("Captain") + department_flag = ENGSEC + head_announce = list(RADIO_CHANNEL_ENGINEERING) + faction = "Station" + total_positions = 1 + spawn_positions = 1 + supervisors = "the captain" + selection_color = "#ee7400" + req_admin_notify = 1 + minimal_player_age = 7 + exp_requirements = 180 + exp_type = EXP_TYPE_CREW + exp_type_department = EXP_TYPE_ENGINEERING + + outfit = /datum/outfit/job/ce + + access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS, + ACCESS_EXTERNAL_AIRLOCKS, ACCESS_ATMOSPHERICS, ACCESS_EVA, + ACCESS_HEADS, ACCESS_CONSTRUCTION, ACCESS_SEC_DOORS, ACCESS_MINISAT, + ACCESS_CE, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM) + minimal_access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS, + ACCESS_EXTERNAL_AIRLOCKS, ACCESS_ATMOSPHERICS, ACCESS_EVA, + ACCESS_HEADS, ACCESS_CONSTRUCTION, ACCESS_SEC_DOORS, ACCESS_MINISAT, + ACCESS_CE, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM) + + display_order = JOB_DISPLAY_ORDER_CHIEF_ENGINEER + blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/paraplegic, /datum/quirk/insanity) + +/datum/outfit/job/ce + name = "Chief Engineer" + jobtype = /datum/job/chief_engineer + + id = /obj/item/card/id/silver + belt = /obj/item/storage/belt/utility/chief/full + l_pocket = /obj/item/pda/heads/ce + ears = /obj/item/radio/headset/heads/ce + uniform = /obj/item/clothing/under/rank/chief_engineer + shoes = /obj/item/clothing/shoes/sneakers/brown + head = /obj/item/clothing/head/hardhat/white + gloves = /obj/item/clothing/gloves/color/black/ce + backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1, /obj/item/modular_computer/tablet/preset/advanced=1) + + backpack = /obj/item/storage/backpack/industrial + satchel = /obj/item/storage/backpack/satchel/eng + duffelbag = /obj/item/storage/backpack/duffelbag/engineering + box = /obj/item/storage/box/engineer + pda_slot = SLOT_L_STORE + chameleon_extras = /obj/item/stamp/ce + +/datum/outfit/job/ce/rig + name = "Chief Engineer (Hardsuit)" + + mask = /obj/item/clothing/mask/breath + suit = /obj/item/clothing/suit/space/hardsuit/engine/elite + shoes = /obj/item/clothing/shoes/magboots/advance + suit_store = /obj/item/tank/internals/oxygen + glasses = /obj/item/clothing/glasses/meson/engine + gloves = /obj/item/clothing/gloves/color/yellow + head = null + internals_slot = SLOT_S_STORE diff --git a/code/modules/jobs/job_types/chief_medical_officer.dm b/code/modules/jobs/job_types/chief_medical_officer.dm new file mode 100644 index 0000000000..4c7249f048 --- /dev/null +++ b/code/modules/jobs/job_types/chief_medical_officer.dm @@ -0,0 +1,59 @@ +/datum/job/cmo + title = "Chief Medical Officer" + flag = CMO_JF + department_head = list("Captain") + department_flag = MEDSCI +// auto_deadmin_role_flags = DEADMIN_POSITION_HEAD + head_announce = list(RADIO_CHANNEL_MEDICAL) + faction = "Station" + total_positions = 1 + spawn_positions = 1 + supervisors = "the captain" + selection_color = "#509ed1" + req_admin_notify = 1 + minimal_player_age = 7 + exp_requirements = 180 + exp_type = EXP_TYPE_CREW + exp_type_department = EXP_TYPE_MEDICAL + + outfit = /datum/outfit/job/cmo + + access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_HEADS, ACCESS_MINERAL_STOREROOM, + ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_CMO, ACCESS_SURGERY, ACCESS_RC_ANNOUNCE, + ACCESS_KEYCARD_AUTH, ACCESS_SEC_DOORS, ACCESS_MAINT_TUNNELS) + minimal_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_HEADS, ACCESS_MINERAL_STOREROOM, + ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_CMO, ACCESS_SURGERY, ACCESS_RC_ANNOUNCE, + ACCESS_KEYCARD_AUTH, ACCESS_SEC_DOORS, ACCESS_MAINT_TUNNELS) + + display_order = JOB_DISPLAY_ORDER_CHIEF_MEDICAL_OFFICER + blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/insanity) + +/datum/outfit/job/cmo + name = "Chief Medical Officer" + jobtype = /datum/job/cmo + + id = /obj/item/card/id/silver + belt = /obj/item/pda/heads/cmo + l_pocket = /obj/item/pinpointer/crew + ears = /obj/item/radio/headset/heads/cmo + uniform = /obj/item/clothing/under/rank/chief_medical_officer + shoes = /obj/item/clothing/shoes/sneakers/brown + suit = /obj/item/clothing/suit/toggle/labcoat/cmo + l_hand = /obj/item/storage/firstaid/regular + suit_store = /obj/item/flashlight/pen + backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1) + + backpack = /obj/item/storage/backpack/medic + satchel = /obj/item/storage/backpack/satchel/med + duffelbag = /obj/item/storage/backpack/duffelbag/med + + chameleon_extras = list(/obj/item/gun/syringe, /obj/item/stamp/cmo) + +/datum/outfit/job/cmo/hardsuit + name = "Chief Medical Officer (Hardsuit)" + + mask = /obj/item/clothing/mask/breath + suit = /obj/item/clothing/suit/space/hardsuit/medical + suit_store = /obj/item/tank/internals/oxygen + r_pocket = /obj/item/flashlight/pen + diff --git a/code/modules/jobs/job_types/civilian.dm b/code/modules/jobs/job_types/civilian.dm deleted file mode 100644 index f21ff69e8e..0000000000 --- a/code/modules/jobs/job_types/civilian.dm +++ /dev/null @@ -1,206 +0,0 @@ -/* -Clown -*/ -/datum/job/clown - title = "Clown" - flag = CLOWN - department_head = list("Head of Personnel") - department_flag = CIVILIAN - faction = "Station" - total_positions = 1 - spawn_positions = 1 - supervisors = "the head of personnel" - selection_color = "#dddddd" - - outfit = /datum/outfit/job/clown - - access = list(ACCESS_THEATRE) - minimal_access = list(ACCESS_THEATRE) - -/datum/job/clown/after_spawn(mob/living/carbon/human/H, mob/M) - . = ..() - H.apply_pref_name("clown", M.client) - -/datum/outfit/job/clown - name = "Clown" - jobtype = /datum/job/clown - - belt = /obj/item/pda/clown - uniform = /obj/item/clothing/under/rank/clown - shoes = /obj/item/clothing/shoes/clown_shoes - mask = /obj/item/clothing/mask/gas/clown_hat - l_pocket = /obj/item/bikehorn - backpack_contents = list( - /obj/item/stamp/clown = 1, - /obj/item/reagent_containers/spray/waterflower = 1, - /obj/item/reagent_containers/food/snacks/grown/banana = 1, - /obj/item/instrument/bikehorn = 1, - ) - - implants = list(/obj/item/implant/sad_trombone) - - backpack = /obj/item/storage/backpack/clown - satchel = /obj/item/storage/backpack/clown - duffelbag = /obj/item/storage/backpack/duffelbag/clown //strangely has a duffel - - box = /obj/item/storage/box/hug/survival - - chameleon_extras = /obj/item/stamp/clown - - -/datum/outfit/job/clown/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE) - ..() - if(visualsOnly) - return - - H.fully_replace_character_name(H.real_name, pick(GLOB.clown_names)) - -/datum/outfit/job/clown/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) - ..() - if(visualsOnly) - return - - H.dna.add_mutation(CLOWNMUT) - H.dna.add_mutation(SMILE) - -/* -Mime -*/ -/datum/job/mime - title = "Mime" - flag = MIME - department_head = list("Head of Personnel") - department_flag = CIVILIAN - faction = "Station" - total_positions = 1 - spawn_positions = 1 - supervisors = "the head of personnel" - selection_color = "#dddddd" - - outfit = /datum/outfit/job/mime - - access = list(ACCESS_THEATRE) - minimal_access = list(ACCESS_THEATRE) - -/datum/job/mime/after_spawn(mob/living/carbon/human/H, mob/M) - H.apply_pref_name("mime", M.client) - -/datum/outfit/job/mime - name = "Mime" - jobtype = /datum/job/mime - - belt = /obj/item/pda/mime - uniform = /obj/item/clothing/under/rank/mime - mask = /obj/item/clothing/mask/gas/mime - gloves = /obj/item/clothing/gloves/color/white - head = /obj/item/clothing/head/frenchberet - suit = /obj/item/clothing/suit/suspenders - backpack_contents = list(/obj/item/reagent_containers/food/drinks/bottle/bottleofnothing=1) - - accessory = /obj/item/clothing/accessory/pocketprotector/cosmetology - backpack = /obj/item/storage/backpack/mime - satchel = /obj/item/storage/backpack/mime - - -/datum/outfit/job/mime/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) - ..() - - if(visualsOnly) - return - - if(H.mind) - H.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/mime_wall(null)) - H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/mime/speak(null)) - H.mind.miming = 1 - -/* -Curator -*/ -/datum/job/curator - title = "Curator" - flag = CURATOR - department_head = list("Head of Personnel") - department_flag = CIVILIAN - faction = "Station" - total_positions = 1 - spawn_positions = 1 - supervisors = "the head of personnel" - selection_color = "#dddddd" - - outfit = /datum/outfit/job/curator - - access = list(ACCESS_LIBRARY) - minimal_access = list(ACCESS_LIBRARY, ACCESS_CONSTRUCTION,ACCESS_MINING_STATION) - -/datum/outfit/job/curator - name = "Curator" - jobtype = /datum/job/curator - - belt = /obj/item/pda/curator - uniform = /obj/item/clothing/under/rank/curator - l_hand = /obj/item/storage/bag/books - r_pocket = /obj/item/key/displaycase - l_pocket = /obj/item/laser_pointer - accessory = /obj/item/clothing/accessory/pocketprotector/full - backpack_contents = list( - /obj/item/melee/curator_whip = 1, - /obj/item/soapstone = 1, - /obj/item/barcodescanner = 1 - ) - - -/datum/outfit/job/curator/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) - ..() - - if(visualsOnly) - return - - H.grant_all_languages(omnitongue=TRUE) -/* -Lawyer -*/ -/datum/job/lawyer - title = "Lawyer" - flag = LAWYER - department_head = list("Head of Personnel") - department_flag = CIVILIAN - faction = "Station" - total_positions = 2 - spawn_positions = 2 - supervisors = "the head of personnel" - selection_color = "#dddddd" - var/lawyers = 0 //Counts lawyer amount - - outfit = /datum/outfit/job/lawyer - - access = list(ACCESS_LAWYER, ACCESS_COURT, ACCESS_SEC_DOORS) - minimal_access = list(ACCESS_LAWYER, ACCESS_COURT, ACCESS_SEC_DOORS) - - mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM) - -/datum/outfit/job/lawyer - name = "Lawyer" - jobtype = /datum/job/lawyer - - belt = /obj/item/pda/lawyer - ears = /obj/item/radio/headset/headset_sec - uniform = /obj/item/clothing/under/lawyer/bluesuit - suit = /obj/item/clothing/suit/toggle/lawyer - shoes = /obj/item/clothing/shoes/laceup - l_hand = /obj/item/storage/briefcase/lawyer - l_pocket = /obj/item/laser_pointer - r_pocket = /obj/item/clothing/accessory/lawyers_badge - - chameleon_extras = /obj/item/stamp/law - - -/datum/outfit/job/lawyer/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE) - ..() - if(visualsOnly) - return - - var/datum/job/lawyer/J = SSjob.GetJobType(jobtype) - J.lawyers++ - if(J.lawyers>1) - uniform = /obj/item/clothing/under/lawyer/purpsuit - suit = /obj/item/clothing/suit/toggle/lawyer/purple diff --git a/code/modules/jobs/job_types/clown.dm b/code/modules/jobs/job_types/clown.dm new file mode 100644 index 0000000000..d8b88ae871 --- /dev/null +++ b/code/modules/jobs/job_types/clown.dm @@ -0,0 +1,58 @@ +/datum/job/clown + title = "Clown" + flag = CLOWN + department_head = list("Head of Personnel") + department_flag = CIVILIAN + faction = "Station" + total_positions = 1 + spawn_positions = 1 + supervisors = "the head of personnel" + selection_color = "#dddddd" + + outfit = /datum/outfit/job/clown + + access = list(ACCESS_THEATRE) + minimal_access = list(ACCESS_THEATRE) + + display_order = JOB_DISPLAY_ORDER_CLOWN + + +/datum/job/clown/after_spawn(mob/living/carbon/human/H, mob/M) + . = ..() + H.apply_pref_name("clown", M.client) + +/datum/outfit/job/clown + name = "Clown" + jobtype = /datum/job/clown + + belt = /obj/item/pda/clown + ears = /obj/item/radio/headset/headset_srv + uniform = /obj/item/clothing/under/rank/clown + shoes = /obj/item/clothing/shoes/clown_shoes + mask = /obj/item/clothing/mask/gas/clown_hat + l_pocket = /obj/item/bikehorn + backpack_contents = list( + /obj/item/stamp/clown = 1, + /obj/item/reagent_containers/spray/waterflower = 1, + /obj/item/reagent_containers/food/snacks/grown/banana = 1, + /obj/item/instrument/bikehorn = 1, + ) + + implants = list(/obj/item/implant/sad_trombone) + + backpack = /obj/item/storage/backpack/clown + satchel = /obj/item/storage/backpack/clown + duffelbag = /obj/item/storage/backpack/duffelbag/clown //strangely has a duffel + + box = /obj/item/storage/box/hug/survival + + chameleon_extras = /obj/item/stamp/clown + +/datum/outfit/job/clown/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) + ..() + if(visualsOnly) + return + + H.fully_replace_character_name(H.real_name, pick(GLOB.clown_names)) //rename the mob AFTER they're equipped so their ID gets updated properly. + H.dna.add_mutation(CLOWNMUT) + H.dna.add_mutation(SMILE) diff --git a/code/modules/jobs/job_types/cook.dm b/code/modules/jobs/job_types/cook.dm new file mode 100644 index 0000000000..c213d4dffc --- /dev/null +++ b/code/modules/jobs/job_types/cook.dm @@ -0,0 +1,52 @@ +/datum/job/cook + title = "Cook" + flag = COOK + department_head = list("Head of Personnel") + department_flag = CIVILIAN + faction = "Station" + total_positions = 2 + spawn_positions = 1 + supervisors = "the head of personnel" + selection_color = "#bbe291" + var/cooks = 0 //Counts cooks amount + + outfit = /datum/outfit/job/cook + + access = list(ACCESS_HYDROPONICS, ACCESS_BAR, ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM) + minimal_access = list(ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM) + + display_order = JOB_DISPLAY_ORDER_COOK + +/datum/outfit/job/cook + name = "Cook" + jobtype = /datum/job/cook + + belt = /obj/item/pda/cook + ears = /obj/item/radio/headset/headset_srv + uniform = /obj/item/clothing/under/rank/chef + suit = /obj/item/clothing/suit/toggle/chef + head = /obj/item/clothing/head/chefhat + mask = /obj/item/clothing/mask/fakemoustache/italian + backpack_contents = list(/obj/item/sharpener = 1) + +/datum/outfit/job/cook/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE) + ..() + var/datum/job/cook/J = SSjob.GetJobType(jobtype) + if(J) // Fix for runtime caused by invalid job being passed + if(J.cooks>0)//Cooks + suit = /obj/item/clothing/suit/apron/chef + head = /obj/item/clothing/head/soft/mime + if(!visualsOnly) + J.cooks++ + +/datum/outfit/job/cook/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) + ..() + if(visualsOnly) + return + var/list/possible_boxes = subtypesof(/obj/item/storage/box/ingredients) + var/chosen_box = pick(possible_boxes) + var/obj/item/storage/box/I = new chosen_box(src) + H.equip_to_slot_or_del(I,SLOT_IN_BACKPACK) + var/datum/martial_art/cqc/under_siege/justacook = new + justacook.teach(H) + diff --git a/code/modules/jobs/job_types/curator.dm b/code/modules/jobs/job_types/curator.dm new file mode 100644 index 0000000000..35fa8483d5 --- /dev/null +++ b/code/modules/jobs/job_types/curator.dm @@ -0,0 +1,43 @@ +/datum/job/curator + title = "Curator" + flag = CURATOR + department_head = list("Head of Personnel") + department_flag = CIVILIAN + faction = "Station" + total_positions = 1 + spawn_positions = 1 + supervisors = "the head of personnel" + selection_color = "#dddddd" + + outfit = /datum/outfit/job/curator + + access = list(ACCESS_LIBRARY) + minimal_access = list(ACCESS_LIBRARY, ACCESS_CONSTRUCTION, ACCESS_MINING_STATION) + + display_order = JOB_DISPLAY_ORDER_CURATOR + +/datum/outfit/job/curator + name = "Curator" + jobtype = /datum/job/curator + + shoes = /obj/item/clothing/shoes/laceup + belt = /obj/item/pda/curator + ears = /obj/item/radio/headset/headset_srv + uniform = /obj/item/clothing/under/rank/curator + l_hand = /obj/item/storage/bag/books + r_pocket = /obj/item/key/displaycase + l_pocket = /obj/item/laser_pointer + accessory = /obj/item/clothing/accessory/pocketprotector/full + backpack_contents = list( + /obj/item/melee/curator_whip = 1, + /obj/item/soapstone = 1, + /obj/item/barcodescanner = 1 + ) + +/datum/outfit/job/curator/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) + ..() + + if(visualsOnly) + return + + H.grant_all_languages(omnitongue=TRUE) diff --git a/code/modules/jobs/job_types/cyborg.dm b/code/modules/jobs/job_types/cyborg.dm new file mode 100644 index 0000000000..29c4c3d833 --- /dev/null +++ b/code/modules/jobs/job_types/cyborg.dm @@ -0,0 +1,27 @@ +/datum/job/cyborg + title = "Cyborg" + flag = CYBORG +// auto_deadmin_role_flags = DEADMIN_POSITION_SILICON + department_flag = ENGSEC + faction = "Station" + total_positions = 0 + spawn_positions = 1 + supervisors = "your laws and the AI" //Nodrak + selection_color = "#ddffdd" + minimal_player_age = 21 + exp_requirements = 120 + exp_type = EXP_TYPE_CREW + + display_order = JOB_DISPLAY_ORDER_CYBORG + +/datum/job/cyborg/equip(mob/living/carbon/human/H, visualsOnly = FALSE, announce = TRUE, latejoin = FALSE, datum/outfit/outfit_override = null, client/preference_source = null) + if(visualsOnly) + CRASH("dynamic preview is unsupported") + return H.Robotize(FALSE, latejoin) + +/datum/job/cyborg/after_spawn(mob/living/silicon/robot/R, mob/M) + R.updatename(M.client) + R.gender = NEUTER + +/datum/job/cyborg/radio_help_message(mob/M) + to_chat(M, "Prefix your message with :b to speak with other cyborgs and AI.") diff --git a/code/modules/jobs/job_types/detective.dm b/code/modules/jobs/job_types/detective.dm new file mode 100644 index 0000000000..27a54fbd1f --- /dev/null +++ b/code/modules/jobs/job_types/detective.dm @@ -0,0 +1,57 @@ +/datum/job/detective + title = "Detective" + flag = DETECTIVE +// auto_deadmin_role_flags = DEADMIN_POSITION_SECURITY + department_head = list("Head of Security") + department_flag = ENGSEC + faction = "Station" + total_positions = 1 + spawn_positions = 1 + supervisors = "the head of security" + selection_color = "#c02f2f" + minimal_player_age = 7 + exp_requirements = 300 + exp_type = EXP_TYPE_CREW + + outfit = /datum/outfit/job/detective + + access = list(ACCESS_SEC_DOORS, ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_COURT, ACCESS_BRIG, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM) + minimal_access = list(ACCESS_SEC_DOORS, ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_COURT, ACCESS_BRIG, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM) + + mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM) + + display_order = JOB_DISPLAY_ORDER_DETECTIVE + blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/nonviolent, /datum/quirk/paraplegic) + +/datum/outfit/job/detective + name = "Detective" + jobtype = /datum/job/detective + + belt = /obj/item/pda/detective + ears = /obj/item/radio/headset/headset_sec/alt + uniform = /obj/item/clothing/under/rank/det + neck = /obj/item/clothing/neck/tie/black + shoes = /obj/item/clothing/shoes/sneakers/brown + suit = /obj/item/clothing/suit/det_suit + gloves = /obj/item/clothing/gloves/color/black + head = /obj/item/clothing/head/fedora/det_hat + l_pocket = /obj/item/toy/crayon/white + r_pocket = /obj/item/lighter + backpack_contents = list(/obj/item/storage/box/evidence=1,\ + /obj/item/detective_scanner=1,\ + /obj/item/melee/classic_baton=1) + mask = /obj/item/clothing/mask/cigarette + + implants = list(/obj/item/implant/mindshield) + + chameleon_extras = list(/obj/item/gun/ballistic/revolver/detective, /obj/item/clothing/glasses/sunglasses) + +/datum/outfit/job/detective/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) + ..() + var/obj/item/clothing/mask/cigarette/cig = H.wear_mask + if(istype(cig)) //Some species specfic changes can mess this up (plasmamen) + cig.light("") + + if(visualsOnly) + return + diff --git a/code/modules/jobs/job_types/engineering.dm b/code/modules/jobs/job_types/engineering.dm deleted file mode 100644 index b2bc8bf241..0000000000 --- a/code/modules/jobs/job_types/engineering.dm +++ /dev/null @@ -1,167 +0,0 @@ -/* -Chief Engineer -*/ -/datum/job/chief_engineer - title = "Chief Engineer" - flag = CHIEF - department_head = list("Captain") - department_flag = ENGSEC - head_announce = list(RADIO_CHANNEL_ENGINEERING) - faction = "Station" - total_positions = 1 - spawn_positions = 1 - supervisors = "the captain" - selection_color = "#ffeeaa" - req_admin_notify = 1 - minimal_player_age = 7 - exp_requirements = 180 - exp_type = EXP_TYPE_CREW - exp_type_department = EXP_TYPE_ENGINEERING - - outfit = /datum/outfit/job/ce - - access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS, - ACCESS_EXTERNAL_AIRLOCKS, ACCESS_ATMOSPHERICS, ACCESS_EMERGENCY_STORAGE, ACCESS_EVA, - ACCESS_HEADS, ACCESS_CONSTRUCTION, ACCESS_SEC_DOORS, ACCESS_MINISAT, - ACCESS_CE, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM) - minimal_access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS, - ACCESS_EXTERNAL_AIRLOCKS, ACCESS_ATMOSPHERICS, ACCESS_EMERGENCY_STORAGE, ACCESS_EVA, - ACCESS_HEADS, ACCESS_CONSTRUCTION, ACCESS_SEC_DOORS, ACCESS_MINISAT, - ACCESS_CE, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM) - -/datum/outfit/job/ce - name = "Chief Engineer" - jobtype = /datum/job/chief_engineer - - id = /obj/item/card/id/silver - belt = /obj/item/storage/belt/utility/chief/full - l_pocket = /obj/item/pda/heads/ce - ears = /obj/item/radio/headset/heads/ce - uniform = /obj/item/clothing/under/rank/chief_engineer - shoes = /obj/item/clothing/shoes/sneakers/brown - head = /obj/item/clothing/head/hardhat/white - gloves = /obj/item/clothing/gloves/color/black/ce - backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1, /obj/item/modular_computer/tablet/preset/advanced=1) - - backpack = /obj/item/storage/backpack/industrial - satchel = /obj/item/storage/backpack/satchel/eng - duffelbag = /obj/item/storage/backpack/duffelbag/engineering - box = /obj/item/storage/box/engineer - pda_slot = SLOT_L_STORE - chameleon_extras = /obj/item/stamp/ce - -/datum/outfit/job/ce/rig - name = "Chief Engineer (Hardsuit)" - - mask = /obj/item/clothing/mask/breath - suit = /obj/item/clothing/suit/space/hardsuit/engine/elite - shoes = /obj/item/clothing/shoes/magboots/advance - suit_store = /obj/item/tank/internals/oxygen - glasses = /obj/item/clothing/glasses/meson/engine - gloves = /obj/item/clothing/gloves/color/yellow - head = null - internals_slot = SLOT_S_STORE - - -/* -Station Engineer -*/ -/datum/job/engineer - title = "Station Engineer" - flag = ENGINEER - department_head = list("Chief Engineer") - department_flag = ENGSEC - faction = "Station" - total_positions = 5 - spawn_positions = 5 - supervisors = "the chief engineer" - selection_color = "#fff5cc" - exp_requirements = 60 - exp_type = EXP_TYPE_CREW - - outfit = /datum/outfit/job/engineer - - access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS, - ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_ATMOSPHERICS, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM) - minimal_access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS, - ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM) - -/datum/outfit/job/engineer - name = "Station Engineer" - jobtype = /datum/job/engineer - - belt = /obj/item/storage/belt/utility/full/engi - l_pocket = /obj/item/pda/engineering - ears = /obj/item/radio/headset/headset_eng - uniform = /obj/item/clothing/under/rank/engineer - shoes = /obj/item/clothing/shoes/workboots - head = /obj/item/clothing/head/hardhat - r_pocket = /obj/item/t_scanner - - backpack = /obj/item/storage/backpack/industrial - satchel = /obj/item/storage/backpack/satchel/eng - duffelbag = /obj/item/storage/backpack/duffelbag/engineering - box = /obj/item/storage/box/engineer - pda_slot = SLOT_L_STORE - backpack_contents = list(/obj/item/modular_computer/tablet/preset/advanced=1) - -/datum/outfit/job/engineer/gloved - name = "Station Engineer (Gloves)" - gloves = /obj/item/clothing/gloves/color/yellow - -/datum/outfit/job/engineer/gloved/rig - name = "Station Engineer (Hardsuit)" - - mask = /obj/item/clothing/mask/breath - suit = /obj/item/clothing/suit/space/hardsuit/engine - suit_store = /obj/item/tank/internals/oxygen - head = null - internals_slot = SLOT_S_STORE - - -/* -Atmospheric Technician -*/ -/datum/job/atmos - title = "Atmospheric Technician" - flag = ATMOSTECH - department_head = list("Chief Engineer") - department_flag = ENGSEC - faction = "Station" - total_positions = 3 - spawn_positions = 2 - supervisors = "the chief engineer" - selection_color = "#fff5cc" - exp_requirements = 60 - exp_type = EXP_TYPE_CREW - - outfit = /datum/outfit/job/atmos - - access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS, - ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_ATMOSPHERICS, ACCESS_MINERAL_STOREROOM) - minimal_access = list(ACCESS_ATMOSPHERICS, ACCESS_MAINT_TUNNELS, ACCESS_EMERGENCY_STORAGE, ACCESS_CONSTRUCTION, ACCESS_MINERAL_STOREROOM) - -/datum/outfit/job/atmos - name = "Atmospheric Technician" - jobtype = /datum/job/atmos - - belt = /obj/item/storage/belt/utility/atmostech - l_pocket = /obj/item/pda/atmos - ears = /obj/item/radio/headset/headset_eng - uniform = /obj/item/clothing/under/rank/atmospheric_technician - r_pocket = /obj/item/analyzer - - backpack = /obj/item/storage/backpack/industrial - satchel = /obj/item/storage/backpack/satchel/eng - duffelbag = /obj/item/storage/backpack/duffelbag/engineering - box = /obj/item/storage/box/engineer - pda_slot = SLOT_L_STORE - backpack_contents = list(/obj/item/modular_computer/tablet/preset/advanced=1) - -/datum/outfit/job/atmos/rig - name = "Atmospheric Technician (Hardsuit)" - - mask = /obj/item/clothing/mask/gas - suit = /obj/item/clothing/suit/space/hardsuit/engine/atmos - suit_store = /obj/item/tank/internals/oxygen - internals_slot = SLOT_S_STORE diff --git a/code/modules/jobs/job_types/geneticist.dm b/code/modules/jobs/job_types/geneticist.dm new file mode 100644 index 0000000000..d7f59ff883 --- /dev/null +++ b/code/modules/jobs/job_types/geneticist.dm @@ -0,0 +1,35 @@ +/datum/job/geneticist + title = "Geneticist" + flag = GENETICIST + department_head = list("Chief Medical Officer", "Research Director") + department_flag = MEDSCI + faction = "Station" + total_positions = 2 + spawn_positions = 2 + supervisors = "the chief medical officer and research director" + selection_color = "#74b5e0" + exp_type = EXP_TYPE_CREW + exp_requirements = 60 + + outfit = /datum/outfit/job/geneticist + + access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_CHEMISTRY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_RESEARCH, ACCESS_XENOBIOLOGY, ACCESS_ROBOTICS, ACCESS_MINERAL_STOREROOM, ACCESS_TECH_STORAGE) + minimal_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM) + + display_order = JOB_DISPLAY_ORDER_GENETICIST + +/datum/outfit/job/geneticist + name = "Geneticist" + jobtype = /datum/job/geneticist + + belt = /obj/item/pda/geneticist + ears = /obj/item/radio/headset/headset_medsci + uniform = /obj/item/clothing/under/rank/geneticist + shoes = /obj/item/clothing/shoes/sneakers/white + suit = /obj/item/clothing/suit/toggle/labcoat/genetics + suit_store = /obj/item/flashlight/pen + + backpack = /obj/item/storage/backpack/genetics + satchel = /obj/item/storage/backpack/satchel/gen + duffelbag = /obj/item/storage/backpack/duffelbag/med + diff --git a/code/modules/jobs/job_types/head_of_personnel.dm b/code/modules/jobs/job_types/head_of_personnel.dm new file mode 100644 index 0000000000..e320ce20b4 --- /dev/null +++ b/code/modules/jobs/job_types/head_of_personnel.dm @@ -0,0 +1,51 @@ +/datum/job/hop + title = "Head of Personnel" + flag = HOP +// auto_deadmin_role_flags = DEADMIN_POSITION_HEAD + department_head = list("Captain") + department_flag = CIVILIAN + head_announce = list(RADIO_CHANNEL_SERVICE) + faction = "Station" + total_positions = 1 + spawn_positions = 1 + supervisors = "the captain" + selection_color = "#3a8529" + req_admin_notify = 1 + minimal_player_age = 10 + exp_requirements = 180 + exp_type = EXP_TYPE_CREW + exp_type_department = EXP_TYPE_SERVICE + + outfit = /datum/outfit/job/hop + + access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_COURT, ACCESS_WEAPONS, + ACCESS_MEDICAL, ACCESS_ENGINE, ACCESS_CHANGE_IDS, ACCESS_AI_UPLOAD, ACCESS_EVA, ACCESS_HEADS, + ACCESS_ALL_PERSONAL_LOCKERS, ACCESS_MAINT_TUNNELS, ACCESS_BAR, ACCESS_JANITOR, ACCESS_CONSTRUCTION, ACCESS_MORGUE, + ACCESS_CREMATORIUM, ACCESS_KITCHEN, ACCESS_CARGO, ACCESS_MAILSORTING, ACCESS_QM, ACCESS_HYDROPONICS, ACCESS_LAWYER, + ACCESS_THEATRE, ACCESS_CHAPEL_OFFICE, ACCESS_LIBRARY, ACCESS_RESEARCH, ACCESS_MINING, ACCESS_VAULT, ACCESS_MINING_STATION, + ACCESS_HOP, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MINERAL_STOREROOM) + minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_COURT, ACCESS_WEAPONS, + ACCESS_MEDICAL, ACCESS_ENGINE, ACCESS_CHANGE_IDS, ACCESS_AI_UPLOAD, ACCESS_EVA, ACCESS_HEADS, + ACCESS_ALL_PERSONAL_LOCKERS, ACCESS_MAINT_TUNNELS, ACCESS_BAR, ACCESS_JANITOR, ACCESS_CONSTRUCTION, ACCESS_MORGUE, + ACCESS_CREMATORIUM, ACCESS_KITCHEN, ACCESS_CARGO, ACCESS_MAILSORTING, ACCESS_QM, ACCESS_HYDROPONICS, ACCESS_LAWYER, + ACCESS_THEATRE, ACCESS_CHAPEL_OFFICE, ACCESS_LIBRARY, ACCESS_RESEARCH, ACCESS_MINING, ACCESS_VAULT, ACCESS_MINING_STATION, + ACCESS_HOP, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MINERAL_STOREROOM) + + display_order = JOB_DISPLAY_ORDER_HEAD_OF_PERSONNEL + + blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/prosopagnosia, /datum/quirk/insanity) + +/datum/outfit/job/hop + name = "Head of Personnel" + jobtype = /datum/job/hop + + id = /obj/item/card/id/silver + belt = /obj/item/pda/heads/hop + ears = /obj/item/radio/headset/heads/hop + uniform = /obj/item/clothing/under/rank/head_of_personnel + shoes = /obj/item/clothing/shoes/sneakers/brown + head = /obj/item/clothing/head/hopcap + backpack_contents = list(/obj/item/storage/box/ids=1,\ + /obj/item/melee/classic_baton/telescopic=1, /obj/item/modular_computer/tablet/preset/advanced = 1) + + chameleon_extras = list(/obj/item/gun/energy/e_gun, /obj/item/stamp/hop) diff --git a/code/modules/jobs/job_types/head_of_security.dm b/code/modules/jobs/job_types/head_of_security.dm new file mode 100644 index 0000000000..33c8856d81 --- /dev/null +++ b/code/modules/jobs/job_types/head_of_security.dm @@ -0,0 +1,68 @@ +/datum/job/hos + title = "Head of Security" + flag = HOS +// auto_deadmin_role_flags = DEADMIN_POSITION_HEAD|DEADMIN_POSITION_SECURITY + department_head = list("Captain") + department_flag = ENGSEC + head_announce = list(RADIO_CHANNEL_SECURITY) + faction = "Station" + total_positions = 1 + spawn_positions = 1 + supervisors = "the captain" + selection_color = "#b90000" + req_admin_notify = 1 + minimal_player_age = 14 + exp_requirements = 300 + exp_type = EXP_TYPE_CREW + exp_type_department = EXP_TYPE_SECURITY + + outfit = /datum/outfit/job/hos + mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM) + + access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_WEAPONS, ACCESS_ENTER_GENPOP, ACCESS_LEAVE_GENPOP, + ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_ALL_PERSONAL_LOCKERS, + ACCESS_RESEARCH, ACCESS_ENGINE, ACCESS_MINING, ACCESS_MEDICAL, ACCESS_CONSTRUCTION, ACCESS_MAILSORTING, + ACCESS_HEADS, ACCESS_HOS, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM) + minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_WEAPONS, ACCESS_ENTER_GENPOP, ACCESS_LEAVE_GENPOP, + ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_ALL_PERSONAL_LOCKERS, + ACCESS_RESEARCH, ACCESS_ENGINE, ACCESS_MINING, ACCESS_MEDICAL, ACCESS_CONSTRUCTION, ACCESS_MAILSORTING, + ACCESS_HEADS, ACCESS_HOS, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM) + + display_order = JOB_DISPLAY_ORDER_HEAD_OF_SECURITY + blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/nonviolent, /datum/quirk/paraplegic, /datum/quirk/insanity) + +/datum/outfit/job/hos + name = "Head of Security" + jobtype = /datum/job/hos + + id = /obj/item/card/id/silver + belt = /obj/item/pda/heads/hos + ears = /obj/item/radio/headset/heads/hos/alt + uniform = /obj/item/clothing/under/rank/head_of_security + shoes = /obj/item/clothing/shoes/jackboots + suit = /obj/item/clothing/suit/armor/hos/trenchcoat + gloves = /obj/item/clothing/gloves/color/black/hos + head = /obj/item/clothing/head/HoS/beret + glasses = /obj/item/clothing/glasses/hud/security/sunglasses + suit_store = /obj/item/gun/energy/e_gun + r_pocket = /obj/item/assembly/flash/handheld + l_pocket = /obj/item/restraints/handcuffs + backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1) + + backpack = /obj/item/storage/backpack/security + satchel = /obj/item/storage/backpack/satchel/sec + duffelbag = /obj/item/storage/backpack/duffelbag/sec + box = /obj/item/storage/box/security + + implants = list(/obj/item/implant/mindshield) + + chameleon_extras = list(/obj/item/gun/energy/e_gun/hos, /obj/item/stamp/hos) + +/datum/outfit/job/hos/hardsuit + name = "Head of Security (Hardsuit)" + + mask = /obj/item/clothing/mask/gas/sechailer + suit = /obj/item/clothing/suit/space/hardsuit/security/hos + suit_store = /obj/item/tank/internals/oxygen + backpack_contents = list(/obj/item/melee/baton/loaded=1, /obj/item/gun/energy/e_gun=1) + diff --git a/code/modules/jobs/job_types/janitor.dm b/code/modules/jobs/job_types/janitor.dm new file mode 100644 index 0000000000..d0a06ca0e0 --- /dev/null +++ b/code/modules/jobs/job_types/janitor.dm @@ -0,0 +1,27 @@ +/datum/job/janitor + title = "Janitor" + flag = JANITOR + department_head = list("Head of Personnel") + department_flag = CIVILIAN + faction = "Station" + total_positions = 2 + spawn_positions = 1 + supervisors = "the head of personnel" + selection_color = "#bbe291" + var/global/janitors = 0 + + outfit = /datum/outfit/job/janitor + + access = list(ACCESS_JANITOR, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM) + minimal_access = list(ACCESS_JANITOR, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM) + + display_order = JOB_DISPLAY_ORDER_JANITOR + +/datum/outfit/job/janitor + name = "Janitor" + jobtype = /datum/job/janitor + + belt = /obj/item/pda/janitor + ears = /obj/item/radio/headset/headset_srv + uniform = /obj/item/clothing/under/rank/janitor + backpack_contents = list(/obj/item/modular_computer/tablet/preset/advanced=1) diff --git a/code/modules/jobs/job_types/lawyer.dm b/code/modules/jobs/job_types/lawyer.dm new file mode 100644 index 0000000000..0b8be52116 --- /dev/null +++ b/code/modules/jobs/job_types/lawyer.dm @@ -0,0 +1,47 @@ +/datum/job/lawyer + title = "Lawyer" + flag = LAWYER + department_head = list("Head of Personnel") + department_flag = CIVILIAN + faction = "Station" + total_positions = 2 + spawn_positions = 2 + supervisors = "the head of personnel" + selection_color = "#dddddd" + var/lawyers = 0 //Counts lawyer amount + + outfit = /datum/outfit/job/lawyer + + access = list(ACCESS_LAWYER, ACCESS_COURT, ACCESS_SEC_DOORS) + minimal_access = list(ACCESS_LAWYER, ACCESS_COURT, ACCESS_SEC_DOORS) + + mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM) + + display_order = JOB_DISPLAY_ORDER_LAWYER + +/datum/outfit/job/lawyer + name = "Lawyer" + jobtype = /datum/job/lawyer + + belt = /obj/item/pda/lawyer + ears = /obj/item/radio/headset/headset_sec + uniform = /obj/item/clothing/under/lawyer/bluesuit + suit = /obj/item/clothing/suit/toggle/lawyer + shoes = /obj/item/clothing/shoes/laceup + l_hand = /obj/item/storage/briefcase/lawyer + l_pocket = /obj/item/laser_pointer + r_pocket = /obj/item/clothing/accessory/lawyers_badge + + chameleon_extras = /obj/item/stamp/law + + +/datum/outfit/job/lawyer/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE) + ..() + if(visualsOnly) + return + + var/datum/job/lawyer/J = SSjob.GetJobType(jobtype) + J.lawyers++ + if(J.lawyers>1) + uniform = /obj/item/clothing/under/lawyer/purpsuit + suit = /obj/item/clothing/suit/toggle/lawyer/purple diff --git a/code/modules/jobs/job_types/medical.dm b/code/modules/jobs/job_types/medical.dm deleted file mode 100644 index 1a6d2aa2f6..0000000000 --- a/code/modules/jobs/job_types/medical.dm +++ /dev/null @@ -1,204 +0,0 @@ -/* -Chief Medical Officer -*/ -/datum/job/cmo - title = "Chief Medical Officer" - flag = CMO_JF - department_head = list("Captain") - department_flag = MEDSCI - head_announce = list(RADIO_CHANNEL_MEDICAL) - faction = "Station" - total_positions = 1 - spawn_positions = 1 - supervisors = "the captain" - selection_color = "#ffddf0" - req_admin_notify = 1 - minimal_player_age = 7 - exp_requirements = 180 - exp_type = EXP_TYPE_CREW - exp_type_department = EXP_TYPE_MEDICAL - - outfit = /datum/outfit/job/cmo - - access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_HEADS, ACCESS_MINERAL_STOREROOM, - ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_CMO, ACCESS_SURGERY, ACCESS_RC_ANNOUNCE, - ACCESS_KEYCARD_AUTH, ACCESS_SEC_DOORS, ACCESS_MAINT_TUNNELS) - minimal_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_HEADS, ACCESS_MINERAL_STOREROOM, - ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_CMO, ACCESS_SURGERY, ACCESS_RC_ANNOUNCE, - ACCESS_KEYCARD_AUTH, ACCESS_SEC_DOORS, ACCESS_MAINT_TUNNELS) - -/datum/outfit/job/cmo - name = "Chief Medical Officer" - jobtype = /datum/job/cmo - - id = /obj/item/card/id/silver - belt = /obj/item/pda/heads/cmo - l_pocket = /obj/item/pinpointer/crew - ears = /obj/item/radio/headset/heads/cmo - uniform = /obj/item/clothing/under/rank/chief_medical_officer - shoes = /obj/item/clothing/shoes/sneakers/brown - suit = /obj/item/clothing/suit/toggle/labcoat/cmo - l_hand = /obj/item/storage/firstaid/regular - suit_store = /obj/item/flashlight/pen - backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1) - - backpack = /obj/item/storage/backpack/medic - satchel = /obj/item/storage/backpack/satchel/med - duffelbag = /obj/item/storage/backpack/duffelbag/med - - chameleon_extras = list(/obj/item/gun/syringe, /obj/item/stamp/cmo) - -/datum/outfit/job/cmo/hardsuit - name = "Chief Medical Officer (Hardsuit)" - - mask = /obj/item/clothing/mask/breath - suit = /obj/item/clothing/suit/space/hardsuit/medical - suit_store = /obj/item/tank/internals/oxygen - r_pocket = /obj/item/flashlight/pen - -/* -Medical Doctor -*/ -/datum/job/doctor - title = "Medical Doctor" - flag = DOCTOR - department_head = list("Chief Medical Officer") - department_flag = MEDSCI - faction = "Station" - total_positions = 5 - spawn_positions = 3 - supervisors = "the chief medical officer" - selection_color = "#ffeef0" - - outfit = /datum/outfit/job/doctor - - access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CHEMISTRY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_MINERAL_STOREROOM) - minimal_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CLONING, ACCESS_MINERAL_STOREROOM) - -/datum/outfit/job/doctor - name = "Medical Doctor" - jobtype = /datum/job/doctor - - belt = /obj/item/pda/medical - ears = /obj/item/radio/headset/headset_med - uniform = /obj/item/clothing/under/rank/medical - shoes = /obj/item/clothing/shoes/sneakers/white - suit = /obj/item/clothing/suit/toggle/labcoat - l_hand = /obj/item/storage/firstaid/regular - suit_store = /obj/item/flashlight/pen - - backpack = /obj/item/storage/backpack/medic - satchel = /obj/item/storage/backpack/satchel/med - duffelbag = /obj/item/storage/backpack/duffelbag/med - - chameleon_extras = /obj/item/gun/syringe - -/* -Chemist -*/ -/datum/job/chemist - title = "Chemist" - flag = CHEMIST - department_head = list("Chief Medical Officer") - department_flag = MEDSCI - faction = "Station" - total_positions = 2 - spawn_positions = 2 - supervisors = "the chief medical officer" - selection_color = "#ffeef0" - exp_type = EXP_TYPE_CREW - exp_requirements = 60 - - outfit = /datum/outfit/job/chemist - - access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CHEMISTRY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_MINERAL_STOREROOM) - minimal_access = list(ACCESS_MEDICAL, ACCESS_CHEMISTRY, ACCESS_MINERAL_STOREROOM) - -/datum/outfit/job/chemist - name = "Chemist" - jobtype = /datum/job/chemist - - glasses = /obj/item/clothing/glasses/science - belt = /obj/item/pda/chemist - ears = /obj/item/radio/headset/headset_med - uniform = /obj/item/clothing/under/rank/chemist - shoes = /obj/item/clothing/shoes/sneakers/white - suit = /obj/item/clothing/suit/toggle/labcoat/chemist - backpack = /obj/item/storage/backpack/chemistry - satchel = /obj/item/storage/backpack/satchel/chem - duffelbag = /obj/item/storage/backpack/duffelbag/med - - chameleon_extras = /obj/item/gun/syringe - -/* -Geneticist -*/ -/datum/job/geneticist - title = "Geneticist" - flag = GENETICIST - department_head = list("Chief Medical Officer", "Research Director") - department_flag = MEDSCI - faction = "Station" - total_positions = 2 - spawn_positions = 2 - supervisors = "the chief medical officer and research director" - selection_color = "#ffeef0" - exp_type = EXP_TYPE_CREW - exp_requirements = 60 - - outfit = /datum/outfit/job/geneticist - - access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_CHEMISTRY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_RESEARCH, ACCESS_XENOBIOLOGY, ACCESS_ROBOTICS, ACCESS_MINERAL_STOREROOM, ACCESS_TECH_STORAGE) - minimal_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM) - -/datum/outfit/job/geneticist - name = "Geneticist" - jobtype = /datum/job/geneticist - - belt = /obj/item/pda/geneticist - ears = /obj/item/radio/headset/headset_medsci - uniform = /obj/item/clothing/under/rank/geneticist - shoes = /obj/item/clothing/shoes/sneakers/white - suit = /obj/item/clothing/suit/toggle/labcoat/genetics - suit_store = /obj/item/flashlight/pen - - backpack = /obj/item/storage/backpack/genetics - satchel = /obj/item/storage/backpack/satchel/gen - duffelbag = /obj/item/storage/backpack/duffelbag/med - -/* -Virologist -*/ -/datum/job/virologist - title = "Virologist" - flag = VIROLOGIST - department_head = list("Chief Medical Officer") - department_flag = MEDSCI - faction = "Station" - total_positions = 1 - spawn_positions = 1 - supervisors = "the chief medical officer" - selection_color = "#ffeef0" - exp_type = EXP_TYPE_CREW - exp_requirements = 60 - - outfit = /datum/outfit/job/virologist - - access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_MINERAL_STOREROOM) - minimal_access = list(ACCESS_MEDICAL, ACCESS_VIROLOGY, ACCESS_MINERAL_STOREROOM) - -/datum/outfit/job/virologist - name = "Virologist" - jobtype = /datum/job/virologist - - belt = /obj/item/pda/viro - ears = /obj/item/radio/headset/headset_med - uniform = /obj/item/clothing/under/rank/virologist - mask = /obj/item/clothing/mask/surgical - shoes = /obj/item/clothing/shoes/sneakers/white - suit = /obj/item/clothing/suit/toggle/labcoat/virologist - suit_store = /obj/item/flashlight/pen - - backpack = /obj/item/storage/backpack/virology - satchel = /obj/item/storage/backpack/satchel/vir - duffelbag = /obj/item/storage/backpack/duffelbag/med diff --git a/code/modules/jobs/job_types/medical_doctor.dm b/code/modules/jobs/job_types/medical_doctor.dm new file mode 100644 index 0000000000..19fa1c7158 --- /dev/null +++ b/code/modules/jobs/job_types/medical_doctor.dm @@ -0,0 +1,35 @@ +/datum/job/doctor + title = "Medical Doctor" + flag = DOCTOR + department_head = list("Chief Medical Officer") + department_flag = MEDSCI + faction = "Station" + total_positions = 5 + spawn_positions = 3 + supervisors = "the chief medical officer" + selection_color = "#74b5e0" + + outfit = /datum/outfit/job/doctor + + access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CHEMISTRY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_VIROLOGY, ACCESS_MINERAL_STOREROOM) + minimal_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CLONING, ACCESS_MINERAL_STOREROOM) + + display_order = JOB_DISPLAY_ORDER_MEDICAL_DOCTOR + +/datum/outfit/job/doctor + name = "Medical Doctor" + jobtype = /datum/job/doctor + + belt = /obj/item/pda/medical + ears = /obj/item/radio/headset/headset_med + uniform = /obj/item/clothing/under/rank/medical + shoes = /obj/item/clothing/shoes/sneakers/white + suit = /obj/item/clothing/suit/toggle/labcoat + l_hand = /obj/item/storage/firstaid/regular + suit_store = /obj/item/flashlight/pen + + backpack = /obj/item/storage/backpack/medic + satchel = /obj/item/storage/backpack/satchel/med + duffelbag = /obj/item/storage/backpack/duffelbag/med + + chameleon_extras = /obj/item/gun/syringe diff --git a/code/modules/jobs/job_types/mime.dm b/code/modules/jobs/job_types/mime.dm new file mode 100644 index 0000000000..1347da7125 --- /dev/null +++ b/code/modules/jobs/job_types/mime.dm @@ -0,0 +1,49 @@ +/datum/job/mime + title = "Mime" + flag = MIME + department_head = list("Head of Personnel") + department_flag = CIVILIAN + faction = "Station" + total_positions = 1 + spawn_positions = 1 + supervisors = "the head of personnel" + selection_color = "#dddddd" + + outfit = /datum/outfit/job/mime + + access = list(ACCESS_THEATRE) + minimal_access = list(ACCESS_THEATRE) + + display_order = JOB_DISPLAY_ORDER_MIME + +/datum/job/mime/after_spawn(mob/living/carbon/human/H, mob/M) + H.apply_pref_name("mime", M.client) + +/datum/outfit/job/mime + name = "Mime" + jobtype = /datum/job/mime + + belt = /obj/item/pda/mime + ears = /obj/item/radio/headset/headset_srv + uniform = /obj/item/clothing/under/rank/mime + mask = /obj/item/clothing/mask/gas/mime + gloves = /obj/item/clothing/gloves/color/white + head = /obj/item/clothing/head/frenchberet + suit = /obj/item/clothing/suit/suspenders + backpack_contents = list(/obj/item/reagent_containers/food/drinks/bottle/bottleofnothing=1) + + backpack = /obj/item/storage/backpack/mime + satchel = /obj/item/storage/backpack/mime + + +/datum/outfit/job/mime/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) + ..() + + if(visualsOnly) + return + + if(H.mind) + H.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/mime_wall(null)) + H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/mime/speak(null)) + H.mind.miming = 1 + diff --git a/code/modules/jobs/job_types/quartermaster.dm b/code/modules/jobs/job_types/quartermaster.dm new file mode 100644 index 0000000000..49a93026ba --- /dev/null +++ b/code/modules/jobs/job_types/quartermaster.dm @@ -0,0 +1,41 @@ +/datum/job/qm + title = "Quartermaster" + flag = QUARTERMASTER + department_head = list("Captain") + department_flag = CIVILIAN + head_announce = list(RADIO_CHANNEL_SUPPLY) +// auto_deadmin_role_flags = DEADMIN_POSITION_HEAD + faction = "Station" + total_positions = 1 + spawn_positions = 1 + supervisors = "the captain" + selection_color = "#a06121" + req_admin_notify = 1 + minimal_player_age = 7 + exp_requirements = 180 + exp_type = EXP_TYPE_CREW + exp_type_department = EXP_TYPE_SUPPLY + + outfit = /datum/outfit/job/quartermaster + + access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_QM, ACCESS_MINING, ACCESS_MINING_STATION, + ACCESS_MINERAL_STOREROOM, ACCESS_VAULT) + minimal_access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_QM, ACCESS_MINING, + ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM, ACCESS_VAULT) + + display_order = JOB_DISPLAY_ORDER_QUARTERMASTER + blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/insanity) + +/datum/outfit/job/quartermaster + name = "Quartermaster" + jobtype = /datum/job/qm + + belt = /obj/item/pda/quartermaster + ears = /obj/item/radio/headset/headset_cargo + uniform = /obj/item/clothing/under/rank/cargo + shoes = /obj/item/clothing/shoes/sneakers/brown + glasses = /obj/item/clothing/glasses/sunglasses + l_hand = /obj/item/clipboard + + chameleon_extras = /obj/item/stamp/qm + diff --git a/code/modules/jobs/job_types/research_director.dm b/code/modules/jobs/job_types/research_director.dm new file mode 100644 index 0000000000..5368ceee64 --- /dev/null +++ b/code/modules/jobs/job_types/research_director.dm @@ -0,0 +1,61 @@ +/datum/job/rd + title = "Research Director" + flag = RD_JF +// auto_deadmin_role_flags = DEADMIN_POSITION_HEAD + department_head = list("Captain") + department_flag = MEDSCI + head_announce = list(RADIO_CHANNEL_SCIENCE) + faction = "Station" + total_positions = 1 + spawn_positions = 1 + supervisors = "the captain" + selection_color = "#7544cc" + req_admin_notify = 1 + minimal_player_age = 7 + exp_type_department = EXP_TYPE_SCIENCE + exp_requirements = 180 + exp_type = EXP_TYPE_CREW + + outfit = /datum/outfit/job/rd + + access = list(ACCESS_RD, ACCESS_HEADS, ACCESS_TOX, ACCESS_GENETICS, ACCESS_MORGUE, + ACCESS_TOX_STORAGE, ACCESS_TELEPORTER, ACCESS_SEC_DOORS, + ACCESS_RESEARCH, ACCESS_ROBOTICS, ACCESS_XENOBIOLOGY, ACCESS_AI_UPLOAD, + ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MINERAL_STOREROOM, + ACCESS_TECH_STORAGE, ACCESS_MINISAT, ACCESS_MAINT_TUNNELS, ACCESS_NETWORK) + minimal_access = list(ACCESS_RD, ACCESS_HEADS, ACCESS_TOX, ACCESS_GENETICS, ACCESS_MORGUE, + ACCESS_TOX_STORAGE, ACCESS_TELEPORTER, ACCESS_SEC_DOORS, + ACCESS_RESEARCH, ACCESS_ROBOTICS, ACCESS_XENOBIOLOGY, ACCESS_AI_UPLOAD, + ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MINERAL_STOREROOM, + ACCESS_TECH_STORAGE, ACCESS_MINISAT, ACCESS_MAINT_TUNNELS, ACCESS_NETWORK) + + display_order = JOB_DISPLAY_ORDER_RESEARCH_DIRECTOR + blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/insanity) + +/datum/outfit/job/rd + name = "Research Director" + jobtype = /datum/job/rd + + id = /obj/item/card/id/silver + belt = /obj/item/pda/heads/rd + ears = /obj/item/radio/headset/heads/rd + uniform = /obj/item/clothing/under/rank/research_director + shoes = /obj/item/clothing/shoes/sneakers/brown + suit = /obj/item/clothing/suit/toggle/labcoat + l_hand = /obj/item/clipboard + l_pocket = /obj/item/laser_pointer + backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1, /obj/item/modular_computer/tablet/preset/advanced=1) + + backpack = /obj/item/storage/backpack/science + satchel = /obj/item/storage/backpack/satchel/tox + + chameleon_extras = /obj/item/stamp/rd + +/datum/outfit/job/rd/rig + name = "Research Director (Hardsuit)" + + l_hand = null + mask = /obj/item/clothing/mask/breath + suit = /obj/item/clothing/suit/space/hardsuit/rd + suit_store = /obj/item/tank/internals/oxygen + internals_slot = SLOT_S_STORE diff --git a/code/modules/jobs/job_types/roboticist.dm b/code/modules/jobs/job_types/roboticist.dm new file mode 100644 index 0000000000..782b175ad4 --- /dev/null +++ b/code/modules/jobs/job_types/roboticist.dm @@ -0,0 +1,34 @@ +/datum/job/roboticist + title = "Roboticist" + flag = ROBOTICIST + department_head = list("Research Director") + department_flag = MEDSCI + faction = "Station" + total_positions = 2 + spawn_positions = 2 + supervisors = "the research director" + selection_color = "#9574cd" + exp_requirements = 60 + exp_type = EXP_TYPE_CREW + + outfit = /datum/outfit/job/roboticist + + access = list(ACCESS_ROBOTICS, ACCESS_TOX, ACCESS_TOX_STORAGE, ACCESS_TECH_STORAGE, ACCESS_MORGUE, ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM, ACCESS_XENOBIOLOGY, ACCESS_GENETICS) + minimal_access = list(ACCESS_ROBOTICS, ACCESS_TECH_STORAGE, ACCESS_MORGUE, ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM) + + display_order = JOB_DISPLAY_ORDER_ROBOTICIST + +/datum/outfit/job/roboticist + name = "Roboticist" + jobtype = /datum/job/roboticist + + belt = /obj/item/storage/belt/utility/full + l_pocket = /obj/item/pda/roboticist + ears = /obj/item/radio/headset/headset_sci + uniform = /obj/item/clothing/under/rank/roboticist + suit = /obj/item/clothing/suit/toggle/labcoat + + backpack = /obj/item/storage/backpack/science + satchel = /obj/item/storage/backpack/satchel/tox + + pda_slot = SLOT_L_STORE diff --git a/code/modules/jobs/job_types/science.dm b/code/modules/jobs/job_types/science.dm deleted file mode 100644 index 21b1a9747a..0000000000 --- a/code/modules/jobs/job_types/science.dm +++ /dev/null @@ -1,131 +0,0 @@ -/* -Research Director -*/ -/datum/job/rd - title = "Research Director" - flag = RD_JF - department_head = list("Captain") - department_flag = MEDSCI - head_announce = list(RADIO_CHANNEL_SCIENCE) - faction = "Station" - total_positions = 1 - spawn_positions = 1 - supervisors = "the captain" - selection_color = "#ffddff" - req_admin_notify = 1 - minimal_player_age = 7 - exp_type_department = EXP_TYPE_SCIENCE - exp_requirements = 180 - exp_type = EXP_TYPE_CREW - - outfit = /datum/outfit/job/rd - - access = list(ACCESS_RD, ACCESS_HEADS, ACCESS_TOX, ACCESS_GENETICS, ACCESS_MORGUE, - ACCESS_TOX_STORAGE, ACCESS_TELEPORTER, ACCESS_SEC_DOORS, - ACCESS_RESEARCH, ACCESS_ROBOTICS, ACCESS_XENOBIOLOGY, ACCESS_AI_UPLOAD, - ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MINERAL_STOREROOM, - ACCESS_TECH_STORAGE, ACCESS_MINISAT, ACCESS_MAINT_TUNNELS, ACCESS_NETWORK) - minimal_access = list(ACCESS_RD, ACCESS_HEADS, ACCESS_TOX, ACCESS_GENETICS, ACCESS_MORGUE, - ACCESS_TOX_STORAGE, ACCESS_TELEPORTER, ACCESS_SEC_DOORS, - ACCESS_RESEARCH, ACCESS_ROBOTICS, ACCESS_XENOBIOLOGY, ACCESS_AI_UPLOAD, - ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MINERAL_STOREROOM, - ACCESS_TECH_STORAGE, ACCESS_MINISAT, ACCESS_MAINT_TUNNELS, ACCESS_NETWORK) - -/datum/outfit/job/rd - name = "Research Director" - jobtype = /datum/job/rd - - id = /obj/item/card/id/silver - belt = /obj/item/pda/heads/rd - ears = /obj/item/radio/headset/heads/rd - uniform = /obj/item/clothing/under/rank/research_director - shoes = /obj/item/clothing/shoes/sneakers/brown - suit = /obj/item/clothing/suit/toggle/labcoat - l_hand = /obj/item/clipboard - l_pocket = /obj/item/laser_pointer - backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1, /obj/item/modular_computer/tablet/preset/advanced=1) - - backpack = /obj/item/storage/backpack/science - satchel = /obj/item/storage/backpack/satchel/tox - - chameleon_extras = /obj/item/stamp/rd - -/datum/outfit/job/rd/rig - name = "Research Director (Hardsuit)" - - l_hand = null - mask = /obj/item/clothing/mask/breath - suit = /obj/item/clothing/suit/space/hardsuit/rd - suit_store = /obj/item/tank/internals/oxygen - internals_slot = SLOT_S_STORE - -/* -Scientist -*/ -/datum/job/scientist - title = "Scientist" - flag = SCIENTIST - department_head = list("Research Director") - department_flag = MEDSCI - faction = "Station" - total_positions = 5 - spawn_positions = 3 - supervisors = "the research director" - selection_color = "#ffeeff" - exp_requirements = 60 - exp_type = EXP_TYPE_CREW - - - outfit = /datum/outfit/job/scientist - - access = list(ACCESS_ROBOTICS, ACCESS_TOX, ACCESS_TOX_STORAGE, ACCESS_RESEARCH, ACCESS_XENOBIOLOGY, ACCESS_MINERAL_STOREROOM, ACCESS_TECH_STORAGE, ACCESS_GENETICS) - minimal_access = list(ACCESS_TOX, ACCESS_TOX_STORAGE, ACCESS_RESEARCH, ACCESS_XENOBIOLOGY, ACCESS_MINERAL_STOREROOM) - -/datum/outfit/job/scientist - name = "Scientist" - jobtype = /datum/job/scientist - - belt = /obj/item/pda/toxins - ears = /obj/item/radio/headset/headset_sci - uniform = /obj/item/clothing/under/rank/scientist - shoes = /obj/item/clothing/shoes/sneakers/white - suit = /obj/item/clothing/suit/toggle/labcoat/science - - backpack = /obj/item/storage/backpack/science - satchel = /obj/item/storage/backpack/satchel/tox - -/* -Roboticist -*/ -/datum/job/roboticist - title = "Roboticist" - flag = ROBOTICIST - department_head = list("Research Director") - department_flag = MEDSCI - faction = "Station" - total_positions = 2 - spawn_positions = 2 - supervisors = "the research director" - selection_color = "#ffeeff" - exp_requirements = 60 - exp_type = EXP_TYPE_CREW - - outfit = /datum/outfit/job/roboticist - - access = list(ACCESS_ROBOTICS, ACCESS_TOX, ACCESS_TOX_STORAGE, ACCESS_TECH_STORAGE, ACCESS_MORGUE, ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM, ACCESS_XENOBIOLOGY, ACCESS_GENETICS) - minimal_access = list(ACCESS_ROBOTICS, ACCESS_TECH_STORAGE, ACCESS_MORGUE, ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM) - -/datum/outfit/job/roboticist - name = "Roboticist" - jobtype = /datum/job/roboticist - - belt = /obj/item/storage/belt/utility/full - l_pocket = /obj/item/pda/roboticist - ears = /obj/item/radio/headset/headset_sci - uniform = /obj/item/clothing/under/rank/roboticist - suit = /obj/item/clothing/suit/toggle/labcoat - - backpack = /obj/item/storage/backpack/science - satchel = /obj/item/storage/backpack/satchel/tox - - pda_slot = SLOT_L_STORE diff --git a/code/modules/jobs/job_types/scientist.dm b/code/modules/jobs/job_types/scientist.dm new file mode 100644 index 0000000000..f40a25d6ba --- /dev/null +++ b/code/modules/jobs/job_types/scientist.dm @@ -0,0 +1,33 @@ +/datum/job/scientist + title = "Scientist" + flag = SCIENTIST + department_head = list("Research Director") + department_flag = MEDSCI + faction = "Station" + total_positions = 5 + spawn_positions = 3 + supervisors = "the research director" + selection_color = "#9574cd" + exp_requirements = 60 + exp_type = EXP_TYPE_CREW + + outfit = /datum/outfit/job/scientist + + access = list(ACCESS_ROBOTICS, ACCESS_TOX, ACCESS_TOX_STORAGE, ACCESS_RESEARCH, ACCESS_XENOBIOLOGY, ACCESS_MINERAL_STOREROOM, ACCESS_TECH_STORAGE, ACCESS_GENETICS) + minimal_access = list(ACCESS_TOX, ACCESS_TOX_STORAGE, ACCESS_RESEARCH, ACCESS_XENOBIOLOGY, ACCESS_MINERAL_STOREROOM) + + display_order = JOB_DISPLAY_ORDER_SCIENTIST + +/datum/outfit/job/scientist + name = "Scientist" + jobtype = /datum/job/scientist + + belt = /obj/item/pda/toxins + ears = /obj/item/radio/headset/headset_sci + uniform = /obj/item/clothing/under/rank/scientist + shoes = /obj/item/clothing/shoes/sneakers/white + suit = /obj/item/clothing/suit/toggle/labcoat/science + + backpack = /obj/item/storage/backpack/science + satchel = /obj/item/storage/backpack/satchel/tox + diff --git a/code/modules/jobs/job_types/security.dm b/code/modules/jobs/job_types/security.dm deleted file mode 100644 index 2a6cc199ee..0000000000 --- a/code/modules/jobs/job_types/security.dm +++ /dev/null @@ -1,341 +0,0 @@ -//Warden and regular officers add this result to their get_access() -/datum/job/proc/check_config_for_sec_maint() - if(CONFIG_GET(flag/security_has_maint_access)) - return list(ACCESS_MAINT_TUNNELS) - return list() - -/* -Head of Security -*/ -/datum/job/hos - title = "Head of Security" - flag = HOS - department_head = list("Captain") - department_flag = ENGSEC - head_announce = list(RADIO_CHANNEL_SECURITY) - faction = "Station" - total_positions = 1 - spawn_positions = 1 - supervisors = "the captain" - selection_color = "#ffdddd" - req_admin_notify = 1 - minimal_player_age = 14 - exp_requirements = 300 - exp_type = EXP_TYPE_CREW - exp_type_department = EXP_TYPE_SECURITY - - outfit = /datum/outfit/job/hos - - access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_WEAPONS, - ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_ALL_PERSONAL_LOCKERS, - ACCESS_RESEARCH, ACCESS_ENGINE, ACCESS_MINING, ACCESS_MEDICAL, ACCESS_CONSTRUCTION, ACCESS_MAILSORTING, - ACCESS_HEADS, ACCESS_HOS, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM) - minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_WEAPONS, - ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_ALL_PERSONAL_LOCKERS, - ACCESS_RESEARCH, ACCESS_ENGINE, ACCESS_MINING, ACCESS_MEDICAL, ACCESS_CONSTRUCTION, ACCESS_MAILSORTING, - ACCESS_HEADS, ACCESS_HOS, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM) - - mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM) - -/datum/outfit/job/hos - name = "Head of Security" - jobtype = /datum/job/hos - - id = /obj/item/card/id/silver - belt = /obj/item/pda/heads/hos - ears = /obj/item/radio/headset/heads/hos/alt - uniform = /obj/item/clothing/under/rank/head_of_security - shoes = /obj/item/clothing/shoes/jackboots - suit = /obj/item/clothing/suit/armor/hos/trenchcoat - gloves = /obj/item/clothing/gloves/color/black/hos - head = /obj/item/clothing/head/HoS/beret - glasses = /obj/item/clothing/glasses/hud/security/sunglasses - suit_store = /obj/item/gun/energy/e_gun - r_pocket = /obj/item/assembly/flash/handheld - l_pocket = /obj/item/restraints/handcuffs - backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1) - - backpack = /obj/item/storage/backpack/security - satchel = /obj/item/storage/backpack/satchel/sec - duffelbag = /obj/item/storage/backpack/duffelbag/sec - box = /obj/item/storage/box/security - - implants = list(/obj/item/implant/mindshield) - - chameleon_extras = list(/obj/item/gun/energy/e_gun/hos, /obj/item/stamp/hos) - -/datum/outfit/job/hos/hardsuit - name = "Head of Security (Hardsuit)" - - mask = /obj/item/clothing/mask/gas/sechailer - suit = /obj/item/clothing/suit/space/hardsuit/security/hos - suit_store = /obj/item/tank/internals/oxygen - backpack_contents = list(/obj/item/melee/baton/loaded=1, /obj/item/gun/energy/e_gun=1) - -/* -Warden -*/ -/datum/job/warden - title = "Warden" - flag = WARDEN - department_head = list("Head of Security") - department_flag = ENGSEC - faction = "Station" - total_positions = 1 - spawn_positions = 1 - supervisors = "the head of security" - selection_color = "#ffeeee" - minimal_player_age = 7 - exp_requirements = 300 - exp_type = EXP_TYPE_CREW - - outfit = /datum/outfit/job/warden - - access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_MAINT_TUNNELS, ACCESS_MORGUE, ACCESS_WEAPONS, ACCESS_FORENSICS_LOCKERS, ACCESS_MINERAL_STOREROOM) - minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM) //SEE /DATUM/JOB/WARDEN/GET_ACCESS() - - mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM) - -/datum/job/warden/get_access() - var/list/L = list() - L = ..() | check_config_for_sec_maint() - return L - -/datum/outfit/job/warden - name = "Warden" - jobtype = /datum/job/warden - - belt = /obj/item/pda/warden - ears = /obj/item/radio/headset/headset_sec/alt - uniform = /obj/item/clothing/under/rank/warden - shoes = /obj/item/clothing/shoes/jackboots - suit = /obj/item/clothing/suit/armor/vest/warden/alt - gloves = /obj/item/clothing/gloves/color/black - head = /obj/item/clothing/head/warden - glasses = /obj/item/clothing/glasses/hud/security/sunglasses - r_pocket = /obj/item/assembly/flash/handheld - l_pocket = /obj/item/restraints/handcuffs - suit_store = /obj/item/gun/energy/e_gun/advtaser - backpack_contents = list(/obj/item/melee/baton/loaded=1) - - backpack = /obj/item/storage/backpack/security - satchel = /obj/item/storage/backpack/satchel/sec - duffelbag = /obj/item/storage/backpack/duffelbag/sec - box = /obj/item/storage/box/security - - implants = list(/obj/item/implant/mindshield) - - chameleon_extras = /obj/item/gun/ballistic/shotgun/automatic/combat/compact - -/* -Detective -*/ -/datum/job/detective - title = "Detective" - flag = DETECTIVE - department_head = list("Head of Security") - department_flag = ENGSEC - faction = "Station" - total_positions = 1 - spawn_positions = 1 - supervisors = "the head of security" - selection_color = "#ffeeee" - minimal_player_age = 7 - exp_requirements = 300 - exp_type = EXP_TYPE_CREW - - outfit = /datum/outfit/job/detective - - access = list(ACCESS_SEC_DOORS, ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_COURT, ACCESS_BRIG, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM) - minimal_access = list(ACCESS_SEC_DOORS, ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_COURT, ACCESS_BRIG, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM) - - mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM) - -/datum/outfit/job/detective - name = "Detective" - jobtype = /datum/job/detective - - belt = /obj/item/pda/detective - ears = /obj/item/radio/headset/headset_sec/alt - uniform = /obj/item/clothing/under/rank/det - shoes = /obj/item/clothing/shoes/sneakers/brown - suit = /obj/item/clothing/suit/det_suit - gloves = /obj/item/clothing/gloves/color/black - head = /obj/item/clothing/head/fedora/det_hat - l_pocket = /obj/item/toy/crayon/white - r_pocket = /obj/item/lighter - backpack_contents = list(/obj/item/storage/box/evidence=1,\ - /obj/item/detective_scanner=1,\ - /obj/item/melee/classic_baton=1) - mask = /obj/item/clothing/mask/cigarette - - implants = list(/obj/item/implant/mindshield) - - chameleon_extras = list(/obj/item/gun/ballistic/revolver/detective, /obj/item/clothing/glasses/sunglasses) - -/datum/outfit/job/detective/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) - ..() - var/obj/item/clothing/mask/cigarette/cig = H.wear_mask - if(istype(cig)) //Some species specfic changes can mess this up (plasmamen) - cig.light("") - - if(visualsOnly) - return - -/* -Security Officer -*/ -/datum/job/officer - title = "Security Officer" - flag = OFFICER - department_head = list("Head of Security") - department_flag = ENGSEC - faction = "Station" - total_positions = 5 //Handled in /datum/controller/occupations/proc/setup_officer_positions() - spawn_positions = 5 //Handled in /datum/controller/occupations/proc/setup_officer_positions() - supervisors = "the head of security, and the head of your assigned department (if applicable)" - selection_color = "#ffeeee" - minimal_player_age = 7 - exp_requirements = 300 - exp_type = EXP_TYPE_CREW - - outfit = /datum/outfit/job/security - - access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_COURT, ACCESS_MAINT_TUNNELS, ACCESS_MORGUE, ACCESS_WEAPONS, ACCESS_FORENSICS_LOCKERS, ACCESS_MINERAL_STOREROOM) - minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_COURT, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM) //BUT SEE /DATUM/JOB/WARDEN/GET_ACCESS() - - mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM) - -/datum/job/officer/get_access() - var/list/L = list() - L |= ..() | check_config_for_sec_maint() - return L - -GLOBAL_LIST_INIT(available_depts, list(SEC_DEPT_ENGINEERING, SEC_DEPT_MEDICAL, SEC_DEPT_SCIENCE, SEC_DEPT_SUPPLY)) - -/datum/job/officer/after_spawn(mob/living/carbon/human/H, mob/M) - // Assign department security - var/department - if(M && M.client && M.client.prefs) - department = M.client.prefs.prefered_security_department - if(!LAZYLEN(GLOB.available_depts) || department == "None") - return - else if(department in GLOB.available_depts) - LAZYREMOVE(GLOB.available_depts, department) - else - department = pick_n_take(GLOB.available_depts) - var/ears = null - var/accessory = null - var/list/dep_access = null - var/destination = null - var/spawn_point = null - switch(department) - if(SEC_DEPT_SUPPLY) - ears = /obj/item/radio/headset/headset_sec/alt/department/supply - dep_access = list(ACCESS_MAILSORTING, ACCESS_MINING, ACCESS_MINING_STATION) - destination = /area/security/checkpoint/supply - spawn_point = locate(/obj/effect/landmark/start/depsec/supply) in GLOB.department_security_spawns - accessory = /obj/item/clothing/accessory/armband/cargo - if(SEC_DEPT_ENGINEERING) - ears = /obj/item/radio/headset/headset_sec/alt/department/engi - dep_access = list(ACCESS_CONSTRUCTION, ACCESS_ENGINE) - destination = /area/security/checkpoint/engineering - spawn_point = locate(/obj/effect/landmark/start/depsec/engineering) in GLOB.department_security_spawns - accessory = /obj/item/clothing/accessory/armband/engine - if(SEC_DEPT_MEDICAL) - ears = /obj/item/radio/headset/headset_sec/alt/department/med - dep_access = list(ACCESS_MEDICAL) - destination = /area/security/checkpoint/medical - spawn_point = locate(/obj/effect/landmark/start/depsec/medical) in GLOB.department_security_spawns - accessory = /obj/item/clothing/accessory/armband/medblue - if(SEC_DEPT_SCIENCE) - ears = /obj/item/radio/headset/headset_sec/alt/department/sci - dep_access = list(ACCESS_RESEARCH) - destination = /area/security/checkpoint/science - spawn_point = locate(/obj/effect/landmark/start/depsec/science) in GLOB.department_security_spawns - accessory = /obj/item/clothing/accessory/armband/science - - if(accessory) - var/obj/item/clothing/under/U = H.w_uniform - U.attach_accessory(new accessory) - if(ears) - if(H.ears) - qdel(H.ears) - H.equip_to_slot_or_del(new ears(H),SLOT_EARS) - - var/obj/item/card/id/W = H.wear_id - W.access |= dep_access - - var/teleport = 0 - if(!CONFIG_GET(flag/sec_start_brig)) - if(destination || spawn_point) - teleport = 1 - if(teleport) - var/turf/T - if(spawn_point) - T = get_turf(spawn_point) - H.Move(T) - else - var/safety = 0 - while(safety < 25) - T = safepick(get_area_turfs(destination)) - if(T && !H.Move(T)) - safety += 1 - continue - else - break - if(department) - to_chat(M, "You have been assigned to [department]!") - else - to_chat(M, "You have not been assigned to any department. Patrol the halls and help where needed.") - - - -/datum/outfit/job/security - name = "Security Officer" - jobtype = /datum/job/officer - - belt = /obj/item/pda/security - ears = /obj/item/radio/headset/headset_sec/alt - uniform = /obj/item/clothing/under/rank/security - gloves = /obj/item/clothing/gloves/color/black - head = /obj/item/clothing/head/helmet/sec - suit = /obj/item/clothing/suit/armor/vest/alt - shoes = /obj/item/clothing/shoes/jackboots - l_pocket = /obj/item/restraints/handcuffs - r_pocket = /obj/item/assembly/flash/handheld - suit_store = /obj/item/gun/energy/e_gun/advtaser - backpack_contents = list(/obj/item/melee/baton/loaded=1) - - backpack = /obj/item/storage/backpack/security - satchel = /obj/item/storage/backpack/satchel/sec - duffelbag = /obj/item/storage/backpack/duffelbag/sec - box = /obj/item/storage/box/security - - implants = list(/obj/item/implant/mindshield) - - chameleon_extras = list(/obj/item/gun/energy/e_gun/advtaser, /obj/item/clothing/glasses/hud/security/sunglasses, /obj/item/clothing/head/helmet) - //The helmet is necessary because /obj/item/clothing/head/helmet/sec is overwritten in the chameleon list by the standard helmet, which has the same name and icon state - - -/obj/item/radio/headset/headset_sec/alt/department/Initialize() - . = ..() - wires = new/datum/wires/radio(src) - secure_radio_connections = new - recalculateChannels() - -/obj/item/radio/headset/headset_sec/alt/department/engi - keyslot = new /obj/item/encryptionkey/headset_sec - keyslot2 = new /obj/item/encryptionkey/headset_eng - -/obj/item/radio/headset/headset_sec/alt/department/supply - keyslot = new /obj/item/encryptionkey/headset_sec - keyslot2 = new /obj/item/encryptionkey/headset_cargo - -/obj/item/radio/headset/headset_sec/alt/department/med - keyslot = new /obj/item/encryptionkey/headset_sec - keyslot2 = new /obj/item/encryptionkey/headset_med - -/obj/item/radio/headset/headset_sec/alt/department/sci - keyslot = new /obj/item/encryptionkey/headset_sec - keyslot2 = new /obj/item/encryptionkey/headset_sci diff --git a/code/modules/jobs/job_types/security_officer.dm b/code/modules/jobs/job_types/security_officer.dm new file mode 100644 index 0000000000..ae50f71c0c --- /dev/null +++ b/code/modules/jobs/job_types/security_officer.dm @@ -0,0 +1,159 @@ +/datum/job/officer + title = "Security Officer" + flag = OFFICER +// auto_deadmin_role_flags = DEADMIN_POSITION_SECURITY + department_head = list("Head of Security") + department_flag = ENGSEC + faction = "Station" + total_positions = 5 //Handled in /datum/controller/occupations/proc/setup_officer_positions() + spawn_positions = 5 //Handled in /datum/controller/occupations/proc/setup_officer_positions() + supervisors = "the head of security, and the head of your assigned department (if applicable)" + selection_color = "#c02f2f" + minimal_player_age = 7 + exp_requirements = 300 + exp_type = EXP_TYPE_CREW + + outfit = /datum/outfit/job/security + + access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_COURT, ACCESS_MAINT_TUNNELS, ACCESS_MORGUE, ACCESS_WEAPONS, ACCESS_ENTER_GENPOP, ACCESS_LEAVE_GENPOP, ACCESS_FORENSICS_LOCKERS, ACCESS_MINERAL_STOREROOM) + minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_COURT, ACCESS_WEAPONS, ACCESS_ENTER_GENPOP, ACCESS_LEAVE_GENPOP, ACCESS_MINERAL_STOREROOM) // See /datum/job/officer/get_access() + + mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM) + + display_order = JOB_DISPLAY_ORDER_SECURITY_OFFICER + blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/nonviolent, /datum/quirk/paraplegic) + +/datum/job/officer/get_access() + var/list/L = list() + L |= ..() | check_config_for_sec_maint() + return L + +GLOBAL_LIST_INIT(available_depts, list(SEC_DEPT_ENGINEERING, SEC_DEPT_MEDICAL, SEC_DEPT_SCIENCE, SEC_DEPT_SUPPLY)) + +/datum/job/officer/after_spawn(mob/living/carbon/human/H, mob/M) + . = ..() + // Assign department security + var/department + if(M && M.client && M.client.prefs) + department = M.client.prefs.prefered_security_department + if(!LAZYLEN(GLOB.available_depts) || department == "None") + return + else if(department in GLOB.available_depts) + LAZYREMOVE(GLOB.available_depts, department) + else + department = pick_n_take(GLOB.available_depts) + var/ears = null + var/accessory = null + var/list/dep_access = null + var/destination = null + var/spawn_point = null + switch(department) + if(SEC_DEPT_SUPPLY) + ears = /obj/item/radio/headset/headset_sec/alt/department/supply + dep_access = list(ACCESS_MAILSORTING, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_CARGO) + destination = /area/security/checkpoint/supply + spawn_point = locate(/obj/effect/landmark/start/depsec/supply) in GLOB.department_security_spawns + accessory = /obj/item/clothing/accessory/armband/cargo + if(SEC_DEPT_ENGINEERING) + ears = /obj/item/radio/headset/headset_sec/alt/department/engi + dep_access = list(ACCESS_CONSTRUCTION, ACCESS_ENGINE, ACCESS_ATMOSPHERICS) + destination = /area/security/checkpoint/engineering + spawn_point = locate(/obj/effect/landmark/start/depsec/engineering) in GLOB.department_security_spawns + accessory = /obj/item/clothing/accessory/armband/engine + if(SEC_DEPT_MEDICAL) + ears = /obj/item/radio/headset/headset_sec/alt/department/med + dep_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CLONING) + destination = /area/security/checkpoint/medical + spawn_point = locate(/obj/effect/landmark/start/depsec/medical) in GLOB.department_security_spawns + accessory = /obj/item/clothing/accessory/armband/medblue + if(SEC_DEPT_SCIENCE) + ears = /obj/item/radio/headset/headset_sec/alt/department/sci + dep_access = list(ACCESS_RESEARCH, ACCESS_TOX) + destination = /area/security/checkpoint/science + spawn_point = locate(/obj/effect/landmark/start/depsec/science) in GLOB.department_security_spawns + accessory = /obj/item/clothing/accessory/armband/science + + if(accessory) + var/obj/item/clothing/under/U = H.w_uniform + U.attach_accessory(new accessory) + if(ears) + if(H.ears) + qdel(H.ears) + H.equip_to_slot_or_del(new ears(H),SLOT_EARS) + + var/obj/item/card/id/W = H.wear_id + W.access |= dep_access + + var/teleport = 0 + if(!CONFIG_GET(flag/sec_start_brig)) + if(destination || spawn_point) + teleport = 1 + if(teleport) + var/turf/T + if(spawn_point) + T = get_turf(spawn_point) + H.Move(T) + else + var/safety = 0 + while(safety < 25) + T = safepick(get_area_turfs(destination)) + if(T && !H.Move(T)) + safety += 1 + continue + else + break + if(department) + to_chat(M, "You have been assigned to [department]!") + else + to_chat(M, "You have not been assigned to any department. Patrol the halls and help where needed.") + + + +/datum/outfit/job/security + name = "Security Officer" + jobtype = /datum/job/officer + + belt = /obj/item/pda/security + ears = /obj/item/radio/headset/headset_sec/alt + uniform = /obj/item/clothing/under/rank/security + gloves = /obj/item/clothing/gloves/color/black + head = /obj/item/clothing/head/helmet/sec + suit = /obj/item/clothing/suit/armor/vest/alt + shoes = /obj/item/clothing/shoes/jackboots + l_pocket = /obj/item/restraints/handcuffs + r_pocket = /obj/item/assembly/flash/handheld + suit_store = /obj/item/gun/energy/e_gun/advtaser + backpack_contents = list(/obj/item/melee/baton/loaded=1) + + backpack = /obj/item/storage/backpack/security + satchel = /obj/item/storage/backpack/satchel/sec + duffelbag = /obj/item/storage/backpack/duffelbag/sec + box = /obj/item/storage/box/security + + implants = list(/obj/item/implant/mindshield) + + chameleon_extras = list(/obj/item/gun/energy/disabler, /obj/item/clothing/glasses/hud/security/sunglasses, /obj/item/clothing/head/helmet) + //The helmet is necessary because /obj/item/clothing/head/helmet/sec is overwritten in the chameleon list by the standard helmet, which has the same name and icon state + + +/obj/item/radio/headset/headset_sec/alt/department/Initialize() + . = ..() + wires = new/datum/wires/radio(src) + secure_radio_connections = new + recalculateChannels() + +/obj/item/radio/headset/headset_sec/alt/department/engi + keyslot = new /obj/item/encryptionkey/headset_sec + keyslot2 = new /obj/item/encryptionkey/headset_eng + +/obj/item/radio/headset/headset_sec/alt/department/supply + keyslot = new /obj/item/encryptionkey/headset_sec + keyslot2 = new /obj/item/encryptionkey/headset_cargo + +/obj/item/radio/headset/headset_sec/alt/department/med + keyslot = new /obj/item/encryptionkey/headset_sec + keyslot2 = new /obj/item/encryptionkey/headset_med + +/obj/item/radio/headset/headset_sec/alt/department/sci + keyslot = new /obj/item/encryptionkey/headset_sec + keyslot2 = new /obj/item/encryptionkey/headset_sci diff --git a/code/modules/jobs/job_types/shaft_miner.dm b/code/modules/jobs/job_types/shaft_miner.dm new file mode 100644 index 0000000000..ef16d8e53f --- /dev/null +++ b/code/modules/jobs/job_types/shaft_miner.dm @@ -0,0 +1,77 @@ +/datum/job/mining + title = "Shaft Miner" + flag = MINER + department_head = list("Quartermaster") + department_flag = CIVILIAN + faction = "Station" + total_positions = 3 + spawn_positions = 3 + supervisors = "the quartermaster" + selection_color = "#ca8f55" + custom_spawn_text = "Remember, you are a miner, not a hunter. Hunting monsters is not a requirement of your job, the only requirement of your job is to provide materials for the station. Don't be afraid to run away if you're inexperienced with fighting the mining area's locals." + + + outfit = /datum/outfit/job/miner + + access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_QM, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM) + minimal_access = list(ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MAILSORTING, ACCESS_MINERAL_STOREROOM) + + display_order = JOB_DISPLAY_ORDER_SHAFT_MINER + +/datum/outfit/job/miner + name = "Shaft Miner (Lavaland)" + jobtype = /datum/job/mining + + belt = /obj/item/pda/shaftminer + ears = /obj/item/radio/headset/headset_cargo/mining + shoes = /obj/item/clothing/shoes/workboots/mining + gloves = /obj/item/clothing/gloves/color/black + uniform = /obj/item/clothing/under/rank/miner/lavaland + l_pocket = /obj/item/reagent_containers/hypospray/medipen/survival + r_pocket = /obj/item/storage/bag/ore //causes issues if spawned in backpack + backpack_contents = list( + /obj/item/flashlight/seclite=1,\ + /obj/item/kitchen/knife/combat/survival=1,\ + /obj/item/mining_voucher=1,\ + /obj/item/suit_voucher=1,\ + /obj/item/stack/marker_beacon/ten=1) + + backpack = /obj/item/storage/backpack/explorer + satchel = /obj/item/storage/backpack/satchel/explorer + duffelbag = /obj/item/storage/backpack/duffelbag + box = /obj/item/storage/box/survival_mining + + chameleon_extras = /obj/item/gun/energy/kinetic_accelerator + +/datum/outfit/job/miner/asteroid + name = "Shaft Miner (Asteroid)" + uniform = /obj/item/clothing/under/rank/miner + shoes = /obj/item/clothing/shoes/workboots + +/datum/outfit/job/miner/equipped + name = "Shaft Miner (Lavaland + Equipment)" + suit = /obj/item/clothing/suit/hooded/explorer/standard + mask = /obj/item/clothing/mask/gas/explorer + glasses = /obj/item/clothing/glasses/meson + suit_store = /obj/item/tank/internals/oxygen + internals_slot = SLOT_S_STORE + backpack_contents = list( + /obj/item/flashlight/seclite=1,\ + /obj/item/kitchen/knife/combat/survival=1, + /obj/item/mining_voucher=1, + /obj/item/t_scanner/adv_mining_scanner/lesser=1, + /obj/item/gun/energy/kinetic_accelerator=1,\ + /obj/item/stack/marker_beacon/ten=1) + +/datum/outfit/job/miner/equipped/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) + ..() + if(visualsOnly) + return + if(istype(H.wear_suit, /obj/item/clothing/suit/hooded)) + var/obj/item/clothing/suit/hooded/S = H.wear_suit + S.ToggleHood() + +/datum/outfit/job/miner/equipped/hardsuit + name = "Shaft Miner (Equipment + Hardsuit)" + suit = /obj/item/clothing/suit/space/hardsuit/mining + mask = /obj/item/clothing/mask/breath diff --git a/code/modules/jobs/job_types/station_engineer.dm b/code/modules/jobs/job_types/station_engineer.dm new file mode 100644 index 0000000000..55381549ba --- /dev/null +++ b/code/modules/jobs/job_types/station_engineer.dm @@ -0,0 +1,54 @@ +/datum/job/engineer + title = "Station Engineer" + flag = ENGINEER + department_head = list("Chief Engineer") + department_flag = ENGSEC + faction = "Station" + total_positions = 5 + spawn_positions = 5 + supervisors = "the chief engineer" + selection_color = "#ff9b3d" + exp_requirements = 60 + exp_type = EXP_TYPE_CREW + + outfit = /datum/outfit/job/engineer + + access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS, + ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_ATMOSPHERICS, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM) + minimal_access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS, + ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM) + + display_order = JOB_DISPLAY_ORDER_STATION_ENGINEER + +/datum/outfit/job/engineer + name = "Station Engineer" + jobtype = /datum/job/engineer + + belt = /obj/item/storage/belt/utility/full/engi + l_pocket = /obj/item/pda/engineering + ears = /obj/item/radio/headset/headset_eng + uniform = /obj/item/clothing/under/rank/engineer + shoes = /obj/item/clothing/shoes/workboots + head = /obj/item/clothing/head/hardhat + r_pocket = /obj/item/t_scanner + + backpack = /obj/item/storage/backpack/industrial + satchel = /obj/item/storage/backpack/satchel/eng + duffelbag = /obj/item/storage/backpack/duffelbag/engineering + box = /obj/item/storage/box/engineer + pda_slot = SLOT_L_STORE + backpack_contents = list(/obj/item/modular_computer/tablet/preset/advanced=1) + +/datum/outfit/job/engineer/gloved + name = "Station Engineer (Gloves)" + gloves = /obj/item/clothing/gloves/color/yellow + +/datum/outfit/job/engineer/gloved/rig + name = "Station Engineer (Hardsuit)" + mask = /obj/item/clothing/mask/breath + suit = /obj/item/clothing/suit/space/hardsuit/engine + suit_store = /obj/item/tank/internals/oxygen + head = null + internals_slot = SLOT_S_STORE + + diff --git a/code/modules/jobs/job_types/virologist.dm b/code/modules/jobs/job_types/virologist.dm new file mode 100644 index 0000000000..dcc13af627 --- /dev/null +++ b/code/modules/jobs/job_types/virologist.dm @@ -0,0 +1,35 @@ +/datum/job/virologist + title = "Virologist" + flag = VIROLOGIST + department_head = list("Chief Medical Officer") + department_flag = MEDSCI + faction = "Station" + total_positions = 1 + spawn_positions = 1 + supervisors = "the chief medical officer" + selection_color = "#74b5e0" + exp_type = EXP_TYPE_CREW + exp_requirements = 60 + + outfit = /datum/outfit/job/virologist + + access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_MINERAL_STOREROOM) + minimal_access = list(ACCESS_MEDICAL, ACCESS_VIROLOGY, ACCESS_MINERAL_STOREROOM) + + display_order = JOB_DISPLAY_ORDER_VIROLOGIST + +/datum/outfit/job/virologist + name = "Virologist" + jobtype = /datum/job/virologist + + belt = /obj/item/pda/viro + ears = /obj/item/radio/headset/headset_med + uniform = /obj/item/clothing/under/rank/virologist + mask = /obj/item/clothing/mask/surgical + shoes = /obj/item/clothing/shoes/sneakers/white + suit = /obj/item/clothing/suit/toggle/labcoat/virologist + suit_store = /obj/item/flashlight/pen + + backpack = /obj/item/storage/backpack/virology + satchel = /obj/item/storage/backpack/satchel/vir + duffelbag = /obj/item/storage/backpack/duffelbag/med diff --git a/code/modules/jobs/job_types/warden.dm b/code/modules/jobs/job_types/warden.dm new file mode 100644 index 0000000000..1787d13ee3 --- /dev/null +++ b/code/modules/jobs/job_types/warden.dm @@ -0,0 +1,56 @@ +/datum/job/warden + title = "Warden" + flag = WARDEN +// auto_deadmin_role_flags = DEADMIN_POSITION_SECURITY + department_head = list("Head of Security") + department_flag = ENGSEC + faction = "Station" + total_positions = 1 + spawn_positions = 1 + supervisors = "the head of security" + selection_color = "#c02f2f" + minimal_player_age = 7 + exp_requirements = 300 + exp_type = EXP_TYPE_CREW + + outfit = /datum/outfit/job/warden + + access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_MAINT_TUNNELS, ACCESS_MORGUE, ACCESS_WEAPONS, ACCESS_ENTER_GENPOP, ACCESS_LEAVE_GENPOP, ACCESS_FORENSICS_LOCKERS, ACCESS_MINERAL_STOREROOM) + minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_WEAPONS, ACCESS_ENTER_GENPOP, ACCESS_LEAVE_GENPOP, ACCESS_MINERAL_STOREROOM) // See /datum/job/warden/get_access() + + mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM) + + display_order = JOB_DISPLAY_ORDER_WARDEN + blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/nonviolent, /datum/quirk/paraplegic) + +/datum/job/warden/get_access() + var/list/L = list() + L = ..() | check_config_for_sec_maint() + return L + +/datum/outfit/job/warden + name = "Warden" + jobtype = /datum/job/warden + + belt = /obj/item/pda/warden + ears = /obj/item/radio/headset/headset_sec/alt + uniform = /obj/item/clothing/under/rank/warden + shoes = /obj/item/clothing/shoes/jackboots + suit = /obj/item/clothing/suit/armor/vest/warden/alt + gloves = /obj/item/clothing/gloves/color/black + head = /obj/item/clothing/head/warden + glasses = /obj/item/clothing/glasses/hud/security/sunglasses + r_pocket = /obj/item/assembly/flash/handheld + l_pocket = /obj/item/restraints/handcuffs + suit_store = /obj/item/gun/energy/e_gun/advtaser + backpack_contents = list(/obj/item/melee/baton/loaded=1) + + backpack = /obj/item/storage/backpack/security + satchel = /obj/item/storage/backpack/satchel/sec + duffelbag = /obj/item/storage/backpack/duffelbag/sec + box = /obj/item/storage/box/security + + implants = list(/obj/item/implant/mindshield) + + chameleon_extras = /obj/item/gun/ballistic/shotgun/automatic/combat/compact + diff --git a/code/modules/keybindings/bindings_client.dm b/code/modules/keybindings/bindings_client.dm index 548a734f74..2b8bfa6860 100644 --- a/code/modules/keybindings/bindings_client.dm +++ b/code/modules/keybindings/bindings_client.dm @@ -4,7 +4,42 @@ set instant = TRUE set hidden = TRUE + client_keysend_amount += 1 + + var/cache = client_keysend_amount + + if(keysend_tripped && next_keysend_trip_reset <= world.time) + keysend_tripped = FALSE + + if(next_keysend_reset <= world.time) + client_keysend_amount = 0 + next_keysend_reset = world.time + (1 SECONDS) + + //The "tripped" system is to confirm that flooding is still happening after one spike + //not entirely sure how byond commands interact in relation to lag + //don't want to kick people if a lag spike results in a huge flood of commands being sent + if(cache >= MAX_KEYPRESS_AUTOKICK) + if(!keysend_tripped) + keysend_tripped = TRUE + next_keysend_trip_reset = world.time + (2 SECONDS) + else + log_admin("Client [ckey] was just autokicked for flooding keysends; likely abuse but potentially lagspike.") + message_admins("Client [ckey] was just autokicked for flooding keysends; likely abuse but potentially lagspike.") + QDEL_IN(src, 1) + return + + ///Check if the key is short enough to even be a real key + if(LAZYLEN(_key) > MAX_KEYPRESS_COMMANDLENGTH) + to_chat(src, "Invalid KeyDown detected! You have been disconnected from the server automatically.") + log_admin("Client [ckey] just attempted to send an invalid keypress. Keymessage was over [MAX_KEYPRESS_COMMANDLENGTH] characters, autokicking due to likely abuse.") + message_admins("Client [ckey] just attempted to send an invalid keypress. Keymessage was over [MAX_KEYPRESS_COMMANDLENGTH] characters, autokicking due to likely abuse.") + QDEL_IN(src, 1) + return + //offset by 1 because the buffer address is 0 indexed because the math was simpler + keys_held[current_key_address + 1] = _key + //the time a key was pressed isn't actually used anywhere (as of 2019-9-10) but this allows easier access usage/checking keys_held[_key] = world.time + current_key_address = ((current_key_address + 1) % HELD_KEY_BUFFER_LENGTH) var/movement = SSinput.movement_keys[_key] if(!(next_move_dir_sub & movement) && !keys_held["Ctrl"]) next_move_dir_add |= movement @@ -35,7 +70,11 @@ set instant = TRUE set hidden = TRUE - keys_held -= _key + //Can't just do a remove because it would alter the length of the rolling buffer, instead search for the key then null it out if it exists + for(var/i in 1 to HELD_KEY_BUFFER_LENGTH) + if(keys_held[i] == _key) + keys_held[i] = null + break var/movement = SSinput.movement_keys[_key] if(!(next_move_dir_add & movement)) next_move_dir_sub |= movement diff --git a/code/modules/keybindings/setup.dm b/code/modules/keybindings/setup.dm index 54df252f5d..8433c9bf5a 100644 --- a/code/modules/keybindings/setup.dm +++ b/code/modules/keybindings/setup.dm @@ -1,9 +1,14 @@ /client - var/list/keys_held = list() // A list of any keys held currently - // These next two vars are to apply movement for keypresses and releases made while move delayed. - // Because discarding that input makes the game less responsive. - var/next_move_dir_add // On next move, add this dir to the move that would otherwise be done - var/next_move_dir_sub // On next move, subtract this dir from the move that would otherwise be done + /// A rolling buffer of any keys held currently + var/list/keys_held = list() + ///used to keep track of the current rolling buffer position + var/current_key_address = 0 + /// These next two vars are to apply movement for keypresses and releases made while move delayed. + /// Because discarding that input makes the game less responsive. + /// On next move, add this dir to the move that would otherwise be done + var/next_move_dir_add + /// On next move, subtract this dir from the move that would otherwise be done + var/next_move_dir_sub // Set a client's focus to an object and override these procs on that object to let it handle keypresses @@ -31,6 +36,11 @@ /client/proc/set_macros() set waitfor = FALSE + //Reset and populate the rolling buffer + keys_held.Cut() + for(var/i in 1 to HELD_KEY_BUFFER_LENGTH) + keys_held += null + erase_all_macros() var/list/macro_sets = SSinput.macro_sets diff --git a/code/modules/library/lib_codex_gigas.dm b/code/modules/library/lib_codex_gigas.dm index d3d95db974..57bf37d528 100644 --- a/code/modules/library/lib_codex_gigas.dm +++ b/code/modules/library/lib_codex_gigas.dm @@ -50,8 +50,8 @@ if(U.job in list("Curator")) // the curator is both faster, and more accurate than normal crew members at research speed = 100 correctness = 100 - correctness -= U.getBrainLoss() *0.5 //Brain damage makes researching hard. - speed += U.getBrainLoss() * 3 + correctness -= U.getOrganLoss(ORGAN_SLOT_BRAIN) *0.5 //Brain damage makes researching hard. + speed += U.getOrganLoss(ORGAN_SLOT_BRAIN) * 3 if(do_after(user, speed, 0, user)) var/usedName = devilName if(!prob(correctness)) diff --git a/code/modules/library/lib_machines.dm b/code/modules/library/lib_machines.dm index 699df5de12..ef58943731 100644 --- a/code/modules/library/lib_machines.dm +++ b/code/modules/library/lib_machines.dm @@ -343,8 +343,11 @@ GLOBAL_LIST(cachedbooks) // List of our cached book datums return ..() /obj/machinery/computer/libraryconsole/bookmanagement/emag_act(mob/user) - if(density && !(obj_flags & EMAGGED)) - obj_flags |= EMAGGED + . = ..() + if(!density || obj_flags & EMAGGED) + return + obj_flags |= EMAGGED + return TRUE /obj/machinery/computer/libraryconsole/bookmanagement/Topic(href, href_list) if(..()) diff --git a/code/modules/mapping/mapping_helpers.dm b/code/modules/mapping/mapping_helpers.dm index 7a875ccf9f..e2459d780a 100644 --- a/code/modules/mapping/mapping_helpers.dm +++ b/code/modules/mapping/mapping_helpers.dm @@ -213,4 +213,4 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_lava) if(!ispath(disease_type,/datum/disease)) CRASH("Wrong disease type passed in.") var/datum/disease/D = new disease_type() - return list(component_type,D) \ No newline at end of file + return list(component_type,D) diff --git a/code/modules/mining/abandoned_crates.dm b/code/modules/mining/abandoned_crates.dm index 86499e694b..f98f0755c8 100644 --- a/code/modules/mining/abandoned_crates.dm +++ b/code/modules/mining/abandoned_crates.dm @@ -169,6 +169,7 @@ locked = FALSE cut_overlays() add_overlay("securecrateg") + tamperproof = 0 // set explosion chance to zero, so we dont accidently hit it with a multitool and instantly die else if (input == null || sanitycheck == null || length(input) != codelen) to_chat(user, "You leave the crate alone.") else @@ -213,9 +214,18 @@ return return ..() +/obj/structure/closet/secure/loot/dive_into(mob/living/user) + if(!locked) + return ..() + to_chat(user, "That seems like a stupid idea.") + return FALSE + /obj/structure/closet/crate/secure/loot/emag_act(mob/user) - if(locked) - boom(user) + . = SEND_SIGNAL(src, COMSIG_ATOM_EMAG_ACT) + if(!locked) + return + boom(user) + return TRUE /obj/structure/closet/crate/secure/loot/togglelock(mob/user) if(locked) @@ -224,4 +234,6 @@ ..() /obj/structure/closet/crate/secure/loot/deconstruct(disassembled = TRUE) + if(!locked && disassembled) + return ..() boom() diff --git a/code/modules/mining/equipment/explorer_gear.dm b/code/modules/mining/equipment/explorer_gear.dm index 2c35c3148f..559ffc0673 100644 --- a/code/modules/mining/equipment/explorer_gear.dm +++ b/code/modules/mining/equipment/explorer_gear.dm @@ -11,6 +11,7 @@ heat_protection = CHEST|GROIN|LEGS|ARMS hoodtype = /obj/item/clothing/head/hooded/explorer armor = list("melee" = 30, "bullet" = 20, "laser" = 20, "energy" = 20, "bomb" = 50, "bio" = 100, "rad" = 50, "fire" = 50, "acid" = 50) + flags_inv = HIDEJUMPSUIT|HIDETAUR allowed = list(/obj/item/flashlight, /obj/item/tank/internals, /obj/item/resonator, /obj/item/mining_scanner, /obj/item/t_scanner/adv_mining_scanner, /obj/item/gun/energy/kinetic_accelerator, /obj/item/pickaxe) resistance_flags = FIRE_PROOF tauric = TRUE //Citadel Add for tauric hardsuits @@ -43,7 +44,7 @@ name = "explorer gas mask" desc = "A military-grade gas mask that can be connected to an air supply." icon_state = "gas_mining" - visor_flags = BLOCK_GAS_SMOKE_EFFECT | MASKINTERNALS + visor_flags = BLOCK_GAS_SMOKE_EFFECT | ALLOWINTERNALS visor_flags_inv = HIDEFACIALHAIR visor_flags_cover = MASKCOVERSMOUTH actions_types = list(/datum/action/item_action/adjust) @@ -129,7 +130,7 @@ /obj/item/clothing/suit/hooded/explorer/seva name = "SEVA Suit" - desc = "A fire-proof suit for exploring hot environments." + desc = "A fire-proof suit for exploring hot environments. Its design and material make it easier for a Goliath to keep their grip on the wearer." icon_state = "seva" item_state = "seva" w_class = WEIGHT_CLASS_BULKY @@ -141,7 +142,7 @@ /obj/item/clothing/head/hooded/explorer/seva name = "SEVA Hood" - desc = "A fire-proof hood for exploring hot environments." + desc = "A fire-proof hood for exploring hot environments. Its design and material make it easier for a Goliath to keep their grip on the wearer." icon_state = "seva" item_state = "seva" max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT @@ -159,7 +160,7 @@ /obj/item/clothing/suit/hooded/explorer/exo name = "Exo-suit" - desc = "A robust suit for exploring dangerous environments." + desc = "A robust suit for fighting dangerous animals. Its design and material make it harder for a Goliath to keep their grip on the wearer." icon_state = "exo" item_state = "exo" w_class = WEIGHT_CLASS_BULKY @@ -170,7 +171,7 @@ /obj/item/clothing/head/hooded/explorer/exo name = "Exo-hood" - desc = "A robust helmet for exploring dangerous environments." + desc = "A robust helmet for fighting dangerous animals. Its design and material make it harder for a Goliath to keep their grip on the wearer." icon_state = "exo" item_state = "exo" armor = list("melee" = 65, "bullet" = 5, "laser" = 5, "energy" = 5, "bomb" = 60, "bio" = 25, "rad" = 10, "fire" = 0, "acid" = 0) diff --git a/code/modules/mining/equipment/kinetic_crusher.dm b/code/modules/mining/equipment/kinetic_crusher.dm index b4afaac17f..ab8aa3e2fd 100644 --- a/code/modules/mining/equipment/kinetic_crusher.dm +++ b/code/modules/mining/equipment/kinetic_crusher.dm @@ -1,50 +1,51 @@ /*********************Mining Hammer****************/ -/obj/item/twohanded/required/kinetic_crusher +/obj/item/twohanded/kinetic_crusher icon = 'icons/obj/mining.dmi' - icon_state = "mining_hammer1" - item_state = "mining_hammer1" + icon_state = "crusher" + item_state = "crusher0" lefthand_file = 'icons/mob/inhands/weapons/hammers_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/hammers_righthand.dmi' name = "proto-kinetic crusher" desc = "An early design of the proto-kinetic accelerator, it is little more than an combination of various mining tools cobbled together, forming a high-tech club. \ While it is an effective mining tool, it did little to aid any but the most skilled and/or suicidal miners against local fauna." - force = 20 //As much as a bone spear, but this is significantly more annoying to carry around due to requiring the use of both hands at all times + force = 0 //You can't hit stuff unless wielded w_class = WEIGHT_CLASS_BULKY slot_flags = ITEM_SLOT_BACK - force_unwielded = 20 //It's never not wielded so these are the same + force_unwielded = 0 force_wielded = 20 throwforce = 5 throw_speed = 4 - light_range = 7 - light_power = 2 armour_penetration = 10 materials = list(MAT_METAL=1150, MAT_GLASS=2075) hitsound = 'sound/weapons/bladeslice.ogg' attack_verb = list("smashed", "crushed", "cleaved", "chopped", "pulped") sharpness = IS_SHARP + actions_types = list(/datum/action/item_action/toggle_light) var/list/trophies = list() var/charged = TRUE var/charge_time = 15 var/detonation_damage = 50 var/backstab_bonus = 30 + var/light_on = FALSE + var/brightness_on = 7 -/obj/item/twohanded/required/kinetic_crusher/Initialize() +/obj/item/twohanded/kinetic_crusher/Initialize() . = ..() AddComponent(/datum/component/butchering, 60, 110) //technically it's huge and bulky, but this provides an incentive to use it -/obj/item/twohanded/required/kinetic_crusher/Destroy() +/obj/item/twohanded/kinetic_crusher/Destroy() QDEL_LIST(trophies) return ..() -/obj/item/twohanded/required/kinetic_crusher/examine(mob/living/user) +/obj/item/twohanded/kinetic_crusher/examine(mob/living/user) ..() - to_chat(user, "Mark a large creature with the destabilizing force, then hit them in melee to do [force + detonation_damage] damage.") - to_chat(user, "Does [force + detonation_damage + backstab_bonus] damage if the target is backstabbed, instead of [force + detonation_damage].") + to_chat(user, "Mark a large creature with the destabilizing force, then hit them in melee to do [force_wielded + detonation_damage] damage.") + to_chat(user, "Does [force_wielded + detonation_damage + backstab_bonus] damage if the target is backstabbed, instead of [force_wielded + detonation_damage].") for(var/t in trophies) var/obj/item/crusher_trophy/T = t to_chat(user, "It has \a [T] attached, which causes [T.effect_desc()].") -/obj/item/twohanded/required/kinetic_crusher/attackby(obj/item/I, mob/living/user) +/obj/item/twohanded/kinetic_crusher/attackby(obj/item/I, mob/living/user) if(istype(I, /obj/item/crowbar)) if(LAZYLEN(trophies)) to_chat(user, "You remove [src]'s trophies.") @@ -60,7 +61,11 @@ else return ..() -/obj/item/twohanded/required/kinetic_crusher/attack(mob/living/target, mob/living/carbon/user) +/obj/item/twohanded/kinetic_crusher/attack(mob/living/target, mob/living/carbon/user) + if(!wielded) + to_chat(user, "[src] is too heavy to use with one hand. You fumble and drop everything.") + user.drop_all_held_items() + return var/datum/status_effect/crusher_damage/C = target.has_status_effect(STATUS_EFFECT_CRUSHERDAMAGETRACKING) var/target_health = target.health ..() @@ -71,11 +76,13 @@ if(!QDELETED(C) && !QDELETED(target)) C.total_damage += target_health - target.health //we did some damage, but let's not assume how much we did -/obj/item/twohanded/required/kinetic_crusher/afterattack(atom/target, mob/living/user, proximity_flag, clickparams) +/obj/item/twohanded/kinetic_crusher/afterattack(atom/target, mob/living/user, proximity_flag, clickparams) . = ..() if(istype(target, /obj/item/crusher_trophy)) var/obj/item/crusher_trophy/T = target T.add_to(src, user) + if(!wielded) + return if(!proximity_flag && charged)//Mark a target, or mine a tile. var/turf/proj_turf = user.loc if(!isturf(proj_turf)) @@ -90,7 +97,7 @@ playsound(user, 'sound/weapons/plasma_cutter.ogg', 100, 1) D.fire() charged = FALSE - icon_state = "mining_hammer1_uncharged" + update_icon() addtimer(CALLBACK(src, .proc/Recharge), charge_time) return if(proximity_flag && isliving(target)) @@ -122,12 +129,37 @@ if(user && lavaland_equipment_pressure_check(get_turf(user))) //CIT CHANGE - makes sure below only happens in low pressure environments user.adjustStaminaLoss(-30)//CIT CHANGE - makes crushers heal stamina -/obj/item/twohanded/required/kinetic_crusher/proc/Recharge() +/obj/item/twohanded/kinetic_crusher/proc/Recharge() if(!charged) charged = TRUE - icon_state = "mining_hammer1" + update_icon() playsound(src.loc, 'sound/weapons/kenetic_reload.ogg', 60, 1) +/obj/item/twohanded/kinetic_crusher/ui_action_click(mob/user, actiontype) + light_on = !light_on + playsound(user, 'sound/weapons/empty.ogg', 100, TRUE) + update_brightness(user) + update_icon() + +/obj/item/twohanded/kinetic_crusher/proc/update_brightness(mob/user = null) + if(light_on) + set_light(brightness_on) + else + set_light(0) + +/obj/item/twohanded/kinetic_crusher/update_icon() + ..() + cut_overlays() + if(!charged) + add_overlay("[icon_state]_uncharged") + if(light_on) + add_overlay("[icon_state]_lit") + spawn(1) + for(var/X in actions) + var/datum/action/A = X + A.UpdateButtonIcon() + item_state = "crusher[wielded]" + //destablizing force /obj/item/projectile/destabilizer name = "destabilizing force" @@ -138,7 +170,7 @@ flag = "bomb" range = 6 log_override = TRUE - var/obj/item/twohanded/required/kinetic_crusher/hammer_synced + var/obj/item/twohanded/kinetic_crusher/hammer_synced /obj/item/projectile/destabilizer/Destroy() hammer_synced = null @@ -177,12 +209,12 @@ return "errors" /obj/item/crusher_trophy/attackby(obj/item/A, mob/living/user) - if(istype(A, /obj/item/twohanded/required/kinetic_crusher)) + if(istype(A, /obj/item/twohanded/kinetic_crusher)) add_to(A, user) else ..() -/obj/item/crusher_trophy/proc/add_to(obj/item/twohanded/required/kinetic_crusher/H, mob/living/user) +/obj/item/crusher_trophy/proc/add_to(obj/item/twohanded/kinetic_crusher/H, mob/living/user) for(var/t in H.trophies) var/obj/item/crusher_trophy/T = t if(istype(T, denied_type) || istype(src, T.denied_type)) @@ -194,7 +226,7 @@ to_chat(user, "You attach [src] to [H].") return TRUE -/obj/item/crusher_trophy/proc/remove_from(obj/item/twohanded/required/kinetic_crusher/H, mob/living/user) +/obj/item/crusher_trophy/proc/remove_from(obj/item/twohanded/kinetic_crusher/H, mob/living/user) forceMove(get_turf(H)) H.trophies -= src return TRUE @@ -281,12 +313,12 @@ /obj/item/crusher_trophy/legion_skull/effect_desc() return "a kinetic crusher to recharge [bonus_value*0.1] second\s faster" -/obj/item/crusher_trophy/legion_skull/add_to(obj/item/twohanded/required/kinetic_crusher/H, mob/living/user) +/obj/item/crusher_trophy/legion_skull/add_to(obj/item/twohanded/kinetic_crusher/H, mob/living/user) . = ..() if(.) H.charge_time -= bonus_value -/obj/item/crusher_trophy/legion_skull/remove_from(obj/item/twohanded/required/kinetic_crusher/H, mob/living/user) +/obj/item/crusher_trophy/legion_skull/remove_from(obj/item/twohanded/kinetic_crusher/H, mob/living/user) . = ..() if(.) H.charge_time += bonus_value @@ -339,7 +371,7 @@ /obj/item/crusher_trophy/demon_claws/effect_desc() return "melee hits to do [bonus_value * 0.2] more damage and heal you for [bonus_value * 0.1], with 5X effect on mark detonation" -/obj/item/crusher_trophy/demon_claws/add_to(obj/item/twohanded/required/kinetic_crusher/H, mob/living/user) +/obj/item/crusher_trophy/demon_claws/add_to(obj/item/twohanded/kinetic_crusher/H, mob/living/user) . = ..() if(.) H.force += bonus_value * 0.2 @@ -347,7 +379,7 @@ H.force_wielded += bonus_value * 0.2 H.detonation_damage += bonus_value * 0.8 -/obj/item/crusher_trophy/demon_claws/remove_from(obj/item/twohanded/required/kinetic_crusher/H, mob/living/user) +/obj/item/crusher_trophy/demon_claws/remove_from(obj/item/twohanded/kinetic_crusher/H, mob/living/user) . = ..() if(.) H.force -= bonus_value * 0.2 diff --git a/code/modules/mining/laborcamp/laborstacker.dm b/code/modules/mining/laborcamp/laborstacker.dm index 4a628c5f34..4e54c3e222 100644 --- a/code/modules/mining/laborcamp/laborstacker.dm +++ b/code/modules/mining/laborcamp/laborstacker.dm @@ -10,12 +10,10 @@ GLOBAL_LIST(labor_sheet_values) density = FALSE var/obj/machinery/mineral/stacking_machine/laborstacker/stacking_machine = null var/machinedir = SOUTH - var/obj/item/card/id/prisoner/inserted_id var/obj/machinery/door/airlock/release_door var/door_tag = "prisonshuttle" var/obj/item/radio/Radio //needed to send messages to sec radio - /obj/machinery/mineral/labor_claim_console/Initialize() . = ..() Radio = new/obj/item/radio(src) @@ -34,18 +32,6 @@ GLOBAL_LIST(labor_sheet_values) /proc/cmp_sheet_list(list/a, list/b) return a["value"] - b["value"] -/obj/machinery/mineral/labor_claim_console/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/card/id/prisoner)) - if(!inserted_id) - if(!user.transferItemToLoc(I, src)) - return - inserted_id = I - to_chat(user, "You insert [I].") - return - else - to_chat(user, "There's an ID inserted already.") - return ..() - /obj/machinery/mineral/labor_claim_console/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) @@ -58,14 +44,20 @@ GLOBAL_LIST(labor_sheet_values) var/can_go_home = FALSE data["emagged"] = (obj_flags & EMAGGED) ? 1 : 0 - if(inserted_id) - data["id"] = inserted_id - data["id_name"] = inserted_id.registered_name - data["points"] = inserted_id.points - data["goal"] = inserted_id.goal - if(check_auth()) + if(obj_flags & EMAGGED) can_go_home = TRUE + data["status_info"] = "No Prisoner ID detected." + var/obj/item/card/id/I = user.get_idcard(TRUE) + if(istype(I, /obj/item/card/id/prisoner)) + var/obj/item/card/id/prisoner/P = I + data["id_points"] = P.points + if(P.points >= P.goal) + can_go_home = TRUE + data["status_info"] = "Goal met!" + else + data["status_info"] = "You are [(P.goal - P.points)] points away." + if(stacking_machine) data["unclaimed_points"] = stacking_machine.points @@ -78,29 +70,19 @@ GLOBAL_LIST(labor_sheet_values) if(..()) return switch(action) - if("handle_id") - if(inserted_id) - if(!usr.get_active_held_item()) - usr.put_in_hands(inserted_id) - inserted_id = null - else - inserted_id.forceMove(get_turf(src)) - inserted_id = null - else - var/obj/item/I = usr.get_active_held_item() - if(istype(I, /obj/item/card/id/prisoner)) - if(!usr.transferItemToLoc(I, src)) - return - inserted_id = I if("claim_points") - inserted_id.points += stacking_machine.points - stacking_machine.points = 0 - to_chat(usr, "Points transferred.") + var/mob/M = usr + var/obj/item/card/id/I = M.get_idcard(TRUE) + if(istype(I, /obj/item/card/id/prisoner)) + var/obj/item/card/id/prisoner/P = I + P.points += stacking_machine.points + stacking_machine.points = 0 + to_chat(usr, "Points transferred.") + else + to_chat(usr, "No valid id for point transfer detected.") if("move_shuttle") if(!alone_in_area(get_area(src), usr)) to_chat(usr, "Prisoners are only allowed to be released while alone.") - else if(!check_auth()) - to_chat(usr, "Prisoners are only allowed to be released when they reach their point goal.") else switch(SSshuttle.moveShuttle("laborcamp", "laborcamp_home", TRUE)) if(1) @@ -112,14 +94,9 @@ GLOBAL_LIST(labor_sheet_values) else if(!(obj_flags & EMAGGED)) Radio.set_frequency(FREQ_SECURITY) - Radio.talk_into(src, "[inserted_id.registered_name] has returned to the station. Minerals and Prisoner ID card ready for retrieval.", FREQ_SECURITY) + Radio.talk_into(src, "A prisoner has returned to the station. Minerals and Prisoner ID card ready for retrieval.", FREQ_SECURITY) to_chat(usr, "Shuttle received message and will be sent shortly.") -/obj/machinery/mineral/labor_claim_console/proc/check_auth() - if(obj_flags & EMAGGED) - return 1 //Shuttle is emagged, let any ol' person through - return (istype(inserted_id) && inserted_id.points >= inserted_id.goal) //Otherwise, only let them out if the prisoner's reached his quota. - /obj/machinery/mineral/labor_claim_console/proc/locate_stacking_machine() stacking_machine = locate(/obj/machinery/mineral/stacking_machine, get_step(src, machinedir)) if(stacking_machine) @@ -128,14 +105,15 @@ GLOBAL_LIST(labor_sheet_values) qdel(src) /obj/machinery/mineral/labor_claim_console/emag_act(mob/user) - if(!(obj_flags & EMAGGED)) - obj_flags |= EMAGGED - to_chat(user, "PZZTTPFFFT") - + . = ..() + if(obj_flags & EMAGGED) + return + obj_flags |= EMAGGED + to_chat(user, "PZZTTPFFFT") + return TRUE /**********************Prisoner Collection Unit**************************/ - /obj/machinery/mineral/stacking_machine/laborstacker force_connect = TRUE var/points = 0 //The unclaimed value of ore stacked. @@ -151,6 +129,7 @@ GLOBAL_LIST(labor_sheet_values) return ..() /**********************Point Lookup Console**************************/ + /obj/machinery/mineral/labor_points_checker name = "points checking console" desc = "A console used by prisoners to check the progress on their quotas. Simply swipe a prisoner ID." diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm index abcb6d5911..5990c70813 100644 --- a/code/modules/mining/lavaland/necropolis_chests.dm +++ b/code/modules/mining/lavaland/necropolis_chests.dm @@ -641,6 +641,8 @@ nemesis_factions = list("mining", "boss") var/transform_cooldown var/swiping = FALSE + total_mass = 2.75 + total_mass_on = 5 /obj/item/melee/transforming/cleaving_saw/examine(mob/user) ..() @@ -785,30 +787,30 @@ /obj/item/melee/ghost_sword/process() ghost_check() -/obj/item/melee/ghost_sword/proc/ghost_check() - var/ghost_counter = 0 - var/turf/T = get_turf(src) - var/list/contents = T.GetAllContents() - var/mob/dead/observer/current_spirits = list() - for(var/thing in contents) - var/atom/A = thing - A.transfer_observers_to(src) - - for(var/i in orbiters?.orbiters) - if(!isobserver(i)) +/obj/item/melee/ghost_sword/proc/recursive_orbit_collect(atom/A, list/L) + for(var/i in A.orbiters?.orbiters) + if(!isobserver(i) || (i in L)) continue + L |= i + recursive_orbit_collect(i, L) + +/obj/item/melee/ghost_sword/proc/ghost_check() + var/list/mob/dead/observer/current_spirits = list() + + recursive_orbit_collect(src, current_spirits) + recursive_orbit_collect(loc, current_spirits) //anything holding us + + for(var/i in spirits - current_spirits) var/mob/dead/observer/G = i - ghost_counter++ - G.invisibility = 0 - current_spirits |= G - - for(var/mob/dead/observer/G in spirits - current_spirits) G.invisibility = GLOB.observer_default_invisibility - + + for(var/i in current_spirits) + var/mob/dead/observer/G = i + G.invisibility = 0 + spirits = current_spirits - - return ghost_counter - + return length(spirits) + /obj/item/melee/ghost_sword/attack(mob/living/target, mob/living/carbon/human/user) force = 0 var/ghost_counter = ghost_check() @@ -1333,4 +1335,4 @@ if(2) new /obj/item/wisp_lantern(src) if(3) - new /obj/item/prisoncube(src) \ No newline at end of file + new /obj/item/prisoncube(src) diff --git a/code/modules/mining/machine_redemption.dm b/code/modules/mining/machine_redemption.dm index 4605f7d693..6c1a00b020 100644 --- a/code/modules/mining/machine_redemption.dm +++ b/code/modules/mining/machine_redemption.dm @@ -13,7 +13,6 @@ speed_process = TRUE circuit = /obj/item/circuitboard/machine/ore_redemption layer = BELOW_OBJ_LAYER - var/obj/item/card/id/inserted_id var/points = 0 var/ore_pickup_rate = 15 var/sheet_per_ore = 1 @@ -48,18 +47,23 @@ point_upgrade = point_upgrade_temp sheet_per_ore = sheet_per_ore_temp +/obj/machinery/mineral/ore_redemption/examine(mob/user) + . = ..() + if(in_range(user, src) || isobserver(user)) + . += "The status display reads: Smelting [sheet_per_ore] sheet(s) per piece of ore.
Ore pickup speed at [ore_pickup_rate].
" + /obj/machinery/mineral/ore_redemption/proc/smelt_ore(obj/item/stack/ore/O) var/datum/component/material_container/mat_container = materials.mat_container if (!mat_container) return - if(istype(O, /obj/item/stack/ore/bluespace_crystal/refined)) + if(O.refined_type == null) return ore_buffer -= O if(O && O.refined_type) - points += O.points * point_upgrade * O.amount + points += O.points * O.amount var/material_amount = mat_container.get_item_material_amount(O) @@ -72,11 +76,8 @@ else var/mats = O.materials & mat_container.materials var/amount = O.amount - var/id = inserted_id && inserted_id.registered_name - if (id) - id = " (ID: [id])" mat_container.insert_item(O, sheet_per_ore) //insert it - materials.silo_log(src, "smelted", amount, "ores[id]", mats) + materials.silo_log(src, "smelted", amount, "ores", mats) qdel(O) /obj/machinery/mineral/ore_redemption/proc/can_smelt_alloy(datum/design/D) @@ -168,15 +169,7 @@ return if(!powered()) - return - if(istype(W, /obj/item/card/id)) - var/obj/item/card/id/I = user.get_active_held_item() - if(istype(I) && !istype(inserted_id)) - if(!user.transferItemToLoc(I, src)) - return - inserted_id = I - interact(user) - return + return ..() if(istype(W, /obj/item/disk/design_disk)) if(user.transferItemToLoc(W, src)) @@ -205,9 +198,6 @@ /obj/machinery/mineral/ore_redemption/ui_data(mob/user) var/list/data = list() data["unclaimedPoints"] = points - if(inserted_id) - data["hasID"] = TRUE - data["claimedPoints"] = inserted_id.mining_points data["materials"] = list() var/datum/component/material_container/mat_container = materials.mat_container @@ -245,32 +235,24 @@ return var/datum/component/material_container/mat_container = materials.mat_container switch(action) - if("Eject") - if(!inserted_id) - return - usr.put_in_hands(inserted_id) - inserted_id = null - return TRUE - if("Insert") - var/obj/item/card/id/I = usr.get_active_held_item() - if(istype(I)) - if(!usr.transferItemToLoc(I,src)) - return - inserted_id = I - else - to_chat(usr, "Not a valid ID!") - return TRUE if("Claim") - if(inserted_id) - inserted_id.mining_points += points - points = 0 + var/mob/M = usr + var/obj/item/card/id/I = M.get_idcard(TRUE) + if(points) + if(I) + I.mining_points += points + points = 0 + else + to_chat(usr, "No ID detected.") + else + to_chat(usr, "No points to claim.") return TRUE if("Release") if(!mat_container) return if(materials.on_hold()) to_chat(usr, "Mineral access is on hold, please contact the quartermaster.") - else if(!check_access(inserted_id) && !allowed(usr)) //Check the ID inside, otherwise check the user + else if(!allowed(usr)) //Check the ID inside, otherwise check the user to_chat(usr, "Required access not found.") else var/mat_id = params["id"] @@ -293,6 +275,7 @@ var/list/mats = list() mats[mat_id] = MINERAL_MATERIAL_AMOUNT materials.silo_log(src, "released", -count, "sheets", mats) + //Logging deleted for quick coding return TRUE if("diskInsert") var/obj/item/disk/design_disk/disk = usr.get_active_held_item() @@ -321,7 +304,7 @@ return var/alloy_id = params["id"] var/datum/design/alloy = stored_research.isDesignResearchedID(alloy_id) - if((check_access(inserted_id) || allowed(usr)) && alloy) + if((check_access(inserted_scan_id) || allowed(usr)) && alloy) var/smelt_amount = can_smelt_alloy(alloy) var/desired = 0 if (params["sheets"]) diff --git a/code/modules/mining/machine_vending.dm b/code/modules/mining/machine_vending.dm index aed90cebdf..5a48538161 100644 --- a/code/modules/mining/machine_vending.dm +++ b/code/modules/mining/machine_vending.dm @@ -20,6 +20,7 @@ new /datum/data/mining_equipment("Soap", /obj/item/soap/nanotrasen, 200), new /datum/data/mining_equipment("Laser Pointer", /obj/item/laser_pointer, 300), new /datum/data/mining_equipment("Alien Toy", /obj/item/clothing/mask/facehugger/toy, 300), + new /datum/data/mining_equipment("Stabilizing Serum", /obj/item/hivelordstabilizer, 400), new /datum/data/mining_equipment("Fulton Beacon", /obj/item/fulton_core, 400), new /datum/data/mining_equipment("Shelter Capsule", /obj/item/survivalcapsule, 400), new /datum/data/mining_equipment("Survival Knife", /obj/item/kitchen/knife/combat/survival, 450), @@ -28,11 +29,10 @@ new /datum/data/mining_equipment("Larger Ore Bag", /obj/item/storage/bag/ore/large, 500), new /datum/data/mining_equipment("500 Point Transfer Card", /obj/item/card/mining_point_card/mp500, 500), new /datum/data/mining_equipment("Tracking Implant Kit", /obj/item/storage/box/minertracker, 600), - new /datum/data/mining_equipment("Survival Medipen", /obj/item/reagent_containers/hypospray/medipen/survival, 750), - new /datum/data/mining_equipment("Stabilizing Serum", /obj/item/hivelordstabilizer, 750), new /datum/data/mining_equipment("Jaunter", /obj/item/wormhole_jaunter, 750), - new /datum/data/mining_equipment("Kinetic Crusher", /obj/item/twohanded/required/kinetic_crusher, 750), + new /datum/data/mining_equipment("Kinetic Crusher", /obj/item/twohanded/kinetic_crusher, 750), new /datum/data/mining_equipment("Kinetic Accelerator", /obj/item/gun/energy/kinetic_accelerator, 750), + new /datum/data/mining_equipment("Survival Medipen", /obj/item/reagent_containers/hypospray/medipen/survival, 750), new /datum/data/mining_equipment("Brute First-Aid Kit", /obj/item/storage/firstaid/brute, 800), new /datum/data/mining_equipment("Burn First-Aid Kit", /obj/item/storage/firstaid/fire, 800), new /datum/data/mining_equipment("First-Aid Kit", /obj/item/storage/firstaid/regular, 800), @@ -54,7 +54,6 @@ new /datum/data/mining_equipment("Super Resonator", /obj/item/resonator/upgraded, 2500), new /datum/data/mining_equipment("Jump Boots", /obj/item/clothing/shoes/bhop, 2500), new /datum/data/mining_equipment("Luxury Shelter Capsule", /obj/item/survivalcapsule/luxury, 3000), - new /datum/data/mining_equipment("Miner Full Replacement", /obj/item/storage/backpack/duffelbag/mining_cloned, 3000), new /datum/data/mining_equipment("Nanotrasen Minebot", /mob/living/simple_animal/hostile/mining_drone, 800), new /datum/data/mining_equipment("Minebot Melee Upgrade", /obj/item/mine_bot_upgrade, 400), new /datum/data/mining_equipment("Minebot Armor Upgrade", /obj/item/mine_bot_upgrade/health, 400), @@ -69,8 +68,8 @@ new /datum/data/mining_equipment("KA Damage Increase", /obj/item/borg/upgrade/modkit/damage, 1000), new /datum/data/mining_equipment("KA Cooldown Decrease", /obj/item/borg/upgrade/modkit/cooldown, 1000), new /datum/data/mining_equipment("KA AoE Damage", /obj/item/borg/upgrade/modkit/aoe/mobs, 2000), + new /datum/data/mining_equipment("Miner Full Replacement", /obj/item/storage/backpack/duffelbag/mining_cloned, 3000), new /datum/data/mining_equipment("Premium Accelerator", /obj/item/gun/energy/kinetic_accelerator/premiumka, 8000) - ) /datum/data/mining_equipment @@ -95,60 +94,42 @@ /obj/machinery/mineral/equipment_vendor/ui_interact(mob/user) . = ..() - var/dat - dat +="
" - if(istype(inserted_id)) - dat += "You have [inserted_id.mining_points] mining points collected. Eject ID.
" - else - dat += "No ID inserted. Insert ID.
" - dat += "
" + var/list/dat = list() dat += "
Equipment point cost list:
- + "} dat += "" dat += {" @@ -309,36 +288,39 @@ What a mess.*/ active1 = null active2 = null - if("Confirm Identity") - eject_id(usr) - if("Log Out") authenticated = null screen = null active1 = null active2 = null + playsound(src, 'sound/machines/terminal_off.ogg', 50, FALSE) if("Log In") - if(issilicon(usr)) - var/mob/living/silicon/borg = usr + var/mob/M = usr + var/obj/item/card/id/I = M.get_idcard(TRUE) + if(issilicon(M)) + var/mob/living/silicon/borg = M active1 = null active2 = null authenticated = borg.name rank = "AI" screen = 1 - else if(IsAdminGhost(usr)) + else if(IsAdminGhost(M)) active1 = null active2 = null - authenticated = usr.client.holder.admin_signature + authenticated = M.client.holder.admin_signature rank = "Central Command" screen = 1 - else if(istype(scan, /obj/item/card/id)) + else if(I && check_access(I)) active1 = null active2 = null - if(check_access(scan)) - authenticated = scan.registered_name - rank = scan.assignment - screen = 1 + authenticated = I.registered_name + rank = I.assignment + screen = 1 + else + to_chat(usr, "Unauthorized Access.") + playsound(src, 'sound/machines/terminal_on.ogg', 50, FALSE) + //RECORD FUNCTIONS if("Record Maintenance") screen = 2 @@ -346,16 +328,14 @@ What a mess.*/ active2 = null if("Browse Record") - var/datum/data/record/R = locate(href_list["d_rec"]) - var/S = locate(href_list["d_rec"]) - if(!( GLOB.data_core.general.Find(R) )) + var/datum/data/record/R = locate(href_list["d_rec"]) in GLOB.data_core.general + if(!R) temp = "Record Not Found!" else + active1 = active2 = R for(var/datum/data/record/E in GLOB.data_core.security) if((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) - S = E - active1 = R - active2 = S + active2 = E screen = 3 @@ -368,7 +348,7 @@ What a mess.*/ var/obj/item/paper/P = new /obj/item/paper( loc ) P.info = "
Security Record - (SR-[GLOB.data_core.securityPrintCount])

" if((istype(active1, /datum/data/record) && GLOB.data_core.general.Find(active1))) - P.info += text("Name: [] ID: []
\nSex: []
\nAge: []
", active1.fields["name"], active1.fields["id"], active1.fields["sex"], active1.fields["age"]) + P.info += text("Name: [] ID: []
\nGender: []
\nAge: []
", active1.fields["name"], active1.fields["id"], active1.fields["gender"], active1.fields["age"]) P.info += "\nSpecies: [active1.fields["species"]]
" P.info += text("\nFingerprint: []
\nPhysical Status: []
\nMental Status: []
", active1.fields["fingerprint"], active1.fields["p_stat"], active1.fields["m_stat"]) else @@ -419,6 +399,7 @@ What a mess.*/ P.info += "Security Record Lost!
" P.name = text("SR-[] '[]'", GLOB.data_core.securityPrintCount, "Record Lost") P.info += "" + P.update_icon() printing = null if("Print Poster") if(!( printing )) @@ -512,7 +493,7 @@ What a mess.*/ G.fields["name"] = "New Record" G.fields["id"] = "[num2hex(rand(1, 1.6777215E7), 6)]" G.fields["rank"] = "Unassigned" - G.fields["sex"] = "Male" + G.fields["gender"] = "Male" G.fields["age"] = "Unknown" G.fields["species"] = "Human" G.fields["photo_front"] = new /icon() @@ -584,12 +565,14 @@ What a mess.*/ if(!canUseSecurityRecordsConsole(usr, t1, a1)) return active1.fields["fingerprint"] = t1 - if("sex") + if("gender") if(istype(active1, /datum/data/record)) - if(active1.fields["sex"] == "Male") - active1.fields["sex"] = "Female" + if(active1.fields["gender"] == "Male") + active1.fields["gender"] = "Female" + else if(active1.fields["gender"] == "Female") + active1.fields["gender"] = "Other" else - active1.fields["sex"] = "Male" + active1.fields["gender"] = "Male" if("age") if(istype(active1, /datum/data/record)) var/t1 = input("Please input age:", "Secure. records", active1.fields["age"], null) as num @@ -767,19 +750,14 @@ What a mess.*/ P = user.get_active_held_item() return P -/obj/machinery/computer/secure_data/proc/print_photo(icon/temp, name) +/obj/machinery/computer/secure_data/proc/print_photo(icon/temp, person_name) if (printing) return printing = TRUE sleep(20) var/obj/item/photo/P = new/obj/item/photo(drop_location()) - var/icon/small_img = icon(temp) - var/icon/ic = icon('icons/obj/items_and_weapons.dmi',"photo") - small_img.Scale(8, 8) - ic.Blend(small_img,ICON_OVERLAY, 13, 13) - P.icon = ic - P.picture.picture_image = temp - P.desc = "The photo on file for [name]." + var/datum/picture/toEmbed = new(name = person_name, desc = "The photo on file for [person_name].", image = temp) + P.set_picture(toEmbed, TRUE, TRUE) P.pixel_x = rand(-10, 10) P.pixel_y = rand(-10, 10) printing = FALSE @@ -799,7 +777,7 @@ What a mess.*/ else R.fields["name"] = "[pick(pick(GLOB.first_names_male), pick(GLOB.first_names_female))] [pick(GLOB.last_names)]" if(2) - R.fields["sex"] = pick("Male", "Female") + R.fields["gender"] = pick("Male", "Female", "Other") if(3) R.fields["age"] = rand(5, 85) if(4) @@ -823,7 +801,7 @@ What a mess.*/ /obj/machinery/computer/secure_data/proc/canUseSecurityRecordsConsole(mob/user, message1 = 0, record1, record2) if(user) if(authenticated) - if(user.canUseTopic(src)) + if(user.canUseTopic(src, !issilicon(user))) if(!trim(message1)) return 0 if(!record1 || record1 == active1) @@ -831,22 +809,3 @@ What a mess.*/ return 1 return 0 -/obj/machinery/computer/secure_data/AltClick(mob/user) - if(user.canUseTopic(src)) - eject_id(user) - -/obj/machinery/computer/secure_data/proc/eject_id(mob/user) - if(scan) - scan.forceMove(drop_location()) - if(!issilicon(user) && Adjacent(user)) - user.put_in_hands(scan) - scan = null - playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0) - else //switching the ID with the one you're holding - if(issilicon(user) || !Adjacent(user)) - return - var/obj/item/card/id/held_id = user.is_holding_item_of_type(/obj/item/card/id) - if(QDELETED(held_id) || !user.transferItemToLoc(held_id, src)) - return - scan = held_id - playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0) diff --git a/code/game/machinery/computer/teleporter.dm b/code/game/machinery/computer/teleporter.dm index b9b95eecd0..f4f20aecc9 100644 --- a/code/game/machinery/computer/teleporter.dm +++ b/code/game/machinery/computer/teleporter.dm @@ -10,6 +10,7 @@ var/obj/machinery/teleport/station/power_station var/calibrating var/turf/target + var/obj/item/implant/imp_t /obj/machinery/computer/teleporter/Initialize() . = ..() @@ -109,6 +110,9 @@ /obj/machinery/computer/teleporter/proc/reset_regime() target = null + if(imp_t) + UnregisterSignal(imp_t, COMSIG_IMPLANT_REMOVING) + imp_t = null if(regime_set == "Teleporter") regime_set = "Gate" else @@ -124,18 +128,32 @@ L[avoid_assoc_duplicate_keys(A.name, areaindex)] = R for(var/obj/item/implant/tracking/I in GLOB.tracked_implants) - if(!I.imp_in || !isliving(I.loc)) + if(!I.imp_in || !isliving(I.imp_in)) continue else - var/mob/living/M = I.loc + var/mob/living/M = I.imp_in if(M.stat == DEAD) if(M.timeofdeath + 6000 < world.time) continue - if(is_eligible(I)) - L[avoid_assoc_duplicate_keys(M.real_name, areaindex)] = I + if(is_eligible(M)) + L[avoid_assoc_duplicate_keys(M.real_name, areaindex)] = M var/desc = input("Please select a location to lock in.", "Locking Computer") as null|anything in L + if(!user.canUseTopic(src, !issilicon(user), NO_DEXTERY)) //check if we are still around + return target = L[desc] + if(imp_t) + UnregisterSignal(imp_t, COMSIG_IMPLANT_REMOVING) + imp_t = null + if(isliving(target)) //make sure the living mob is still implanted to be a valid target + var/mob/living/M = target + var/obj/item/implant/tracking/I = locate() in M.implants + if(I) + RegisterSignal(I, COMSIG_IMPLANT_REMOVING, .proc/untarget_implant) + imp_t = I + else + target = null + return var/turf/T = get_turf(target) log_game("[key_name(user)] has set the teleporter target to [target] at [AREACOORD(T)]") @@ -149,6 +167,8 @@ to_chat(user, "No active connected stations located.") return var/desc = input("Please select a station to lock in.", "Locking Computer") as null|anything in L + if(!user.canUseTopic(src, !issilicon(user), NO_DEXTERY)) //again, check if we are still around + return var/obj/machinery/teleport/station/target_station = L[desc] if(!target_station || !target_station.teleporter_hub) return @@ -164,6 +184,14 @@ target_station.teleporter_console.stat &= ~NOPOWER target_station.teleporter_console.update_icon() +/obj/machinery/computer/teleporter/proc/untarget_implant() //untargets from mob the racker was once implanted in to prevent issues. + target = null + if(power_station) + power_station.engaged = FALSE + power_station.teleporter_hub?.update_icon() + UnregisterSignal(imp_t, COMSIG_IMPLANT_REMOVING) + imp_t = null + /obj/machinery/computer/teleporter/proc/is_eligible(atom/movable/AM) var/turf/T = get_turf(AM) if(!T) diff --git a/modular_citadel/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm similarity index 69% rename from modular_citadel/code/game/machinery/cryopod.dm rename to code/game/machinery/cryopod.dm index 15e7d34c65..e358f10346 100644 --- a/modular_citadel/code/game/machinery/cryopod.dm +++ b/code/game/machinery/cryopod.dm @@ -20,105 +20,146 @@ req_one_access = list(ACCESS_HEADS, ACCESS_ARMORY) //Heads of staff or the warden can go here to claim recover items from their department that people went were cryodormed with. var/mode = null + var/menu = 1 //Which menu screen to display + //Used for logging people entering cryosleep and important items they are carrying. var/list/frozen_crew = list() var/list/frozen_items = list() - var/storage_type = "crewmembers" - var/storage_name = "Cryogenic Oversight Control" + // Used for containing rare items traitors need to steal, so it's not + // game-over if they get iced + var/list/objective_items = list() + // A cache of theft datums so you don't have to re-create them for + // each item check + var/list/theft_cache = list() + var/allow_items = TRUE +/obj/machinery/computer/cryopod/attack_ai() + attack_hand() + /obj/machinery/computer/cryopod/ui_interact(mob/user = usr) - . = ..() + if(!is_operational()) + return user.set_machine(src) add_fingerprint(user) - var/dat + var/dat = "" - dat += "

[storage_name]
" - dat += "Welcome, [user.real_name].


" - dat += "View storage log.
" - if(allow_items) - dat += "View objects.
" - dat += "Recover object.
" - dat += "Recover all objects.
" + dat += "

Welcome, [user.real_name].


" + dat += "

" - user << browse(dat, "window=cryopod_console") - onclose(user, "cryopod_console") + switch(src.menu) + if(1) + dat += "View crew storage log

" + if(allow_items) + dat += "View objects storage log

" + dat += "Recover object

" + dat += "Recover all objects
" + if(2) + dat += "<< Back

" + dat += "

Recently stored Crew




" + if(!frozen_crew.len) + dat += "There has been no storage usage at this terminal.
" + else + for(var/person in frozen_crew) + dat += "[person]
" + dat += "
" + if(3) + dat += "<< Back

" + dat += "

Recently stored objects




" + if(!frozen_items.len) + dat += "There has been no storage usage at this terminal.
" + else + for(var/obj/item/I in frozen_items) + dat += "[I.name]
" + dat += "
" + + var/datum/browser/popup = new(user, "cryopod_console", "Cryogenic System Control") + popup.set_content(dat) + popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) + popup.open() /obj/machinery/computer/cryopod/Topic(href, href_list) if(..()) - return 1 + return TRUE var/mob/user = usr add_fingerprint(user) - if(href_list["log"]) - - var/dat = "Recently stored [storage_type]


" - for(var/person in frozen_crew) - dat += "[person]
" - dat += "
" - - user << browse(dat, "window=cryolog") - - if(href_list["view"]) - if(!allow_items) return - - var/dat = "Recently stored objects


" - for(var/obj/item/I in frozen_items) - dat += "[I.name]
" - dat += "
" - - user << browse(dat, "window=cryoitems") - - else if(href_list["item"]) + if(href_list["item"]) if(!allowed(user)) to_chat(user, "Access Denied.") + playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0) + updateUsrDialog() return if(!allow_items) return if(frozen_items.len == 0) to_chat(user, "There is nothing to recover from storage.") + playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0) + updateUsrDialog() return var/obj/item/I = input(user, "Please choose which object to retrieve.","Object recovery",null) as null|anything in frozen_items + playsound(src, "terminal_type", 25, 0) if(!I) return if(!(I in frozen_items)) to_chat(user, "\The [I] is no longer in storage.") + playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0) + updateUsrDialog() return visible_message("The console beeps happily as it disgorges \the [I].") + playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0) - I.forceMove(get_turf(src)) + I.forceMove(drop_location()) + if(user && Adjacent(user) && !issiliconoradminghost(user)) + user.put_in_hands(I) frozen_items -= I + updateUsrDialog() else if(href_list["allitems"]) + playsound(src, "terminal_type", 25, 0) if(!allowed(user)) to_chat(user, "Access Denied.") + playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0) + updateUsrDialog() return if(!allow_items) return if(frozen_items.len == 0) to_chat(user, "There is nothing to recover from storage.") + playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0) return visible_message("The console beeps happily as it disgorges the desired objects.") + playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0) for(var/obj/item/I in frozen_items) - I.forceMove(get_turf(src)) + I.forceMove(drop_location()) frozen_items -= I + updateUsrDialog() + else if (href_list["menu"]) + src.menu = text2num(href_list["menu"]) + playsound(src, "terminal_type", 25, 0) + updateUsrDialog() + + ui_interact(usr) updateUsrDialog() + return /obj/item/circuitboard/cryopodcontrol name = "Circuit board (Cryogenic Oversight Console)" build_path = "/obj/machinery/computer/cryopod" +/obj/machinery/computer/cryopod/contents_explosion() + return //Cryopods themselves. /obj/machinery/cryopod @@ -176,16 +217,17 @@ /obj/item/gun/energy/laser/cyborg ) -/obj/machinery/cryopod/Initialize() +/obj/machinery/cryopod/Initialize(mapload) . = ..() update_icon() - find_control_computer(TRUE) + find_control_computer(mapload) /obj/machinery/cryopod/proc/find_control_computer(urgent = FALSE) for(var/obj/machinery/computer/cryopod/C in get_area(src)) control_computer = C if(C) return C + break // Don't send messages unless we *need* the computer, and less than five minutes have passed since last time we messaged if(!control_computer && urgent && last_no_computer_message + 5*60*10 < world.time) @@ -193,7 +235,7 @@ message_admins("Cryopod in [get_area(src)] could not find control computer!") last_no_computer_message = world.time - return null + return control_computer != null /obj/machinery/cryopod/close_machine(mob/user) if(!control_computer) @@ -242,10 +284,75 @@ despawn_occupant() +#define CRYO_DESTROY 0 +#define CRYO_PRESERVE 1 +#define CRYO_OBJECTIVE 2 + +/obj/machinery/cryopod/proc/should_preserve_item(obj/item/I) + for(var/datum/objective_item/steal/T in control_computer.theft_cache) + if(istype(I, T.targetitem) && T.check_special_completion(I)) + return CRYO_OBJECTIVE + for(var/T in preserve_items) + if(istype(I, T) && !(I.type in do_not_preserve_items)) + return CRYO_PRESERVE + return CRYO_DESTROY + // This function can not be undone; do not call this unless you are sure /obj/machinery/cryopod/proc/despawn_occupant() + if(!control_computer) + find_control_computer() + var/mob/living/mob_occupant = occupant + //Handle Borg stuff first + if(iscyborg(mob_occupant)) + var/mob/living/silicon/robot/R = mob_occupant + if(!istype(R)) return ..() + + R.contents -= R.mmi + qdel(R.mmi) + for(var/obj/item/I in R.module) // the tools the borg has; metal, glass, guns etc + for(var/obj/item/O in I) // the things inside the tools, if anything; mainly for janiborg trash bags + if(should_preserve_item(O) != CRYO_DESTROY) // Preserve important things inside the item + continue + O.forceMove(src) + R.module.remove_module(I, TRUE) //delete the module itself so it doesn't transfer over. + + //Drop all items into the pod. + for(var/obj/item/I in mob_occupant) + mob_occupant.doUnEquip(I) + I.forceMove(src) + + if(I.contents.len) //Make sure we catch anything not handled by qdel() on the items. + if(should_preserve_item(I) != CRYO_DESTROY) // Don't remove the contents of things that need preservation + continue + for(var/obj/item/O in I.contents) + if(istype(O, /obj/item/tank)) //Stop eating pockets, you fuck! + continue + O.forceMove(src) + + //Delete all items not on the preservation list. + var/list/items = contents + items -= mob_occupant // Don't delete the occupant + + for(var/obj/item/I in items) + if(istype(I, /obj/item/pda)) + var/obj/item/pda/P = I + QDEL_NULL(P.id) + qdel(P) + continue + + var/preserve = should_preserve_item(I) + if(preserve == CRYO_DESTROY) + qdel(I) + else if(control_computer && control_computer.allow_items) + control_computer.frozen_items += I + if(preserve == CRYO_OBJECTIVE) + control_computer.objective_items += I + I.loc = null + else + I.forceMove(loc) + //Update any existing objectives involving this mob. for(var/datum/objective/O in GLOB.objectives) // We don't want revs to get objectives that aren't for heads of staff. Letting @@ -302,30 +409,6 @@ announcer.announce("CRYOSTORAGE", mob_occupant.real_name, announce_rank, list()) visible_message("\The [src] hums and hisses as it moves [mob_occupant.real_name] into storage.") - - for(var/obj/item/W in mob_occupant.GetAllContents()) - if(W.loc.loc && (( W.loc.loc == loc ) || (W.loc.loc == control_computer))) - continue//means we already moved whatever this thing was in - //I'm a professional, okay - for(var/T in preserve_items) - if(istype(W, T)) - if(control_computer && control_computer.allow_items) - control_computer.frozen_items += W - mob_occupant.transferItemToLoc(W, control_computer, TRUE) - else - mob_occupant.transferItemToLoc(W, loc, TRUE) - - for(var/obj/item/W in mob_occupant.GetAllContents()) - qdel(W)//because we moved all items to preserve away - //and yes, this totally deletes their bodyparts one by one, I just couldn't bother - - if(iscyborg(mob_occupant)) - var/mob/living/silicon/robot/R = occupant - if(!istype(R)) return ..() - - R.contents -= R.mmi - qdel(R.mmi) - // Ghost and delete the mob. if(!mob_occupant.get_ghost(1)) mob_occupant.ghostize(0) // Players who cryo out may not re-enter the round @@ -334,6 +417,10 @@ open_machine() name = initial(name) +#undef CRYO_DESTROY +#undef CRYO_PRESERVE +#undef CRYO_OBJECTIVE + /obj/machinery/cryopod/MouseDrop_T(mob/living/target, mob/user) if(!istype(target) || user.incapacitated() || !target.Adjacent(user) || !Adjacent(user) || !ismob(target) || (!ishuman(user) && !iscyborg(user)) || !istype(user.loc, /turf) || target.buckled) return @@ -358,7 +445,7 @@ var/generic_plsnoleave_message = " Please adminhelp before leaving the round, even if there are no administrators online!" - if(target == user && world.time - target.client.cryo_warned > 5 * 600)//if we haven't warned them in the last 5 minutes + if(target == user && world.time - target.client.cryo_warned > 5 MINUTES)//if we haven't warned them in the last 5 minutes var/caught = FALSE if(target.mind.assigned_role in GLOB.command_positions) alert("You're a Head of Staff![generic_plsnoleave_message] Be sure to put your locker items back into your locker!") @@ -366,13 +453,13 @@ if(iscultist(target) || is_servant_of_ratvar(target)) to_chat(target, "You're a Cultist![generic_plsnoleave_message]") caught = TRUE - if(istype(SSticker.mode, /datum/antagonist/blob)) - if(target.mind in GLOB.overminds) - alert("You're a Blob![generic_plsnoleave_message]") - caught = TRUE if(is_devil(target)) alert("You're a Devil![generic_plsnoleave_message]") caught = TRUE + if(istype(SSticker.mode, /datum/antagonist/gang)) + if(target.mind.has_antag_datum(/datum/antagonist/gang)) + alert("You're a Gangster![generic_plsnoleave_message]") + caught = TRUE if(istype(SSticker.mode, /datum/antagonist/rev)) if(target.mind.has_antag_datum(/datum/antagonist/rev/head)) alert("You're a Head Revolutionary![generic_plsnoleave_message]") @@ -385,8 +472,9 @@ target.client.cryo_warned = world.time return - if(!Adjacent(user)) + if(!target || user.incapacitated() || !target.Adjacent(user) || !Adjacent(user) || (!ishuman(user) && !iscyborg(user)) || !istype(user.loc, /turf) || target.buckled) return + //rerun the checks in case of shenanigans if(target == user) visible_message("[user] starts climbing into the cryo pod.") @@ -396,7 +484,6 @@ if(occupant) to_chat(user, "\The [src] is in use.") return - close_machine(target) to_chat(target, "If you ghost, log out or close your client now, your character will shortly be permanently removed from the round.") @@ -407,4 +494,4 @@ //Attacks/effects. /obj/machinery/cryopod/blob_act() - return //Sorta gamey, but we don't really want these to be destroyed. + return //Sorta gamey, but we don't really want these to be destroyed. \ No newline at end of file diff --git a/code/game/machinery/dna_scanner.dm b/code/game/machinery/dna_scanner.dm index 7895fb8c9f..c9e1e7195b 100644 --- a/code/game/machinery/dna_scanner.dm +++ b/code/game/machinery/dna_scanner.dm @@ -89,11 +89,11 @@ return C return null -/obj/machinery/dna_scannernew/close_machine(mob/living/carbon/user) +/obj/machinery/dna_scannernew/close_machine(atom/movable/target) if(!state_open) return FALSE - ..(user) + ..(target) // search for ghosts, if the corpse is empty and the scanner is connected to a cloner var/mob/living/mob_occupant = get_mob_or_brainmob(occupant) @@ -111,7 +111,7 @@ return TRUE /obj/machinery/dna_scannernew/open_machine() - if(state_open) + if(state_open || panel_open) return FALSE ..() @@ -126,23 +126,48 @@ return open_machine() -/obj/machinery/dna_scannernew/attackby(obj/item/I, mob/user, params) - - if(!occupant && default_deconstruction_screwdriver(user, icon_state, icon_state, I))//sent icon_state is irrelevant... - update_icon()//..since we're updating the icon here, since the scanner can be unpowered when opened/closed +/obj/machinery/dna_scannernew/screwdriver_act(mob/living/user, obj/item/I) + . = TRUE + if(..()) return + if(occupant) + to_chat(user, "[src] is currently occupied!") + return + if(state_open) + to_chat(user, "[src] must be closed to [panel_open ? "close" : "open"] its maintenance hatch!") + return + if(default_deconstruction_screwdriver(user, icon_state, icon_state, I)) //sent icon_state is irrelevant... + update_icon() //..since we're updating the icon here, since the scanner can be unpowered when opened/closed + return + return FALSE +/obj/machinery/dna_scannernew/wrench_act(mob/living/user, obj/item/I) + . = ..() + if(default_change_direction_wrench(user, I)) + return TRUE + +/obj/machinery/dna_scannernew/crowbar_act(mob/living/user, obj/item/I) + . = ..() if(default_pry_open(I)) - return - + return TRUE if(default_deconstruction_crowbar(I)) - return + return TRUE - return ..() +/obj/machinery/dna_scannernew/default_pry_open(obj/item/I) //wew + . = !(state_open || panel_open || (flags_1 & NODECONSTRUCT_1)) && I.tool_behaviour == TOOL_CROWBAR + if(.) + I.play_tool_sound(src, 50) + visible_message("[usr] pries open [src].", "You pry open [src].") + open_machine() /obj/machinery/dna_scannernew/interact(mob/user) toggle_open(user) +/obj/machinery/dna_scannernew/AltClick(mob/user) + if(!user.canUseTopic(src, !issilicon(user))) + return + interact(user) + /obj/machinery/dna_scannernew/MouseDrop_T(mob/target, mob/user) if(user.stat || user.lying || !Adjacent(user) || !user.Adjacent(target) || !iscarbon(target) || !user.IsAdvancedToolUser()) return diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 1081cb5fa7..365d19b826 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -1280,20 +1280,23 @@ return !density || (check_access(ID) && !locked && hasPower()) /obj/machinery/door/airlock/emag_act(mob/user) - if(!operating && density && hasPower() && !(obj_flags & EMAGGED)) - operating = TRUE - update_icon(AIRLOCK_EMAG, 1) - sleep(6) - if(QDELETED(src)) - return - operating = FALSE - if(!open()) - update_icon(AIRLOCK_CLOSED, 1) - obj_flags |= EMAGGED - lights = FALSE - locked = TRUE - loseMainPower() - loseBackupPower() + . = ..() + if(operating || !density || !hasPower() || obj_flags & EMAGGED) + return + operating = TRUE + update_icon(AIRLOCK_EMAG, 1) + addtimer(CALLBACK(src, .proc/open_sesame), 6) + return TRUE + +/obj/machinery/door/airlock/proc/open_sesame() + operating = FALSE + if(!open()) + update_icon(AIRLOCK_CLOSED, 1) + obj_flags |= EMAGGED + lights = FALSE + locked = TRUE + loseMainPower() + loseBackupPower() /obj/machinery/door/airlock/attack_alien(mob/living/carbon/alien/humanoid/user) add_fingerprint(user) diff --git a/code/game/machinery/doors/unpowered.dm b/code/game/machinery/doors/unpowered.dm index 2e7e7d5cba..702f700617 100644 --- a/code/game/machinery/doors/unpowered.dm +++ b/code/game/machinery/doors/unpowered.dm @@ -13,9 +13,6 @@ else return ..() -/obj/machinery/door/unpowered/emag_act() - return - /obj/machinery/door/unpowered/shuttle icon = 'icons/turf/shuttle.dmi' name = "door" diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm index 97ab664b85..933bb4f42a 100644 --- a/code/game/machinery/doors/windowdoor.dm +++ b/code/game/machinery/doors/windowdoor.dm @@ -206,15 +206,20 @@ ..() /obj/machinery/door/window/emag_act(mob/user) - if(!operating && density && !(obj_flags & EMAGGED)) - obj_flags |= EMAGGED - operating = TRUE - flick("[src.base_state]spark", src) - playsound(src, "sparks", 75, 1) - sleep(6) - operating = FALSE - desc += "
Its access panel is smoking slightly." - open(2) + . = ..() + if(operating || !density || obj_flags & EMAGGED) + return + obj_flags |= EMAGGED + operating = TRUE + flick("[src.base_state]spark", src) + playsound(src, "sparks", 75, 1) + addtimer(CALLBACK(src, .proc/open_windows_me), 6) + return TRUE + +/obj/machinery/door/window/proc/open_windows_me() + operating = FALSE + desc += "
Its access panel is smoking slightly." + open(2) /obj/machinery/door/window/attackby(obj/item/I, mob/living/user, params) diff --git a/code/game/machinery/embedded_controller/access_controller.dm b/code/game/machinery/embedded_controller/access_controller.dm index 70ce3d36ae..3b9322d207 100644 --- a/code/game/machinery/embedded_controller/access_controller.dm +++ b/code/game/machinery/embedded_controller/access_controller.dm @@ -26,6 +26,7 @@ findObjsByTag() /obj/machinery/doorButtons/emag_act(mob/user) + . = ..() if(obj_flags & EMAGGED) return obj_flags |= EMAGGED @@ -33,6 +34,7 @@ req_one_access = list() playsound(src, "sparks", 100, 1) to_chat(user, "You short out the access controller.") + return TRUE /obj/machinery/doorButtons/proc/removeMe() diff --git a/code/game/machinery/exp_cloner.dm b/code/game/machinery/exp_cloner.dm index e8364d2271..25e5948b51 100644 --- a/code/game/machinery/exp_cloner.dm +++ b/code/game/machinery/exp_cloner.dm @@ -42,17 +42,18 @@ icon_state = "pod_1" //Get the clone body ready maim_clone(H) - ADD_TRAIT(H, TRAIT_STABLEHEART, "cloning") - ADD_TRAIT(H, TRAIT_EMOTEMUTE, "cloning") - ADD_TRAIT(H, TRAIT_MUTE, "cloning") - ADD_TRAIT(H, TRAIT_NOBREATH, "cloning") - ADD_TRAIT(H, TRAIT_NOCRITDAMAGE, "cloning") + ADD_TRAIT(H, TRAIT_STABLEHEART, CLONING_POD_TRAIT) + ADD_TRAIT(H, TRAIT_STABLELIVER, CLONING_POD_TRAIT) + ADD_TRAIT(H, TRAIT_EMOTEMUTE, CLONING_POD_TRAIT) + ADD_TRAIT(H, TRAIT_MUTE, CLONING_POD_TRAIT) + ADD_TRAIT(H, TRAIT_NOBREATH, CLONING_POD_TRAIT) + ADD_TRAIT(H, TRAIT_NOCRITDAMAGE, CLONING_POD_TRAIT) H.Unconscious(80) - var/list/candidates = pollCandidatesForMob("Do you want to play as [clonename]'s defective clone?", null, null, null, 100, H) + var/list/candidates = pollCandidatesForMob("Do you want and agree to play as a [clonename]'s defective clone, respect their character and not engage in ERP without permission from the original?", null, null, null, 100, H, POLL_IGNORE_CLONE) if(LAZYLEN(candidates)) var/mob/dead/observer/C = pick(candidates) - H.key = C.key + C.transfer_ckey(H) if(grab_ghost_when == CLONER_FRESH_CLONE) H.grab_ghost() diff --git a/code/game/machinery/firealarm.dm b/code/game/machinery/firealarm.dm index 8f0d56a49e..5c2676c2b9 100644 --- a/code/game/machinery/firealarm.dm +++ b/code/game/machinery/firealarm.dm @@ -97,6 +97,7 @@ alarm() /obj/machinery/firealarm/emag_act(mob/user) + . = ..() if(obj_flags & EMAGGED) return obj_flags |= EMAGGED @@ -104,6 +105,7 @@ user.visible_message("Sparks fly out of [src]!", "You emag [src], disabling its thermal sensors.") playsound(src, "sparks", 50, 1) + return TRUE /obj/machinery/firealarm/temperature_expose(datum/gas_mixture/air, temperature, volume) if((temperature > T0C + 200 || temperature < BODYTEMP_COLD_DAMAGE_LIMIT) && (last_alarm+FIREALARM_COOLDOWN < world.time) && !(obj_flags & EMAGGED) && detecting && !stat) diff --git a/code/game/machinery/gulag_item_reclaimer.dm b/code/game/machinery/gulag_item_reclaimer.dm index f6cb58bbbc..f51c145635 100644 --- a/code/game/machinery/gulag_item_reclaimer.dm +++ b/code/game/machinery/gulag_item_reclaimer.dm @@ -9,7 +9,6 @@ idle_power_usage = 100 active_power_usage = 2500 var/list/stored_items = list() - var/obj/item/card/id/prisoner/inserted_id = null var/obj/machinery/gulag_teleporter/linked_teleporter = null /obj/machinery/gulag_item_reclaimer/Destroy() @@ -18,28 +17,15 @@ I.forceMove(get_turf(src)) if(linked_teleporter) linked_teleporter.linked_reclaimer = null - if(inserted_id) - inserted_id.forceMove(get_turf(src)) - inserted_id = null return ..() /obj/machinery/gulag_item_reclaimer/emag_act(mob/user) + . = ..() if(obj_flags & EMAGGED) // emagging lets anyone reclaim all the items return req_access = list() obj_flags |= EMAGGED - -/obj/machinery/gulag_item_reclaimer/attackby(obj/item/I, mob/user) - if(istype(I, /obj/item/card/id)) - if(!inserted_id) - if(!user.transferItemToLoc(I, src)) - return - inserted_id = I - to_chat(user, "You insert [I].") - return - else - to_chat(user, "There's an ID inserted already.") - return ..() + return TRUE /obj/machinery/gulag_item_reclaimer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) @@ -55,15 +41,19 @@ if(allowed(user)) can_reclaim = TRUE - if(inserted_id) - data["id"] = inserted_id - data["id_name"] = inserted_id.registered_name - if(inserted_id.points >= inserted_id.goal) + var/obj/item/card/id/I = user.get_idcard(TRUE) + if(istype(I, /obj/item/card/id/prisoner)) + var/obj/item/card/id/prisoner/P = I + if(P.points >= P.goal) can_reclaim = TRUE var/list/mobs = list() for(var/i in stored_items) var/mob/thismob = i + if(QDELETED(thismob)) + say("Alert! Unable to locate vital signals of a previously processed prisoner. Ejecting equipment!") + drop_items(thismob) + continue var/list/mob_info = list() mob_info["name"] = thismob.real_name mob_info["mob"] = "[REF(thismob)]" @@ -78,16 +68,6 @@ /obj/machinery/gulag_item_reclaimer/ui_act(action, list/params) switch(action) - if("handle_id") - if(inserted_id) - usr.put_in_hands(inserted_id) - inserted_id = null - else - var/obj/item/I = usr.is_holding_item_of_type(/obj/item/card/id) - if(I) - if(!usr.transferItemToLoc(I, src)) - return - inserted_id = I if("release_items") var/mob/M = locate(params["mobref"]) if(M == usr || allowed(usr)) @@ -98,8 +78,9 @@ /obj/machinery/gulag_item_reclaimer/proc/drop_items(mob/user) if(!stored_items[user]) return + var/drop_location = drop_location() for(var/i in stored_items[user]) var/obj/item/W = i stored_items[user] -= W - W.forceMove(get_turf(src)) + W.forceMove(drop_location) stored_items -= user diff --git a/code/game/machinery/gulag_teleporter.dm b/code/game/machinery/gulag_teleporter.dm index 47136e8c27..6b944f762d 100644 --- a/code/game/machinery/gulag_teleporter.dm +++ b/code/game/machinery/gulag_teleporter.dm @@ -136,16 +136,17 @@ The console is located at computer/gulag_teleporter.dm linked_reclaimer.stored_items[occupant] = list() var/mob/living/mob_occupant = occupant for(var/obj/item/W in mob_occupant) - if(!is_type_in_typecache(W, telegulag_required_items) && mob_occupant.temporarilyRemoveItemFromInventory(W)) - if(istype(W, /obj/item/restraints/handcuffs)) - W.forceMove(get_turf(src)) - continue - if(linked_reclaimer) - linked_reclaimer.stored_items[mob_occupant] += W - linked_reclaimer.contents += W - W.forceMove(linked_reclaimer) - else - W.forceMove(src) + if(!is_type_in_typecache(W, telegulag_required_items)) + if(mob_occupant.temporarilyRemoveItemFromInventory(W)) + if(istype(W, /obj/item/restraints/handcuffs)) + W.forceMove(get_turf(src)) + continue + if(linked_reclaimer) + linked_reclaimer.stored_items[mob_occupant] += W + linked_reclaimer.contents += W + W.forceMove(linked_reclaimer) + else + W.forceMove(src) /obj/machinery/gulag_teleporter/proc/handle_prisoner(obj/item/id, datum/data/record/R) if(!ishuman(occupant)) diff --git a/code/game/machinery/harvester.dm b/code/game/machinery/harvester.dm index 8be7becfdd..db015eb7c1 100644 --- a/code/game/machinery/harvester.dm +++ b/code/game/machinery/harvester.dm @@ -138,7 +138,7 @@ to_chat(user, "[src] is currently occupied!") return if(state_open) - to_chat(user, "[src] must be closed to [panel_open ? "close" : "open"] it's maintenance hatch!") + to_chat(user, "[src] must be closed to [panel_open ? "close" : "open"] its maintenance hatch!") return if(default_deconstruction_screwdriver(user, "[initial(icon_state)]-o", initial(icon_state), I)) return @@ -158,11 +158,13 @@ open_machine() /obj/machinery/harvester/emag_act(mob/user) + . = ..() if(obj_flags & EMAGGED) return obj_flags |= EMAGGED allow_living = TRUE to_chat(user, "You overload [src]'s lifesign scanners.") + return TRUE /obj/machinery/harvester/container_resist(mob/living/user) if(!harvesting) diff --git a/code/game/machinery/iv_drip.dm b/code/game/machinery/iv_drip.dm index 84a688c724..b217c14e53 100644 --- a/code/game/machinery/iv_drip.dm +++ b/code/game/machinery/iv_drip.dm @@ -145,7 +145,7 @@ return // If the human is losing too much blood, beep. - if(attached.blood_volume < BLOOD_VOLUME_SAFE && prob(5)) + if(attached.blood_volume < ( (BLOOD_VOLUME_SAFE*attached.blood_ratio) && prob(5) ) ) visible_message("[src] beeps loudly.") playsound(loc, 'sound/machines/twobeep.ogg', 50, 1) attached.transfer_blood_to(beaker, amount) @@ -218,4 +218,4 @@ to_chat(user, "[attached ? attached : "No one"] is attached.") #undef IV_TAKING -#undef IV_INJECTING \ No newline at end of file +#undef IV_INJECTING diff --git a/code/game/machinery/limbgrower.dm b/code/game/machinery/limbgrower.dm index a3250fe1b0..88ab4ec6f8 100644 --- a/code/game/machinery/limbgrower.dm +++ b/code/game/machinery/limbgrower.dm @@ -27,8 +27,10 @@ "human", "lizard", "fly", - "moth", + "insect", "plasmaman", + "mammal", + "xeno", "other" ) @@ -215,6 +217,7 @@ return dat /obj/machinery/limbgrower/emag_act(mob/user) + . = ..() if(obj_flags & EMAGGED) return for(var/id in SSresearch.techweb_designs) @@ -223,3 +226,4 @@ stored_research.add_design(D) to_chat(user, "A warning flashes onto the screen, stating that safety overrides have been deactivated!") obj_flags |= EMAGGED + return TRUE diff --git a/code/game/machinery/porta_turret/portable_turret.dm b/code/game/machinery/porta_turret/portable_turret.dm index b0204ddeb8..165170cf0f 100644 --- a/code/game/machinery/porta_turret/portable_turret.dm +++ b/code/game/machinery/porta_turret/portable_turret.dm @@ -40,6 +40,8 @@ var/stun_projectile = null //stun mode projectile type var/stun_projectile_sound + var/nonlethal_projectile //projectile to use in stun mode when the target is resting, if any + var/nonlethal_projectile_sound var/lethal_projectile = null //lethal mode projectile type var/lethal_projectile_sound @@ -290,6 +292,7 @@ return ..() /obj/machinery/porta_turret/emag_act(mob/user) + . = ..() if(obj_flags & EMAGGED) return to_chat(user, "You short out [src]'s threat assessment circuits.") @@ -300,6 +303,7 @@ update_icon() sleep(60) //6 seconds for the traitor to gtfo of the area before the turret decides to ruin his shit on = TRUE //turns it back on. The cover popUp() popDown() are automatically called in process(), no need to define it here + return TRUE /obj/machinery/porta_turret/emp_act(severity) @@ -533,13 +537,22 @@ T = closer break + var/mob/living/carbon/C + if(iscarbon(target)) + C = target + update_icon() var/obj/item/projectile/A //any emagged turrets drains 2x power and uses a different projectile? if(mode == TURRET_STUN) - use_power(reqpower) - A = new stun_projectile(T) - playsound(loc, stun_projectile_sound, 75, 1) + if(nonlethal_projectile && C && C.resting) + use_power(reqpower*0.5) + A = new nonlethal_projectile(T) + playsound(loc, nonlethal_projectile_sound, 75, 1) + else + use_power(reqpower) + A = new stun_projectile(T) + playsound(loc, stun_projectile_sound, 75, 1) else use_power(reqpower * 2) A = new lethal_projectile(T) @@ -651,6 +664,8 @@ base_icon_state = "standard" stun_projectile = /obj/item/projectile/energy/electrode stun_projectile_sound = 'sound/weapons/taser.ogg' + nonlethal_projectile = /obj/item/projectile/beam/disabler + nonlethal_projectile_sound = 'sound/weapons/taser2.ogg' lethal_projectile = /obj/item/projectile/beam/laser lethal_projectile_sound = 'sound/weapons/laser.ogg' desc = "An energy blaster auto-turret." @@ -660,6 +675,8 @@ base_icon_state = "standard" stun_projectile = /obj/item/projectile/energy/electrode stun_projectile_sound = 'sound/weapons/taser.ogg' + nonlethal_projectile = /obj/item/projectile/beam/disabler + nonlethal_projectile_sound = 'sound/weapons/taser2.ogg' lethal_projectile = /obj/item/projectile/beam/laser/heavylaser lethal_projectile_sound = 'sound/weapons/lasercannonfire.ogg' desc = "An energy blaster auto-turret." @@ -679,6 +696,8 @@ /obj/machinery/porta_turret/ai faction = list("silicon") + nonlethal_projectile = /obj/item/projectile/beam/disabler + nonlethal_projectile_sound = 'sound/weapons/taser2.ogg' /obj/machinery/porta_turret/ai/assess_perp(mob/living/carbon/human/perp) return 10 //AI turrets shoot at everything not in their faction @@ -837,6 +856,7 @@ to_chat(user, "Access denied.") /obj/machinery/turretid/emag_act(mob/user) + . = ..() if(obj_flags & EMAGGED) return to_chat(user, "You short out the turret controls' access analysis module.") @@ -844,6 +864,7 @@ locked = FALSE if(user && user.machine == src) attack_hand(user) + return TRUE /obj/machinery/turretid/attack_ai(mob/user) if(!ailock || IsAdminGhost(user)) diff --git a/code/game/machinery/porta_turret/portable_turret_cover.dm b/code/game/machinery/porta_turret/portable_turret_cover.dm index 6ff795c1cc..afb00d4ee2 100644 --- a/code/game/machinery/porta_turret/portable_turret_cover.dm +++ b/code/game/machinery/porta_turret/portable_turret_cover.dm @@ -86,10 +86,13 @@ . = 0 /obj/machinery/porta_turret_cover/emag_act(mob/user) - if(!(parent_turret.obj_flags & EMAGGED)) - to_chat(user, "You short out [parent_turret]'s threat assessment circuits.") - visible_message("[parent_turret] hums oddly...") - parent_turret.obj_flags |= EMAGGED - parent_turret.on = 0 - spawn(40) - parent_turret.on = 1 + . = ..() + if(parent_turret.obj_flags & EMAGGED) + return + to_chat(user, "You short out [parent_turret]'s threat assessment circuits.") + visible_message("[parent_turret] hums oddly...") + parent_turret.obj_flags |= EMAGGED + parent_turret.on = 0 + spawn(40) + parent_turret.on = 1 + return TRUE diff --git a/code/game/machinery/recycler.dm b/code/game/machinery/recycler.dm index ff40a8539a..9d431487e0 100644 --- a/code/game/machinery/recycler.dm +++ b/code/game/machinery/recycler.dm @@ -65,6 +65,7 @@ return ..() /obj/machinery/recycler/emag_act(mob/user) + . = ..() if(obj_flags & EMAGGED) return obj_flags |= EMAGGED @@ -73,6 +74,7 @@ update_icon() playsound(src, "sparks", 75, 1, -1) to_chat(user, "You use the cryptographic sequencer on [src].") + return TRUE /obj/machinery/recycler/update_icon() ..() diff --git a/code/game/machinery/shieldgen.dm b/code/game/machinery/shieldgen.dm index e2aebd2370..fc6577a4f1 100644 --- a/code/game/machinery/shieldgen.dm +++ b/code/game/machinery/shieldgen.dm @@ -195,6 +195,7 @@ return ..() /obj/machinery/shieldgen/emag_act(mob/user) + . = ..() if(obj_flags & EMAGGED) to_chat(user, "The access controller is damaged!") return @@ -202,6 +203,7 @@ locked = FALSE playsound(src, "sparks", 100, 1) to_chat(user, "You short out the access controller.") + return TRUE /obj/machinery/shieldgen/update_icon() if(active) @@ -387,6 +389,7 @@ add_fingerprint(user) /obj/machinery/shieldwallgen/emag_act(mob/user) + . = ..() if(obj_flags & EMAGGED) to_chat(user, "The access controller is damaged!") return @@ -394,6 +397,7 @@ locked = FALSE playsound(src, "sparks", 100, 1) to_chat(user, "You short out the access controller.") + return TRUE //////////////Containment Field START /obj/machinery/shieldwall diff --git a/code/game/machinery/slotmachine.dm b/code/game/machinery/slotmachine.dm index 298587cdea..4b73032a8a 100644 --- a/code/game/machinery/slotmachine.dm +++ b/code/game/machinery/slotmachine.dm @@ -99,6 +99,7 @@ return ..() /obj/machinery/computer/slot_machine/emag_act() + . = ..() if(obj_flags & EMAGGED) return obj_flags |= EMAGGED @@ -106,6 +107,7 @@ spark_system.set_up(4, 0, src.loc) spark_system.start() playsound(src, "sparks", 50, 1) + return TRUE /obj/machinery/computer/slot_machine/ui_interact(mob/living/user) . = ..() diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm index 90166dacf0..d308d180d0 100644 --- a/code/game/machinery/suit_storage_unit.dm +++ b/code/game/machinery/suit_storage_unit.dm @@ -210,13 +210,13 @@ add_fingerprint(user) /obj/machinery/suit_storage_unit/proc/cook() + var/mob/living/mob_occupant = occupant if(uv_cycles) uv_cycles-- uv = TRUE locked = TRUE update_icon() if(occupant) - var/mob/living/mob_occupant = occupant if(uv_super) mob_occupant.adjustFireLoss(rand(20, 36)) else @@ -245,10 +245,27 @@ visible_message("[src]'s door slides open. The glowing yellow lights dim to a gentle green.") else visible_message("[src]'s door slides open, barraging you with the nauseating smell of charred flesh.") + mob_occupant.radiation = 0 playsound(src, 'sound/machines/airlockclose.ogg', 25, 1) - for(var/obj/item/I in src) //Scorches away blood and forensic evidence, although the SSU itself is unaffected - SEND_SIGNAL(I, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRONG) - var/datum/component/radioactive/contamination = I.GetComponent(/datum/component/radioactive) + var/list/things_to_clear = list() //Done this way since using GetAllContents on the SSU itself would include circuitry and such. + if(suit) + things_to_clear += suit + things_to_clear += suit.GetAllContents() + if(helmet) + things_to_clear += helmet + things_to_clear += helmet.GetAllContents() + if(mask) + things_to_clear += mask + things_to_clear += mask.GetAllContents() + if(storage) + things_to_clear += storage + things_to_clear += storage.GetAllContents() + if(occupant) + things_to_clear += occupant + things_to_clear += occupant.GetAllContents() + for(var/atom/movable/AM in things_to_clear) //Scorches away blood and forensic evidence, although the SSU itself is unaffected + SEND_SIGNAL(AM, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRONG) + var/datum/component/radioactive/contamination = AM.GetComponent(/datum/component/radioactive) if(contamination) qdel(contamination) open_machine(FALSE) diff --git a/code/game/machinery/syndicatebeacon.dm b/code/game/machinery/syndicatebeacon.dm index a1ed7fb848..8a33241d46 100644 --- a/code/game/machinery/syndicatebeacon.dm +++ b/code/game/machinery/syndicatebeacon.dm @@ -1,3 +1,7 @@ +GLOBAL_VAR_INIT(singularity_counter, 0) + +#define METEOR_DISASTER_MODIFIER 0.5 + //////////////////////////////////////// //Singularity beacon //////////////////////////////////////// @@ -13,39 +17,57 @@ stat = 0 verb_say = "states" var/cooldown = 0 - - var/active = 0 + var/active = FALSE + var/meteor_buff = FALSE var/icontype = "beacon" - /obj/machinery/power/singularity_beacon/proc/Activate(mob/user = null) + if(active) + return FALSE if(surplus() < 1500) if(user) to_chat(user, "The connected wire doesn't have enough current.") - return + return FALSE + if(is_station_level(z)) + increment_meteor_waves() for(var/obj/singularity/singulo in GLOB.singularities) if(singulo.z == z) singulo.target = src icon_state = "[icontype]1" - active = 1 + active = TRUE if(user) to_chat(user, "You activate the beacon.") + return TRUE - -/obj/machinery/power/singularity_beacon/proc/Deactivate(mob/user = null) +/obj/machinery/power/singularity_beacon/proc/Deactivate(mob/user) + if(!active) + return FALSE for(var/obj/singularity/singulo in GLOB.singularities) if(singulo.target == src) singulo.target = null icon_state = "[icontype]0" - active = 0 + active = FALSE if(user) to_chat(user, "You deactivate the beacon.") + if(meteor_buff) + decrement_meteor_waves() + return TRUE +/obj/machinery/power/singularity_beacon/proc/increment_meteor_waves() + meteor_buff = TRUE + GLOB.singularity_counter++ + for(var/datum/round_event_control/meteor_wave/W in SSevents.control) + W.weight += round(initial(W.weight) * METEOR_DISASTER_MODIFIER) + +/obj/machinery/power/singularity_beacon/proc/decrement_meteor_waves() + meteor_buff = FALSE + GLOB.singularity_counter-- + for(var/datum/round_event_control/meteor_wave/W in SSevents.control) + W.weight -= round(initial(W.weight) * METEOR_DISASTER_MODIFIER) /obj/machinery/power/singularity_beacon/attack_ai(mob/user) return - /obj/machinery/power/singularity_beacon/attack_hand(mob/user) . = ..() if(.) @@ -86,6 +108,12 @@ if(!active) return + var/is_on_station = is_station_level(z) + if(meteor_buff && !is_on_station) + decrement_meteor_waves() + else if(!meteor_buff && is_on_station) + increment_meteor_waves() + if(surplus() >= 1500) add_load(1500) if(cooldown <= world.time) @@ -133,3 +161,5 @@ /obj/item/sbeacondrop/clownbomb desc = "A label on it reads: Warning: Activating this device will send a silly explosive to your location." droptype = /obj/machinery/syndicatebomb/badmin/clown + +#undef METEOR_DISASTER_MODIFIER diff --git a/code/game/machinery/telecomms/computers/message.dm b/code/game/machinery/telecomms/computers/message.dm index b11c6c102d..64f4cc7835 100644 --- a/code/game/machinery/telecomms/computers/message.dm +++ b/code/game/machinery/telecomms/computers/message.dm @@ -42,21 +42,23 @@ return ..() /obj/machinery/computer/message_monitor/emag_act(mob/user) + . = ..() if(obj_flags & EMAGGED) return - if(!isnull(linkedServer)) - obj_flags |= EMAGGED - screen = 2 - spark_system.set_up(5, 0, src) - spark_system.start() - var/obj/item/paper/monitorkey/MK = new(loc, linkedServer) - // Will help make emagging the console not so easy to get away with. - MK.info += "

�%@%(*$%&(�&?*(%&�/{}" - var/time = 100 * length(linkedServer.decryptkey) - addtimer(CALLBACK(src, .proc/UnmagConsole), time) - message = rebootmsg - else + if(isnull(linkedServer)) to_chat(user, "A no server error appears on the screen.") + return + obj_flags |= EMAGGED + screen = 2 + spark_system.set_up(5, 0, src) + spark_system.start() + var/obj/item/paper/monitorkey/MK = new(loc, linkedServer) + // Will help make emagging the console not so easy to get away with. + MK.info += "

�%@%(*$%&(�&?*(%&�/{}" + var/time = 100 * length(linkedServer.decryptkey) + addtimer(CALLBACK(src, .proc/UnmagConsole), time) + message = rebootmsg + return TRUE /obj/machinery/computer/message_monitor/New() . = ..() @@ -419,6 +421,7 @@ "name" = "[customsender]", "job" = "[customjob]", "message" = custommessage, + "emoji_message" = emoji_parse(custommessage), "targets" = list("[customrecepient.owner] ([customrecepient.ownjob])") )) // this will log the signal and transmit it to the target diff --git a/code/game/machinery/telecomms/machines/message_server.dm b/code/game/machinery/telecomms/machines/message_server.dm index cc390e1fc0..56870c5198 100644 --- a/code/game/machinery/telecomms/machines/message_server.dm +++ b/code/game/machinery/telecomms/machines/message_server.dm @@ -106,10 +106,11 @@ return "Everyone" return data["targets"][1] -/datum/signal/subspace/pda/proc/format_message() +/datum/signal/subspace/pda/proc/format_message(emojify = FALSE) + var/message = emojify ? data["emoji_message"] : data["message"] if (logged && data["photo"]) - return "\"[data["message"]]\" (Photo)" - return "\"[data["message"]]\"" + return "\"[message]\" (Photo)" + return "\"[message]\"" /datum/signal/subspace/pda/broadcast() if (!logged) // Can only go through if a message server logs it diff --git a/code/game/machinery/teleporter.dm b/code/game/machinery/teleporter.dm index 64081a77e4..1f1f13ee22 100644 --- a/code/game/machinery/teleporter.dm +++ b/code/game/machinery/teleporter.dm @@ -68,16 +68,16 @@ if (ismovableatom(M)) if(do_teleport(M, com.target, channel = TELEPORT_CHANNEL_BLUESPACE)) use_power(5000) - if(!calibrated && prob(30 - ((accurate) * 10))) //oh dear a problem - log_game("[M] ([key_name(M)]) was turned into a fly person") - if(ishuman(M))//don't remove people from the round randomly you jerks - var/mob/living/carbon/human/human = M - if(human.dna && human.dna.species.id == "human") - to_chat(M, "You hear a buzzing in your ears.") - human.set_species(/datum/species/fly) - human.apply_effect((rand(120 - accurate * 40, 180 - accurate * 60)), EFFECT_IRRADIATE, 0) - calibrated = 0 + if(!calibrated && iscarbon(M) && prob(30 - ((accurate) * 10))) //oh dear a problem + var/mob/living/carbon/C = M + if(C.dna?.species && C.dna.species.id != "fly" && !HAS_TRAIT(C, TRAIT_RADIMMUNE)) + to_chat(C, "You hear a buzzing in your ears.") + C.set_species(/datum/species/fly) + log_game("[C] ([key_name(C)]) was turned into a fly person") + C.apply_effect((rand(120 - accurate * 40, 180 - accurate * 60)), EFFECT_IRRADIATE, 0) + + calibrated = FALSE return /obj/machinery/teleport/hub/update_icon() diff --git a/code/game/machinery/turnstile.dm b/code/game/machinery/turnstile.dm new file mode 100644 index 0000000000..1fd78056d4 --- /dev/null +++ b/code/game/machinery/turnstile.dm @@ -0,0 +1,84 @@ +/obj/machinery/turnstile + name = "turnstile" + desc = "A mechanical door that permits one-way access and prevents tailgating." + icon = 'icons/obj/turnstile.dmi' + icon_state = "turnstile_map" + density = FALSE + armor = list(melee = 50, bullet = 50, laser = 50, energy = 50, bomb = 10, bio = 100, rad = 100, fire = 90, acid = 70) + anchored = TRUE + use_power = FALSE + idle_power_usage = 2 + resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF + layer = OPEN_DOOR_LAYER + +/obj/machinery/turnstile/Initialize() + . = ..() + icon_state = "turnstile" + +/obj/machinery/turnstile/CanAtmosPass(turf/T) + return TRUE + +/obj/machinery/turnstile/bullet_act(obj/item/projectile/P, def_zone) + return -1 //Pass through! + +/obj/machinery/turnstile/proc/allowed_access(var/mob/B) + if(B.pulledby && ismob(B.pulledby)) + return allowed(B.pulledby) | allowed(B) + else + return allowed(B) + +/obj/machinery/turnstile/CanPass(atom/movable/AM, turf/T) + if(ismob(AM)) + var/mob/B = AM + if(isliving(AM)) + var/mob/living/M = AM + + if(world.time - M.last_bumped <= 5) + return FALSE + M.last_bumped = world.time + + var/allowed_access = FALSE + var/turf/behind = get_step(src, dir) + + if(B in behind.contents) + allowed_access = allowed_access(B) + else + to_chat(usr, "\the [src] resists your efforts.") + return FALSE + + if(allowed_access) + flick("operate", src) + playsound(src,'sound/items/ratchet.ogg',50,0,3) + return TRUE + else + flick("deny", src) + playsound(src,'sound/machines/deniedbeep.ogg',50,0,3) + return FALSE + if(ispath(AM, /obj/item/)) + return TRUE + else + return FALSE + +/obj/machinery/turnstile/CheckExit(atom/movable/AM as mob|obj, target) + if(isliving(AM)) + var/mob/living/M = AM + var/outdir = dir + if(allowed_access(M)) + switch(dir) + if(NORTH) + outdir = SOUTH + if(SOUTH) + outdir = NORTH + if(EAST) + outdir = WEST + if(WEST) + outdir = EAST + var/turf/outturf = get_step(src, outdir) + var/canexit = (target == src.loc) | (target == outturf) + + if(!canexit && world.time - M.last_bumped <= 5) + to_chat(usr, "\the [src] resists your efforts.") + M.last_bumped = world.time + return canexit + else + return TRUE \ No newline at end of file diff --git a/code/game/mecha/combat/durand.dm b/code/game/mecha/combat/durand.dm index 7896d7aa35..cd7051d074 100644 --- a/code/game/mecha/combat/durand.dm +++ b/code/game/mecha/combat/durand.dm @@ -20,3 +20,6 @@ ..() defense_action.Remove(user) +/obj/mecha/combat/Initialize() + . = ..() + trackers += new /obj/item/mecha_parts/mecha_tracking(src) diff --git a/code/game/mecha/combat/gygax.dm b/code/game/mecha/combat/gygax.dm index 95137938d0..564f308df3 100644 --- a/code/game/mecha/combat/gygax.dm +++ b/code/game/mecha/combat/gygax.dm @@ -6,6 +6,7 @@ dir_in = 1 //Facing North. max_integrity = 250 deflect_chance = 5 + force = 20 armor = list("melee" = 25, "bullet" = 20, "laser" = 30, "energy" = 15, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100) max_temperature = 25000 infra_luminosity = 6 @@ -13,6 +14,7 @@ internal_damage_threshold = 35 max_equip = 3 step_energy_drain = 3 + leg_overload_coeff = 300 /obj/mecha/combat/gygax/dark desc = "A lightweight exosuit, painted in a dark scheme. This model appears to have some modifications." @@ -20,6 +22,7 @@ icon_state = "darkgygax" max_integrity = 300 deflect_chance = 15 + force = 25 armor = list("melee" = 40, "bullet" = 40, "laser" = 50, "energy" = 35, "bomb" = 20, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100) max_temperature = 35000 leg_overload_coeff = 100 @@ -63,3 +66,6 @@ ..() thrusters_action.Remove(user) +/obj/mecha/combat/Initialize() + . = ..() + trackers += new /obj/item/mecha_parts/mecha_tracking(src) diff --git a/code/game/mecha/combat/honker.dm b/code/game/mecha/combat/honker.dm index 125aecd667..4c32e9c367 100644 --- a/code/game/mecha/combat/honker.dm +++ b/code/game/mecha/combat/honker.dm @@ -154,4 +154,6 @@ color = color+pick(colors) return color - +/obj/mecha/combat/Initialize() + . = ..() + trackers += new /obj/item/mecha_parts/mecha_tracking(src) diff --git a/code/game/mecha/combat/neovgre.dm b/code/game/mecha/combat/neovgre.dm new file mode 100644 index 0000000000..2b2ed150e2 --- /dev/null +++ b/code/game/mecha/combat/neovgre.dm @@ -0,0 +1,96 @@ +/obj/mecha/combat/neovgre + name = "Neovgre, the Anima Bulwark" + desc = "Nezbere's most powerful creation, a mighty war machine of unmatched power said to have ended wars in a single night." + icon = 'icons/mecha/neovgre.dmi' + icon_state = "neovgre" + max_integrity = 500 //This is THE ratvarian superweaon, its deployment is an investment + armor = list("melee" = 50, "bullet" = 40, "laser" = 25, "energy" = 25, "bomb" = 50, "bio" = 100, "rad" = 100, "fire" = 100, "acid" = 100) //Its similar to the clockwork armour albeit with a few buffs becuase RATVARIAN SUPERWEAPON!! + force = 50 //SMASHY SMASHY!! + internal_damage_threshold = 0 + step_in = 3 + pixel_x = -16 + layer = ABOVE_MOB_LAYER + breach_time = 100 //ten seconds till all goes to shit + recharge_rate = 100 + wreckage = /obj/structure/mecha_wreckage/durand/neovgre + +/obj/mecha/combat/neovgre/GrantActions(mob/living/user, human_occupant = 0) //No Eject action for you sonny jim, your life for Ratvar! + internals_action.Grant(user, src) + cycle_action.Grant(user, src) + lights_action.Grant(user, src) + stats_action.Grant(user, src) + strafing_action.Grant(user, src) + +/obj/mecha/combat/neovgre/RemoveActions(mob/living/user, human_occupant = 0) + internals_action.Remove(user) + cycle_action.Remove(user) + lights_action.Remove(user) + stats_action.Remove(user) + strafing_action.Remove(user) + +/obj/mecha/combat/neovgre/MouseDrop_T(mob/M, mob/user) + if(!is_servant_of_ratvar(user)) + to_chat(user, "BEGONE HERETIC!") + return + else + ..() + +/obj/mecha/combat/neovgre/moved_inside(mob/living/carbon/human/H) + var/list/Itemlist = H.get_contents() + for(var/obj/item/clockwork/slab/W in Itemlist) + to_chat(H, "You safely store [W] inside [src].") + qdel(W) + . = ..() + +/obj/mecha/combat/neovgre/obj_destruction() + for(var/mob/M in src) + to_chat(M, "You are consumed by the fires raging within Neovgre...") + M.dust() + playsound(src, 'sound/magic/lightning_chargeup.ogg', 100, 0) + src.visible_message("The reactor has gone critical, its going to blow!") + addtimer(CALLBACK(src,.proc/go_critical),breach_time) + +/obj/mecha/combat/neovgre/proc/go_critical() + explosion(get_turf(loc), 3, 5, 10, 20, 30) + Destroy(src) + +/obj/mecha/combat/neovgre/container_resist(mob/living/user) + to_chat(user, "Neovgre requires a lifetime commitment friend, no backing out now!") + return + +/obj/mecha/combat/neovgre/process() + ..() + if(GLOB.ratvar_awakens) // At this point only timley intervention by lord singulo could hople to stop the superweapon + cell.charge = INFINITY + max_integrity = INFINITY + obj_integrity = max_integrity + CHECK_TICK //Just to be on the safe side lag wise + else if(cell.charge < cell.maxcharge) + for(var/obj/effect/clockwork/sigil/transmission/T in range(SIGIL_ACCESS_RANGE, src)) + var/delta = min(recharge_rate, cell.maxcharge - cell.charge) + if (get_clockwork_power() <= delta) + cell.charge += delta + adjust_clockwork_power(-delta) + CHECK_TICK + +/obj/mecha/combat/neovgre/Initialize() + .=..() + GLOB.neovgre_exists ++ + var/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/heavy/neovgre/N = new + N.attach(src) + +/obj/structure/mecha_wreckage/durand/neovgre + name = "\improper Neovgre wreckage?" + desc = "On closer inspection this looks like the wreck of a durand with some spraypainted cardboard duct taped to it!" + +/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/heavy/neovgre + equip_cooldown = 8 //Rapid fire heavy laser cannon, simple yet elegant + energy_drain = 30 + name = "Aribter Laser Cannon" + desc = "Please re-attach this to neovgre and stop asking questions about why it looks like a normal Nanotrasen issue Solaris laser cannon - Nezbere" + fire_sound = "sound/weapons/neovgre_laser.ogg" + +/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/heavy/neovgre/can_attach(obj/mecha/combat/neovgre/M) + if(istype(M)) + return 1 + return 0 diff --git a/code/game/mecha/combat/phazon.dm b/code/game/mecha/combat/phazon.dm index f5f369c2ad..1264a647c4 100644 --- a/code/game/mecha/combat/phazon.dm +++ b/code/game/mecha/combat/phazon.dm @@ -28,3 +28,6 @@ switch_damtype_action.Remove(user) phasing_action.Remove(user) +/obj/mecha/combat/Initialize() + . = ..() + trackers += new /obj/item/mecha_parts/mecha_tracking(src) diff --git a/code/game/mecha/equipment/tools/medical_tools.dm b/code/game/mecha/equipment/tools/medical_tools.dm index 21bbdfd14b..ae3fdb15b4 100644 --- a/code/game/mecha/equipment/tools/medical_tools.dm +++ b/code/game/mecha/equipment/tools/medical_tools.dm @@ -166,7 +166,7 @@ Toxin Content: [patient.getToxLoss()]%
Burn Severity: [patient.getFireLoss()]%
[patient.getCloneLoss() ? "Subject appears to have cellular damage." : ""]
- [patient.getBrainLoss() ? "Significant brain damage detected." : ""]
+ [patient.getOrganLoss(ORGAN_SLOT_BRAIN) ? "Significant brain damage detected." : ""]
[length(patient.get_traumas()) ? "Brain Traumas detected." : ""]
"} diff --git a/code/game/mecha/equipment/tools/mining_tools.dm b/code/game/mecha/equipment/tools/mining_tools.dm index d539e0a9d5..eb3261bb27 100644 --- a/code/game/mecha/equipment/tools/mining_tools.dm +++ b/code/game/mecha/equipment/tools/mining_tools.dm @@ -13,6 +13,8 @@ energy_drain = 10 force = 15 harmful = TRUE + tool_behaviour = TOOL_DRILL + toolspeed = 0.9 var/drill_delay = 7 var/drill_level = DRILL_BASIC @@ -141,6 +143,7 @@ drill_delay = 4 drill_level = DRILL_HARDENED force = 15 + toolspeed = 0.7 /obj/item/mecha_parts/mecha_equipment/mining_scanner diff --git a/code/game/mecha/equipment/tools/work_tools.dm b/code/game/mecha/equipment/tools/work_tools.dm index ea9465184a..36708fcf90 100644 --- a/code/game/mecha/equipment/tools/work_tools.dm +++ b/code/game/mecha/equipment/tools/work_tools.dm @@ -11,6 +11,8 @@ var/dam_force = 20 var/obj/mecha/working/ripley/cargo_holder harmful = TRUE + tool_behaviour = TOOL_RETRACTOR + toolspeed = 0.8 /obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/can_attach(obj/mecha/working/ripley/M as obj) if(..()) diff --git a/code/game/mecha/equipment/weapons/weapons.dm b/code/game/mecha/equipment/weapons/weapons.dm index 2e5a13beb2..9f8f3ef742 100644 --- a/code/game/mecha/equipment/weapons/weapons.dm +++ b/code/game/mecha/equipment/weapons/weapons.dm @@ -279,12 +279,12 @@ name = "\improper Melon Seed \"Scattershot\"" desc = "A weapon for combat exosuits. Shoots a spread of pellets, shaped as seed." icon_state = "mecha_scatter" - equip_cooldown = 30 + equip_cooldown = 20 projectile = /obj/item/projectile/bullet/seed - projectiles = 4 - projectile_energy_cost = 55 + projectiles = 20 + projectile_energy_cost = 25 projectiles_per_shot = 10 - variance = 20 + variance = 25 harmful = TRUE /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/lmg diff --git a/code/game/mecha/mech_fabricator.dm b/code/game/mecha/mech_fabricator.dm index 01e304872f..e1dc80911f 100644 --- a/code/game/mecha/mech_fabricator.dm +++ b/code/game/mecha/mech_fabricator.dm @@ -64,10 +64,15 @@ /obj/machinery/mecha_part_fabricator/emag_act() + . = ..() if(obj_flags & EMAGGED) return obj_flags |= EMAGGED req_access = list() + INVOKE_ASYNC(src, .proc/error_action_sucessful) + return TRUE + +/obj/machinery/mecha_part_fabricator/proc/error_action_sucessful() say("DB error \[Code 0x00F1\]") sleep(10) say("Attempting auto-repair...") diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index 22aac63d2b..7348c8a575 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -49,6 +49,8 @@ var/lights = FALSE var/lights_power = 6 var/last_user_hud = 1 // used to show/hide the mecha hud while preserving previous preference + var/breach_time = 0 + var/recharge_rate = 0 var/bumpsmash = 0 //Whether or not the mech destroys walls by running into it. //inner atmos diff --git a/code/game/mecha/mecha_control_console.dm b/code/game/mecha/mecha_control_console.dm index 9498eec3da..18c9b3eb2f 100644 --- a/code/game/mecha/mecha_control_console.dm +++ b/code/game/mecha/mecha_control_console.dm @@ -109,7 +109,7 @@ var/obj/mecha/M = in_mecha() if(M) M.emp_act(EMP_HEAVY) - addtimer(CALLBACK(src, /obj/item/mecha_parts/mecha_tracking/proc/recharge), 5 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE) + addtimer(CALLBACK(src, /obj/item/mecha_parts/mecha_tracking/proc/recharge), 15 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE) recharging = 1 /obj/item/mecha_parts/mecha_tracking/proc/recharge() diff --git a/code/game/objects/buckling.dm b/code/game/objects/buckling.dm index 9c3df5395f..693d32e545 100644 --- a/code/game/objects/buckling.dm +++ b/code/game/objects/buckling.dm @@ -89,6 +89,7 @@ buckled_mob.clear_alert("buckled") buckled_mobs -= buckled_mob SEND_SIGNAL(src, COMSIG_MOVABLE_UNBUCKLE, buckled_mob, force) + SEND_SIGNAL(src, COMSIG_MOVABLE_UNBUCKLE, src, force) post_unbuckle_mob(.) diff --git a/code/game/objects/effects/alien_acid.dm b/code/game/objects/effects/alien_acid.dm index 1a605d64b0..3b5a029df4 100644 --- a/code/game/objects/effects/alien_acid.dm +++ b/code/game/objects/effects/alien_acid.dm @@ -17,7 +17,7 @@ target = get_turf(src) if(acid_amt) - acid_level = min(acid_amt*acid_pwr, 12000) //capped so the acid effect doesn't last a half hour on the floor. + acid_level = min( (CLAMP(round(acid_amt, 1), 0, INFINITY)) *acid_pwr, 12000) //capped so the acid effect doesn't last a half hour on the floor. //handle APCs and newscasters and stuff nicely pixel_x = target.pixel_x + rand(-4,4) diff --git a/code/game/objects/effects/decals/cleanable/misc.dm b/code/game/objects/effects/decals/cleanable/misc.dm index cc69b88cc4..9f072c48b6 100644 --- a/code/game/objects/effects/decals/cleanable/misc.dm +++ b/code/game/objects/effects/decals/cleanable/misc.dm @@ -42,6 +42,9 @@ /obj/effect/decal/cleanable/glass/ex_act() qdel(src) +/obj/effect/decal/cleanable/glass/plasma + icon_state = "plasmatiny" + /obj/effect/decal/cleanable/dirt name = "dirt" desc = "Someone should clean that up." diff --git a/code/game/objects/effects/decals/turfdecal/tilecoloring.dm b/code/game/objects/effects/decals/turfdecal/tilecoloring.dm index 1708753dc1..1e755bc7e9 100644 --- a/code/game/objects/effects/decals/turfdecal/tilecoloring.dm +++ b/code/game/objects/effects/decals/turfdecal/tilecoloring.dm @@ -36,4 +36,203 @@ /obj/effect/turf_decal/tile/neutral name = "neutral corner" color = "#D4D4D4" - alpha = 50 \ No newline at end of file + alpha = 50 + +/obj/effect/turf_decal/trimline + layer = TURF_PLATING_DECAL_LAYER + alpha = 110 + icon_state = "trimline_box" + +/obj/effect/turf_decal/trimline/white + color = "#FFFFFF" + +/obj/effect/turf_decal/trimline/white/line + name = "trim decal" + icon_state = "trimline" + +/obj/effect/turf_decal/trimline/white/corner + icon_state = "trimline_corner" + +/obj/effect/turf_decal/trimline/white/end + icon_state = "trimline_end" + +/obj/effect/turf_decal/trimline/white/filled + icon_state = "trimline_box_fill" + +/obj/effect/turf_decal/trimline/white/filled/line + icon_state = "trimline_fill" + +/obj/effect/turf_decal/trimline/white/filled/corner + icon_state = "trimline_corner_fill" + +/obj/effect/turf_decal/trimline/white/filled/end + icon_state = "trimline_end_fill" + +/obj/effect/turf_decal/trimline/red + color = "#DE3A3A" + +/obj/effect/turf_decal/trimline/red/line + icon_state = "trimline" + +/obj/effect/turf_decal/trimline/red/corner + icon_state = "trimline_corner" + +/obj/effect/turf_decal/trimline/red/end + icon_state = "trimline_end" + +/obj/effect/turf_decal/trimline/red/filled + icon_state = "trimline_box_fill" + +/obj/effect/turf_decal/trimline/red/filled/line + icon_state = "trimline_fill" + +/obj/effect/turf_decal/trimline/red/filled/corner + icon_state = "trimline_corner_fill" + +/obj/effect/turf_decal/trimline/red/filled/end + icon_state = "trimline_end_fill" + +/obj/effect/turf_decal/trimline/green + color = "#9FED58" + +/obj/effect/turf_decal/trimline/green/line + icon_state = "trimline" + +/obj/effect/turf_decal/trimline/green/corner + icon_state = "trimline_corner" + +/obj/effect/turf_decal/trimline/green/end + icon_state = "trimline_end" + +/obj/effect/turf_decal/trimline/green/filled + icon_state = "trimline_box_fill" + +/obj/effect/turf_decal/trimline/green/filled/line + icon_state = "trimline_fill" + +/obj/effect/turf_decal/trimline/green/filled/corner + icon_state = "trimline_corner_fill" + +/obj/effect/turf_decal/trimline/green/filled/end + icon_state = "trimline_end_fill" + +/obj/effect/turf_decal/trimline/blue + color = "#52B4E9" + +/obj/effect/turf_decal/trimline/blue/line + icon_state = "trimline" + +/obj/effect/turf_decal/trimline/blue/corner + icon_state = "trimline_corner" + +/obj/effect/turf_decal/trimline/blue/end + icon_state = "trimline_end" + +/obj/effect/turf_decal/trimline/blue/filled + icon_state = "trimline_box_fill" + +/obj/effect/turf_decal/trimline/blue/filled/line + icon_state = "trimline_fill" + +/obj/effect/turf_decal/trimline/blue/filled/corner + icon_state = "trimline_corner_fill" + +/obj/effect/turf_decal/trimline/blue/filled/end + icon_state = "trimline_end_fill" + +/obj/effect/turf_decal/trimline/yellow + color = "#EFB341" + +/obj/effect/turf_decal/trimline/yellow/line + icon_state = "trimline" + +/obj/effect/turf_decal/trimline/yellow/corner + icon_state = "trimline_corner" + +/obj/effect/turf_decal/trimline/yellow/end + icon_state = "trimline_end" + +/obj/effect/turf_decal/trimline/yellow/filled + icon_state = "trimline_box_fill" + +/obj/effect/turf_decal/trimline/yellow/filled/line + icon_state = "trimline_fill" + +/obj/effect/turf_decal/trimline/yellow/filled/corner + icon_state = "trimline_corner_fill" + +/obj/effect/turf_decal/trimline/yellow/filled/end + icon_state = "trimline_end_fill" + +/obj/effect/turf_decal/trimline/purple + color = "#D381C9" + +/obj/effect/turf_decal/trimline/purple/line + icon_state = "trimline" + +/obj/effect/turf_decal/trimline/purple/corner + icon_state = "trimline_corner" + +/obj/effect/turf_decal/trimline/purple/end + icon_state = "trimline_end" + +/obj/effect/turf_decal/trimline/purple/filled + icon_state = "trimline_box_fill" + +/obj/effect/turf_decal/trimline/purple/filled/line + icon_state = "trimline_fill" + +/obj/effect/turf_decal/trimline/purple/filled/corner + icon_state = "trimline_corner_fill" + +/obj/effect/turf_decal/trimline/purple/filled/end + icon_state = "trimline_end_fill" + +/obj/effect/turf_decal/trimline/brown + color = "#A46106" + +/obj/effect/turf_decal/trimline/brown/line + icon_state = "trimline" + +/obj/effect/turf_decal/trimline/brown/corner + icon_state = "trimline_corner" + +/obj/effect/turf_decal/trimline/brown/end + icon_state = "trimline_end" + +/obj/effect/turf_decal/trimline/brown/filled + icon_state = "trimline_box_fill" + +/obj/effect/turf_decal/trimline/brown/filled/line + icon_state = "trimline_fill" + +/obj/effect/turf_decal/trimline/brown/filled/corner + icon_state = "trimline_corner_fill" + +/obj/effect/turf_decal/trimline/brown/filled/end + icon_state = "trimline_end_fill" + +/obj/effect/turf_decal/trimline/neutral + color = "#D4D4D4" + alpha = 50 + +/obj/effect/turf_decal/trimline/neutral/line + icon_state = "trimline" + +/obj/effect/turf_decal/trimline/neutral/corner + icon_state = "trimline_corner" + +/obj/effect/turf_decal/trimline/neutral/end + icon_state = "trimline_end" + +/obj/effect/turf_decal/trimline/neutral/filled + icon_state = "trimline_box_fill" + +/obj/effect/turf_decal/trimline/neutral/filled/line + icon_state = "trimline_fill" + +/obj/effect/turf_decal/trimline/neutral/filled/corner + icon_state = "trimline_corner_fill" + +/obj/effect/turf_decal/trimline/brown/filled/end + icon_state = "trimline_end_fill" \ No newline at end of file diff --git a/code/game/objects/effects/effect_system/effects_smoke.dm b/code/game/objects/effects/effect_system/effects_smoke.dm index 79deac475b..028110170a 100644 --- a/code/game/objects/effects/effect_system/effects_smoke.dm +++ b/code/game/objects/effects/effect_system/effects_smoke.dm @@ -288,7 +288,7 @@ contained = "\[[contained]\]" var/where = "[AREACOORD(location)]" - if(carry.my_atom.fingerprintslast) + if(carry.my_atom && carry.my_atom.fingerprintslast) var/mob/M = get_mob_by_key(carry.my_atom.fingerprintslast) var/more = "" if(M) diff --git a/code/game/objects/effects/spawners/bundle.dm b/code/game/objects/effects/spawners/bundle.dm index 2fe8d2a460..b9acba70d9 100644 --- a/code/game/objects/effects/spawners/bundle.dm +++ b/code/game/objects/effects/spawners/bundle.dm @@ -133,7 +133,7 @@ /obj/effect/spawner/bundle/costume/holiday_priest name = "holiday priest costume spawner" items = list( - /obj/item/clothing/suit/holidaypriest) + /obj/item/clothing/suit/chaplain/holidaypriest) /obj/effect/spawner/bundle/costume/marisawizard name = "marisa wizard costume spawner" diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 384a1e4ee4..6a706fede9 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -33,6 +33,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) var/usesound = null var/throwhitsound = null var/w_class = WEIGHT_CLASS_NORMAL + var/total_mass //Total mass in arbitrary pound-like values. If there's no balance reasons for an item to have otherwise, this var should be the item's weight in pounds. var/slot_flags = 0 //This is used to determine on which slots an item can fit. pass_flags = PASSTABLE pressure_resistance = 4 @@ -67,6 +68,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) var/strip_delay = 40 //In deciseconds, how long an item takes to remove from another person var/breakouttime = 0 var/list/materials + var/reskinned = FALSE var/list/attack_verb //Used in attackby() to say how something was attacked "[x] has been [z.attack_verb] by [y] with [z]" var/list/species_exception = null // list() of species types, if a species cannot put items in a certain slot, but species type is in list, it will be able to wear that item @@ -419,10 +421,10 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) //the mob M is attempting to equip this item into the slot passed through as 'slot'. Return 1 if it can do this and 0 if it can't. //if this is being done by a mob other than M, it will include the mob equipper, who is trying to equip the item to mob M. equipper will be null otherwise. //If you are making custom procs but would like to retain partial or complete functionality of this one, include a 'return ..()' to where you want this to happen. -//Set disable_warning to 1 if you wish it to not give you outputs. +//Set disable_warning to TRUE if you wish it to not give you outputs. /obj/item/proc/mob_can_equip(mob/living/M, mob/living/equipper, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE) if(!M) - return 0 + return FALSE return M.can_equip(src, slot, disable_warning, bypass_equip_delay_self) @@ -512,12 +514,12 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) log_combat(user, M, "attacked", "[src.name]", "(INTENT: [uppertext(user.a_intent)])") - M.adjust_blurriness(3) - M.adjust_eye_damage(rand(2,4)) var/obj/item/organ/eyes/eyes = M.getorganslot(ORGAN_SLOT_EYES) if (!eyes) return - if(eyes.eye_damage >= 10) + M.adjust_blurriness(3) + eyes.applyOrganDamage(rand(2,4)) + if(eyes.damage >= 10) M.adjust_blurriness(15) if(M.stat != DEAD) to_chat(M, "Your eyes start to bleed profusely!") @@ -531,7 +533,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) M.adjust_blurriness(10) M.Unconscious(20) M.Knockdown(40) - if (prob(eyes.eye_damage - 10 + 1)) + if (prob(eyes.damage - 10 + 1)) M.become_blind(EYE_DAMAGE) to_chat(M, "You go blind!") @@ -579,6 +581,9 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) /obj/item/proc/get_belt_overlay() //Returns the icon used for overlaying the object on a belt return mutable_appearance('icons/obj/clothing/belt_overlays.dmi', icon_state) +/obj/item/proc/get_worn_belt_overlay(icon_file) + return + /obj/item/proc/update_slot_icon() if(!ismob(loc)) return diff --git a/code/game/objects/items/RCD.dm b/code/game/objects/items/RCD.dm index 1ff3c7df9f..cf706359f7 100644 --- a/code/game/objects/items/RCD.dm +++ b/code/game/objects/items/RCD.dm @@ -37,6 +37,7 @@ RLD var/has_ammobar = FALSE //controls whether or not does update_icon apply ammo indicator overlays var/ammo_sections = 10 //amount of divisions in the ammo indicator overlay/number of ammo indicator states var/custom_range = 7 + var/upgrade = FALSE /obj/item/construction/Initialize() . = ..() @@ -82,6 +83,11 @@ RLD loaded = loadwithsheets(W, sheetmultiplier * 0.25, user) // 1 matter for 1 floortile, as 4 tiles are produced from 1 metal if(loaded) to_chat(user, "[src] now holds [matter]/[max_matter] matter-units.") + else if(istype(W, /obj/item/rcd_upgrade)) + to_chat(user, "You upgrade the RCD with the [W]!") + upgrade = TRUE + playsound(src.loc, 'sound/machines/click.ogg', 50, 1) + qdel(W) else return ..() update_icon() //ensures that ammo counters (if present) get updated @@ -148,6 +154,7 @@ RLD has_ammobar = TRUE var/mode = 1 var/ranged = FALSE + var/computer_dir = 1 var/airlock_type = /obj/machinery/door/airlock var/airlock_glass = FALSE // So the floor's rcd_act knows how much ammo to use var/window_type = /obj/structure/window/fulltile @@ -270,6 +277,28 @@ RLD return FALSE return TRUE +/obj/item/construction/rcd/proc/change_computer_dir(mob/user) + if(!user) + return + var/list/computer_dirs = list( + "NORTH" = image(icon = 'icons/mob/radial.dmi', icon_state = "cnorth"), + "EAST" = image(icon = 'icons/mob/radial.dmi', icon_state = "ceast"), + "SOUTH" = image(icon = 'icons/mob/radial.dmi', icon_state = "csouth"), + "WEST" = image(icon = 'icons/mob/radial.dmi', icon_state = "cwest") + ) + var/computerdirs = show_radial_menu(user, src, computer_dirs, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = TRUE, tooltips = TRUE) + if(!check_menu(user)) + return + switch(computerdirs) + if("NORTH") + computer_dir = 1 + if("EAST") + computer_dir = 4 + if("SOUTH") + computer_dir = 2 + if("WEST") + computer_dir = 8 + /obj/item/construction/rcd/proc/change_airlock_setting(mob/user) if(!user) return @@ -434,10 +463,15 @@ RLD ..() var/list/choices = list( "Airlock" = image(icon = 'icons/mob/radial.dmi', icon_state = "airlock"), - "Deconstruct" = image(icon= 'icons/mob/radial.dmi', icon_state = "delete"), "Grilles & Windows" = image(icon = 'icons/mob/radial.dmi', icon_state = "grillewindow"), "Floors & Walls" = image(icon = 'icons/mob/radial.dmi', icon_state = "wallfloor") ) + if(upgrade) + choices += list( + "Deconstruct" = image(icon= 'icons/mob/radial.dmi', icon_state = "delete"), + "Machine Frames" = image(icon = 'icons/mob/radial.dmi', icon_state = "machine"), + "Computer Frames" = image(icon = 'icons/mob/radial.dmi', icon_state = "computer_dir"), + ) if(mode == RCD_AIRLOCK) choices += list( "Change Access" = image(icon = 'icons/mob/radial.dmi', icon_state = "access"), @@ -459,6 +493,12 @@ RLD mode = RCD_DECONSTRUCT if("Grilles & Windows") mode = RCD_WINDOWGRILLE + if("Machine Frames") + mode = RCD_MACHINE + if("Computer Frames") + mode = RCD_COMPUTER + change_computer_dir(user) + return if("Change Access") change_airlock_access(user) return @@ -511,6 +551,7 @@ RLD no_ammo_message = "Insufficient charge." desc = "A device used to rapidly build walls and floors." canRturf = TRUE + upgrade = TRUE /obj/item/construction/rcd/borg/useResource(amount, mob/user) @@ -542,6 +583,9 @@ RLD /obj/item/construction/rcd/loaded matter = 160 +/obj/item/construction/rcd/loaded/upgraded + upgrade = TRUE + /obj/item/construction/rcd/combat name = "Combat RCD" desc = "A device used to rapidly build and deconstruct. Reload with metal, plasteel, glass or compressed matter cartridges. This RCD has been upgraded to be able to remove Rwalls!" @@ -582,7 +626,7 @@ RLD name = "admin RCD" max_matter = INFINITY matter = INFINITY - + upgrade = TRUE // Ranged RCD @@ -776,6 +820,12 @@ RLD return TRUE return FALSE +/obj/item/rcd_upgrade + name = "RCD advanced design disk" + desc = "It contains the design for machine frames, computer frames, and deconstruction." + icon = 'icons/obj/module.dmi' + icon_state = "datadisk3" + #undef GLOW_MODE #undef LIGHT_MODE #undef REMOVE_MODE diff --git a/code/game/objects/items/RSF.dm b/code/game/objects/items/RSF.dm index f0d15cc3a2..9c343c2e06 100644 --- a/code/game/objects/items/RSF.dm +++ b/code/game/objects/items/RSF.dm @@ -134,12 +134,14 @@ RSF return /obj/item/cookiesynth/emag_act(mob/user) + . = ..() obj_flags ^= EMAGGED if(obj_flags & EMAGGED) to_chat(user, "You short out [src]'s reagent safety checker!") else to_chat(user, "You reset [src]'s reagent safety checker!") - toxin = 0 + toxin = FALSE + return TRUE /obj/item/cookiesynth/attack_self(mob/user) var/mob/living/silicon/robot/P = null @@ -180,7 +182,7 @@ RSF to_chat(user, "Fabricating Cookie..") var/obj/item/reagent_containers/food/snacks/cookie/S = new /obj/item/reagent_containers/food/snacks/cookie(T) if(toxin) - S.reagents.add_reagent("chloralhydratedelayed", 10) + S.reagents.add_reagent("chloralhydrate", 10) if (iscyborg(user)) var/mob/living/silicon/robot/R = user R.cell.charge -= 100 diff --git a/code/game/objects/items/body_egg.dm b/code/game/objects/items/body_egg.dm index 80fc0f43fd..ea72197cf0 100644 --- a/code/game/objects/items/body_egg.dm +++ b/code/game/objects/items/body_egg.dm @@ -17,26 +17,27 @@ /obj/item/organ/body_egg/Insert(var/mob/living/carbon/M, special = 0) ..() ADD_TRAIT(owner, TRAIT_XENO_HOST, TRAIT_GENERIC) - START_PROCESSING(SSobj, src) owner.med_hud_set_status() INVOKE_ASYNC(src, .proc/AddInfectionImages, owner) /obj/item/organ/body_egg/Remove(var/mob/living/carbon/M, special = 0) - STOP_PROCESSING(SSobj, src) if(owner) REMOVE_TRAIT(owner, TRAIT_XENO_HOST, TRAIT_GENERIC) owner.med_hud_set_status() INVOKE_ASYNC(src, .proc/RemoveInfectionImages, owner) ..() -/obj/item/organ/body_egg/process() +/obj/item/organ/body_egg/on_death() + . = ..() if(!owner) return - if(!(src in owner.internal_organs)) - Remove(owner) - return egg_process() +/obj/item/organ/body_egg/on_life() + . = ..() + egg_process() + + /obj/item/organ/body_egg/proc/egg_process() return diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm index 96bbe759ca..875a4bd04f 100644 --- a/code/game/objects/items/cards_ids.dm +++ b/code/game/objects/items/cards_ids.dm @@ -93,34 +93,22 @@ /obj/item/card/emag/afterattack(atom/target, mob/user, proximity) . = ..() var/atom/A = target - if(!proximity && prox_check) + if(!proximity && prox_check || !(isobj(A) || issilicon(A) || isbot(A) || isdrone(A))) + return + if(istype(A, /obj/item/storage) && !(istype(A, /obj/item/storage/lockbox) || istype(A, /obj/item/storage/pod))) return - //Citadel changes: modular code misfiring, so we're bypassing into main code. if(!uses) user.visible_message("[src] emits a weak spark. It's burnt out!") playsound(src, 'sound/effects/light_flicker.ogg', 100, 1) return else if(uses <= 3) playsound(src, 'sound/effects/light_flicker.ogg', 30, 1) //Tiiiiiiny warning sound to let ya know your emag's almost dead - - if(isturf(A)) + if(!A.emag_act(user)) return - if(istype(A,/obj/item/storage/lockbox) || istype(A, /obj/item/storage/pod)) - A.emag_act(user) - uses = max(uses - 1, 0) - if(!uses) - user.visible_message("[src] fizzles and sparks. It seems like it's out of charges.") - playsound(src, 'sound/effects/light_flicker.ogg', 100, 1) - if(istype(A,/obj/item/storage)) - return - if(!(isobj(A) || issilicon(A) || isbot(A) || isdrone(A))) - return - else - A.emag_act(user) - uses = max(uses - 1, 0) - if(!uses) - user.visible_message("[src] fizzles and sparks. It seems like it's out of charges.") - playsound(src, 'sound/effects/light_flicker.ogg', 100, 1) + uses = max(uses - 1, 0) + if(!uses) + user.visible_message("[src] fizzles and sparks. It seems like it's out of charges.") + playsound(src, 'sound/effects/light_flicker.ogg', 100, 1) /obj/item/card/emagfake @@ -354,12 +342,41 @@ update_label("John Doe", "Clowny") lefthand_file = 'icons/mob/inhands/equipment/idcards_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/idcards_righthand.dmi' assignment = "Prisoner" - registered_name = "Scum" + access = list(ACCESS_ENTER_GENPOP) + + //Lavaland labor camp var/goal = 0 //How far from freedom? var/points = 0 + //Genpop + var/sentence = 0 //When world.time is greater than this number, the card will have its ACCESS_ENTER_GENPOP access replaced with ACCESS_LEAVE_GENPOP the next time it's checked, unless this value is 0/null + var/crime= "\[REDACTED\]" -/obj/item/card/id/prisoner/attack_self(mob/user) - to_chat(usr, "You have accumulated [points] out of the [goal] points you need for freedom.") +/obj/item/card/id/prisoner/GetAccess() + if((sentence && world.time >= sentence) || (goal && points >= goal)) + access = list(ACCESS_LEAVE_GENPOP) + return ..() + +/obj/item/card/id/prisoner/process() + if(!sentence) + STOP_PROCESSING(SSobj, src) + return + if(world.time >= sentence) + playsound(loc, 'sound/machines/ping.ogg', 50, 1) + if(isliving(loc)) + to_chat(loc, "[src] buzzes: You have served your sentence! You may now exit prison through the turnstiles and collect your belongings.") + STOP_PROCESSING(SSobj, src) + return + +/obj/item/card/id/prisoner/examine(mob/user) + . = ..() + if(sentence && world.time < sentence) + to_chat(user, "You're currently serving a sentence for [crime]. [DisplayTimeText(sentence - world.time)] left.") + else if(goal) + to_chat(user, "You have accumulated [points] out of the [goal] points you need for freedom.") + else if(!sentence) + to_chat(user, "You are currently serving a permanent sentence for [crime].") + else + to_chat(user, "Your sentence is up! You're free!") /obj/item/card/id/prisoner/one name = "Prisoner #13-001" diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm index 000c52ae43..09a128c558 100644 --- a/code/game/objects/items/cigs_lighters.dm +++ b/code/game/objects/items/cigs_lighters.dm @@ -764,20 +764,22 @@ CIGARETTE PACKETS ARE IN FANCY.DM ..() /obj/item/clothing/mask/vape/emag_act(mob/user)// I WON'T REGRET WRITTING THIS, SURLY. - if(screw) - if(!(obj_flags & EMAGGED)) - cut_overlays() - obj_flags |= EMAGGED - super = FALSE - to_chat(user, "You maximize the voltage of [src].") - add_overlay("vapeopen_high") - var/datum/effect_system/spark_spread/sp = new /datum/effect_system/spark_spread //for effect - sp.set_up(5, 1, src) - sp.start() - else - to_chat(user, "[src] is already emagged!") - else + . = ..() + if(!screw) to_chat(user, "You need to open the cap to do that.") + return + if(obj_flags & EMAGGED) + to_chat(user, "[src] is already emagged!") + return + cut_overlays() + obj_flags |= EMAGGED + super = FALSE + to_chat(user, "You maximize the voltage of [src].") + add_overlay("vapeopen_high") + var/datum/effect_system/spark_spread/sp = new /datum/effect_system/spark_spread //for effect + sp.set_up(5, 1, src) + sp.start() + return TRUE /obj/item/clothing/mask/vape/attack_self(mob/user) if(reagents.total_volume > 0) diff --git a/code/game/objects/items/circuitboards/computer_circuitboards.dm b/code/game/objects/items/circuitboards/computer_circuitboards.dm index 7d2ffe0a02..ac7879f9ec 100644 --- a/code/game/objects/items/circuitboards/computer_circuitboards.dm +++ b/code/game/objects/items/circuitboards/computer_circuitboards.dm @@ -59,7 +59,7 @@ name = "Department Management Console (Computer Board)" build_path = /obj/machinery/computer/card/minor var/target_dept = 1 - var/list/dept_list = list("General","Security","Medical","Science","Engineering") + var/list/dept_list = list("Civilian","Security","Medical","Science","Engineering","Cargo") /obj/item/circuitboard/computer/card/minor/attackby(obj/item/I, mob/user, params) if(istype(I, /obj/item/screwdriver)) @@ -162,10 +162,11 @@ /obj/item/circuitboard/computer/prisoner name = "Prisoner Management Console (Computer Board)" - build_path = /obj/machinery/computer/prisoner + build_path = /obj/machinery/computer/prisoner/management + /obj/item/circuitboard/computer/gulag_teleporter_console name = "Labor Camp teleporter console (Computer Board)" - build_path = /obj/machinery/computer/gulag_teleporter_computer + build_path = /obj/machinery/computer/prisoner/gulag_teleporter_computer /obj/item/circuitboard/computer/rdconsole/production name = "R&D Console Production Only (Computer Board)" @@ -217,10 +218,13 @@ to_chat(user, "The spectrum chip is unresponsive.") /obj/item/circuitboard/computer/cargo/emag_act(mob/living/user) - if(!(obj_flags & EMAGGED)) - contraband = TRUE - obj_flags |= EMAGGED - to_chat(user, "You adjust [src]'s routing and receiver spectrum, unlocking special supplies and contraband.") + . = ..() + if(obj_flags & EMAGGED) + return + contraband = TRUE + obj_flags |= EMAGGED + to_chat(user, "You adjust [src]'s routing and receiver spectrum, unlocking special supplies and contraband.") + return TRUE /obj/item/circuitboard/computer/cargo/express name = "Express Supply Console (Computer Board)" @@ -234,8 +238,12 @@ obj_flags &= ~EMAGGED /obj/item/circuitboard/computer/cargo/express/emag_act(mob/living/user) - to_chat(user, "You change the routing protocols, allowing the Drop Pod to land anywhere on the station.") - obj_flags |= EMAGGED + . = SEND_SIGNAL(src, COMSIG_ATOM_EMAG_ACT) + if(obj_flags & EMAGGED) + return + to_chat(user, "You change the routing protocols, allowing the Drop Pod to land anywhere on the station.") + obj_flags |= EMAGGED + return TRUE /obj/item/circuitboard/computer/cargo/request name = "Supply Request Console (Computer Board)" @@ -366,4 +374,4 @@ /obj/item/circuitboard/computer/nanite_cloud_controller name = "Nanite Cloud Control (Computer Board)" - build_path = /obj/machinery/computer/nanite_cloud_controller \ No newline at end of file + build_path = /obj/machinery/computer/nanite_cloud_controller diff --git a/code/game/objects/items/circuitboards/machine_circuitboards.dm b/code/game/objects/items/circuitboards/machine_circuitboards.dm index 2a01a7e18f..639d570462 100644 --- a/code/game/objects/items/circuitboards/machine_circuitboards.dm +++ b/code/game/objects/items/circuitboards/machine_circuitboards.dm @@ -399,6 +399,7 @@ /obj/machinery/smartfridge/food = "food", /obj/machinery/smartfridge/drinks = "drinks", /obj/machinery/smartfridge/extract = "slimes", + /obj/machinery/smartfridge/organ = "organs", /obj/machinery/smartfridge/chemistry = "chems", /obj/machinery/smartfridge/chemistry/virology = "viruses", /obj/machinery/smartfridge/disks = "disks") diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm index 99d6c874e8..102c6a8eed 100644 --- a/code/game/objects/items/crayons.dm +++ b/code/game/objects/items/crayons.dm @@ -1,6 +1,9 @@ #define RANDOM_GRAFFITI "Random Graffiti" #define RANDOM_LETTER "Random Letter" +#define RANDOM_PUNCTUATION "Random Punctuation" #define RANDOM_NUMBER "Random Number" +#define RANDOM_SYMBOL "Random Symbol" +#define RANDOM_DRAWING "Random Drawing" #define RANDOM_ORIENTED "Random Oriented" #define RANDOM_RUNE "Random Rune" #define RANDOM_ANY "Random Anything" @@ -32,16 +35,16 @@ var/drawtype var/text_buffer = "" - var/list/graffiti = list("amyjon","face","matt","revolution","engie","guy","end","dwarf","uboa","body","cyka","arrow","star","poseur tag","prolizard","antilizard", "tile") //cit edit - var/list/letters = list("a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z") - var/list/numerals = list("0","1","2","3","4","5","6","7","8","9") - var/list/oriented = list("arrow","body") // These turn to face the same way as the drawer - var/list/runes = list("rune1","rune2","rune3","rune4","rune5","rune6") - var/list/randoms = list(RANDOM_ANY, RANDOM_RUNE, RANDOM_ORIENTED, - RANDOM_NUMBER, RANDOM_GRAFFITI, RANDOM_LETTER) - var/list/graffiti_large_h = list("yiffhell", "secborg", "paint") + var/static/list/graffiti = list("amyjon","face","matt","revolution","engie","guy","end","dwarf","uboa","body","cyka","star","poseur tag","prolizard","antilizard", "tile") + var/static/list/symbols = list("danger","firedanger","electricdanger","biohazard","radiation","safe","evac","space","med","trade","shop","food","peace","like","skull","nay","heart","credit") + var/static/list/drawings = list("smallbrush","brush","largebrush","splatter","snake","stickman","carp","ghost","clown","taser","disk","fireaxe","toolbox","corgi","cat","toilet","blueprint","beepsky","scroll","bottle","shotgun") + var/static/list/oriented = list("arrow","line","thinline","shortline","body","chevron","footprint","clawprint","pawprint") // These turn to face the same way as the drawer + var/static/list/runes = list("rune1","rune2","rune3","rune4","rune5","rune6") + var/static/list/randoms = list(RANDOM_ANY, RANDOM_RUNE, RANDOM_ORIENTED, + RANDOM_NUMBER, RANDOM_GRAFFITI, RANDOM_LETTER, RANDOM_SYMBOL, RANDOM_PUNCTUATION, RANDOM_DRAWING) + var/static/list/graffiti_large_h = list("yiffhell", "secborg", "paint") - var/list/all_drawables + var/static/list/all_drawables = graffiti + symbols + drawings + oriented + runes + graffiti_large_h var/paint_mode = PAINT_NORMAL @@ -54,8 +57,6 @@ var/instant = FALSE var/self_contained = TRUE // If it deletes itself when it is empty - var/list/validSurfaces = list(/turf/open/floor) - var/edible = TRUE // That doesn't mean eating it is a good idea var/list/reagent_contents = list("nutriment" = 1) @@ -71,6 +72,9 @@ var/datum/team/gang/gang //For marking territory. var/gang_tag_delay = 30 //this is the delay for gang mode tag applications on anything that gang = true on. +/obj/item/toy/crayon/proc/isValidSurface(surface) + return istype(surface, /turf/open/floor) + /obj/item/toy/crayon/suicide_act(mob/user) user.visible_message("[user] is jamming [src] up [user.p_their()] nose and into [user.p_their()] brain. It looks like [user.p_theyre()] trying to commit suicide!") return (BRUTELOSS|OXYLOSS) @@ -81,7 +85,6 @@ if(name == "crayon") name = "[item_color] crayon" - all_drawables = graffiti + letters + numerals + oriented + runes + graffiti_large_h drawtype = pick(all_drawables) refill() @@ -153,55 +156,62 @@ to_chat(user, "The cap on [src] is now [is_capped ? "on" : "off"].") update_icon() -/obj/item/toy/crayon/ui_data() - var/list/data = list() - data["drawables"] = list() - var/list/D = data["drawables"] +/obj/item/toy/crayon/proc/staticDrawables() + + . = list() var/list/g_items = list() - D += list(list("name" = "Graffiti", "items" = g_items)) + . += list(list("name" = "Graffiti", "items" = g_items)) for(var/g in graffiti) g_items += list(list("item" = g)) var/list/glh_items = list() - D += list(list("name" = "Graffiti Large Horizontal", "items" = glh_items)) + . += list(list("name" = "Graffiti Large Horizontal", "items" = glh_items)) for(var/glh in graffiti_large_h) glh_items += list(list("item" = glh)) - var/list/L_items = list() - D += list(list("name" = "Letters", "items" = L_items)) - for(var/L in letters) - L_items += list(list("item" = L)) + var/list/S_items = list() + . += list(list("name" = "Symbols", "items" = S_items)) + for(var/S in symbols) + S_items += list(list("item" = S)) - var/list/N_items = list() - D += list(list(name = "Numerals", "items" = N_items)) - for(var/N in numerals) - N_items += list(list("item" = N)) + var/list/D_items = list() + . += list(list("name" = "Drawings", "items" = D_items)) + for(var/D in drawings) + D_items += list(list("item" = D)) var/list/O_items = list() - D += list(list(name = "Oriented", "items" = O_items)) + . += list(list(name = "Oriented", "items" = O_items)) for(var/O in oriented) O_items += list(list("item" = O)) var/list/R_items = list() - D += list(list(name = "Runes", "items" = R_items)) + . += list(list(name = "Runes", "items" = R_items)) for(var/R in runes) R_items += list(list("item" = R)) var/list/rand_items = list() - D += list(list(name = "Random", "items" = rand_items)) + . += list(list(name = "Random", "items" = rand_items)) for(var/i in randoms) rand_items += list(list("item" = i)) - data["selected_stencil"] = drawtype - data["text_buffer"] = text_buffer - data["has_cap"] = has_cap - data["is_capped"] = is_capped - data["can_change_colour"] = can_change_colour - data["current_colour"] = paint_color +/obj/item/toy/crayon/ui_data() - return data + var/static/list/crayon_drawables + + if (!crayon_drawables) + crayon_drawables = staticDrawables() + + . = list() + .["drawables"] = crayon_drawables + .["selected_stencil"] = drawtype + .["text_buffer"] = text_buffer + + .["has_cap"] = has_cap + .["is_capped"] = is_capped + .["can_change_colour"] = can_change_colour + .["current_colour"] = paint_color /obj/item/toy/crayon/ui_act(action, list/params) if(..()) @@ -216,6 +226,7 @@ if(stencil in all_drawables + randoms) drawtype = stencil . = TRUE + text_buffer = "" if(stencil in graffiti_large_h) paint_mode = PAINT_LARGE_HORIZONTAL text_buffer = "" @@ -223,8 +234,13 @@ paint_mode = PAINT_NORMAL if("select_colour") if(can_change_colour) - paint_color = input(usr,"","Choose Color",paint_color) as color|null - . = TRUE + var/chosen_colour = input(usr,"","Choose Color",paint_color) as color|null + + if (!isnull(chosen_colour)) + paint_color = chosen_colour + . = TRUE + else + . = FALSE if("enter_text") var/txt = stripped_input(usr,"Choose what to write.", "Scribbles",default = text_buffer) @@ -235,18 +251,16 @@ update_icon() /obj/item/toy/crayon/proc/crayon_text_strip(text) - var/list/base = string2charlist(lowertext(text)) - var/list/out = list() - for(var/a in base) - if(a in (letters|numerals)) - out += a - return jointext(out,"") + var/static/regex/crayon_r = new /regex(@"[^\w!?,.=%#&+\/\-]") + return replacetext(lowertext(text), crayon_r, "") /obj/item/toy/crayon/afterattack(atom/target, mob/user, proximity, params) . = ..() if(!proximity || !check_allowed_items(target)) return + var/static/list/punctuation = list("!","?",".",",","/","+","-","=","%","#","&") + var/cost = 1 if(paint_mode == PAINT_LARGE_HORIZONTAL) cost = 5 @@ -264,13 +278,19 @@ if(istype(target, /obj/effect/decal/cleanable)) target = target.loc - if(!is_type_in_list(target,validSurfaces)) + if(!isValidSurface(target)) return var/drawing = drawtype switch(drawtype) if(RANDOM_LETTER) - drawing = pick(letters) + drawing = ascii2text(rand(97, 122)) // a-z + if(RANDOM_PUNCTUATION) + drawing = pick(punctuation) + if(RANDOM_SYMBOL) + drawing = pick(symbols) + if(RANDOM_DRAWING) + drawing = pick(drawings) if(RANDOM_GRAFFITI) drawing = pick(graffiti) if(RANDOM_RUNE) @@ -278,17 +298,24 @@ if(RANDOM_ORIENTED) drawing = pick(oriented) if(RANDOM_NUMBER) - drawing = pick(numerals) + drawing = ascii2text(rand(48, 57)) // 0-9 if(RANDOM_ANY) drawing = pick(all_drawables) var/temp = "rune" - if(drawing in letters) + var/ascii = (length(drawing) == 1) ? TRUE : FALSE + if(ascii && is_alpha(drawing)) temp = "letter" - else if(drawing in graffiti) - temp = "graffiti" - else if(drawing in numerals) + else if(ascii && is_digit(drawing)) temp = "number" + else if(drawing in punctuation) + temp = "punctuation mark" + else if(drawing in symbols) + temp = "symbol" + else if(drawing in drawings) + temp = "drawing" + else if(drawing in graffiti|oriented) + temp = "graffiti" // If a gang member is using a gang spraycan, it'll behave differently var/gang_mode = FALSE @@ -338,7 +365,7 @@ return if(length(text_buffer)) - drawing = copytext(text_buffer,1,2) + drawing = text_buffer[1] var/list/turf/affected_turfs = list() @@ -362,7 +389,7 @@ if(PAINT_LARGE_HORIZONTAL) var/turf/left = locate(target.x-1,target.y,target.z) var/turf/right = locate(target.x+1,target.y,target.z) - if(is_type_in_list(left, validSurfaces) && is_type_in_list(right, validSurfaces)) + if(isValidSurface(left) && isValidSurface(right)) var/obj/effect/decal/cleanable/crayon/C = new(left, paint_color, drawing, temp, graf_rot, PAINT_LARGE_HORIZONTAL_ICON) C.add_hiddenprint(user) affected_turfs += left @@ -377,8 +404,9 @@ else to_chat(user, "You spray a [temp] on \the [target.name]") - if(length(text_buffer)) + if(length(text_buffer) > 1) text_buffer = copytext(text_buffer,2) + SStgui.update_uis(src) if(post_noise) audible_message("You hear spraying.") @@ -516,7 +544,7 @@ charges = -1 -/obj/item/toy/crayon/rainbow/afterattack(atom/target, mob/user, proximity) +/obj/item/toy/crayon/rainbow/afterattack(atom/target, mob/user, proximity, params) paint_color = rgb(rand(0,255), rand(0,255), rand(0,255)) . = ..() @@ -591,12 +619,14 @@ can_change_colour = TRUE gang = TRUE //Gang check is true for all things upon the honored hierarchy of spraycans, except those that are FALSE. - validSurfaces = list(/turf/open/floor, /turf/closed/wall) reagent_contents = list("welding_fuel" = 1, "ethanol" = 1) pre_noise = TRUE post_noise = FALSE +/obj/item/toy/crayon/spraycan/isValidSurface(surface) + return (istype(surface, /turf/open/floor) || istype(surface, /turf/closed/wall)) + /obj/item/toy/crayon/spraycan/suicide_act(mob/user) var/mob/living/carbon/human/H = user if(is_capped || !actually_paints) @@ -622,8 +652,8 @@ return (OXYLOSS) -/obj/item/toy/crayon/spraycan/New() - ..() +/obj/item/toy/crayon/spraycan/Initialize() + . = ..() // If default crayon red colour, pick a more fun spraycan colour if(!paint_color) paint_color = pick("#DA0000","#FF9300","#FFF200","#A8E61D","#00B7EF", @@ -640,7 +670,7 @@ to_chat(user, "It is empty.") to_chat(user, "Alt-click [src] to [ is_capped ? "take the cap off" : "put the cap on"].") -/obj/item/toy/crayon/spraycan/afterattack(atom/target, mob/user, proximity) +/obj/item/toy/crayon/spraycan/afterattack(atom/target, mob/user, proximity, params) if(!proximity) return @@ -656,8 +686,7 @@ playsound(user.loc, 'sound/effects/spray.ogg', 25, 1, 5) var/mob/living/carbon/C = target - user.visible_message("[user] sprays [src] into the face of [target]!") - to_chat(target, "[user] sprays [src] into your face!") + C.visible_message("[user] sprays [src] into the face of [C]!", "[user] sprays [src] into your face!") if(C.client) C.blur_eyes(3) @@ -678,13 +707,20 @@ return - if(istype(target, /obj/structure/window)) + if(isobj(target)) if(actually_paints) + if(color_hex2num(paint_color) < 350 && !istype(target, /obj/structure/window) && !istype(target, /obj/effect/decal/cleanable/crayon)) //Colors too dark are rejected + to_chat(usr, "A color that dark on an object like this? Surely not...") + return FALSE + target.add_atom_colour(paint_color, WASHABLE_COLOUR_PRIORITY) - if(color_hex2num(paint_color) < 255) - target.set_opacity(255) - else - target.set_opacity(initial(target.opacity)) + + if(istype(target, /obj/structure/window)) + if(color_hex2num(paint_color) < 255) + target.set_opacity(255) + else + target.set_opacity(initial(target.opacity)) + . = use_charges(user, 2) var/fraction = min(1, . / reagents.maximum_volume) reagents.reaction(target, TOUCH, fraction * volume_multiplier) @@ -692,6 +728,7 @@ if(pre_noise || post_noise) playsound(user.loc, 'sound/effects/spray.ogg', 5, 1, 5) + user.visible_message("[user] coats [target] with spray paint!", "You coat [target] with spray paint.") return . = ..() @@ -709,7 +746,7 @@ desc = "A metallic container containing shiny synthesised paint." charges = -1 -/obj/item/toy/crayon/spraycan/borg/afterattack(atom/target,mob/user,proximity) +/obj/item/toy/crayon/spraycan/borg/afterattack(atom/target,mob/user,proximity, params) var/diff = ..() if(!iscyborg(user)) to_chat(user, "How did you get this?") @@ -754,7 +791,9 @@ reagent_contents = list("lube" = 1, "banana" = 1) volume_multiplier = 5 - validSurfaces = list(/turf/open/floor) + +/obj/item/toy/crayon/spraycan/lubecan/isValidSurface(surface) + return istype(surface, /turf/open/floor) /obj/item/toy/crayon/spraycan/mimecan name = "silent spraycan" @@ -792,8 +831,16 @@ if(user.mind && user.mind.has_antag_datum(/datum/antagonist/gang) || isobserver(user)) to_chat(user, "This spraycan has been specially modified with a stage 2 nozzle kit, making it faster.") +/obj/item/toy/crayon/spraycan/infinite + name = "infinite spraycan" + charges = -1 + desc = "Now with 30% more bluespace technology." + #undef RANDOM_GRAFFITI #undef RANDOM_LETTER +#undef RANDOM_PUNCTUATION +#undef RANDOM_SYMBOL +#undef RANDOM_DRAWING #undef RANDOM_NUMBER #undef RANDOM_ORIENTED #undef RANDOM_RUNE diff --git a/code/game/objects/items/defib.dm b/code/game/objects/items/defib.dm index 55e75b3992..a4f286bf88 100644 --- a/code/game/objects/items/defib.dm +++ b/code/game/objects/items/defib.dm @@ -140,12 +140,10 @@ return ..() /obj/item/defibrillator/emag_act(mob/user) - if(safety) - safety = FALSE - to_chat(user, "You silently disable [src]'s safety protocols with the cryptographic sequencer.") - else - safety = TRUE - to_chat(user, "You silently enable [src]'s safety protocols with the cryptographic sequencer.") + . = ..() + safety = !safety + to_chat(user, "You silently [safety ? "enable" : "disable"] [src]'s safety protocols with the cryptographic sequencer.") + return TRUE /obj/item/defibrillator/emp_act(severity) . = ..() @@ -442,9 +440,20 @@ do_help(H, user) -/obj/item/twohanded/shockpaddles/proc/can_defib(mob/living/carbon/H) +/obj/item/twohanded/shockpaddles/proc/can_defib(mob/living/carbon/H) //Our code here is different than tg, if it breaks in testing; BUG_PROBABLE_CAUSE + var/obj/item/organ/heart = H.getorgan(/obj/item/organ/heart) + if(H.suiciding || H.hellbound || HAS_TRAIT(H, TRAIT_HUSK)) + return + if((world.time - H.timeofdeath) > tlimit) + return + if((H.getBruteLoss() >= MAX_REVIVE_BRUTE_DAMAGE) || (H.getFireLoss() >= MAX_REVIVE_FIRE_DAMAGE)) + return + if(!heart || (heart.organ_flags & ORGAN_FAILING)) + return var/obj/item/organ/brain/BR = H.getorgan(/obj/item/organ/brain) - return (!H.suiciding && !(HAS_TRAIT(H, TRAIT_NOCLONE)) && !H.hellbound && ((world.time - H.timeofdeath) < tlimit) && (H.getBruteLoss() < 180) && (H.getFireLoss() < 180) && H.getorgan(/obj/item/organ/heart) && BR && !BR.damaged_brain) + if(QDELETED(BR) || BR.brain_death || (BR.organ_flags & ORGAN_FAILING) || H.suiciding) + return + return TRUE /obj/item/twohanded/shockpaddles/proc/shock_touching(dmg, mob/H) if(req_defib) @@ -559,14 +568,12 @@ if(do_after(user, primetimer, target = H)) //beginning to place the paddles on patient's chest to allow some time for people to move away to stop the process user.visible_message("[user] places [src] on [H]'s chest.", "You place [src] on [H]'s chest.") playsound(src, 'sound/machines/defib_charge.ogg', 75, 0) - var/tplus = world.time - H.timeofdeath - // past this much time the patient is unrecoverable - // (in deciseconds) - // brain damage starts setting in on the patient after - // some time left rotting + // patients rot when they are killed, and die when they are dead + var/tplus = world.time - H.timeofdeath //length of time spent dead var/tloss = deathtimer var/total_burn = 0 var/total_brute = 0 + var/obj/item/organ/heart = H.getorgan(/obj/item/organ/heart) if(do_after(user, primetimer2, target = H)) //placed on chest and short delay to shock for dramatic effect, revive time is 5sec total for(var/obj/item/carried_item in H.contents) if(istype(carried_item, /obj/item/clothing/suit/space)) @@ -591,16 +598,26 @@ failed = "[req_defib ? "[defib]" : "[src]"] buzzes: Resuscitation failed - Patient's soul appears to be on another plane of existence. Further attempts futile." else if (tplus > tlimit) failed = "[req_defib ? "[defib]" : "[src]"] buzzes: Resuscitation failed - Body has decayed for too long. Further attempts futile." - else if (!H.getorgan(/obj/item/organ/heart)) + else if (!heart) failed = "[req_defib ? "[defib]" : "[src]"] buzzes: Resuscitation failed - Patient's heart is missing." + else if (heart.organ_flags & ORGAN_FAILING) + failed = "[req_defib ? "[defib]" : "[src]"] buzzes: Resuscitation failed - Patient's heart too damaged." else if(total_burn >= 180 || total_brute >= 180) failed = "[req_defib ? "[defib]" : "[src]"] buzzes: Resuscitation failed - Severe tissue damage makes recovery of patient impossible via defibrillator. Further attempts futile." else if(H.get_ghost()) failed = "[req_defib ? "[defib]" : "[src]"] buzzes: Resuscitation failed - No activity in patient's brain. Further attempts may be successful." else var/obj/item/organ/brain/BR = H.getorgan(/obj/item/organ/brain) - if(!BR || BR.damaged_brain) - failed = "[req_defib ? "[defib]" : "[src]"] buzzes: Resuscitation failed - Patient's brain is missing or damaged beyond point of no return. Further attempts futile." + if(BR) //BUG_PROBABLE_CAUSE - slight difference between us and tg + if(BR.organ_flags & ORGAN_FAILING) + failed = "[req_defib ? "[defib]" : "[src]"] buzzes: Resuscitation failed - Patient's brain tissue is damaged making recovery of patient impossible via defibrillator. Further attempts futile." + if(BR.brain_death) + failed = "[req_defib ? "[defib]" : "[src]"] buzzes: Resuscitation failed - Patient's brain damaged beyond point of no return. Further attempts futile." + if(H.suiciding || BR.brainmob?.suiciding) + failed = "[req_defib ? "[defib]" : "[src]"] buzzes: Resuscitation failed - No intelligence pattern can be detected in patient's brain. Further attempts futile." + else + failed = "[req_defib ? "[defib]" : "[src]"] buzzes: Resuscitation failed - Patient's brain is missing. Further attempts futile." + if(failed) user.visible_message(failed) @@ -625,7 +642,7 @@ H.Jitter(100) SEND_SIGNAL(H, COMSIG_LIVING_MINOR_SHOCK) if(tplus > tloss) - H.adjustBrainLoss( max(0, min(99, ((tlimit - tplus) / tlimit * 100))), 150) + H.adjustOrganLoss(ORGAN_SLOT_BRAIN, max(0, min(99, ((tlimit - tplus) / tlimit * 100))), 150) log_combat(user, H, "revived", defib) if(req_defib) if(defib.healdisk) @@ -643,7 +660,11 @@ playsound(src, 'sound/machines/defib_failed.ogg', 50, 0) else if(H.undergoing_cardiac_arrest()) H.set_heartattack(FALSE) - user.visible_message("[req_defib ? "[defib]" : "[src]"] pings: Patient's heart is now beating again.") + if(!(heart.organ_flags & ORGAN_FAILING)) + H.set_heartattack(FALSE) + user.visible_message("[req_defib ? "[defib]" : "[src]"] pings: Patient's heart is now beating again.") + else + user.visible_message("[req_defib ? "[defib]" : "[src]"] buzzes: Resuscitation failed, heart damage detected.") playsound(src, 'sound/machines/defib_zap.ogg', 50, 1, -1) diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index 45baa542d4..b0494539ce 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -714,6 +714,7 @@ GLOBAL_LIST_EMPTY(PDAs) return if((last_text && world.time < last_text + 10) || (everyone && last_everyone && world.time < last_everyone + PDA_SPAM_DELAY)) return + var/emoji_message = emoji_parse(message) if(prob(1)) message += "\nSent from my PDA" // Send the signal @@ -734,7 +735,8 @@ GLOBAL_LIST_EMPTY(PDAs) "name" = "[owner]", "job" = "[ownjob]", "message" = message, - "targets" = string_targets + "targets" = string_targets, + "emoji_message" = emoji_message )) if (picture) signal.data["photo"] = picture @@ -751,13 +753,13 @@ GLOBAL_LIST_EMPTY(PDAs) // Log it in our logs tnote += "→ To [target_text]:
[signal.format_message()]
" // Show it to ghosts - var/ghost_message = "[owner] PDA Message --> [target_text]: [signal.format_message()]" + var/ghost_message = "[owner] PDA Message --> [target_text]: [signal.format_message(TRUE)]" for(var/mob/M in GLOB.player_list) if(isobserver(M) && M.client && (M.client.prefs.chat_toggles & CHAT_GHOSTPDA)) to_chat(M, "[FOLLOW_LINK(M, user)] [ghost_message]") // Log in the talk log user.log_talk(message, LOG_PDA, tag="PDA: [initial(name)] to [target_text]") - to_chat(user, "Message sent to [target_text]: \"[message]\"") + to_chat(user, "Message sent to [target_text]: \"[emoji_message]\"") if (!silent) playsound(src, 'sound/machines/terminal_success.ogg', 15, 1) // Reset the photo @@ -787,7 +789,7 @@ GLOBAL_LIST_EMPTY(PDAs) hrefstart = "" hrefend = "" - to_chat(L, "[icon2html(src)] Message from [hrefstart][signal.data["name"]] ([signal.data["job"]])[hrefend], [signal.format_message()] (Reply)") + to_chat(L, "[icon2html(src)] Message from [hrefstart][signal.data["name"]] ([signal.data["job"]])[hrefend], [signal.format_message(TRUE)] (Reply)") update_icon(TRUE) diff --git a/code/game/objects/items/devices/PDA/cart.dm b/code/game/objects/items/devices/PDA/cart.dm index bf352e8eb7..3885a1f4d9 100644 --- a/code/game/objects/items/devices/PDA/cart.dm +++ b/code/game/objects/items/devices/PDA/cart.dm @@ -498,6 +498,23 @@ Code: else menu += "[ldat]" + menu += "

Pimpin' Ride:

" + + ldat = null + for (var/obj/vehicle/ridden/janicart/M in world) + var/turf/ml = get_turf(M) + + if(ml) + if (ml.z != cl.z) + continue + var/direction = get_dir(src, M) + ldat += "Ride - \[[ml.x],[ml.y] ([uppertext(dir2text(direction))])\]
" + + if (!ldat) + menu += "None" + else + menu += "[ldat]" + menu += "

Located Janitorial Cart:

" ldat = null diff --git a/code/game/objects/items/devices/dogborg_sleeper.dm b/code/game/objects/items/devices/dogborg_sleeper.dm index 7f3c7f3bfc..c1a9136f76 100644 --- a/code/game/objects/items/devices/dogborg_sleeper.dm +++ b/code/game/objects/items/devices/dogborg_sleeper.dm @@ -211,7 +211,7 @@ data["occupant"]["toxLoss"] = mob_occupant.getToxLoss() data["occupant"]["fireLoss"] = mob_occupant.getFireLoss() data["occupant"]["cloneLoss"] = mob_occupant.getCloneLoss() - data["occupant"]["brainLoss"] = mob_occupant.getBrainLoss() + data["occupant"]["brainLoss"] = mob_occupant.getOrganLoss(ORGAN_SLOT_BRAIN) data["occupant"]["reagents"] = list() if(mob_occupant.reagents.reagent_list.len) for(var/datum/reagent/R in mob_occupant.reagents.reagent_list) @@ -544,4 +544,26 @@ user.visible_message("[hound.name]'s garbage processor groans lightly as [trashman] slips inside.", "Your garbage compactor groans lightly as [trashman] slips inside.") playsound(hound, 'sound/effects/bin_close.ogg', 80, 1) return + else if(issilicon(target)) + var/mob/living/silicon/trashbot = target + if (!trashbot.devourable) + to_chat(user, "[target] registers an error code to your [src]") + return + if(patient) + to_chat(user,"Your [src] is already occupied.") + return + if(trashbot.buckled) + to_chat(user,"[trashbot] is buckled and can not be put into your [src].") + return + user.visible_message("[hound.name] is ingesting [trashbot] into their [src].", "You start ingesting [trashbot] into your [src.name]...") + if(do_after(user, 30, target = trashbot) && !patient && !trashbot.buckled && length(contents) < max_item_count) + if(!in_range(src, trashbot)) //Proximity is probably old news by now, do a new check. + return //If they moved away, you can't eat them. + trashbot.forceMove(src) + trashbot.reset_perspective(src) + update_gut() + user.visible_message("[hound.name]'s garbage processor groans lightly as [trashbot] slips inside.", "Your garbage compactor groans lightly as [trashbot] slips inside.") + playsound(hound, 'sound/effects/bin_close.ogg', 80, 1) + return + return diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm index 722510dccb..b937f961c0 100644 --- a/code/game/objects/items/devices/flashlight.dm +++ b/code/game/objects/items/devices/flashlight.dm @@ -96,7 +96,7 @@ if(BODY_ZONE_PRECISE_MOUTH) - if((M.head && M.head.flags_cover & HEADCOVERSMOUTH) || (M.wear_mask && M.wear_mask.flags_cover & MASKCOVERSMOUTH)) + if(M.is_mouth_covered()) to_chat(user, "You're going to need to remove that [(M.head && M.head.flags_cover & HEADCOVERSMOUTH) ? "helmet" : "mask"] first.") return diff --git a/code/game/objects/items/devices/geiger_counter.dm b/code/game/objects/items/devices/geiger_counter.dm index 7823e570e0..90cdd0386c 100644 --- a/code/game/objects/items/devices/geiger_counter.dm +++ b/code/game/objects/items/devices/geiger_counter.dm @@ -158,7 +158,7 @@ if(!M.radiation) to_chat(user, "[icon2html(src, user)] Radiation levels within normal boundaries.") else - to_chat(user, "[icon2html(src, user)] Subject is irradiated. Radiation levels: [M.radiation].") + to_chat(user, "[icon2html(src, user)] Subject is irradiated. Radiation levels: [M.radiation] rad.") if(rad_strength) to_chat(user, "[icon2html(src, user)] Target contains radioactive contamination. Radioactive strength: [rad_strength]") @@ -192,13 +192,15 @@ update_icon() /obj/item/geiger_counter/emag_act(mob/user) + . = ..() if(obj_flags & EMAGGED) return if(scanning) to_chat(user, "Turn off [src] before you perform this action!") - return 0 + return to_chat(user, "You override [src]'s radiation storing protocols. It will now generate small doses of radiation, and stored rads are now projected into creatures you scan.") obj_flags |= EMAGGED + return TRUE /obj/item/geiger_counter/cyborg var/datum/component/mobhook diff --git a/code/game/objects/items/devices/gps.dm b/code/game/objects/items/devices/gps.dm index 637bb794d3..9d1b670e71 100644 --- a/code/game/objects/items/devices/gps.dm +++ b/code/game/objects/items/devices/gps.dm @@ -167,8 +167,19 @@ GLOBAL_LIST_EMPTY(GPS_list) gpstag = "Eerie Signal" desc = "Report to a coder immediately." invisibility = INVISIBILITY_MAXIMUM + var/obj/item/implant/gps/implant -/obj/item/gps/mining/internal +/obj/item/gps/internal/Initialize(mapload, obj/item/implant/gps/_implant) + . = ..() + implant = _implant + +/obj/item/gps/internal/Destroy() + if(implant?.imp_in) + qdel(implant) + else + return ..() + +/obj/item/gps/internal/mining icon_state = "gps-m" gpstag = "MINER" desc = "A positioning system helpful for rescuing trapped or injured miners, keeping one on you at all times while mining might just save your life." diff --git a/code/game/objects/items/devices/lightreplacer.dm b/code/game/objects/items/devices/lightreplacer.dm index 6615ebe8a8..1e31f14cfd 100644 --- a/code/game/objects/items/devices/lightreplacer.dm +++ b/code/game/objects/items/devices/lightreplacer.dm @@ -149,9 +149,11 @@ to_chat(user, "You fill \the [src] with lights from \the [S]. " + status_string() + "") /obj/item/lightreplacer/emag_act() + . = ..() if(obj_flags & EMAGGED) return Emag() + return TRUE /obj/item/lightreplacer/attack_self(mob/user) to_chat(user, status_string()) diff --git a/code/game/objects/items/devices/megaphone.dm b/code/game/objects/items/devices/megaphone.dm index 347bb6894d..915fcac504 100644 --- a/code/game/objects/items/devices/megaphone.dm +++ b/code/game/objects/items/devices/megaphone.dm @@ -38,11 +38,13 @@ speech_args[SPEECH_SPANS] |= voicespan /obj/item/megaphone/emag_act(mob/user) + . = ..() if(obj_flags & EMAGGED) return to_chat(user, "You overload \the [src]'s voice synthesizer.") obj_flags |= EMAGGED voicespan = list(SPAN_REALLYBIG, "userdanger") + return TRUE /obj/item/megaphone/sec name = "security megaphone" diff --git a/code/game/objects/items/devices/multitool.dm b/code/game/objects/items/devices/multitool.dm index f8b1d6e15b..207497922e 100644 --- a/code/game/objects/items/devices/multitool.dm +++ b/code/game/objects/items/devices/multitool.dm @@ -32,6 +32,24 @@ var/datum/integrated_io/selected_io = null //functional for integrated circuits. var/mode = 0 +/obj/item/multitool/chaplain + name = "\improper hypertool" + desc = "Used for pulsing wires to test which to cut. Also emits microwaves to fry some brains!" + damtype = BRAIN + force = 18 + armour_penetration = 35 + hitsound = 'sound/effects/sparks4.ogg' + var/chaplain_spawnable = TRUE + total_mass = TOTAL_MASS_MEDIEVAL_WEAPON + throw_speed = 3 + throw_range = 4 + throwforce = 10 + obj_flags = UNIQUE_RENAME + +/obj/item/multitool/chaplain/Initialize() + . = ..() + AddComponent(/datum/component/anti_magic, TRUE, TRUE) + /obj/item/multitool/examine(mob/user) ..() if(selected_io) @@ -237,3 +255,10 @@ icon = 'icons/obj/abductor.dmi' icon_state = "multitool" toolspeed = 0.1 + +/obj/item/multitool/advanced + name = "advanced multitool" + desc = "The reproduction of an abductor's multitool, this multitool is a classy silver." + icon = 'icons/obj/advancedtools.dmi' + icon_state = "multitool" + toolspeed = 0.2 diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index 7c136f556e..926810cfbf 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -413,3 +413,16 @@ /obj/item/radio/off // Station bounced radios, their only difference is spawning with the speakers off, this was made to help the lag. listening = 0 // And it's nice to have a subtype too for future features. dog_fashion = /datum/dog_fashion/back + +/obj/item/radio/internal + var/obj/item/implant/radio/implant + +/obj/item/radio/internal/Initialize(mapload, obj/item/implant/radio/_implant) + . = ..() + implant = _implant + +/obj/item/radio/internal/Destroy() + if(implant?.imp_in) + qdel(implant) + else + return ..() diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index 57b9e89af7..7655654f78 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -135,7 +135,7 @@ SLIME SCANNER var/mob/living/carbon/human/H = M if(H.undergoing_cardiac_arrest() && H.stat != DEAD) to_chat(user, "Subject suffering from heart attack: Apply defibrillation or other electric shock immediately!") - if(H.undergoing_liver_failure() && H.stat != DEAD) + if(H.undergoing_liver_failure() && H.stat != DEAD) //might be depreciated BUG_PROBABLE_CAUSE to_chat(user, "Subject is suffering from liver failure: Apply Corazone and begin a liver transplant immediately!") var/msg = "*---------*\nAnalyzing results for [M]:\n\tOverall status: [mob_status]\n" @@ -157,12 +157,46 @@ SLIME SCANNER msg += "\tSubject appears to have [M.getCloneLoss() > 30 ? "Severe" : "Minor"] cellular damage.\n" if(advanced) msg += "\tCellular Damage Level: [M.getCloneLoss()].\n" - if (M.getBrainLoss() >= 200 || !M.getorgan(/obj/item/organ/brain)) - msg += "\tSubject's brain function is non-existent.\n" - else if (M.getBrainLoss() >= 120) - msg += "\tSevere brain damage detected. Subject likely to have mental traumas.\n" - else if (M.getBrainLoss() >= 45) - msg += "\tBrain damage detected.\n" + if (!M.getorgan(/obj/item/organ/brain)) + to_chat(user, "\tSubject lacks a brain.") //Unsure how this won't proc for 50% of the cit playerbase (This is a joke everyone on cit a cute.) + if(ishuman(M) && advanced) // Should I make this not advanced? + var/mob/living/carbon/human/H = M + var/obj/item/organ/liver/L = H.getorganslot("liver") + if(L) + if(L.swelling > 20) + msg += "\tSubject is suffering from an enlarged liver.\n" //i.e. shrink their liver or give them a transplant. + else + msg += "\tSubject's liver is missing.\n" + var/obj/item/organ/tongue/T = H.getorganslot("tongue") + if(T) + if(T.damage > 40) + msg += "\tSubject is suffering from severe burn tissue on their tongue.\n" //i.e. their tongue is shot + if(T.name == "fluffy tongue") + msg += "\tSubject is suffering from a fluffified tongue. Suggested cure: Yamerol or a tongue transplant.\n" + else + msg += "\tSubject's tongue is missing.\n" + var/obj/item/organ/lungs/Lung = H.getorganslot("lungs") + if(Lung) + if(Lung.damage > 150) + msg += "\tSubject is suffering from acute emphysema leading to trouble breathing.\n" //i.e. Their lungs are shot + else + msg += "\tSubject's lungs have collapsed from trauma!\n" + var/obj/item/organ/genital/penis/P = H.getorganslot("penis") + if(P) + if(P.length>20) + msg += "\tSubject has a sizeable gentleman's organ at [P.length] inches.\n" + var/obj/item/organ/genital/breasts/Br = H.getorganslot("breasts") + if(Br) + if(Br.cached_size>5) + msg += "\tSubject has a sizeable bosom with a [Br.size] cup.\n" + + if (M.getOrganLoss(ORGAN_SLOT_BRAIN) >= 200 || !M.getorgan(/obj/item/organ/brain)) + msg += "\tSubject's brain function is non-existent.\n" + else if (M.getOrganLoss(ORGAN_SLOT_BRAIN) >= 120) + msg += "\tSevere brain damage detected. Subject likely to have mental traumas.\n" + else if (M.getOrganLoss(ORGAN_SLOT_BRAIN) >= 45) + msg += "\tBrain damage detected.\n" + if(iscarbon(M)) var/mob/living/carbon/C = M if(LAZYLEN(C.get_traumas())) @@ -182,15 +216,25 @@ SLIME SCANNER if(C.roundstart_quirks.len) msg += "\tSubject has the following physiological traits: [C.get_trait_string()].\n" if(advanced) - msg += "\tBrain Activity Level: [(200 - M.getBrainLoss())/2]%.\n" - if (M.radiation) + msg += "\tBrain Activity Level: [(200 - M.getOrganLoss(ORGAN_SLOT_BRAIN))/2]%.\n" + if(M.radiation) msg += "\tSubject is irradiated.\n" - if(advanced) - msg += "\tRadiation Level: [M.radiation]%.\n" + msg += "\tRadiation Level: [M.radiation] rad\n" if(advanced && M.hallucinating()) msg += "\tSubject is hallucinating.\n" + //MKUltra + if(advanced && M.has_status_effect(/datum/status_effect/chem/enthrall)) + msg += "\tSubject has abnormal brain fuctions.\n" + + //Astrogen shenanigans + if(advanced && M.reagents.has_reagent("astral")) + if(M.mind) + msg += "\tWarning: subject may be possesed.\n" + else + msg += "\tSubject appears to be astrally projecting.\n" + //Eyes and ears if(advanced) if(iscarbon(M)) @@ -206,11 +250,11 @@ SLIME SCANNER healthy = FALSE msg += "\tSubject is deaf.\n" else - if(ears.ear_damage) - msg += "\tSubject has [ears.ear_damage > UNHEALING_EAR_DAMAGE? "permanent ": "temporary "]hearing damage.\n" + if(ears.damage) + to_chat(user, "\tSubject has [ears.damage > ears.maxHealth ? "permanent ": "temporary "]hearing damage.") healthy = FALSE if(ears.deaf) - msg += "\tSubject is [ears.ear_damage > UNHEALING_EAR_DAMAGE ? "permanently ": "temporarily "] deaf.\n" + to_chat(user, "\tSubject is [ears.damage > ears.maxHealth ? "permanently ": "temporarily "] deaf.") healthy = FALSE if(healthy) msg += "\tHealthy.\n" @@ -226,13 +270,13 @@ SLIME SCANNER if(HAS_TRAIT(C, TRAIT_NEARSIGHT)) msg += "\tSubject is nearsighted.\n" healthy = FALSE - if(eyes.eye_damage > 30) + if(eyes.damage > 30) msg += "\tSubject has severe eye damage.\n" healthy = FALSE - else if(eyes.eye_damage > 20) + else if(eyes.damage > 20) msg += "\tSubject has significant eye damage.\n" healthy = FALSE - else if(eyes.eye_damage) + else if(eyes.damage) msg += "\tSubject has minor eye damage.\n" healthy = FALSE if(healthy) @@ -256,6 +300,60 @@ SLIME SCANNER for(var/obj/item/bodypart/org in damaged) msg += "\t\t[capitalize(org.name)]: [(org.brute_dam > 0) ? "[org.brute_dam]" : "0"]-[(org.burn_dam > 0) ? "[org.burn_dam]" : "0"]\n" + //Organ damages report + if(ishuman(M)) + var/mob/living/carbon/human/H = M + var/minor_damage + var/major_damage + var/max_damage + var/report_organs = FALSE + + //Piece together the lists to be reported + for(var/O in H.internal_organs) + var/obj/item/organ/organ = O + if(organ.organ_flags & ORGAN_FAILING) + report_organs = TRUE //if we report one organ, we report all organs, even if the lists are empty, just for consistency + if(max_damage) + max_damage += ", " //prelude the organ if we've already reported an organ + max_damage += organ.name //this just slaps the organ name into the string of text + else + max_damage = "\tNon-Functional Organs: " //our initial statement + max_damage += organ.name + else if(organ.damage > organ.high_threshold) + report_organs = TRUE + if(major_damage) + major_damage += ", " + major_damage += organ.name + else + major_damage = "\tSeverely Damaged Organs: " + major_damage += organ.name + else if(organ.damage > organ.low_threshold) + report_organs = TRUE + if(minor_damage) + minor_damage += ", " + minor_damage += organ.name + else + minor_damage = "\tMildly Damaged Organs: " + minor_damage += organ.name + + if(report_organs) //we either finish the list, or set it to be empty if no organs were reported in that category + if(!max_damage) + max_damage = "\tNon-Functional Organs: " + else + max_damage += "" + if(!major_damage) + major_damage = "\tSeverely Damaged Organs: " + else + major_damage += "" + if(!minor_damage) + minor_damage = "\tMildly Damaged Organs: " + else + minor_damage += "" + msg += "[minor_damage]" + msg += "[major_damage]" + msg += "[max_damage]" + + // Species and body temperature if(ishuman(M)) var/mob/living/carbon/human/H = M @@ -310,7 +408,7 @@ SLIME SCANNER var/mob/living/carbon/human/H = C if(H.bleed_rate) msg += "Subject is bleeding!\n" - var/blood_percent = round((C.blood_volume / BLOOD_VOLUME_NORMAL)*100) + var/blood_percent = round((C.blood_volume / (BLOOD_VOLUME_NORMAL * C.blood_ratio))*100) var/blood_type = C.dna.blood_type if(blood_id != "blood")//special blood substance var/datum/reagent/R = GLOB.chemical_reagents_list[blood_id] @@ -318,9 +416,9 @@ SLIME SCANNER blood_type = R.name else blood_type = blood_id - if(C.blood_volume <= BLOOD_VOLUME_SAFE && C.blood_volume > BLOOD_VOLUME_OKAY) + if(C.blood_volume <= (BLOOD_VOLUME_SAFE*C.blood_ratio) && C.blood_volume > (BLOOD_VOLUME_OKAY*C.blood_ratio)) msg += "LOW blood level [blood_percent] %, [C.blood_volume] cl, type: [blood_type]\n" - else if(C.blood_volume <= BLOOD_VOLUME_OKAY) + else if(C.blood_volume <= (BLOOD_VOLUME_OKAY*C.blood_ratio)) msg += "CRITICAL blood level [blood_percent] %, [C.blood_volume] cl, type: [blood_type]\n" else msg += "Blood level [blood_percent] %, [C.blood_volume] cl, type: [blood_type]\n" @@ -343,7 +441,7 @@ SLIME SCANNER if(M.reagents.reagent_list.len) var/list/datum/reagent/reagents = list() for(var/datum/reagent/R in M.reagents.reagent_list) - if(R.invisible) + if(R.chemical_flags & REAGENT_INVISIBLE) continue reagents += R @@ -362,6 +460,21 @@ SLIME SCANNER msg += "[R.name]\n" else msg += "Subject is not addicted to any reagents.\n" + + if(M.reagents.has_reagent("fermiTox")) + var/datum/reagent/fermiTox = M.reagents.has_reagent("fermiTox") + switch(fermiTox.volume) + if(5 to 10) + msg += "Subject contains a low amount of toxic isomers.\n" + if(10 to 25) + msg += "Subject contains toxic isomers.\n" + if(25 to 50) + msg += "Subject contains a substantial amount of toxic isomers.\n" + if(50 to 95) + msg += "Subject contains a high amount of toxic isomers.\n" + if(95 to INFINITY) + msg += "Subject contains a extremely dangerous amount of toxic isomers.\n" + msg += "*---------*" to_chat(user, msg) diff --git a/code/game/objects/items/eightball.dm b/code/game/objects/items/eightball.dm index bdaa716075..9dc3e421fd 100644 --- a/code/game/objects/items/eightball.dm +++ b/code/game/objects/items/eightball.dm @@ -206,7 +206,7 @@ switch(action) if("vote") var/selected_answer = params["answer"] - if(!selected_answer in possible_answers) + if(!(selected_answer in possible_answers)) return else votes[user.ckey] = selected_answer diff --git a/code/game/objects/items/granters.dm b/code/game/objects/items/granters.dm index 71687f0d5a..fdb016df38 100644 --- a/code/game/objects/items/granters.dm +++ b/code/game/objects/items/granters.dm @@ -302,7 +302,7 @@ spellname = "charge" icon_state ="bookcharge" desc = "This book is made of 100% postconsumer wizard." - remarks = list("I feel ALIVE!", "I CAN TASTE THE MANA!", "What a RUSH!", "I'm FLYING through these pages!", "THIS GENIUS IS MAKING IT!", "This book is ACTION PAcKED!", "HE'S DONE IT", "LETS GOOOOOOOOOOOO") + remarks = list("I feel ALIVE!", "I CAN TASTE THE MANA!", "What a RUSH!", "I'm FLYING through these pages!", "THIS GENIUS IS MAKING IT!", "This book is ACTION PAcKED!", "HE'S DONE IT", "LETS GOOOOOOOOOOOO", "Just wait faster is all...") /obj/item/book/granter/spell/charge/recoil(mob/user) ..() @@ -440,7 +440,15 @@ oneuse = FALSE remarks = list("So that is how icing is made!", "Placing fruit on top? How simple...", "Huh layering cake seems harder then this...", "This book smells like candy", "A clown must have made this page, or they forgot to spell check it before printing...", "Wait, a way to cook slime to be safe?") -//Later content when I have free time - Trilby Date:02-Aug-2019 +/obj/item/book/granter/crafting_recipe/coldcooking //IceCream + name = "Cooking with Ice" + desc = "A cook book that teaches you many old icecream treats." + crafting_recipe_types = list(/datum/crafting_recipe/food/banana_split, /datum/crafting_recipe/food/root_float, /datum/crafting_recipe/food/bluecharrie_float, /datum/crafting_recipe/food/charrie_float) + icon_state = "cooking_learing_ice" + oneuse = FALSE + remarks = list("Looks like these would sell much better in a plasma fire...", "Using glass bowls rather then cones?", "Mixing soda and ice-cream?", "Tall glasses with of liquids and solids...", "Just add a bit of icecream and cherry on top?") + +//Later content when I have free time - Trilby Date:24-Aug-2019 /obj/item/book/granter/crafting_recipe/under_the_oven //Illegal cook book name = "Under The Oven" @@ -449,11 +457,3 @@ icon_state = "cooking_learing_illegal" oneuse = FALSE remarks = list() - -/obj/item/book/granter/crafting_recipe/coldcooking //IceCream - name = "Cooking with Ice" - desc = "A cook book that teaches you many old icecream treats." - crafting_recipe_types = list() - icon_state = "cooking_learing_ice" - oneuse = FALSE - remarks = list() \ No newline at end of file diff --git a/code/game/objects/items/grenades/plastic.dm b/code/game/objects/items/grenades/plastic.dm index 709fedbe5a..1956a1f317 100644 --- a/code/game/objects/items/grenades/plastic.dm +++ b/code/game/objects/items/grenades/plastic.dm @@ -174,6 +174,7 @@ gender = PLURAL var/open_panel = 0 can_attach_mob = TRUE + full_damage_on_mobs = TRUE /obj/item/grenade/plastic/c4/New() wires = new /datum/wires/explosive/c4(src) diff --git a/code/game/objects/items/handcuffs.dm b/code/game/objects/items/handcuffs.dm index 36a92b3db9..246dd77684 100644 --- a/code/game/objects/items/handcuffs.dm +++ b/code/game/objects/items/handcuffs.dm @@ -1,5 +1,6 @@ /obj/item/restraints breakouttime = 600 + var/demoralize_criminals = TRUE // checked on carbon/carbon.dm to decide wheter to apply the handcuffed negative moodlet or not. /obj/item/restraints/suicide_act(mob/living/carbon/user) user.visible_message("[user] is strangling [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit suicide!") @@ -164,21 +165,6 @@ /obj/item/restraints/handcuffs/cable/white item_color = "white" -/obj/item/restraints/handcuffs/alien - icon_state = "handcuffAlien" - -/obj/item/restraints/handcuffs/fake - name = "fake handcuffs" - desc = "Fake handcuffs meant for gag purposes." - breakouttime = 10 //Deciseconds = 1s - -/obj/item/restraints/handcuffs/fake/kinky - name = "kinky handcuffs" - desc = "Fake handcuffs meant for erotic roleplay." - icon = 'modular_citadel/icons/obj/items_and_weapons.dmi' - icon_state = "handcuffgag" - item_state = "kinkycuff" - /obj/item/restraints/handcuffs/cable/attackby(obj/item/I, mob/user, params) ..() if(istype(I, /obj/item/stack/rods)) @@ -213,7 +199,6 @@ /obj/item/restraints/handcuffs/cable/zipties name = "zipties" desc = "Plastic, disposable zipties that can be used to restrain temporarily but are destroyed after use." - icon_state = "zipties" item_state = "zipties" lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi' @@ -229,6 +214,22 @@ /obj/item/restraints/handcuffs/cable/zipties/used/attack() return +/obj/item/restraints/handcuffs/alien + icon_state = "handcuffAlien" + +/obj/item/restraints/handcuffs/fake + name = "fake handcuffs" + desc = "Fake handcuffs meant for gag purposes." + breakouttime = 10 //Deciseconds = 1s + demoralize_criminals = FALSE + +/obj/item/restraints/handcuffs/fake/kinky + name = "kinky handcuffs" + desc = "Fake handcuffs meant for erotic roleplay." + icon = 'modular_citadel/icons/obj/items_and_weapons.dmi' + icon_state = "handcuffgag" + item_state = "kinkycuff" + //Legcuffs /obj/item/restraints/legcuffs diff --git a/code/game/objects/items/his_grace.dm b/code/game/objects/items/his_grace.dm index 65a4bd542b..3be57d23f1 100644 --- a/code/game/objects/items/his_grace.dm +++ b/code/game/objects/items/his_grace.dm @@ -12,8 +12,9 @@ lefthand_file = 'icons/mob/inhands/equipment/toolbox_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/toolbox_righthand.dmi' icon = 'icons/obj/items_and_weapons.dmi' - w_class = WEIGHT_CLASS_GIGANTIC + w_class = WEIGHT_CLASS_BULKY force = 12 + total_mass = TOTAL_MASS_NORMAL_ITEM // average toolbox attack_verb = list("robusted") hitsound = 'sound/weapons/smash.ogg' var/awakened = FALSE diff --git a/code/game/objects/items/holy_weapons.dm b/code/game/objects/items/holy_weapons.dm index 0e8a9fef9e..ccb82f7029 100644 --- a/code/game/objects/items/holy_weapons.dm +++ b/code/game/objects/items/holy_weapons.dm @@ -34,6 +34,7 @@ desc = "God wills it!" icon_state = "knight_templar" item_state = "knight_templar" + allowed = list(/obj/item/storage/book/bible, HOLY_WEAPONS, /obj/item/reagent_containers/food/drinks/bottle/holywater, /obj/item/storage/fancy/candle_box, /obj/item/candle, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman) // CITADEL CHANGES: More variants /obj/item/clothing/suit/armor/riot/chaplain/teutonic @@ -122,7 +123,6 @@ icon_state = "studentuni" item_state = "studentuni" body_parts_covered = ARMS|CHEST - allowed = list(/obj/item/storage/book/bible, /obj/item/nullrod, /obj/item/reagent_containers/food/drinks/bottle/holywater, /obj/item/storage/fancy/candle_box, /obj/item/candle, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman) /obj/item/clothing/head/helmet/chaplain/cage name = "cage" @@ -166,7 +166,6 @@ icon_state = "witchhunter" item_state = "witchhunter" body_parts_covered = CHEST|GROIN|LEGS|ARMS - allowed = list(/obj/item/storage/book/bible, /obj/item/nullrod, /obj/item/reagent_containers/food/drinks/bottle/holywater, /obj/item/storage/fancy/candle_box, /obj/item/candle, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman) /obj/item/clothing/head/helmet/chaplain/witchunter_hat name = "witchunter hat" @@ -191,7 +190,7 @@ icon_state = "chaplain_hoodie" item_state = "chaplain_hoodie" body_parts_covered = CHEST|GROIN|LEGS|ARMS - allowed = list(/obj/item/storage/book/bible, /obj/item/nullrod, /obj/item/reagent_containers/food/drinks/bottle/holywater, /obj/item/storage/fancy/candle_box, /obj/item/candle, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman) + allowed = list(/obj/item/storage/book/bible, HOLY_WEAPONS, /obj/item/reagent_containers/food/drinks/bottle/holywater, /obj/item/storage/fancy/candle_box, /obj/item/candle, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman) hoodtype = /obj/item/clothing/head/hooded/chaplain_hood /obj/item/clothing/head/hooded/chaplain_hood @@ -229,8 +228,8 @@ throwforce = 10 w_class = WEIGHT_CLASS_TINY obj_flags = UNIQUE_RENAME - var/reskinned = FALSE var/chaplain_spawnable = TRUE + total_mass = TOTAL_MASS_MEDIEVAL_WEAPON /obj/item/nullrod/Initialize() . = ..() @@ -247,10 +246,8 @@ /obj/item/nullrod/proc/reskin_holy_weapon(mob/M) if(GLOB.holy_weapon_type) return - var/obj/item/nullrod/holy_weapon - var/list/holy_weapons_list = typesof(/obj/item/nullrod) + list( - /obj/item/melee/transforming/energy/sword/cx/chaplain - ) + var/obj/item/holy_weapon + var/list/holy_weapons_list = subtypesof(/obj/item/nullrod) + list(HOLY_WEAPONS) var/list/display_names = list() for(var/V in holy_weapons_list) var/obj/item/nullrod/rodtype = V @@ -273,6 +270,13 @@ qdel(src) M.put_in_active_hand(holy_weapon) +/obj/item/nullrod/proc/jedi_spin(mob/living/user) + for(var/i in list(NORTH,SOUTH,EAST,WEST,EAST,SOUTH,NORTH,SOUTH,EAST,WEST,EAST,SOUTH)) + user.setDir(i) + if(i == WEST) + user.emote("flip") + sleep(1) + /obj/item/nullrod/godhand icon_state = "disintegrate" item_state = "disintegrate" @@ -285,14 +289,12 @@ hitsound = 'sound/weapons/sear.ogg' damtype = BURN attack_verb = list("punched", "cross countered", "pummeled") - + total_mass = TOTAL_MASS_HAND_REPLACEMENT /obj/item/nullrod/godhand/Initialize() . = ..() ADD_TRAIT(src, TRAIT_NODROP, HAND_REPLACEMENT_TRAIT) - - /obj/item/nullrod/staff icon_state = "godstaff-red" item_state = "godstaff-red" @@ -356,6 +358,8 @@ slot_flags = ITEM_SLOT_BELT attack_verb = list("sawed", "torn", "cut", "chopped", "diced") hitsound = 'sound/weapons/chainsawhit.ogg' + tool_behaviour = TOOL_SAW + toolspeed = 1.5 //slower than a real saw /obj/item/nullrod/claymore/glowing icon_state = "swordon" @@ -511,7 +515,8 @@ slot_flags = ITEM_SLOT_BELT attack_verb = list("sawed", "torn", "cut", "chopped", "diced") hitsound = 'sound/weapons/chainsawhit.ogg' - + tool_behaviour = TOOL_SAW + toolspeed = 0.5 /obj/item/nullrod/hammmer icon_state = "hammeron" @@ -536,6 +541,9 @@ sharpness = IS_SHARP attack_verb = list("sawed", "torn", "cut", "chopped", "diced") hitsound = 'sound/weapons/chainsawhit.ogg' + total_mass = TOTAL_MASS_HAND_REPLACEMENT + tool_behaviour = TOOL_SAW + toolspeed = 2 /obj/item/nullrod/chainsaw/Initialize() . = ..() @@ -584,6 +592,7 @@ lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' slot_flags = ITEM_SLOT_BELT + force = 12 reach = 2 attack_verb = list("whipped", "lashed") hitsound = 'sound/weapons/chainhit.ogg' @@ -612,6 +621,7 @@ item_flags = ABSTRACT w_class = WEIGHT_CLASS_HUGE sharpness = IS_SHARP + total_mass = TOTAL_MASS_HAND_REPLACEMENT /obj/item/nullrod/armblade/Initialize() . = ..() @@ -659,6 +669,44 @@ lefthand_file = 'icons/mob/inhands/weapons/staves_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi' +/obj/item/nullrod/claymore/bostaff/attack(mob/target, mob/living/user) + add_fingerprint(user) + if((HAS_TRAIT(user, TRAIT_CLUMSY)) && prob(50)) + to_chat(user, "You club yourself over the head with [src].") + user.Knockdown(60) + if(ishuman(user)) + var/mob/living/carbon/human/H = user + H.apply_damage(2*force, BRUTE, BODY_ZONE_HEAD) + else + user.take_bodypart_damage(2*force) + return + if(iscyborg(target)) + return ..() + if(!isliving(target)) + return ..() + var/mob/living/carbon/C = target + if(C.stat || C.health < 0 || C.staminaloss > 130 ) + to_chat(user, "It would be dishonorable to attack a foe while they cannot retaliate.") + return + if(user.a_intent == INTENT_DISARM) + if(!ishuman(target)) + return ..() + var/mob/living/carbon/human/H = target + var/list/fluffmessages = list("[user] clubs [H] with [src]!", \ + "[user] smacks [H] with the butt of [src]!", \ + "[user] broadsides [H] with [src]!", \ + "[user] smashes [H]'s head with [src]!", \ + "[user] beats [H] with front of [src]!", \ + "[user] twirls and slams [H] with [src]!") + H.visible_message("[pick(fluffmessages)]", \ + "[pick(fluffmessages)]") + playsound(get_turf(user), 'sound/effects/woodhit.ogg', 75, 1, -1) + H.adjustStaminaLoss(rand(12,18)) + if(prob(25)) + (INVOKE_ASYNC(src, .proc/jedi_spin, user)) + else + return ..() + /obj/item/nullrod/tribal_knife icon_state = "crysknife" item_state = "crysknife" @@ -701,8 +749,8 @@ name = "egyptian staff" desc = "A tutorial in mummification is carved into the staff. You could probably craft the wraps if you had some cloth." icon = 'icons/obj/guns/magic.dmi' - icon_state = "pharoah_sceptre" - item_state = "pharoah_sceptre" + icon_state = "pharaoh_sceptre" + item_state = "pharaoh_sceptre" lefthand_file = 'icons/mob/inhands/weapons/staves_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi' w_class = WEIGHT_CLASS_NORMAL diff --git a/code/game/objects/items/implants/implant.dm b/code/game/objects/items/implants/implant.dm index 482cfb0d8e..0786172f25 100644 --- a/code/game/objects/items/implants/implant.dm +++ b/code/game/objects/items/implants/implant.dm @@ -72,7 +72,7 @@ else return FALSE - forceMove(target) + moveToNullspace() imp_in = target target.implants += src if(activated) @@ -89,12 +89,12 @@ return TRUE /obj/item/implant/proc/removed(mob/living/source, silent = FALSE, special = 0) - moveToNullspace() + SEND_SIGNAL(src, COMSIG_IMPLANT_REMOVING, args) imp_in = null source.implants -= src for(var/X in actions) var/datum/action/A = X - A.Grant(source) + A.Remove(source) if(ishuman(source)) var/mob/living/carbon/human/H = source H.sec_hud_set_implants() diff --git a/code/game/objects/items/implants/implant_chem.dm b/code/game/objects/items/implants/implant_chem.dm index c6c8be1a83..8da1d1e472 100644 --- a/code/game/objects/items/implants/implant_chem.dm +++ b/code/game/objects/items/implants/implant_chem.dm @@ -3,6 +3,7 @@ desc = "Injects things." icon_state = "reagents" activated = FALSE + var/obj/item/imp_chemholder/chemholder /obj/item/implant/chem/get_data() var/dat = {"Implant Specifications:
@@ -29,6 +30,26 @@ GLOB.tracked_chem_implants -= src return ..() +/obj/item/implant/chem/implant(mob/living/target, mob/user, silent = FALSE) + . = ..() + if(!.) + return + if(chemholder) + chemholder.forceMove(target) + return + chemholder = new(imp_in, src) + reagents.trans_to(chemholder, reagents.total_volume) + +/obj/item/implant/chem/removed(mob/target, silent = FALSE, special = 0) + . = ..() + if(!.) + return + if(!special) + chemholder.reagents.trans_to(src, chemholder.reagents.total_volume) + QDEL_NULL(chemholder) + else + chemholder?.moveToNullspace() + /obj/item/implant/chem/trigger(emote, mob/living/source) if(emote == "deathgasp") if(istype(source) && !(source.stat == DEAD)) @@ -45,13 +66,12 @@ injectamount = reagents.total_volume else injectamount = cause - reagents.trans_to(R, injectamount) + chemholder.reagents.trans_to(R, injectamount) to_chat(R, "You hear a faint beep.") - if(!reagents.total_volume) + if(!chemholder.reagents.total_volume) to_chat(R, "You hear a faint click from your chest.") qdel(src) - /obj/item/implantcase/chem name = "implant case - 'Remote Chemical'" desc = "A glass case containing a remote chemical implant." @@ -63,3 +83,17 @@ return TRUE else return ..() + +/obj/item/imp_chemholder + var/obj/item/implant/chem/implant + +/obj/item/imp_chemholder/Initialize(mapload, obj/item/implant/chem/_implant) + . = ..() + create_reagents(50) + implant = _implant + +/obj/item/imp_chemholder/Destroy() + if(implant?.imp_in) + qdel(implant) + else + return ..() \ No newline at end of file diff --git a/code/game/objects/items/implants/implant_clown.dm b/code/game/objects/items/implants/implant_clown.dm index ae1fef109d..bb98e72b30 100644 --- a/code/game/objects/items/implants/implant_clown.dm +++ b/code/game/objects/items/implants/implant_clown.dm @@ -11,7 +11,7 @@ /obj/item/implant/sad_trombone/trigger(emote, mob/source) if(emote == "deathgasp") - playsound(loc, 'sound/misc/sadtrombone.ogg', 50, 0) + playsound(source.loc, 'sound/misc/sadtrombone.ogg', 50, 0) /obj/item/implanter/sad_trombone name = "implanter (sad trombone)" diff --git a/code/game/objects/items/implants/implant_explosive.dm b/code/game/objects/items/implants/implant_explosive.dm index e749a6c4be..b93c9419a3 100644 --- a/code/game/objects/items/implants/implant_explosive.dm +++ b/code/game/objects/items/implants/implant_explosive.dm @@ -11,8 +11,9 @@ var/popup = FALSE // is the DOUWANNABLOWUP window open? var/active = FALSE -/obj/item/implant/explosive/on_mob_death(mob/living/L, gibbed) - activate("death") +/obj/item/implant/explosive/trigger(emote, mob/source) + if(emote == "deathgasp") + activate("death") /obj/item/implant/explosive/get_data() var/dat = {"Implant Specifications:
@@ -29,32 +30,18 @@ /obj/item/implant/explosive/activate(cause) . = ..() if(!cause || !imp_in || active) - return 0 + return FALSE if(cause == "action_button" && !popup) popup = TRUE var/response = alert(imp_in, "Are you sure you want to activate your [name]? This will cause you to explode!", "[name] Confirmation", "Yes", "No") popup = FALSE if(response == "No") - return 0 - heavy = round(heavy) - medium = round(medium) - weak = round(weak) - to_chat(imp_in, "You activate your [name].") - active = TRUE - var/turf/boomturf = get_turf(imp_in) - message_admins("[ADMIN_LOOKUPFLW(imp_in)] has activated their [name] at [ADMIN_VERBOSEJMP(boomturf)], with cause of [cause].") -//If the delay is short, just blow up already jeez - if(delay <= 7) - explosion(src,heavy,medium,weak,weak, flame_range = weak) - if(imp_in) - imp_in.gib(1) - qdel(src) - return - timed_explosion() + return FALSE + addtimer(CALLBACK(src, .proc/timed_explosion, cause), 1) /obj/item/implant/explosive/implant(mob/living/target) for(var/X in target.implants) - if(istype(X, type)) + if(istype(X, /obj/item/implant/explosive)) var/obj/item/implant/explosive/imp_e = X imp_e.heavy += heavy imp_e.medium += medium @@ -65,22 +52,37 @@ return ..() -/obj/item/implant/explosive/proc/timed_explosion() - imp_in.visible_message("[imp_in] starts beeping ominously!") - playsound(loc, 'sound/items/timer.ogg', 30, 0) - sleep(delay*0.25) - if(imp_in && !imp_in.stat) +/obj/item/implant/explosive/proc/timed_explosion(cause) + if(cause == "death" && imp_in.stat != DEAD) + return FALSE + heavy = round(heavy) + medium = round(medium) + weak = round(weak) + to_chat(imp_in, "You activate your [name].") + active = TRUE + var/turf/boomturf = get_turf(imp_in) + message_admins("[ADMIN_LOOKUPFLW(imp_in)] has activated their [name] at [ADMIN_VERBOSEJMP(boomturf)], with cause of [cause].") + if(delay > 7) + imp_in?.visible_message("[imp_in] starts beeping ominously!") + playsound(get_turf(imp_in ? imp_in : src), 'sound/items/timer.ogg', 30, 0) + addtimer(CALLBACK(src, .proc/double_pain, TRUE), delay * 0.25) + addtimer(CALLBACK(src, .proc/double_pain), delay * 0.5) + addtimer(CALLBACK(src, .proc/double_pain), delay * 0.75) + addtimer(CALLBACK(src, .proc/boom_goes_the_weasel), delay) + else //If the delay is short, just blow up already jeez + boom_goes_the_weasel() + +/obj/item/implant/explosive/proc/double_pain(message = FALSE) + playsound(get_turf(imp_in ? imp_in : src), 'sound/items/timer.ogg', 30, 0) + if(!imp_in) + return + if(message && imp_in.stat == CONSCIOUS) imp_in.visible_message("[imp_in] doubles over in pain!") - imp_in.Knockdown(140) - playsound(loc, 'sound/items/timer.ogg', 30, 0) - sleep(delay*0.25) - playsound(loc, 'sound/items/timer.ogg', 30, 0) - sleep(delay*0.25) - playsound(loc, 'sound/items/timer.ogg', 30, 0) - sleep(delay*0.25) - explosion(src,heavy,medium,weak,weak, flame_range = weak) - if(imp_in) - imp_in.gib(1) + imp_in.Knockdown(140) + +/obj/item/implant/explosive/proc/boom_goes_the_weasel() + explosion(get_turf(imp_in ? imp_in : src), heavy, medium, weak, weak, flame_range = weak) + imp_in?.gib(TRUE) qdel(src) /obj/item/implant/explosive/macro @@ -95,17 +97,7 @@ /obj/item/implant/explosive/macro/implant(mob/living/target) for(var/X in target.implants) if(istype(X, type)) - return 0 - - for(var/Y in target.implants) - if(istype(Y, /obj/item/implant/explosive)) - var/obj/item/implant/explosive/imp_e = Y - heavy += imp_e.heavy - medium += imp_e.medium - weak += imp_e.weak - delay += imp_e.delay - qdel(imp_e) - break + return FALSE return ..() diff --git a/code/game/objects/items/implants/implant_mindshield.dm b/code/game/objects/items/implants/implant_mindshield.dm index b9907cbfca..2a99c6e1ec 100644 --- a/code/game/objects/items/implants/implant_mindshield.dm +++ b/code/game/objects/items/implants/implant_mindshield.dm @@ -1,7 +1,6 @@ /obj/item/implant/mindshield name = "mindshield implant" desc = "Protects against brainwashing." - resistance_flags = INDESTRUCTIBLE activated = 0 /obj/item/implant/mindshield/get_data() diff --git a/code/game/objects/items/implants/implant_misc.dm b/code/game/objects/items/implants/implant_misc.dm index 3a4295c61e..75b0c67798 100644 --- a/code/game/objects/items/implants/implant_misc.dm +++ b/code/game/objects/items/implants/implant_misc.dm @@ -69,62 +69,4 @@ healthstring = "Oxygen Deprivation Damage => [round(L.getOxyLoss())]
Fire Damage => [round(L.getFireLoss())]
Toxin Damage => [round(L.getToxLoss())]
Brute Force Damage => [round(L.getBruteLoss())]
" if (!healthstring) healthstring = "ERROR" - return healthstring - -/obj/item/implant/radio - name = "internal radio implant" - activated = TRUE - var/obj/item/radio/radio - var/radio_key - var/subspace_transmission = FALSE - icon = 'icons/obj/radio.dmi' - icon_state = "walkietalkie" - -/obj/item/implant/radio/activate() - . = ..() - // needs to be GLOB.deep_inventory_state otherwise it won't open - radio.ui_interact(usr, "main", null, FALSE, null, GLOB.deep_inventory_state) - -/obj/item/implant/radio/Initialize(mapload) - . = ..() - - radio = new(src) - // almost like an internal headset, but without the - // "must be in ears to hear" restriction. - radio.name = "internal radio" - radio.subspace_transmission = subspace_transmission - radio.canhear_range = 0 - if(radio_key) - radio.keyslot = new radio_key - radio.recalculateChannels() - -/obj/item/implant/radio/mining - radio_key = /obj/item/encryptionkey/headset_cargo - -/obj/item/implant/radio/syndicate - desc = "Are you there God? It's me, Syndicate Comms Agent." - radio_key = /obj/item/encryptionkey/syndicate - subspace_transmission = TRUE - -/obj/item/implant/radio/slime - name = "slime radio" - icon = 'icons/obj/surgery.dmi' - icon_state = "adamantine_resonator" - radio_key = /obj/item/encryptionkey/headset_sci - subspace_transmission = TRUE - -/obj/item/implant/radio/get_data() - var/dat = {"Implant Specifications:
- Name: Internal Radio Implant
- Life: 24 hours
- Implant Details: Allows user to use an internal radio, useful if user expects equipment loss, or cannot equip conventional radios."} - return dat - -/obj/item/implanter/radio - name = "implanter (internal radio)" - imp_type = /obj/item/implant/radio - -/obj/item/implanter/radio/syndicate - name = "implanter (internal syndicate radio)" - imp_type = /obj/item/implant/radio/syndicate - + return healthstring \ No newline at end of file diff --git a/code/game/objects/items/implants/implant_radio.dm b/code/game/objects/items/implants/implant_radio.dm new file mode 100644 index 0000000000..5d3d579a4e --- /dev/null +++ b/code/game/objects/items/implants/implant_radio.dm @@ -0,0 +1,69 @@ +/obj/item/implant/radio + name = "internal radio implant" + activated = TRUE + var/obj/item/radio/internal/radio + var/radio_key + var/subspace_transmission = FALSE + icon = 'icons/obj/radio.dmi' + icon_state = "walkietalkie" + +/obj/item/implant/radio/activate() + . = ..() + // needs to be GLOB.deep_inventory_state otherwise it won't open + radio.ui_interact(usr, "main", null, FALSE, null, GLOB.deep_inventory_state) + +/obj/item/implant/radio/implant(mob/living/target, mob/user, silent = FALSE) + . = ..() + if(!.) + return + if(radio) + radio.forceMove(target) + return + radio = new(target) + // almost like an internal headset, but without the + // "must be in ears to hear" restriction. + radio.name = "internal radio" + radio.subspace_transmission = subspace_transmission + radio.canhear_range = 0 + if(radio_key) + radio.keyslot = new radio_key + radio.recalculateChannels() + +/obj/item/implant/radio/removed(mob/target, silent = FALSE, special = 0) + . = ..() + if(!.) + return + if(!special) + qdel(radio) + else + radio?.moveToNullspace() + +/obj/item/implant/radio/mining + radio_key = /obj/item/encryptionkey/headset_cargo + +/obj/item/implant/radio/syndicate + desc = "Are you there God? It's me, Syndicate Comms Agent." + radio_key = /obj/item/encryptionkey/syndicate + subspace_transmission = TRUE + +/obj/item/implant/radio/slime + name = "slime radio" + icon = 'icons/obj/surgery.dmi' + icon_state = "adamantine_resonator" + radio_key = /obj/item/encryptionkey/headset_sci + subspace_transmission = TRUE + +/obj/item/implant/radio/get_data() + var/dat = {"Implant Specifications:
+ Name: Internal Radio Implant
+ Life: 24 hours
+ Implant Details: Allows user to use an internal radio, useful if user expects equipment loss, or cannot equip conventional radios."} + return dat + +/obj/item/implanter/radio + name = "implanter (internal radio)" + imp_type = /obj/item/implant/radio + +/obj/item/implanter/radio/syndicate + name = "implanter (internal syndicate radio)" + imp_type = /obj/item/implant/radio/syndicate \ No newline at end of file diff --git a/code/game/objects/items/implants/implant_storage.dm b/code/game/objects/items/implants/implant_storage.dm index ec6b4d64c3..739873af00 100644 --- a/code/game/objects/items/implants/implant_storage.dm +++ b/code/game/objects/items/implants/implant_storage.dm @@ -4,30 +4,44 @@ icon_state = "storage" item_color = "r" var/max_slot_stacking = 4 + var/obj/item/storage/bluespace_pocket/pocket /obj/item/implant/storage/activate() . = ..() - SEND_SIGNAL(src, COMSIG_TRY_STORAGE_SHOW, imp_in, TRUE) + SEND_SIGNAL(pocket, COMSIG_TRY_STORAGE_SHOW, imp_in, TRUE) /obj/item/implant/storage/removed(source, silent = FALSE, special = 0) - . = ..() - if(.) - if(!special) - qdel(GetComponent(/datum/component/storage/concrete/implant)) + if(!special) + qdel(pocket) + else + pocket?.moveToNullspace() + return ..() /obj/item/implant/storage/implant(mob/living/target, mob/user, silent = FALSE) for(var/X in target.implants) if(istype(X, type)) var/obj/item/implant/storage/imp_e = X - GET_COMPONENT_FROM(STR, /datum/component/storage, imp_e) + GET_COMPONENT_FROM(STR, /datum/component/storage, imp_e.pocket) if(!STR || (STR && STR.max_items < max_slot_stacking)) - imp_e.AddComponent(/datum/component/storage/concrete/implant) + imp_e.pocket.AddComponent(/datum/component/storage/concrete/implant) qdel(src) return TRUE return FALSE - AddComponent(/datum/component/storage/concrete/implant) + . = ..() + if(.) + if(pocket) + pocket.forceMove(target) + else + pocket = new(target) - return ..() +/obj/item/storage/bluespace_pocket + name = "internal bluespace pocket" + icon_state = "pillbox" + w_class = WEIGHT_CLASS_TINY + desc = "A tiny yet spacious pocket, usually found implanted inside sneaky syndicate agents and nowhere else." + component_type = /datum/component/storage/concrete/implant + resistance_flags = INDESTRUCTIBLE //A bomb! + item_flags = DROPDEL /obj/item/implanter/storage name = "implanter (storage)" diff --git a/code/game/objects/items/implants/implant_track.dm b/code/game/objects/items/implants/implant_track.dm index 913c577f2c..4b7ae3bbac 100644 --- a/code/game/objects/items/implants/implant_track.dm +++ b/code/game/objects/items/implants/implant_track.dm @@ -3,8 +3,8 @@ desc = "Track with this." activated = 0 -/obj/item/implant/tracking/New() - ..() +/obj/item/implant/tracking/Initialize() + . = ..() GLOB.tracked_implants += src /obj/item/implant/tracking/Destroy() @@ -15,7 +15,31 @@ imp_type = /obj/item/implant/tracking /obj/item/implanter/tracking/gps - imp_type = /obj/item/gps/mining/internal + imp_type = /obj/item/implant/gps + +/obj/item/implant/gps + name = "\improper GPS implant" + desc = "Track with this and a GPS." + activated = FALSE + var/obj/item/gps/internal/mining/real_gps + +/obj/item/implant/gps/implant(mob/living/target, mob/user, silent = FALSE) + . = ..() + if(!.) + return + if(real_gps) + real_gps.forceMove(target) + else + real_gps = new(target) + +/obj/item/implant/gps/removed(mob/living/source, silent = FALSE, special = 0) + . = ..() + if(!.) + return + if(!special) + qdel(real_gps) + else + real_gps?.moveToNullspace() /obj/item/implant/tracking/get_data() var/dat = {"Implant Specifications:
diff --git a/code/game/objects/items/implants/implantuplink.dm b/code/game/objects/items/implants/implant_uplink.dm similarity index 93% rename from code/game/objects/items/implants/implantuplink.dm rename to code/game/objects/items/implants/implant_uplink.dm index 9000fbbe34..9895c1e34c 100644 --- a/code/game/objects/items/implants/implantuplink.dm +++ b/code/game/objects/items/implants/implant_uplink.dm @@ -1,23 +1,23 @@ -/obj/item/implant/uplink - name = "uplink implant" - desc = "Sneeki breeki." - icon = 'icons/obj/radio.dmi' - icon_state = "radio" - lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi' - righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi' - var/starting_tc = 0 - -/obj/item/implant/uplink/Initialize(mapload, _owner) - . = ..() - AddComponent(/datum/component/uplink, _owner, TRUE, FALSE, null, starting_tc) - -/obj/item/implanter/uplink - name = "implanter (uplink)" - imp_type = /obj/item/implant/uplink - -/obj/item/implanter/uplink/precharged - name = "implanter (precharged uplink)" - imp_type = /obj/item/implant/uplink/precharged - -/obj/item/implant/uplink/precharged - starting_tc = 10 +/obj/item/implant/uplink + name = "uplink implant" + desc = "Sneeki breeki." + icon = 'icons/obj/radio.dmi' + icon_state = "radio" + lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi' + righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi' + var/starting_tc = 0 + +/obj/item/implant/uplink/Initialize(mapload, _owner) + . = ..() + AddComponent(/datum/component/uplink, _owner, TRUE, FALSE, null, starting_tc, GLOB.not_incapacitated_state) + +/obj/item/implanter/uplink + name = "implanter (uplink)" + imp_type = /obj/item/implant/uplink + +/obj/item/implanter/uplink/precharged + name = "implanter (precharged uplink)" + imp_type = /obj/item/implant/uplink/precharged + +/obj/item/implant/uplink/precharged + starting_tc = 10 diff --git a/code/game/objects/items/manuals.dm b/code/game/objects/items/manuals.dm index 02d0a1c36a..6ae34e9ca2 100644 --- a/code/game/objects/items/manuals.dm +++ b/code/game/objects/items/manuals.dm @@ -244,7 +244,7 @@ ..() /obj/item/book/manual/wiki/proc/initialize_wikibook() - var/wikiurl = CONFIG_GET(string/wikiurl) + var/wikiurl = CONFIG_GET(string/wikiurltg) if(wikiurl) dat = {" @@ -270,13 +270,67 @@ "} -/obj/item/book/manual/wiki/chemistry +/obj/item/book/manual/wiki/cit + name = "Citadel infobook" + icon_state ="book8" + author = "Nanotrasen" + title = "Citadel infobook" + page_link = "" + window_size = "1500x800" //Too squashed otherwise + +/obj/item/book/manual/wiki/cit/initialize_wikibook() + var/wikiurl = CONFIG_GET(string/wikiurl) + if(wikiurl) + dat = {" + + + + + + +

You start skimming through the manual...

+ + + + + + "} + +/obj/item/book/manual/wiki/cit/chemistry name = "Chemistry Textbook" icon_state ="chemistrybook" author = "Nanotrasen" title = "Chemistry Textbook" + page_link = "main/guides/guide_chemistry" + +/obj/item/book/manual/wiki/cit/chem_recipies + name = "Chemistry Recipies" + icon_state ="chemrecibook" + author = "Chemcat" + title = "Chemistry Recipies" + page_link = "main/guides/chem_recipies" + +/obj/item/book/manual/wiki/chemistry + name = "Outdated Chemistry Textbook" + icon_state ="chemistrybook_old" + author = "Nanotrasen" + title = "Outdated Chemistry Textbook" page_link = "Guide_to_chemistry" +/obj/item/book/manual/wiki/chemistry/Initialize() + ..() + new /obj/item/book/manual/wiki/cit/chemistry(loc) + new /obj/item/book/manual/wiki/cit/chem_recipies(loc) + /obj/item/book/manual/wiki/engineering_construction name = "Station Repairs and Construction" icon_state ="bookEngineering" diff --git a/code/game/objects/items/melee/energy.dm b/code/game/objects/items/melee/energy.dm index 935d2a007e..57b9973aa3 100644 --- a/code/game/objects/items/melee/energy.dm +++ b/code/game/objects/items/melee/energy.dm @@ -5,9 +5,12 @@ armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 30) resistance_flags = FIRE_PROOF var/brightness_on = 3 + total_mass = 0.4 //Survival flashlights typically weigh around 5 ounces. + /obj/item/melee/transforming/energy/Initialize() . = ..() + total_mass_on = (total_mass_on ? total_mass_on : (w_class_on * 0.75)) if(active) set_light(brightness_on) START_PROCESSING(SSobj, src) @@ -79,6 +82,7 @@ attack_verb_off = list("attacked", "chopped", "cleaved", "torn", "cut") attack_verb_on = list() light_color = "#40ceff" + total_mass = null /obj/item/melee/transforming/energy/axe/suicide_act(mob/user) user.visible_message("[user] swings [src] towards [user.p_their()] head! It looks like [user.p_theyre()] trying to commit suicide!") @@ -138,6 +142,8 @@ w_class = WEIGHT_CLASS_NORMAL sharpness = IS_SHARP light_color = "#40ceff" + tool_behaviour = TOOL_SAW + toolspeed = 0.7 /obj/item/melee/transforming/energy/sword/cyborg/saw/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) return 0 diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm index 0d45960767..10b84917bb 100644 --- a/code/game/objects/items/melee/misc.dm +++ b/code/game/objects/items/melee/misc.dm @@ -44,6 +44,7 @@ hitsound = 'sound/weapons/bladeslice.ogg' attack_verb = list("attacked", "impaled", "stabbed", "sliced", "torn", "ripped", "diced", "cut") sharpness = IS_SHARP + total_mass = TOTAL_MASS_HAND_REPLACEMENT /obj/item/melee/synthetic_arm_blade/Initialize() . = ..() @@ -67,6 +68,7 @@ attack_verb = list("slashed", "cut") hitsound = 'sound/weapons/rapierhit.ogg' materials = list(MAT_METAL = 1000) + total_mass = 3.4 /obj/item/melee/sabre/Initialize() . = ..() @@ -89,6 +91,12 @@ if(istype(B)) playsound(B, 'sound/items/sheath.ogg', 25, 1) +/obj/item/melee/sabre/get_belt_overlay() + return mutable_appearance('icons/obj/clothing/belt_overlays.dmi', "sabre") + +/obj/item/melee/sabre/get_worn_belt_overlay(icon_file) + return mutable_appearance(icon_file, "-sabre") + /obj/item/melee/sabre/suicide_act(mob/living/user) user.visible_message("[user] is trying to cut off all [user.p_their()] limbs with [src]! it looks like [user.p_theyre()] trying to commit suicide!") var/i = 0 @@ -147,13 +155,20 @@ flags_1 = CONDUCT_1 obj_flags = UNIQUE_RENAME w_class = WEIGHT_CLASS_BULKY - sharpness = IS_SHARP_ACCURATE //It cant be sharpend cook -_- + sharpness = IS_SHARP_ACCURATE //It cant be sharpend cook -_- attack_verb = list("slashed", "cut", "pierces", "pokes") + total_mass = 3.4 /obj/item/melee/rapier/Initialize() . = ..() AddComponent(/datum/component/butchering, 20, 65, 0) +/obj/item/melee/rapier/get_belt_overlay() + return mutable_appearance('icons/obj/clothing/belt_overlays.dmi', "rapier") + +/obj/item/melee/rapier/get_worn_belt_overlay(icon_file) + return mutable_appearance(icon_file, "-rapier") + /obj/item/melee/classic_baton name = "police baton" desc = "A wooden truncheon for beating criminal scum." @@ -165,8 +180,13 @@ slot_flags = ITEM_SLOT_BELT force = 12 //9 hit crit w_class = WEIGHT_CLASS_NORMAL - var/cooldown = 0 + var/cooldown = 13 var/on = TRUE + var/last_hit = 0 + var/stun_stam_cost_coeff = 1.25 + var/hardstun_ds = 1 + var/softstun_ds = 0 + var/stam_dmg = 30 /obj/item/melee/classic_baton/attack(mob/living/target, mob/living/user) if(!on) @@ -192,12 +212,10 @@ if(!isliving(target)) return if (user.a_intent == INTENT_HARM) - if(!..()) - return - if(!iscyborg(target)) + if(!..() || !iscyborg(target)) return else - if(cooldown <= world.time) + if(last_hit < world.time) if(ishuman(target)) var/mob/living/carbon/human/H = target if (H.check_shields(src, 0, "[user]'s [name]", MELEE_ATTACK)) @@ -205,7 +223,7 @@ if(check_martial_counter(H, user)) return playsound(get_turf(src), 'sound/effects/woodhit.ogg', 75, 1, -1) - target.Knockdown(60) + target.Knockdown(softstun_ds, TRUE, FALSE, hardstun_ds, stam_dmg) log_combat(user, target, "stunned", src) src.add_fingerprint(user) target.visible_message("[user] has knocked down [target] with [src]!", \ @@ -214,7 +232,7 @@ target.LAssailant = null else target.LAssailant = user - cooldown = world.time + 40 + last_hit = world.time + cooldown user.adjustStaminaLossBuffered(getweight())//CIT CHANGE - makes swinging batons cost stamina /obj/item/melee/classic_baton/telescopic @@ -230,6 +248,7 @@ item_flags = NONE force = 0 on = FALSE + total_mass = TOTAL_MASS_NORMAL_ITEM /obj/item/melee/classic_baton/telescopic/suicide_act(mob/user) var/mob/living/carbon/human/H = user @@ -390,6 +409,7 @@ var/static/list/ovens var/on = FALSE var/datum/beam/beam + total_mass = 2.5 /obj/item/melee/roastingstick/Initialize() . = ..() diff --git a/code/game/objects/items/melee/transforming.dm b/code/game/objects/items/melee/transforming.dm index 0d39e6c847..aabb930bb2 100644 --- a/code/game/objects/items/melee/transforming.dm +++ b/code/game/objects/items/melee/transforming.dm @@ -13,6 +13,7 @@ var/list/nemesis_factions //Any mob with a faction that exists in this list will take bonus damage/effects var/w_class_on = WEIGHT_CLASS_BULKY var/clumsy_check = TRUE + var/total_mass_on //Total mass in ounces when transformed. Primarily for balance purposes. Don't think about it too hard. /obj/item/melee/transforming/Initialize() . = ..() @@ -46,6 +47,7 @@ active = !active if(active) force = force_on + total_mass = total_mass_on throwforce = throwforce_on hitsound = hitsound_on throw_speed = 4 @@ -62,6 +64,7 @@ attack_verb = attack_verb_off icon_state = initial(icon_state) w_class = initial(w_class) + total_mass = initial(total_mass) if(is_sharp()) var/datum/component/butchering/BT = LoadComponent(/datum/component/butchering) BT.butchering_enabled = TRUE @@ -84,4 +87,4 @@ /obj/item/melee/transforming/proc/clumsy_transform_effect(mob/living/user) if(clumsy_check && HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50)) to_chat(user, "You accidentally cut yourself with [src], like a doofus!") - user.take_bodypart_damage(5,5) + user.take_bodypart_damage(5,5) \ No newline at end of file diff --git a/code/game/objects/items/paint.dm b/code/game/objects/items/paint.dm index a6f5830dd4..cc2f5e9be7 100644 --- a/code/game/objects/items/paint.dm +++ b/code/game/objects/items/paint.dm @@ -90,14 +90,14 @@ add_fingerprint(user) -/obj/item/paint/afterattack(turf/target, mob/user, proximity) +/obj/item/paint/afterattack(atom/target, mob/user, proximity) . = ..() if(!proximity) return if(paintleft <= 0) icon_state = "paint_empty" return - if(!istype(target) || isspaceturf(target)) + if(!isturf(target) || isspaceturf(target)) return var/newcolor = "#" + item_color target.add_atom_colour(newcolor, WASHABLE_COLOUR_PRIORITY) @@ -105,12 +105,14 @@ /obj/item/paint/paint_remover gender = PLURAL name = "paint remover" - desc = "Used to remove color from floors and walls." + desc = "Used to remove color from anything." icon_state = "paint_neutral" -/obj/item/paint/paint_remover/afterattack(turf/target, mob/user, proximity) +/obj/item/paint/paint_remover/afterattack(atom/target, mob/user, proximity) . = ..() if(!proximity) return - if(istype(target) && target.color != initial(target.color)) + if(!isturf(target) || !isobj(target)) + return + if(target.color != initial(target.color)) target.remove_atom_colour(WASHABLE_COLOUR_PRIORITY) diff --git a/code/game/objects/items/pet_carrier.dm b/code/game/objects/items/pet_carrier.dm index a73be6e12e..30442d7304 100644 --- a/code/game/objects/items/pet_carrier.dm +++ b/code/game/objects/items/pet_carrier.dm @@ -122,7 +122,7 @@ if(user.mob_size <= MOB_SIZE_SMALL) to_chat(user, "You poke a limb through [src]'s bars and start fumbling for the lock switch... (This will take some time.)") to_chat(loc, "You see [user] reach through the bars and fumble for the lock switch!") - if(!do_after(user, rand(300, 400), target = user) || open || !locked || !user in occupants) + if(!do_after(user, rand(300, 400), target = user) || open || !locked || !(user in occupants)) return loc.visible_message("[user] flips the lock switch on [src] by reaching through!", null, null, null, user) to_chat(user, "Bingo! The lock pops open!") @@ -132,7 +132,7 @@ else loc.visible_message("[src] starts rattling as something pushes against the door!", null, null, null, user) to_chat(user, "You start pushing out of [src]... (This will take about 20 seconds.)") - if(!do_after(user, 200, target = user) || open || !locked || !user in occupants) + if(!do_after(user, 200, target = user) || open || !locked || !(user in occupants)) return loc.visible_message("[user] shoves out of [src]!", null, null, null, user) to_chat(user, "You shove open [src]'s door against the lock's resistance and fall out!") @@ -185,7 +185,7 @@ occupant_weight += occupant.mob_size /obj/item/pet_carrier/proc/remove_occupant(mob/living/occupant, turf/new_turf) - if(!occupant in occupants || !istype(occupant)) + if(!(occupant in occupants) || !istype(occupant)) return occupant.forceMove(new_turf ? new_turf : drop_location()) occupants -= occupant diff --git a/code/game/objects/items/plushes.dm b/code/game/objects/items/plushes.dm index 40380dfe80..48588cf9f3 100644 --- a/code/game/objects/items/plushes.dm +++ b/code/game/objects/items/plushes.dm @@ -629,7 +629,7 @@ /obj/item/toy/plush/mothplushie name = "insect plushie" - desc = "An adorable stuffed toy that resembles some kind of insect" + desc = "An adorable stuffed toy that resembles some kind of insect." icon_state = "bumble" item_state = "bumble" squeak_override = list('modular_citadel/sound/voice/mothsqueak.ogg' = 1) @@ -773,8 +773,10 @@ item_state = "blep" /obj/item/toy/plush/mammal/circe + desc = "A luxuriously soft toy that resembles a nine-tailed kitsune." icon_state = "circe" item_state = "circe" + attack_verb = list("medicated", "tailhugged", "kissed") /obj/item/toy/plush/mammal/robin icon_state = "robin" @@ -839,8 +841,10 @@ item_state = "rae" /obj/item/toy/plush/mammal/zed + desc = "A masked stuffed toy that resembles a fierce miner. He even comes with his own little crusher!" icon_state = "zed" item_state = "zed" + attack_verb = list("ENDED", "CRUSHED", "GNOMED") /obj/item/toy/plush/mammal/justin icon_state = "justin" @@ -852,6 +856,12 @@ item_state = "reece" attack_verb = list("healed", "cured", "demoted") +/obj/item/toy/plush/mammal/redwood + desc = "An adorable stuffed toy resembling a Nanotrasen Captain. That just happens to be a bunny." + icon_state = "redwood" + item_state = "redwood" + attack_verb = list("ordered", "bapped", "reprimanded") + /obj/item/toy/plush/mammal/dog desc = "An adorable stuffed toy that resembles a canine." icon_state = "katlin" @@ -898,6 +908,12 @@ obj_flags = UNIQUE_RENAME unique_reskin = list("Goodboye" = "fritz", "Badboye" = "fritz_bad") +/obj/item/toy/plush/mammal/dog/jesse + desc = "An adorable wolf toy that resembles a cream-colored wolf. He has a little pride flag!" + icon_state = "jesse" + item_state = "jesse" + attack_verb = list("greeted", "merc'd", "howdy'd") + /obj/item/toy/plush/catgirl name = "feline plushie" desc = "An adorable stuffed toy that resembles a feline." @@ -935,3 +951,15 @@ item_state = "fermis" attack_verb = list("cuddled", "petpatted", "wigglepurred") squeak_override = list('modular_citadel/sound/voice/merowr.ogg' = 1) + +/obj/item/toy/plush/catgirl/mariaf + desc = "An adorable stuffed toy that resembles a very tall cat girl." + icon_state = "mariaf" + item_state = "mariaf" + attack_verb = list("hugged", "stabbed", "licked") + +/obj/item/toy/plush/catgirl/maya + desc = "An adorable stuffed toy that resembles an angry cat girl. She has her own tiny nuke disk!" + icon_state = "maya" + item_state = "maya" + attack_verb = list("nuked", "arrested", "harmbatonned") diff --git a/code/game/objects/items/robot/robot_items.dm b/code/game/objects/items/robot/robot_items.dm index 6d7c3036f9..5454b0fdb8 100644 --- a/code/game/objects/items/robot/robot_items.dm +++ b/code/game/objects/items/robot/robot_items.dm @@ -282,11 +282,13 @@ var/cooldown = 0 /obj/item/harmalarm/emag_act(mob/user) + . = ..() obj_flags ^= EMAGGED if(obj_flags & EMAGGED) to_chat(user, "You short out the safeties on [src]!") else to_chat(user, "You reset the safeties on [src]!") + return TRUE /obj/item/harmalarm/attack_self(mob/user) var/safety = !(obj_flags & EMAGGED) diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm index cd2ccff170..95110692c9 100644 --- a/code/game/objects/items/robot/robot_parts.dm +++ b/code/game/objects/items/robot/robot_parts.dm @@ -254,7 +254,7 @@ to_chat(user, "The MMI indicates that their mind is currently inactive; it might change!") return - if(BM.stat == DEAD || (M.brain && M.brain.damaged_brain)) + if(BM.stat == DEAD || (M.brain && M.brain.organ_flags & ORGAN_FAILING)) to_chat(user, "Sticking a dead brain into the frame would sort of defeat the purpose!") return diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index d5806494e6..9c929a6ebf 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -9,7 +9,7 @@ var/locked = FALSE var/installed = 0 var/require_module = 0 - var/module_type = null + var/list/module_type // if true, is not stored in the robot to be ejected // if module is reset var/one_use = FALSE @@ -18,7 +18,7 @@ if(R.stat == DEAD) to_chat(user, "[src] will not function on a deceased cyborg.") return FALSE - if(module_type && !istype(R.module, module_type)) + if(module_type && !is_type_in_list(R.module, module_type)) to_chat(R, "Upgrade mounting error! No suitable hardpoint detected!") to_chat(user, "There's no mounting point for the module!") return FALSE @@ -93,7 +93,6 @@ desc = "Used to cool a mounted disabler, increasing the potential current in it and thus its recharge rate." icon_state = "cyborg_upgrade3" require_module = 1 - //module_type = /obj/item/robot_module/security /obj/item/borg/upgrade/disablercooler/action(mob/living/silicon/robot/R, user = usr) . = ..() @@ -141,7 +140,7 @@ desc = "A diamond drill replacement for the mining module's standard drill." icon_state = "cyborg_upgrade3" require_module = 1 - module_type = /obj/item/robot_module/miner + module_type = list(/obj/item/robot_module/miner) /obj/item/borg/upgrade/ddrill/action(mob/living/silicon/robot/R, user = usr) . = ..() @@ -173,7 +172,7 @@ desc = "A satchel of holding replacement for mining cyborg's ore satchel module." icon_state = "cyborg_upgrade3" require_module = 1 - module_type = /obj/item/robot_module/miner + module_type = list(/obj/item/robot_module/miner) /obj/item/borg/upgrade/soh/action(mob/living/silicon/robot/R) . = ..() @@ -200,7 +199,7 @@ desc = "A trash bag of holding replacement for the janiborg's standard trash bag." icon_state = "cyborg_upgrade3" require_module = 1 - module_type = /obj/item/robot_module/janitor + module_type = list(/obj/item/robot_module/janitor, /obj/item/robot_module/scrubpup) /obj/item/borg/upgrade/tboh/action(mob/living/silicon/robot/R) . = ..() @@ -227,7 +226,7 @@ desc = "An advanced mop replacement for the janiborg's standard mop." icon_state = "cyborg_upgrade3" require_module = 1 - module_type = /obj/item/robot_module/janitor + module_type = list(/obj/item/robot_module/janitor, /obj/item/robot_module/scrubpup) /obj/item/borg/upgrade/amop/action(mob/living/silicon/robot/R) . = ..() @@ -276,7 +275,7 @@ icon_state = "ash_plating" resistance_flags = LAVA_PROOF | FIRE_PROOF require_module = 1 - module_type = /obj/item/robot_module/miner + module_type = list(/obj/item/robot_module/miner) /obj/item/borg/upgrade/lavaproof/action(mob/living/silicon/robot/R, user = usr) . = ..() @@ -405,7 +404,9 @@ to produce more advanced and complex medical reagents." icon_state = "cyborg_upgrade3" require_module = 1 - module_type = /obj/item/robot_module/medical + module_type = list(/obj/item/robot_module/medical, + /obj/item/robot_module/syndicate_medical, + /obj/item/robot_module/medihound) var/list/additional_reagents = list() /obj/item/borg/upgrade/hypospray/action(mob/living/silicon/robot/R, user = usr) @@ -467,7 +468,9 @@ defibrillator, for on the scene revival." icon_state = "cyborg_upgrade3" require_module = 1 - module_type = /obj/item/robot_module/medical + module_type = list(/obj/item/robot_module/medical, + /obj/item/robot_module/syndicate_medical, + /obj/item/robot_module/medihound) /obj/item/borg/upgrade/defib/action(mob/living/silicon/robot/R, user = usr) . = ..() @@ -489,7 +492,9 @@ out procedures" icon_state = "cyborg_upgrade3" require_module = 1 - module_type = /obj/item/robot_module/medical + module_type = list(/obj/item/robot_module/medical, + /obj/item/robot_module/syndicate_medical, + /obj/item/robot_module/medihound) /obj/item/borg/upgrade/processor/action(mob/living/silicon/robot/R, user = usr) . = ..() @@ -514,7 +519,7 @@ /obj/item/robot_module/medical, /obj/item/robot_module/syndicate_medical, /obj/item/robot_module/medihound, - /obj/item/robot_module/borgi) + /obj/item/robot_module/borgi) /obj/item/borg/upgrade/advhealth/action(mob/living/silicon/robot/R, user = usr) . = ..() @@ -598,7 +603,7 @@ icon = 'icons/obj/storage.dmi' icon_state = "borgrped" require_module = TRUE - module_type = /obj/item/robot_module/engineering + module_type = list(/obj/item/robot_module/engineering) /obj/item/borg/upgrade/rped/action(mob/living/silicon/robot/R, user = usr) . = ..() @@ -626,7 +631,9 @@ icon = 'icons/obj/device.dmi' icon_state = "pinpointer_crew" require_module = TRUE - module_type = /obj/item/robot_module/medical + module_type = list(/obj/item/robot_module/medical, + /obj/item/robot_module/syndicate_medical, + /obj/item/robot_module/medihound) /obj/item/borg/upgrade/pinpointer/action(mob/living/silicon/robot/R, user = usr) . = ..() @@ -664,3 +671,33 @@ desc = "Allows you to to turn a cyborg into a clown, honk." icon_state = "cyborg_upgrade3" new_module = /obj/item/robot_module/clown + +// Citadel's Vtech Controller +/obj/effect/proc_holder/silicon/cyborg/vtecControl + name = "vTec Control" + desc = "Allows finer-grained control of the vTec speed boost." + action_icon = 'icons/mob/actions.dmi' + action_icon_state = "Chevron_State_0" + + var/currentState = 0 + var/maxReduction = 2 + + +/obj/effect/proc_holder/silicon/cyborg/vtecControl/Click(mob/living/silicon/robot/user) + var/mob/living/silicon/robot/self = usr + + currentState = (currentState + 1) % 3 + + if(usr) + switch(currentState) + if (0) + self.speed = maxReduction + if (1) + self.speed -= maxReduction*0.5 + if (2) + self.speed -= maxReduction*1.25 + + action.button_icon_state = "Chevron_State_[currentState]" + action.UpdateButtonIcon() + + return diff --git a/code/game/objects/items/singularityhammer.dm b/code/game/objects/items/singularityhammer.dm index 1fe57d151f..b6559c9091 100644 --- a/code/game/objects/items/singularityhammer.dm +++ b/code/game/objects/items/singularityhammer.dm @@ -16,6 +16,7 @@ armor = list("melee" = 50, "bullet" = 50, "laser" = 50, "energy" = 0, "bomb" = 50, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100) resistance_flags = FIRE_PROOF | ACID_PROOF force_string = "LORD SINGULOTH HIMSELF" + total_mass = TOTAL_MASS_MEDIEVAL_WEAPON /obj/item/twohanded/singularityhammer/New() ..() @@ -84,6 +85,7 @@ throwforce = 30 throw_range = 7 w_class = WEIGHT_CLASS_HUGE + total_mass = TOTAL_MASS_MEDIEVAL_WEAPON /obj/item/twohanded/mjollnir/proc/shock(mob/living/target) target.Stun(60) diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm index cf967e25ba..c9fc59a3fe 100644 --- a/code/game/objects/items/stacks/sheets/glass.dm +++ b/code/game/objects/items/stacks/sheets/glass.dm @@ -23,8 +23,9 @@ GLOBAL_LIST_INIT(glass_recipes, list ( \ armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 100) resistance_flags = ACID_PROOF merge_type = /obj/item/stack/sheet/glass - grind_results = list("silicon" = 20) + grind_results = list(/datum/reagent/silicon = 20) point_value = 1 + tableVariant = /obj/structure/table/glass /obj/item/stack/sheet/glass/suicide_act(mob/living/carbon/user) user.visible_message("[user] begins to slice [user.p_their()] neck with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!") @@ -87,7 +88,8 @@ GLOBAL_LIST_INIT(pglass_recipes, list ( \ armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 75, "acid" = 100) resistance_flags = ACID_PROOF merge_type = /obj/item/stack/sheet/plasmaglass - grind_results = list("silicon" = 20, "plasma" = 10) + grind_results = list(/datum/reagent/silicon = 20, /datum/reagent/toxin/plasma = 10) + tableVariant = /obj/structure/table/plasmaglass /obj/item/stack/sheet/plasmaglass/fifty amount = 50 @@ -138,7 +140,7 @@ GLOBAL_LIST_INIT(reinforced_glass_recipes, list ( \ armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 70, "acid" = 100) resistance_flags = ACID_PROOF merge_type = /obj/item/stack/sheet/rglass - grind_results = list("silicon" = 20, "iron" = 10) + grind_results = list(/datum/reagent/silicon = 20, /datum/reagent/iron = 10) point_value = 4 /obj/item/stack/sheet/rglass/attackby(obj/item/W, mob/user, params) @@ -177,11 +179,11 @@ GLOBAL_LIST_INIT(prglass_recipes, list ( \ singular_name = "reinforced plasma glass sheet" icon_state = "sheet-prglass" item_state = "sheet-prglass" - materials = list(MAT_PLASMA=MINERAL_MATERIAL_AMOUNT * 0.5, MAT_GLASS=MINERAL_MATERIAL_AMOUNT, MAT_METAL = MINERAL_MATERIAL_AMOUNT * 0.5,) + materials = list(MAT_PLASMA=MINERAL_MATERIAL_AMOUNT * 0.5, MAT_GLASS=MINERAL_MATERIAL_AMOUNT, MAT_METAL=MINERAL_MATERIAL_AMOUNT * 0.5,) armor = list("melee" = 20, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 80, "acid" = 100) resistance_flags = ACID_PROOF merge_type = /obj/item/stack/sheet/plasmarglass - grind_results = list("silicon" = 20, "plasma" = 10, "iron" = 10) + grind_results = list(/datum/reagent/silicon = 20, /datum/reagent/toxin/plasma = 10, /datum/reagent/iron = 10) point_value = 23 /obj/item/stack/sheet/plasmarglass/Initialize(mapload, new_amount, merge = TRUE) @@ -243,8 +245,9 @@ GLOBAL_LIST_INIT(plastitaniumglass_recipes, list( resistance_flags = ACID_PROOF armor = list("melee" = 100, "bullet" = 0, "laser" = 0, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 100) max_integrity = 40 - var/cooldown = 0 sharpness = IS_SHARP + var/icon_prefix + /obj/item/shard/suicide_act(mob/user) user.visible_message("[user] is slitting [user.p_their()] [pick("wrists", "throat")] with the shard of glass! It looks like [user.p_theyre()] trying to commit suicide.") @@ -266,9 +269,19 @@ GLOBAL_LIST_INIT(plastitaniumglass_recipes, list( if("large") pixel_x = rand(-5, 5) pixel_y = rand(-5, 5) - var/matrix/M = matrix(transform) - M.Turn(rand(-170, 170)) - transform = M + if (icon_prefix) + icon_state = "[icon_prefix][icon_state]" + + var/turf/T = get_turf(src) + if(T && is_station_level(T.z)) + SSblackbox.record_feedback("tally", "station_mess_created", 1, name) + +/obj/item/shard/Destroy() + . = ..() + + var/turf/T = get_turf(src) + if(T && is_station_level(T.z)) + SSblackbox.record_feedback("tally", "station_mess_destroyed", 1, name) /obj/item/shard/afterattack(atom/A as mob|obj, mob/user, proximity) . = ..() @@ -298,6 +311,7 @@ GLOBAL_LIST_INIT(plastitaniumglass_recipes, list( return ..() /obj/item/shard/welder_act(mob/living/user, obj/item/I) + ..() if(I.use_tool(src, user, 0, volume=50)) var/obj/item/stack/sheet/glass/NG = new (user.loc) for(var/obj/item/stack/sheet/glass/G in user.loc) @@ -316,4 +330,13 @@ GLOBAL_LIST_INIT(plastitaniumglass_recipes, list( playsound(loc, 'sound/effects/glass_step.ogg', 30, 1) else playsound(loc, 'sound/effects/glass_step.ogg', 50, 1) - . = ..() + return ..() + +/obj/item/shard/plasma + name = "purple shard" + desc = "A nasty looking shard of plasma glass." + force = 6 + throwforce = 11 + icon_state = "plasmalarge" + materials = list(MAT_PLASMA=MINERAL_MATERIAL_AMOUNT * 0.5, MAT_GLASS=MINERAL_MATERIAL_AMOUNT) + icon_prefix = "plasma" \ No newline at end of file diff --git a/code/game/objects/items/stacks/sheets/mineral.dm b/code/game/objects/items/stacks/sheets/mineral.dm index 7df165461b..46c0d47388 100644 --- a/code/game/objects/items/stacks/sheets/mineral.dm +++ b/code/game/objects/items/stacks/sheets/mineral.dm @@ -232,6 +232,7 @@ GLOBAL_LIST_INIT(gold_recipes, list ( \ grind_results = list("silver" = 20) point_value = 20 merge_type = /obj/item/stack/sheet/mineral/silver + tableVariant = /obj/structure/table/optable GLOBAL_LIST_INIT(silver_recipes, list ( \ new/datum/stack_recipe("silver door", /obj/structure/mineral_door/silver, 10, one_per_turf = 1, on_floor = 1), \ diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index 5594059463..c085306892 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -107,6 +107,7 @@ GLOBAL_LIST_INIT(metal_recipes, list ( \ merge_type = /obj/item/stack/sheet/metal grind_results = list("iron" = 20) point_value = 2 + tableVariant = /obj/structure/table /obj/item/stack/sheet/metal/ratvar_act() new /obj/item/stack/tile/brass(loc, amount) @@ -168,6 +169,7 @@ GLOBAL_LIST_INIT(plasteel_recipes, list ( \ merge_type = /obj/item/stack/sheet/plasteel grind_results = list("iron" = 20, "plasma" = 20) point_value = 23 + tableVariant = /obj/structure/table/reinforced /obj/item/stack/sheet/plasteel/Initialize(mapload, new_amount, merge = TRUE) recipes = GLOB.plasteel_recipes @@ -201,6 +203,7 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \ new/datum/stack_recipe("dresser", /obj/structure/dresser, 10, time = 15, one_per_turf = TRUE, on_floor = TRUE), \ new/datum/stack_recipe("picture frame", /obj/item/wallframe/picture, 1, time = 10),\ new/datum/stack_recipe("display case chassis", /obj/structure/displaycase_chassis, 5, one_per_turf = TRUE, on_floor = TRUE), \ + new/datum/stack_recipe("loom", /obj/structure/loom, 10, time = 15, one_per_turf = TRUE, on_floor = TRUE), \ new/datum/stack_recipe("wooden buckler", /obj/item/shield/riot/buckler, 20, time = 40), \ new/datum/stack_recipe("apiary", /obj/structure/beebox, 40, time = 50),\ new/datum/stack_recipe("tiki mask", /obj/item/clothing/mask/gas/tiki_mask, 2), \ @@ -278,6 +281,31 @@ GLOBAL_LIST_INIT(cloth_recipes, list ( \ /obj/item/stack/sheet/cloth/ten amount = 10 +//Durathread fuck slash-asterisk comments + GLOBAL_LIST_INIT(durathread_recipes, list ( \ + new/datum/stack_recipe("durathread jumpsuit", /obj/item/clothing/under/durathread, 4, time = 40), + new/datum/stack_recipe("durathread beret", /obj/item/clothing/head/beret/durathread, 2, time = 40), \ + new/datum/stack_recipe("durathread beanie", /obj/item/clothing/head/beanie/durathread, 2, time = 40), \ + new/datum/stack_recipe("durathread bandana", /obj/item/clothing/mask/bandana/durathread, 1, time = 25), \ + )) + +/obj/item/stack/sheet/durathread + name = "durathread" + desc = "A fabric sown from incredibly durable threads, known for its usefulness in armor production." + singular_name = "durathread roll" + icon_state = "sheet-durathread" + item_state = "sheet-cloth" + resistance_flags = FLAMMABLE + force = 0 + throwforce = 0 + merge_type = /obj/item/stack/sheet/durathread + +/obj/item/stack/sheet/durathread/Initialize(mapload, new_amount, merge = TRUE) + recipes = GLOB.durathread_recipes + return ..() + + + /* * Cardboard */ @@ -415,6 +443,8 @@ GLOBAL_LIST_INIT(brass_recipes, list ( \ new/datum/stack_recipe("brass window - directional", /obj/structure/window/reinforced/clockwork/unanchored, time = 0, on_floor = TRUE, window_checks = TRUE), \ new/datum/stack_recipe("brass window - fulltile", /obj/structure/window/reinforced/clockwork/fulltile/unanchored, 2, time = 0, on_floor = TRUE, window_checks = TRUE), \ new/datum/stack_recipe("brass chair", /obj/structure/chair/brass, 1, time = 0, one_per_turf = TRUE, on_floor = TRUE), \ + new/datum/stack_recipe("brass bar stool", /obj/structure/chair/stool/bar/brass, 1, time = 0, one_per_turf = TRUE, on_floor = TRUE), \ + new/datum/stack_recipe("brass stool", /obj/structure/chair/stool/brass, 1, time = 0, one_per_turf = TRUE, on_floor = TRUE), \ new/datum/stack_recipe("brass table frame", /obj/structure/table_frame/brass, 1, time = 5, one_per_turf = TRUE, on_floor = TRUE), \ null, new/datum/stack_recipe("sender - pressure sensor", /obj/structure/destructible/clockwork/trap/trigger/pressure_sensor, 2, time = 20, one_per_turf = TRUE, on_floor = TRUE), \ @@ -426,7 +456,7 @@ GLOBAL_LIST_INIT(brass_recipes, list ( \ new/datum/stack_recipe("receiver - steam vent", /obj/structure/destructible/clockwork/trap/steam_vent, 3, time = 30, one_per_turf = TRUE, on_floor = TRUE, placement_checks = STACK_CHECK_CARDINALS), \ new/datum/stack_recipe("receiver - power nullifier", /obj/structure/destructible/clockwork/trap/power_nullifier, 5, time = 20, one_per_turf = TRUE, on_floor = TRUE, placement_checks = STACK_CHECK_CARDINALS), \ null, - new/datum/stack_recipe("brass flask", /obj/item/reagent_containers/food/drinks/holyoil/null), \ + new/datum/stack_recipe("brass flask", /obj/item/reagent_containers/food/drinks/bottle/holyoil/empty), \ )) @@ -446,6 +476,7 @@ GLOBAL_LIST_INIT(brass_recipes, list ( \ novariants = FALSE grind_results = list("iron" = 5, "teslium" = 15, "holyoil" = 1) merge_type = /obj/item/stack/tile/brass + tableVariant = /obj/structure/table/reinforced/brass /obj/item/stack/tile/brass/narsie_act() new /obj/item/stack/sheet/runed_metal(loc, amount) @@ -478,6 +509,8 @@ GLOBAL_LIST_INIT(bronze_recipes, list ( \ new/datum/stack_recipe("bronze boots", /obj/item/clothing/shoes/bronze), \ null, new/datum/stack_recipe("bronze chair", /obj/structure/chair/bronze, 1, time = 0, one_per_turf = TRUE, on_floor = TRUE), \ + new/datum/stack_recipe("bronze bar stool", /obj/structure/chair/stool/bar/bronze, 1, time = 0, one_per_turf = TRUE, on_floor = TRUE), \ + new/datum/stack_recipe("bronze stool", /obj/structure/chair/stool/bronze, 1, time = 0, one_per_turf = TRUE, on_floor = TRUE), \ )) /obj/item/stack/tile/bronze @@ -496,6 +529,7 @@ GLOBAL_LIST_INIT(bronze_recipes, list ( \ novariants = FALSE grind_results = list("iron" = 5, "copper" = 3) //we have no "tin" reagent so this is the closest thing merge_type = /obj/item/stack/tile/bronze + tableVariant = /obj/structure/table/bronze /obj/item/stack/tile/bronze/attack_self(mob/living/user) if(is_servant_of_ratvar(user)) //still lets them build with it, just gives a message @@ -599,3 +633,29 @@ new /datum/stack_recipe("paper frame door", /obj/structure/mineral_door/paperfra amount = 20 /obj/item/stack/sheet/paperframes/fifty amount = 50 + + +//durathread and cotton raw +/obj/item/stack/sheet/cotton + name = "raw cotton bundle" + desc = "A bundle of raw cotton ready to be spun on the loom." + singular_name = "raw cotton ball" + icon_state = "sheet-cotton" + is_fabric = TRUE + resistance_flags = FLAMMABLE + force = 0 + throwforce = 0 + merge_type = /obj/item/stack/sheet/cotton + pull_effort = 30 + loom_result = /obj/item/stack/sheet/cloth + +/obj/item/stack/sheet/cotton/durathread + name = "raw durathread bundle" + desc = "A bundle of raw durathread ready to be spun on the loom." + singular_name = "raw durathread ball" + icon_state = "sheet-durathreadraw" + merge_type = /obj/item/stack/sheet/cotton/durathread + pull_effort = 70 + loom_result = /obj/item/stack/sheet/durathread + + diff --git a/code/game/objects/items/stacks/sheets/sheets.dm b/code/game/objects/items/stacks/sheets/sheets.dm index 21b43eba20..908fc88383 100644 --- a/code/game/objects/items/stacks/sheets/sheets.dm +++ b/code/game/objects/items/stacks/sheets/sheets.dm @@ -12,4 +12,7 @@ novariants = FALSE var/perunit = MINERAL_MATERIAL_AMOUNT var/sheettype = null //this is used for girders in the creation of walls/false walls - var/point_value = 0 //turn-in value for the gulag stacker - loosely relative to its rarity. \ No newline at end of file + var/point_value = 0 //turn-in value for the gulag stacker - loosely relative to its rarity + var/is_fabric = FALSE //is this a valid material for the loom? + var/loom_result //result from pulling on the loom + var/pull_effort = 0 //amount of delay when pulling on the loom \ No newline at end of file diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index 4217a58f81..155d1f1643 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -22,6 +22,7 @@ var/full_w_class = WEIGHT_CLASS_NORMAL //The weight class the stack should have at amount > 2/3rds max_amount var/novariants = TRUE //Determines whether the item should update it's sprites based on amount. //NOTE: When adding grind_results, the amounts should be for an INDIVIDUAL ITEM - these amounts will be multiplied by the stack size in on_grind() + var/obj/structure/table/tableVariant // we tables now (stores table variant to be built from this stack) /obj/item/stack/on_grind() for(var/i in 1 to grind_results.len) //This should only call if it's ground, so no need to check if grind_results exists diff --git a/code/game/objects/items/stacks/telecrystal.dm b/code/game/objects/items/stacks/telecrystal.dm index c1fb396529..7c34ae87bf 100644 --- a/code/game/objects/items/stacks/telecrystal.dm +++ b/code/game/objects/items/stacks/telecrystal.dm @@ -9,9 +9,10 @@ item_flags = NOBLUDGEON /obj/item/stack/telecrystal/attack(mob/target, mob/user) - if(target == user) //You can't go around smacking people with crystals to find out if they have an uplink or not. - for(var/obj/item/implant/uplink/I in target) - if(I && I.imp_in) + if(target == user && isliving(user)) //You can't go around smacking people with crystals to find out if they have an uplink or not. + var/mob/living/L = user + for(var/obj/item/implant/uplink/I in L.implants) + if(I?.imp_in) GET_COMPONENT_FROM(hidden_uplink, /datum/component/uplink, I) if(hidden_uplink) hidden_uplink.telecrystals += amount diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm index 3b28c30402..847e1b521e 100644 --- a/code/game/objects/items/stacks/tiles/tile_types.dm +++ b/code/game/objects/items/stacks/tiles/tile_types.dm @@ -99,33 +99,117 @@ icon_state = "tile-carpet" turf_type = /turf/open/floor/carpet resistance_flags = FLAMMABLE - -/obj/item/stack/tile/carpet/fifty - amount = 50 + tableVariant = /obj/structure/table/wood/fancy /obj/item/stack/tile/carpet/black name = "black carpet" icon_state = "tile-carpet-black" turf_type = /turf/open/floor/carpet/black + tableVariant = /obj/structure/table/wood/fancy/black + +/obj/item/stack/tile/carpet/blackred + name = "red carpet" + icon_state = "tile-carpet-blackred" + turf_type = /turf/open/floor/carpet/blackred + tableVariant = /obj/structure/table/wood/fancy/blackred + +/obj/item/stack/tile/carpet/monochrome + name = "monochrome carpet" + icon_state = "tile-carpet-monochrome" + turf_type = /turf/open/floor/carpet/monochrome + tableVariant = /obj/structure/table/wood/fancy/monochrome + +/obj/item/stack/tile/carpet/blue + name = "blue carpet" + icon_state = "tile-carpet-blue" + item_state = "tile-carpet-blue" + turf_type = /turf/open/floor/carpet/blue + tableVariant = /obj/structure/table/wood/fancy/blue + +/obj/item/stack/tile/carpet/cyan + name = "cyan carpet" + icon_state = "tile-carpet-cyan" + item_state = "tile-carpet-cyan" + turf_type = /turf/open/floor/carpet/cyan + tableVariant = /obj/structure/table/wood/fancy/cyan + +/obj/item/stack/tile/carpet/green + name = "green carpet" + icon_state = "tile-carpet-green" + item_state = "tile-carpet-green" + turf_type = /turf/open/floor/carpet/green + tableVariant = /obj/structure/table/wood/fancy/green + +/obj/item/stack/tile/carpet/orange + name = "orange carpet" + icon_state = "tile-carpet-orange" + item_state = "tile-carpet-orange" + turf_type = /turf/open/floor/carpet/orange + tableVariant = /obj/structure/table/wood/fancy/orange + +/obj/item/stack/tile/carpet/purple + name = "purple carpet" + icon_state = "tile-carpet-purple" + item_state = "tile-carpet-purple" + turf_type = /turf/open/floor/carpet/purple + tableVariant = /obj/structure/table/wood/fancy/purple + +/obj/item/stack/tile/carpet/red + name = "red carpet" + icon_state = "tile-carpet-red" + item_state = "tile-carpet-red" + turf_type = /turf/open/floor/carpet/red + tableVariant = /obj/structure/table/wood/fancy/red + +/obj/item/stack/tile/carpet/royalblack + name = "royal black carpet" + icon_state = "tile-carpet-royalblack" + item_state = "tile-carpet-royalblack" + turf_type = /turf/open/floor/carpet/royalblack + tableVariant = /obj/structure/table/wood/fancy/royalblack + +/obj/item/stack/tile/carpet/royalblue + name = "royal blue carpet" + icon_state = "tile-carpet-royalblue" + item_state = "tile-carpet-royalblue" + turf_type = /turf/open/floor/carpet/royalblue + tableVariant = /obj/structure/table/wood/fancy/royalblue + +/obj/item/stack/tile/carpet/fifty + amount = 50 /obj/item/stack/tile/carpet/black/fifty amount = 50 -/obj/item/stack/tile/carpet/blackred - name = "red carpet" - icon_state = "tile-carpet-blackred" - turf_type = /turf/open/floor/carpet/blackred - /obj/item/stack/tile/carpet/blackred/fifty - amount = 50 - -/obj/item/stack/tile/carpet/monochrome - name = "monochrome carpet" - icon_state = "tile-carpet-monochrome" - turf_type = /turf/open/floor/carpet/monochrome + amount = 50 /obj/item/stack/tile/carpet/monochrome/fifty - amount = 50 + amount = 50 + +/obj/item/stack/tile/carpet/blue/fifty + amount = 50 + +/obj/item/stack/tile/carpet/cyan/fifty + amount = 50 + +/obj/item/stack/tile/carpet/green/fifty + amount = 50 + +/obj/item/stack/tile/carpet/orange/fifty + amount = 50 + +/obj/item/stack/tile/carpet/purple/fifty + amount = 50 + +/obj/item/stack/tile/carpet/red/fifty + amount = 50 + +/obj/item/stack/tile/carpet/royalblack/fifty + amount = 50 + +/obj/item/stack/tile/carpet/royalblue/fifty + amount = 50 /obj/item/stack/tile/fakespace name = "astral carpet" diff --git a/code/game/objects/items/storage/backpack.dm b/code/game/objects/items/storage/backpack.dm index eb71311c96..ad8c4306a5 100644 --- a/code/game/objects/items/storage/backpack.dm +++ b/code/game/objects/items/storage/backpack.dm @@ -46,6 +46,7 @@ item_flags = NO_MAT_REDEMPTION armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 60, "acid" = 50) component_type = /datum/component/storage/concrete/bluespace/bag_of_holding + rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE /obj/item/storage/backpack/holding/satchel name = "satchel of holding" @@ -53,6 +54,7 @@ icon_state = "holdingsat" item_state = "holdingsat" species_exception = list(/datum/species/angel) + rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE /obj/item/storage/backpack/holding/ComponentInitialize() . = ..() @@ -81,6 +83,7 @@ icon_state = "giftbag0" item_state = "giftbag" w_class = WEIGHT_CLASS_BULKY + rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE /obj/item/storage/backpack/santabag/ComponentInitialize() . = ..() @@ -133,6 +136,8 @@ desc = "It's a special backpack made exclusively for Nanotrasen officers." icon_state = "captainpack" item_state = "captainpack" + resistance_flags = FIRE_PROOF + rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE /obj/item/storage/backpack/industrial name = "industrial backpack" @@ -140,6 +145,7 @@ icon_state = "engiepack" item_state = "engiepack" resistance_flags = FIRE_PROOF + rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE /obj/item/storage/backpack/botany name = "botany backpack" @@ -194,6 +200,8 @@ desc = "A tough satchel with extra pockets." icon_state = "satchel-eng" item_state = "engiepack" + resistance_flags = FIRE_PROOF + rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE /obj/item/storage/backpack/satchel/med name = "medical satchel" @@ -248,18 +256,21 @@ desc = "A bone satchel fashend with watcher wings and large bones from goliath. Can be worn on the belt." icon = 'icons/obj/mining.dmi' icon_state = "goliath_saddle" - slot_flags = ITEM_SLOT_BACK | ITEM_SLOT_BELT + slot_flags = ITEM_SLOT_BACK /obj/item/storage/backpack/satchel/bone/ComponentInitialize() . = ..() GET_COMPONENT(STR, /datum/component/storage) - STR.max_combined_w_class = 10 + STR.max_combined_w_class = 20 + STR.max_items = 15 /obj/item/storage/backpack/satchel/cap name = "captain's satchel" desc = "An exclusive satchel for Nanotrasen officers." icon_state = "satchel-cap" item_state = "captainpack" + resistance_flags = FIRE_PROOF + rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE /obj/item/storage/backpack/satchel/flat name = "smuggler's satchel" @@ -355,6 +366,7 @@ new /obj/item/cautery(src) new /obj/item/surgical_drapes(src) new /obj/item/clothing/mask/surgical(src) + new /obj/item/reagent_containers/medspray/sterilizine(src) new /obj/item/razor(src) /obj/item/storage/backpack/duffelbag/sec @@ -376,12 +388,23 @@ new /obj/item/cautery(src) new /obj/item/surgical_drapes(src) new /obj/item/clothing/mask/surgical(src) + new /obj/item/reagent_containers/medspray/sterilizine(src) /obj/item/storage/backpack/duffelbag/engineering name = "industrial duffel bag" desc = "A large duffel bag for holding extra tools and supplies." icon_state = "duffel-eng" item_state = "duffel-eng" + resistance_flags = FIRE_PROOF + rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE + +/obj/item/storage/backpack/duffelbag/durathread + name = "durathread duffel bag" + desc = "A lightweight duffel bag made out of durathread." + icon_state = "duffel-durathread" + item_state = "duffel-durathread" + resistance_flags = FIRE_PROOF + slowdown = 0 /obj/item/storage/backpack/duffelbag/drone name = "drone duffel bag" @@ -389,6 +412,7 @@ icon_state = "duffel-drone" item_state = "duffel-drone" resistance_flags = FIRE_PROOF + rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE /obj/item/storage/backpack/duffelbag/drone/PopulateContents() new /obj/item/screwdriver(src) @@ -398,6 +422,7 @@ new /obj/item/stack/cable_coil/random(src) new /obj/item/wirecutters(src) new /obj/item/multitool(src) + new /obj/item/pipe_dispenser(src) /obj/item/storage/backpack/duffelbag/clown name = "clown's duffel bag" @@ -415,6 +440,7 @@ icon_state = "duffel-syndie" item_state = "duffel-syndieammo" slowdown = 0 + rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE /obj/item/storage/backpack/duffelbag/syndie/ComponentInitialize() . = ..() @@ -460,18 +486,16 @@ new /obj/item/mmi/syndie(src) new /obj/item/implantcase(src) new /obj/item/implanter(src) + new /obj/item/reagent_containers/medspray/sterilizine(src) /obj/item/storage/backpack/duffelbag/syndie/surgery_adv name = "advanced surgery duffel bag" desc = "A large duffel bag for holding surgical tools. Bears the logo of an advanced med-tech firm." /obj/item/storage/backpack/duffelbag/syndie/surgery_adv/PopulateContents() - new /obj/item/hemostat/adv(src) - new /obj/item/circular_saw/adv(src) - new /obj/item/scalpel/adv(src) - new /obj/item/retractor/adv(src) - new /obj/item/cautery/adv(src) - new /obj/item/surgicaldrill/adv(src) + new /obj/item/scalpel/advanced(src) + new /obj/item/retractor/advanced(src) + new /obj/item/surgicaldrill/advanced(src) new /obj/item/surgical_drapes(src) new /obj/item/storage/firstaid/tactical(src) new /obj/item/clothing/suit/straight_jacket(src) @@ -479,6 +503,7 @@ new /obj/item/mmi/syndie(src) new /obj/item/implantcase(src) new /obj/item/implanter(src) + new /obj/item/reagent_containers/medspray/sterilizine(src) /obj/item/storage/backpack/duffelbag/syndie/ammo name = "ammunition duffel bag" diff --git a/code/game/objects/items/storage/bags.dm b/code/game/objects/items/storage/bags.dm index e4debeff49..0a475b2af1 100644 --- a/code/game/objects/items/storage/bags.dm +++ b/code/game/objects/items/storage/bags.dm @@ -81,6 +81,7 @@ desc = "The latest and greatest in custodial convenience, a trashbag that is capable of holding vast quantities of garbage." icon_state = "bluetrashbag" item_flags = NO_MAT_REDEMPTION + rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE /obj/item/storage/bag/trash/bluespace/ComponentInitialize() . = ..() @@ -105,6 +106,7 @@ component_type = /datum/component/storage/concrete/stack var/spam_protection = FALSE //If this is TRUE, the holder won't receive any messages when they fail to pick up ore through crossing it var/datum/component/mobhook + rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE /obj/item/storage/bag/ore/ComponentInitialize() . = ..() @@ -364,7 +366,7 @@ STR.max_combined_w_class = 200 STR.max_items = 50 STR.insert_preposition = "in" - STR.can_hold = typecacheof(list(/obj/item/reagent_containers/pill, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/glass/bottle)) + STR.can_hold = typecacheof(list(/obj/item/reagent_containers/pill, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/syringe/dart)) /* * Biowaste bag (mostly for xenobiologists) @@ -391,6 +393,7 @@ icon = 'icons/obj/chemical.dmi' icon_state = "bspace_biobag" desc = "A bag for the safe transportation and disposal of biowaste and other biological materials." + rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE /obj/item/storage/bag/bio/holding/ComponentInitialize() . = ..() diff --git a/code/game/objects/items/storage/belt.dm b/code/game/objects/items/storage/belt.dm index b746058588..e354123ab9 100755 --- a/code/game/objects/items/storage/belt.dm +++ b/code/game/objects/items/storage/belt.dm @@ -10,6 +10,7 @@ attack_verb = list("whipped", "lashed", "disciplined") max_integrity = 300 var/content_overlays = FALSE //If this is true, the belt will gain overlays based on what it's holding + var/worn_overlays = FALSE //worn counterpart of the above. /obj/item/storage/belt/suicide_act(mob/living/carbon/user) user.visible_message("[user] begins belting [user.p_them()]self with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!") @@ -23,6 +24,12 @@ add_overlay(M) ..() +/obj/item/storage/belt/worn_overlays(isinhands, icon_file) + . = ..() + if(!isinhands && worn_overlays) + for(var/obj/item/I in contents) + . += I.get_worn_belt_overlay(icon_file) + /obj/item/storage/belt/Initialize() . = ..() update_icon() @@ -33,6 +40,7 @@ icon_state = "utilitybelt" item_state = "utility" content_overlays = TRUE + rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE //because this is easier than trying to have showers wash all contents. /obj/item/storage/belt/utility/ComponentInitialize() . = ..() @@ -177,12 +185,9 @@ content_overlays = FALSE /obj/item/storage/belt/medical/surgery_belt_adv/PopulateContents() - new /obj/item/hemostat/adv(src) - new /obj/item/circular_saw/adv(src) - new /obj/item/scalpel/adv(src) - new /obj/item/retractor/adv(src) - new /obj/item/cautery/adv(src) - new /obj/item/surgicaldrill/adv(src) + new /obj/item/scalpel/advanced(src) + new /obj/item/retractor/advanced(src) + new /obj/item/surgicaldrill/advanced(src) new /obj/item/surgical_drapes(src) /obj/item/storage/belt/security @@ -337,6 +342,7 @@ desc = "A set of tactical webbing worn by Syndicate boarding parties." icon_state = "militarywebbing" item_state = "militarywebbing" + rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE /obj/item/storage/belt/military/ComponentInitialize() . = ..() @@ -424,6 +430,48 @@ GET_COMPONENT(STR, /datum/component/storage) STR.max_items = 6 +/obj/item/storage/belt/durathread + name = "durathread toolbelt" + desc = "A toolbelt made out of durathread, it seems resistant enough to hold even big tools like an RCD, it also has higher capacity." + icon_state = "webbing-durathread" + item_state = "webbing-durathread" + resistance_flags = FIRE_PROOF + +/obj/item/storage/belt/durathread/ComponentInitialize() + . = ..() + var/datum/component/storage/STR = GetComponent(/datum/component/storage) + STR.max_items = 14 + STR.max_combined_w_class = 32 + STR.max_w_class = WEIGHT_CLASS_NORMAL + STR.can_hold = typecacheof(list( + /obj/item/crowbar, + /obj/item/screwdriver, + /obj/item/weldingtool, + /obj/item/wirecutters, + /obj/item/wrench, + /obj/item/multitool, + /obj/item/flashlight, + /obj/item/stack/cable_coil, + /obj/item/t_scanner, + /obj/item/analyzer, + /obj/item/geiger_counter, + /obj/item/extinguisher/mini, + /obj/item/radio, + /obj/item/clothing/gloves, + /obj/item/holosign_creator/atmos, + /obj/item/holosign_creator/engineering, + /obj/item/forcefield_projector, + /obj/item/assembly/signaler, + /obj/item/lightreplacer, + /obj/item/rcd_ammo, + /obj/item/construction/rcd, + /obj/item/pipe_dispenser, + /obj/item/stack/rods, + /obj/item/stack/tile/plasteel, + /obj/item/grenade/chem_grenade/metalfoam, + /obj/item/grenade/chem_grenade/smart_metal_foam + )) + /obj/item/storage/belt/grenade name = "grenadier belt" desc = "A belt for holding grenades." @@ -481,6 +529,7 @@ desc = "A belt designed to hold various rods of power. A veritable fanny pack of exotic magic." icon_state = "soulstonebelt" item_state = "soulstonebelt" + rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE /obj/item/storage/belt/wands/ComponentInitialize() . = ..() @@ -517,12 +566,15 @@ /obj/item/grenade/chem_grenade, /obj/item/lightreplacer, /obj/item/flashlight, + /obj/item/reagent_containers/glass/beaker, + /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/spray, /obj/item/soap, /obj/item/holosign_creator, /obj/item/key/janitor, /obj/item/clothing/gloves, /obj/item/melee/flyswatter, + /obj/item/paint/paint_remover, /obj/item/assembly/mousetrap )) @@ -541,6 +593,22 @@ /obj/item/ammo_casing/shotgun )) +/obj/item/storage/belt/bandolier/durathread + name = "durathread bandolier" + desc = "An double stacked bandolier made out of durathread." + icon_state = "bandolier-durathread" + item_state = "bandolier-durathread" + resistance_flags = FIRE_PROOF + +/obj/item/storage/belt/bandolier/durathread/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_items = 32 + STR.display_numerical_stacking = TRUE + STR.can_hold = typecacheof(list( + /obj/item/ammo_casing + )) + /obj/item/storage/belt/medolier name = "medolier" desc = "A medical bandolier for holding smartdarts." @@ -552,6 +620,9 @@ GET_COMPONENT(STR, /datum/component/storage) STR.max_items = 15 STR.display_numerical_stacking = FALSE + STR.allow_quick_gather = TRUE + STR.allow_quick_empty = TRUE + STR.click_gather = TRUE STR.can_hold = typecacheof(list( /obj/item/reagent_containers/syringe/dart )) @@ -560,6 +631,25 @@ for(var/i in 1 to 16) new /obj/item/reagent_containers/syringe/dart/(src) +/obj/item/storage/belt/medolier/afterattack(obj/target, mob/user , proximity) + if(!(istype(target, /obj/item/reagent_containers/glass/beaker))) + return + if(!proximity) + return + if(!target.reagents) + return + + for(var/obj/item/reagent_containers/syringe/dart/D in contents) + if(round(target.reagents.total_volume, 1) <= 0) + to_chat(user, "You soak as many of the darts as you can with the contents from [target].") + return + if(D.mode == SYRINGE_INJECT) + continue + + D.afterattack(target, user, proximity) + + ..() + /obj/item/storage/belt/holster name = "shoulder holster" desc = "A holster to carry a handgun and ammo. WARNING: Badasses only." @@ -653,9 +743,10 @@ icon_state = "sheath" item_state = "sheath" w_class = WEIGHT_CLASS_BULKY + content_overlays = TRUE + worn_overlays = TRUE var/list/fitting_swords = list(/obj/item/melee/sabre, /obj/item/melee/baton/stunsword) var/starting_sword = /obj/item/melee/sabre - var/sword_overlay /obj/item/storage/belt/sabre/ComponentInitialize() . = ..() @@ -682,27 +773,13 @@ to_chat(user, "[src] is empty.") /obj/item/storage/belt/sabre/update_icon() - icon_state = initial(icon_state) - item_state = initial(item_state) - sword_overlay = null - if(contents.len) - var/obj/item/I = contents[1] - sword_overlay = initial(I.icon_state) - add_overlay("-[sword_overlay]") - item_state += "-[I.icon_state]" - if(loc && isliving(loc)) + . = ..() + if(isliving(loc)) var/mob/living/L = loc L.regenerate_icons() - ..() - -/obj/item/storage/belt/sabre/worn_overlays(isinhands, icon_file) - . = ..() - if(!isinhands) - . += mutable_appearance(icon_file, "-[sword_overlay]") /obj/item/storage/belt/sabre/PopulateContents() new starting_sword(src) - update_icon() /obj/item/storage/belt/sabre/rapier name = "rapier sheath" diff --git a/code/game/objects/items/storage/book.dm b/code/game/objects/items/storage/book.dm index df7b203f91..85a06f0c1e 100644 --- a/code/game/objects/items/storage/book.dm +++ b/code/game/objects/items/storage/book.dm @@ -140,7 +140,7 @@ GLOBAL_LIST_INIT(bibleitemstates, list("bible", "koran", "scrapbook", "bible", else if(iscarbon(M)) var/mob/living/carbon/C = M if(!istype(C.head, /obj/item/clothing/head)) - C.adjustBrainLoss(10, 80) + C.adjustOrganLoss(ORGAN_SLOT_BRAIN, 10, 80) to_chat(C, "You feel dumber.") if(smack) diff --git a/code/game/objects/items/storage/boxes.dm b/code/game/objects/items/storage/boxes.dm index 5a4d85885b..dd6a6b8453 100644 --- a/code/game/objects/items/storage/boxes.dm +++ b/code/game/objects/items/storage/boxes.dm @@ -33,6 +33,7 @@ resistance_flags = FLAMMABLE var/foldable = /obj/item/stack/sheet/cardboard var/illustration = "writing" + rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE //exploits ahoy /obj/item/storage/box/Initialize(mapload) . = ..() @@ -1131,6 +1132,7 @@ name = "Nanotrasen MRE Ration Kit Menu 0" desc = "A package containing food suspended in an outdated bluespace pocket which lasts for centuries. If you're lucky you may even be able to enjoy the meal without getting food poisoning." icon_state = "mre" + illustration = null var/can_expire = TRUE var/spawner_chance = 2 var/expiration_date @@ -1184,7 +1186,7 @@ /obj/item/storage/box/mre/menu3 name = "\improper Nanotrasen MRE Ration Kit Menu 3" - desc = "The holy grail of MREs. This item contains the fabled MRE pizza and a sample of coffee instant type 2. Any NT employee lucky enough to get their hands on one of these is truly blessed." + desc = "The holy grail of MREs. This item contains the fabled MRE pizza, spicy nachos and a sample of coffee instant type 2. Any NT employee lucky enough to get their hands on one of these is truly blessed." icon_state = "menu3" can_expire = FALSE //always fresh, never expired. spawner_chance = 1 @@ -1192,11 +1194,29 @@ /obj/item/storage/box/mre/menu3/PopulateContents() new /obj/item/reagent_containers/food/snacks/pizzaslice/pepperoni(src) new /obj/item/reagent_containers/food/snacks/breadslice/plain(src) - new /obj/item/reagent_containers/food/snacks/cheesewedge(src) + new /obj/item/reagent_containers/food/snacks/cubannachos(src) new /obj/item/reagent_containers/food/snacks/grown/chili(src) new /obj/item/reagent_containers/food/drinks/coffee/type2(src) new /obj/item/tank/internals/emergency_oxygen(src) +/obj/item/storage/box/mre/menu4 + name = "\improper Nanotrasen MRE Ration Kit Menu 4" + +/obj/item/storage/box/mre/menu4/safe + spawner_chance = 0 + desc = "A package containing food suspended in a bluespace pocket capable of lasting till the end of time." + can_expire = FALSE + +/obj/item/storage/box/mre/menu4/PopulateContents() + if(prob(66)) + new /obj/item/reagent_containers/food/snacks/salad/boiledrice(src) + else + new /obj/item/reagent_containers/food/snacks/salad/ricebowl(src) + new /obj/item/reagent_containers/food/snacks/burger/tofu(src) + new /obj/item/reagent_containers/food/snacks/salad/fruit(src) + new /obj/item/reagent_containers/food/snacks/cracker(src) + new /obj/item/tank/internals/emergency_oxygen(src) + //Where do I put this? /obj/item/secbat name = "Secbat box" diff --git a/code/game/objects/items/storage/briefcase.dm b/code/game/objects/items/storage/briefcase.dm index bca13f2a45..ed547bc17d 100644 --- a/code/game/objects/items/storage/briefcase.dm +++ b/code/game/objects/items/storage/briefcase.dm @@ -40,9 +40,18 @@ /obj/item/storage/briefcase/lawyer/family name = "battered briefcase" - desc = "An old briefcase, this one has seen better days in its time. It's clear they don't make them nowadays as good as they used to. Comes with an added belt clip!" + icon_state = "gbriefcase" + lefthand_file = 'icons/mob/inhands/equipment/briefcase_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/briefcase_righthand.dmi' + desc = "An old briefcase with a golden trim. It's clear they don't make them as good as they used to. Comes with an added belt clip!" slot_flags = ITEM_SLOT_BELT +/obj/item/storage/briefcase/lawyer/family/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_w_class = WEIGHT_CLASS_NORMAL + STR.max_combined_w_class = 14 + /obj/item/storage/briefcase/lawyer/family/PopulateContents() new /obj/item/stamp/law(src) new /obj/item/pen/fountain(src) diff --git a/code/game/objects/items/storage/firstaid.dm b/code/game/objects/items/storage/firstaid.dm index e9b074d40c..312ef35430 100644 --- a/code/game/objects/items/storage/firstaid.dm +++ b/code/game/objects/items/storage/firstaid.dm @@ -1,365 +1,391 @@ -/* First aid storage - * Contains: - * First Aid Kits - * Pill Bottles - * Dice Pack (in a pill bottle) - */ - -/* - * First Aid Kits - */ -/obj/item/storage/firstaid - name = "first-aid kit" - desc = "It's an emergency medical kit for those serious boo-boos." - icon_state = "firstaid" - lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' - throw_speed = 3 - throw_range = 7 - var/empty = FALSE - -/obj/item/storage/firstaid/regular - icon_state = "firstaid" - desc = "A first aid kit with the ability to heal common types of injuries." - -/obj/item/storage/firstaid/regular/suicide_act(mob/living/carbon/user) - user.visible_message("[user] begins giving [user.p_them()]self aids with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!") - return BRUTELOSS - -/obj/item/storage/firstaid/regular/PopulateContents() - if(empty) - return - new /obj/item/stack/medical/gauze(src) - new /obj/item/stack/medical/bruise_pack(src) - new /obj/item/stack/medical/bruise_pack(src) - new /obj/item/stack/medical/ointment(src) - new /obj/item/stack/medical/ointment(src) - new /obj/item/reagent_containers/hypospray/medipen(src) - new /obj/item/healthanalyzer(src) - -/obj/item/storage/firstaid/ancient - icon_state = "firstaid" - desc = "A first aid kit with the ability to heal common types of injuries." - -/obj/item/storage/firstaid/ancient/PopulateContents() - if(empty) - return - new /obj/item/stack/medical/gauze(src) - new /obj/item/stack/medical/bruise_pack(src) - new /obj/item/stack/medical/bruise_pack(src) - new /obj/item/stack/medical/bruise_pack(src) - new /obj/item/stack/medical/ointment(src) - new /obj/item/stack/medical/ointment(src) - new /obj/item/stack/medical/ointment(src) - -/obj/item/storage/firstaid/fire - name = "burn treatment kit" - desc = "A specialized medical kit for when the toxins lab -spontaneously- burns down." - icon_state = "ointment" - item_state = "firstaid-ointment" - -/obj/item/storage/firstaid/fire/suicide_act(mob/living/carbon/user) - user.visible_message("[user] begins rubbing \the [src] against [user.p_them()]self! It looks like [user.p_theyre()] trying to start a fire!") - return FIRELOSS - -/obj/item/storage/firstaid/fire/Initialize(mapload) - . = ..() - icon_state = pick("ointment","firefirstaid") - -/obj/item/storage/firstaid/fire/PopulateContents() - if(empty) - return - for(var/i in 1 to 3) - new /obj/item/reagent_containers/pill/patch/silver_sulf(src) - new /obj/item/reagent_containers/pill/oxandrolone(src) - new /obj/item/reagent_containers/pill/oxandrolone(src) - new /obj/item/reagent_containers/hypospray/medipen(src) - new /obj/item/healthanalyzer(src) - -/obj/item/storage/firstaid/toxin - name = "toxin treatment kit" - desc = "Used to treat toxic blood content and radiation poisoning." - icon_state = "antitoxin" - item_state = "firstaid-toxin" - -/obj/item/storage/firstaid/toxin/suicide_act(mob/living/carbon/user) - user.visible_message("[user] begins licking the lead paint off \the [src]! It looks like [user.p_theyre()] trying to commit suicide!") - return TOXLOSS - -/obj/item/storage/firstaid/toxin/Initialize(mapload) - . = ..() - icon_state = pick("antitoxin","antitoxfirstaid","antitoxfirstaid2","antitoxfirstaid3") - -/obj/item/storage/firstaid/toxin/PopulateContents() - if(empty) - return - for(var/i in 1 to 4) - new /obj/item/reagent_containers/syringe/charcoal(src) - for(var/i in 1 to 2) - new /obj/item/storage/pill_bottle/charcoal(src) - new /obj/item/healthanalyzer(src) - -/obj/item/storage/firstaid/radbgone - name = "radiation treatment kit" - desc = "Used to treat minor toxic blood content and major radiation poisoning." - icon_state = "antitoxin" - item_state = "firstaid-toxin" - -/obj/item/storage/firstaid/radbgone/suicide_act(mob/living/carbon/user) - user.visible_message("[user] begins licking the lead paint off \the [src]! It looks like [user.p_theyre()] trying to commit suicide!") - return TOXLOSS - -/obj/item/storage/firstaid/radbgone/PopulateContents() - if(empty) - return - if(prob(50)) - new /obj/item/reagent_containers/pill/mutarad(src) - if(prob(80)) - new /obj/item/reagent_containers/pill/antirad_plus(src) - new /obj/item/reagent_containers/syringe/charcoal(src) - new /obj/item/storage/pill_bottle/charcoal(src) - new /obj/item/reagent_containers/pill/mutadone(src) - new /obj/item/reagent_containers/pill/antirad(src) - new /obj/item/reagent_containers/food/drinks/bottle/vodka(src) - new /obj/item/healthanalyzer(src) - - -/obj/item/storage/firstaid/o2 - name = "oxygen deprivation treatment kit" - desc = "A box full of oxygen goodies." - icon_state = "o2" - item_state = "firstaid-o2" - -/obj/item/storage/firstaid/o2/suicide_act(mob/living/carbon/user) - user.visible_message("[user] begins hitting [user.p_their()] neck with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!") - return OXYLOSS - -/obj/item/storage/firstaid/o2/PopulateContents() - if(empty) - return - for(var/i in 1 to 4) - new /obj/item/reagent_containers/pill/salbutamol(src) - new /obj/item/reagent_containers/hypospray/medipen(src) - new /obj/item/reagent_containers/hypospray/medipen(src) - new /obj/item/healthanalyzer(src) - -/obj/item/storage/firstaid/brute - name = "brute trauma treatment kit" - desc = "A first aid kit for when you get toolboxed." - icon_state = "brute" - item_state = "firstaid-brute" - -/obj/item/storage/firstaid/brute/suicide_act(mob/living/carbon/user) - user.visible_message("[user] begins beating [user.p_them()]self over the head with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!") - return BRUTELOSS - -/obj/item/storage/firstaid/brute/PopulateContents() - if(empty) - return - for(var/i in 1 to 4) - new /obj/item/reagent_containers/pill/patch/styptic(src) - new /obj/item/stack/medical/gauze(src) - new /obj/item/stack/medical/gauze(src) - new /obj/item/healthanalyzer(src) - -/obj/item/storage/firstaid/tactical - name = "combat medical kit" - desc = "I hope you've got insurance." - icon_state = "bezerk" - -/obj/item/storage/firstaid/tactical/ComponentInitialize() - . = ..() - GET_COMPONENT(STR, /datum/component/storage) - STR.max_w_class = WEIGHT_CLASS_NORMAL - -/obj/item/storage/firstaid/tactical/PopulateContents() - if(empty) - return - new /obj/item/stack/medical/gauze(src) - new /obj/item/defibrillator/compact/combat/loaded(src) - new /obj/item/reagent_containers/hypospray/combat(src) - new /obj/item/reagent_containers/pill/patch/styptic(src) - new /obj/item/reagent_containers/pill/patch/silver_sulf(src) - new /obj/item/reagent_containers/syringe/lethal/choral(src) - new /obj/item/clothing/glasses/hud/health/night(src) - -/* - * Pill Bottles - */ - -/obj/item/storage/pill_bottle - name = "pill bottle" - desc = "It's an airtight container for storing medication." - icon_state = "pill_canister" - icon = 'icons/obj/chemical.dmi' - item_state = "contsolid" - lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' - w_class = WEIGHT_CLASS_SMALL - -/obj/item/storage/pill_bottle/ComponentInitialize() - . = ..() - GET_COMPONENT(STR, /datum/component/storage) - STR.allow_quick_gather = TRUE - STR.click_gather = TRUE - STR.can_hold = typecacheof(list(/obj/item/reagent_containers/pill, /obj/item/dice)) - -/obj/item/storage/pill_bottle/suicide_act(mob/user) - user.visible_message("[user] is trying to get the cap off [src]! It looks like [user.p_theyre()] trying to commit suicide!") - return (TOXLOSS) - -/obj/item/storage/pill_bottle/charcoal - name = "bottle of charcoal pills" - desc = "Contains pills used to counter toxins." - -/obj/item/storage/pill_bottle/charcoal/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/reagent_containers/pill/charcoal(src) - -/obj/item/storage/pill_bottle/antirad - name = "bottle of charcoal pills" - desc = "Contains pills used to counter radiation poisoning." - -/obj/item/storage/pill_bottle/anitrad/PopulateContents() - for(var/i in 1 to 5) - new /obj/item/reagent_containers/pill/antirad(src) - -/obj/item/storage/pill_bottle/epinephrine - name = "bottle of epinephrine pills" - desc = "Contains pills used to stabilize patients." - -/obj/item/storage/pill_bottle/epinephrine/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/reagent_containers/pill/epinephrine(src) - -/obj/item/storage/pill_bottle/mutadone - name = "bottle of mutadone pills" - desc = "Contains pills used to treat genetic abnormalities." - -/obj/item/storage/pill_bottle/mutadone/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/reagent_containers/pill/mutadone(src) - -/obj/item/storage/pill_bottle/mannitol - name = "bottle of mannitol pills" - desc = "Contains pills used to treat brain damage." - -/obj/item/storage/pill_bottle/mannitol/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/reagent_containers/pill/mannitol(src) - -/obj/item/storage/pill_bottle/stimulant - name = "bottle of stimulant pills" - desc = "Guaranteed to give you that extra burst of energy during a long shift!" - -/obj/item/storage/pill_bottle/stimulant/PopulateContents() - for(var/i in 1 to 5) - new /obj/item/reagent_containers/pill/stimulant(src) - -/obj/item/storage/pill_bottle/mining - name = "bottle of patches" - desc = "Contains patches used to treat brute and burn damage." - -/obj/item/storage/pill_bottle/mining/PopulateContents() - new /obj/item/reagent_containers/pill/patch/silver_sulf(src) - for(var/i in 1 to 3) - new /obj/item/reagent_containers/pill/patch/styptic(src) - -/obj/item/storage/pill_bottle/zoom - name = "suspicious pill bottle" - desc = "The label is pretty old and almost unreadable, you recognize some chemical compounds." - -/obj/item/storage/pill_bottle/zoom/PopulateContents() - for(var/i in 1 to 5) - new /obj/item/reagent_containers/pill/zoom(src) - -/obj/item/storage/pill_bottle/happy - name = "suspicious pill bottle" - desc = "There is a smiley on the top." - -/obj/item/storage/pill_bottle/happy/PopulateContents() - for(var/i in 1 to 5) - new /obj/item/reagent_containers/pill/happy(src) - -/obj/item/storage/pill_bottle/lsd - name = "suspicious pill bottle" - desc = "There is a badly drawn thing with the shape of a mushroom." - -/obj/item/storage/pill_bottle/lsd/PopulateContents() - for(var/i in 1 to 5) - new /obj/item/reagent_containers/pill/lsd(src) - -/obj/item/storage/pill_bottle/aranesp - name = "suspicious pill bottle" - desc = "The label says 'gotta go fast'." - -/obj/item/storage/pill_bottle/aranesp/PopulateContents() - for(var/i in 1 to 5) - new /obj/item/reagent_containers/pill/aranesp(src) - -/obj/item/storage/pill_bottle/antirad_plus - name = "anti radiation deluxe pill bottle" - desc = "The label says 'Med-Co branded pills'." - -/obj/item/storage/pill_bottle/antirad_plus/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/reagent_containers/pill/antirad_plus(src) - -/obj/item/storage/pill_bottle/mutarad - name = "radiation treatment deluxe pill bottle" - desc = "The label says 'Med-Co branded pills' and below that 'Contains Mutadone in each pill!`." - -/obj/item/storage/pill_bottle/mutarad/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/reagent_containers/pill/mutarad(src) - -/obj/item/storage/pill_bottle/penis_enlargement - name = "penis enlargement pills" - desc = "You want penis enlargement pills?" - -/obj/item/storage/pill_bottle/penis_enlargement/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/reagent_containers/pill/penis_enlargement(src) - -///////////// -//Organ Box// -///////////// - -/obj/item/storage/belt/organbox - name = "Organ Storge" - desc = "A compact box that helps hold massive amounts of implants, organs, and some tools. Has a belt clip for easy carrying" - w_class = WEIGHT_CLASS_BULKY - icon = 'icons/obj/mysterybox.dmi' - icon_state = "organbox_open" - lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' - throw_speed = 1 - throw_range = 1 - -/obj/item/storage/belt/organbox/ComponentInitialize() - . = ..() - GET_COMPONENT(STR, /datum/component/storage) - STR.max_items = 16 - STR.max_w_class = WEIGHT_CLASS_BULKY - STR.max_combined_w_class = 20 - STR.can_hold = typecacheof(list( - /obj/item/storage/pill_bottle, - /obj/item/reagent_containers/hypospray, - /obj/item/healthanalyzer, - /obj/item/reagent_containers/syringe, - /obj/item/clothing/glasses/hud/health, - /obj/item/hemostat, - /obj/item/scalpel, - /obj/item/retractor, - /obj/item/cautery, - /obj/item/surgical_drapes, - /obj/item/autosurgeon, - /obj/item/organ, - /obj/item/implant, - /obj/item/implantpad, - /obj/item/implantcase, - /obj/item/implanter, - /obj/item/circuitboard/computer/operating, - /obj/item/stack/sheet/mineral/silver, - /obj/item/organ_storage - )) + +/* First aid storage + * Contains: + * First Aid Kits + * Pill Bottles + * Dice Pack (in a pill bottle) + */ + +/* + * First Aid Kits + */ +/obj/item/storage/firstaid + name = "first-aid kit" + desc = "It's an emergency medical kit for those serious boo-boos." + icon_state = "firstaid" + lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' + throw_speed = 3 + throw_range = 7 + var/empty = FALSE + +/obj/item/storage/firstaid/regular + icon_state = "firstaid" + desc = "A first aid kit with the ability to heal common types of injuries." + +/obj/item/storage/firstaid/regular/suicide_act(mob/living/carbon/user) + user.visible_message("[user] begins giving [user.p_them()]self aids with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!") + return BRUTELOSS + +/obj/item/storage/firstaid/regular/PopulateContents() + if(empty) + return + new /obj/item/stack/medical/gauze(src) + new /obj/item/stack/medical/bruise_pack(src) + new /obj/item/stack/medical/bruise_pack(src) + new /obj/item/stack/medical/ointment(src) + new /obj/item/stack/medical/ointment(src) + new /obj/item/reagent_containers/hypospray/medipen(src) + new /obj/item/healthanalyzer(src) + +/obj/item/storage/firstaid/ancient + icon_state = "firstaid" + desc = "A first aid kit with the ability to heal common types of injuries." + +/obj/item/storage/firstaid/ancient/PopulateContents() + if(empty) + return + new /obj/item/stack/medical/gauze(src) + new /obj/item/stack/medical/bruise_pack(src) + new /obj/item/stack/medical/bruise_pack(src) + new /obj/item/stack/medical/bruise_pack(src) + new /obj/item/stack/medical/ointment(src) + new /obj/item/stack/medical/ointment(src) + new /obj/item/stack/medical/ointment(src) + +/obj/item/storage/firstaid/fire + name = "burn treatment kit" + desc = "A specialized medical kit for when the toxins lab -spontaneously- burns down." + icon_state = "ointment" + item_state = "firstaid-ointment" + +/obj/item/storage/firstaid/fire/suicide_act(mob/living/carbon/user) + user.visible_message("[user] begins rubbing \the [src] against [user.p_them()]self! It looks like [user.p_theyre()] trying to start a fire!") + return FIRELOSS + +/obj/item/storage/firstaid/fire/Initialize(mapload) + . = ..() + icon_state = pick("ointment","firefirstaid") + +/obj/item/storage/firstaid/fire/PopulateContents() + if(empty) + return + for(var/i in 1 to 3) + new /obj/item/reagent_containers/pill/patch/silver_sulf(src) + new /obj/item/reagent_containers/pill/oxandrolone(src) + new /obj/item/reagent_containers/pill/oxandrolone(src) + new /obj/item/reagent_containers/hypospray/medipen(src) + new /obj/item/healthanalyzer(src) + +/obj/item/storage/firstaid/toxin + name = "toxin treatment kit" + desc = "Used to treat toxic blood content and radiation poisoning." + icon_state = "antitoxin" + item_state = "firstaid-toxin" + +/obj/item/storage/firstaid/toxin/suicide_act(mob/living/carbon/user) + user.visible_message("[user] begins licking the lead paint off \the [src]! It looks like [user.p_theyre()] trying to commit suicide!") + return TOXLOSS + +/obj/item/storage/firstaid/toxin/Initialize(mapload) + . = ..() + icon_state = pick("antitoxin","antitoxfirstaid","antitoxfirstaid2","antitoxfirstaid3") + +/obj/item/storage/firstaid/toxin/PopulateContents() + if(empty) + return + for(var/i in 1 to 4) + new /obj/item/reagent_containers/syringe/charcoal(src) + for(var/i in 1 to 2) + new /obj/item/storage/pill_bottle/charcoal(src) + new /obj/item/healthanalyzer(src) + +/obj/item/storage/firstaid/radbgone + name = "radiation treatment kit" + desc = "Used to treat minor toxic blood content and major radiation poisoning." + icon_state = "antitoxin" + item_state = "firstaid-toxin" + +/obj/item/storage/firstaid/radbgone/suicide_act(mob/living/carbon/user) + user.visible_message("[user] begins licking the lead paint off \the [src]! It looks like [user.p_theyre()] trying to commit suicide!") + return TOXLOSS + +/obj/item/storage/firstaid/radbgone/PopulateContents() + if(empty) + return + if(prob(50)) + new /obj/item/reagent_containers/pill/mutarad(src) + if(prob(80)) + new /obj/item/reagent_containers/pill/antirad_plus(src) + new /obj/item/reagent_containers/syringe/charcoal(src) + new /obj/item/storage/pill_bottle/charcoal(src) + new /obj/item/reagent_containers/pill/mutadone(src) + new /obj/item/reagent_containers/pill/antirad(src) + new /obj/item/reagent_containers/food/drinks/bottle/vodka(src) + new /obj/item/healthanalyzer(src) + + +/obj/item/storage/firstaid/o2 + name = "oxygen deprivation treatment kit" + desc = "A box full of oxygen goodies." + icon_state = "o2" + item_state = "firstaid-o2" + +/obj/item/storage/firstaid/o2/suicide_act(mob/living/carbon/user) + user.visible_message("[user] begins hitting [user.p_their()] neck with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!") + return OXYLOSS + +/obj/item/storage/firstaid/o2/PopulateContents() + if(empty) + return + for(var/i in 1 to 4) + new /obj/item/reagent_containers/pill/salbutamol(src) + new /obj/item/reagent_containers/hypospray/medipen(src) + new /obj/item/reagent_containers/hypospray/medipen(src) + new /obj/item/healthanalyzer(src) + +/obj/item/storage/firstaid/brute + name = "brute trauma treatment kit" + desc = "A first aid kit for when you get toolboxed." + icon_state = "brute" + item_state = "firstaid-brute" + +/obj/item/storage/firstaid/brute/suicide_act(mob/living/carbon/user) + user.visible_message("[user] begins beating [user.p_them()]self over the head with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!") + return BRUTELOSS + +/obj/item/storage/firstaid/brute/PopulateContents() + if(empty) + return + for(var/i in 1 to 4) + new /obj/item/reagent_containers/pill/patch/styptic(src) + new /obj/item/stack/medical/gauze(src) + new /obj/item/stack/medical/gauze(src) + new /obj/item/healthanalyzer(src) + +/obj/item/storage/firstaid/tactical + name = "combat medical kit" + desc = "I hope you've got insurance." + icon_state = "bezerk" + +/obj/item/storage/firstaid/tactical/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_w_class = WEIGHT_CLASS_NORMAL + +/obj/item/storage/firstaid/tactical/PopulateContents() + if(empty) + return + new /obj/item/stack/medical/gauze(src) + new /obj/item/defibrillator/compact/combat/loaded(src) + new /obj/item/reagent_containers/hypospray/combat(src) + new /obj/item/reagent_containers/pill/patch/styptic(src) + new /obj/item/reagent_containers/pill/patch/silver_sulf(src) + new /obj/item/reagent_containers/syringe/lethal/choral(src) + new /obj/item/clothing/glasses/hud/health/night(src) + +/* + * Pill Bottles + */ + +/obj/item/storage/pill_bottle + name = "pill bottle" + desc = "It's an airtight container for storing medication." + icon_state = "pill_canister" + icon = 'icons/obj/chemical.dmi' + item_state = "contsolid" + lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' + w_class = WEIGHT_CLASS_SMALL + +/obj/item/storage/pill_bottle/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.allow_quick_gather = TRUE + STR.click_gather = TRUE + STR.can_hold = typecacheof(list(/obj/item/reagent_containers/pill, /obj/item/dice)) + +/obj/item/storage/pill_bottle/suicide_act(mob/user) + user.visible_message("[user] is trying to get the cap off [src]! It looks like [user.p_theyre()] trying to commit suicide!") + return (TOXLOSS) + +/obj/item/storage/pill_bottle/charcoal + name = "bottle of charcoal pills" + desc = "Contains pills used to counter toxins." + +/obj/item/storage/pill_bottle/charcoal/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/reagent_containers/pill/charcoal(src) + +/obj/item/storage/pill_bottle/antirad + name = "bottle of charcoal pills" + desc = "Contains pills used to counter radiation poisoning." + +/obj/item/storage/pill_bottle/anitrad/PopulateContents() + for(var/i in 1 to 5) + new /obj/item/reagent_containers/pill/antirad(src) + +/obj/item/storage/pill_bottle/epinephrine + name = "bottle of epinephrine pills" + desc = "Contains pills used to stabilize patients." + +/obj/item/storage/pill_bottle/epinephrine/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/reagent_containers/pill/epinephrine(src) + +/obj/item/storage/pill_bottle/mutadone + name = "bottle of mutadone pills" + desc = "Contains pills used to treat genetic abnormalities." + +/obj/item/storage/pill_bottle/mutadone/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/reagent_containers/pill/mutadone(src) + +/obj/item/storage/pill_bottle/mannitol + name = "bottle of mannitol pills" + desc = "Contains pills used to treat brain damage." + +/obj/item/storage/pill_bottle/mannitol/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/reagent_containers/pill/mannitol(src) + +/obj/item/storage/pill_bottle/stimulant + name = "bottle of stimulant pills" + desc = "Guaranteed to give you that extra burst of energy during a long shift!" + +/obj/item/storage/pill_bottle/stimulant/PopulateContents() + for(var/i in 1 to 5) + new /obj/item/reagent_containers/pill/stimulant(src) + +/obj/item/storage/pill_bottle/mining + name = "bottle of patches" + desc = "Contains patches used to treat brute and burn damage." + +/obj/item/storage/pill_bottle/mining/PopulateContents() + new /obj/item/reagent_containers/pill/patch/silver_sulf(src) + for(var/i in 1 to 3) + new /obj/item/reagent_containers/pill/patch/styptic(src) + +/obj/item/storage/pill_bottle/zoom + name = "suspicious pill bottle" + desc = "The label is pretty old and almost unreadable, you recognize some chemical compounds." + +/obj/item/storage/pill_bottle/zoom/PopulateContents() + for(var/i in 1 to 5) + new /obj/item/reagent_containers/pill/zoom(src) + +/obj/item/storage/pill_bottle/happy + name = "suspicious pill bottle" + desc = "There is a smiley on the top." + +/obj/item/storage/pill_bottle/happy/PopulateContents() + for(var/i in 1 to 5) + new /obj/item/reagent_containers/pill/happy(src) + +/obj/item/storage/pill_bottle/lsd + name = "suspicious pill bottle" + desc = "There is a badly drawn thing with the shape of a mushroom." + +/obj/item/storage/pill_bottle/lsd/PopulateContents() + for(var/i in 1 to 5) + new /obj/item/reagent_containers/pill/lsd(src) + +/obj/item/storage/pill_bottle/aranesp + name = "suspicious pill bottle" + desc = "The label says 'gotta go fast'." + +/obj/item/storage/pill_bottle/aranesp/PopulateContents() + for(var/i in 1 to 5) + new /obj/item/reagent_containers/pill/aranesp(src) + +/obj/item/storage/pill_bottle/psicodine + name = "bottle of psicodine pills" + desc = "Contains pills used to treat mental distress and traumas." + +/obj/item/storage/pill_bottle/psicodine/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/reagent_containers/pill/psicodine(src) + +/obj/item/storage/pill_bottle/happiness + name = "happiness pill bottle" + desc = "The label is long gone, in its place an 'H' written with a marker." + +/obj/item/storage/pill_bottle/happiness/PopulateContents() + for(var/i in 1 to 5) + new /obj/item/reagent_containers/pill/happiness(src) + +/obj/item/storage/pill_bottle/antirad_plus + name = "anti radiation deluxe pill bottle" + desc = "The label says 'Med-Co branded pills'." + +/obj/item/storage/pill_bottle/antirad_plus/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/reagent_containers/pill/antirad_plus(src) + +/obj/item/storage/pill_bottle/mutarad + name = "radiation treatment deluxe pill bottle" + desc = "The label says 'Med-Co branded pills' and below that 'Contains Mutadone in each pill!`." + +/obj/item/storage/pill_bottle/mutarad/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/reagent_containers/pill/mutarad(src) + +/obj/item/storage/pill_bottle/penis_enlargement + name = "penis enlargement pills" + desc = "You want penis enlargement pills?" + +/obj/item/storage/pill_bottle/penis_enlargement/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/reagent_containers/pill/penis_enlargement(src) + +/obj/item/storage/pill_bottle/breast_enlargement + name = "breast enlargement pills" + desc = "Made by Fermichem - They have a woman with breasts larger than she is on them. The warming states not to take more than 10u at a time." + +/obj/item/storage/pill_bottle/breast_enlargement/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/reagent_containers/pill/breast_enlargement(src) + +///////////// +//Organ Box// +///////////// + +/obj/item/storage/belt/organbox + name = "Organ Storge" + desc = "A compact box that helps hold massive amounts of implants, organs, and some tools. Has a belt clip for easy carrying" + w_class = WEIGHT_CLASS_BULKY + icon = 'icons/obj/mysterybox.dmi' + icon_state = "organbox_open" + lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' + throw_speed = 1 + throw_range = 1 + +/obj/item/storage/belt/organbox/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_items = 16 + STR.max_w_class = WEIGHT_CLASS_BULKY + STR.max_combined_w_class = 20 + STR.can_hold = typecacheof(list( + /obj/item/storage/pill_bottle, + /obj/item/reagent_containers/hypospray, + /obj/item/healthanalyzer, + /obj/item/reagent_containers/syringe, + /obj/item/clothing/glasses/hud/health, + /obj/item/hemostat, + /obj/item/scalpel, + /obj/item/retractor, + /obj/item/cautery, + /obj/item/surgical_drapes, + /obj/item/autosurgeon, + /obj/item/organ, + /obj/item/implant, + /obj/item/implantpad, + /obj/item/implantcase, + /obj/item/implanter, + /obj/item/circuitboard/computer/operating, + /obj/item/stack/sheet/mineral/silver, + /obj/item/organ_storage + )) + diff --git a/code/game/objects/items/storage/lockbox.dm b/code/game/objects/items/storage/lockbox.dm index 4924051855..eeebc6f4c5 100644 --- a/code/game/objects/items/storage/lockbox.dm +++ b/code/game/objects/items/storage/lockbox.dm @@ -48,14 +48,16 @@ to_chat(user, "It's locked!") /obj/item/storage/lockbox/emag_act(mob/user) - if(!broken) - broken = TRUE - SEND_SIGNAL(src, COMSIG_TRY_STORAGE_SET_LOCKSTATE, FALSE) - desc += "It appears to be broken." - icon_state = src.icon_broken - if(user) - visible_message("\The [src] has been broken by [user] with an electromagnetic card!") - return + . = ..() + if(broken) + return + broken = TRUE + SEND_SIGNAL(src, COMSIG_TRY_STORAGE_SET_LOCKSTATE, FALSE) + desc += "It appears to be broken." + icon_state = src.icon_broken + if(user) + visible_message("\The [src] has been broken by [user] with an electromagnetic card!") + return TRUE /obj/item/storage/lockbox/Entered() . = ..() diff --git a/code/game/objects/items/storage/toolbox.dm b/code/game/objects/items/storage/toolbox.dm index 5b99bb85bf..d18212be42 100644 --- a/code/game/objects/items/storage/toolbox.dm +++ b/code/game/objects/items/storage/toolbox.dm @@ -19,6 +19,7 @@ GLOBAL_LIST_EMPTY(rubber_toolbox_icons) var/latches = "single_latch" var/has_latches = TRUE var/can_rubberify = TRUE + rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE //very protecc too /obj/item/storage/toolbox/Initialize(mapload) . = ..() diff --git a/code/game/objects/items/storage/uplink_kits.dm b/code/game/objects/items/storage/uplink_kits.dm index a6a3cea373..cf5d685b4a 100644 --- a/code/game/objects/items/storage/uplink_kits.dm +++ b/code/game/objects/items/storage/uplink_kits.dm @@ -1,7 +1,7 @@ /obj/item/storage/box/syndicate /obj/item/storage/box/syndicate/PopulateContents() - switch (pickweight(list("bloodyspai" = 3, "stealth" = 2, "bond" = 2, "screwed" = 2, "sabotage" = 3, "guns" = 2, "murder" = 2, "implant" = 1, "hacker" = 3, "darklord" = 1, "sniper" = 1, "metaops" = 1, "ninja" = 1))) + switch (pickweight(list("bloodyspai" = 3, "stealth" = 2, "bond" = 2, "screwed" = 2, "sabotage" = 3, "guns" = 2, "murder" = 2, "baseball" = 1, "implant" = 1, "hacker" = 3, "darklord" = 1, "sniper" = 1, "metaops" = 1, "ninja" = 1))) if("bloodyspai") // 30 tc now this is more right new /obj/item/clothing/under/chameleon(src) // 2 tc since it's not the full set new /obj/item/clothing/mask/chameleon(src) // Goes with above @@ -52,7 +52,7 @@ new /obj/item/clothing/under/suit_jacket/really_black(src) new /obj/item/screwdriver/power(src) //2 tc item - if("murder") // 35 tc now + if("murder") // 35 tc new /obj/item/melee/transforming/energy/sword/saber(src) new /obj/item/clothing/glasses/thermal/syndi(src) new /obj/item/card/emag(src) @@ -62,6 +62,17 @@ new /obj/item/clothing/glasses/phantomthief/syndicate(src) new /obj/item/reagent_containers/syringe/stimulants(src) + if("baseball") // 42~ tc + new /obj/item/melee/baseball_bat/ablative/syndi(src) //Lets say 12 tc, lesser sleeping carp + new /obj/item/clothing/glasses/sunglasses/garb(src) //Lets say 2 tc + new /obj/item/card/emag(src) //6 tc + new /obj/item/clothing/shoes/sneakers/noslip(src) //2tc + new /obj/item/encryptionkey/syndicate(src) //1tc + new /obj/item/autosurgeon/anti_drop(src) //Lets just say 7~ + new /obj/item/clothing/under/syndicate/baseball(src) //3tc + new /obj/item/clothing/head/soft/baseball(src) //Lets say 4 tc + new /obj/item/reagent_containers/hypospray/medipen/stimulants/baseball(src) //lets say 5tc + if("implant") // 67+ tc holy shit what the fuck this is a lottery disguised as fun boxes isn't it? new /obj/item/implanter/freedom(src) new /obj/item/implanter/uplink/precharged(src) @@ -132,7 +143,7 @@ new /obj/item/card/emag(src) // 6 tc if("ninja") // 40~ tc worth - new /obj/item/katana(src) // Unique , basicly a better esword. 10 tc? + new /obj/item/katana(src) // Unique , basicly a better esword. 10 tc? new /obj/item/implanter/adrenalin(src) // 8 tc new /obj/item/throwing_star(src) // ~5 tc for all 6 new /obj/item/throwing_star(src) @@ -294,6 +305,7 @@ new /obj/item/radio/headset/chameleon(src) new /obj/item/stamp/chameleon(src) new /obj/item/pda/chameleon(src) + new /obj/item/clothing/neck/cloak/chameleon(src) //5*(2*4) = 5*8 = 45, 45 damage if you hit one person with all 5 stars. //Not counting the damage it will do while embedded (2*4 = 8, at 15% chance) diff --git a/code/game/objects/items/storage/wallets.dm b/code/game/objects/items/storage/wallets.dm index c263c2669d..cb5790e45f 100644 --- a/code/game/objects/items/storage/wallets.dm +++ b/code/game/objects/items/storage/wallets.dm @@ -36,7 +36,8 @@ /obj/item/reagent_containers/syringe, /obj/item/screwdriver, /obj/item/valentine, - /obj/item/stamp)) + /obj/item/stamp, + /obj/item/key)) /obj/item/storage/wallet/Exited(atom/movable/AM) . = ..() @@ -60,7 +61,7 @@ /obj/item/storage/wallet/update_icon() var/new_state = "wallet" if(front_id) - new_state = "wallet_[front_id.icon_state]" + new_state = "wallet_id" if(new_state != icon_state) //avoid so many icon state changes. icon_state = new_state diff --git a/code/game/objects/items/tanks/tanks.dm b/code/game/objects/items/tanks/tanks.dm index 1245b7de94..d409e40575 100644 --- a/code/game/objects/items/tanks/tanks.dm +++ b/code/game/objects/items/tanks/tanks.dm @@ -23,7 +23,7 @@ toggle_internals(user) /obj/item/tank/proc/toggle_internals(mob/user) - var/mob/living/carbon/human/H = user + var/mob/living/carbon/H = user if(!istype(H)) return @@ -33,13 +33,19 @@ H.update_internals_hud_icon(0) else if(!H.getorganslot(ORGAN_SLOT_BREATHING_TUBE)) - if(!H.wear_mask) - to_chat(H, "You need a mask!") - return - if(H.wear_mask.mask_adjusted) - H.wear_mask.adjustmask(H) - if(!(H.wear_mask.clothing_flags & MASKINTERNALS)) - to_chat(H, "[H.wear_mask] can't use [src]!") + var/obj/item/clothing/check + var/internals = FALSE + + for(check in GET_INTERNAL_SLOTS(H)) + if(istype(check, /obj/item/clothing/mask)) + var/obj/item/clothing/mask/M = check + if(M.mask_adjusted) + M.adjustmask(H) + if(CHECK_BITFIELD(check.clothing_flags, ALLOWINTERNALS)) + internals = TRUE + + if(!internals) + to_chat(H, "You are not wearing an internals mask!") return if(H.internal) diff --git a/code/game/objects/items/teleportation.dm b/code/game/objects/items/teleportation.dm index 1ccc88d892..e16b0dd690 100644 --- a/code/game/objects/items/teleportation.dm +++ b/code/game/objects/items/teleportation.dm @@ -75,15 +75,14 @@ temp += "Implant Signals:
" for (var/obj/item/implant/tracking/W in GLOB.tracked_implants) - if (!W.imp_in || !isliving(W.loc)) + if (!isliving(W.imp_in)) continue - else - var/mob/living/M = W.loc - if (M.stat == DEAD) - if (M.timeofdeath + 6000 < world.time) - continue + var/mob/living/M = W.imp_in + if (M.stat == DEAD) + if (M.timeofdeath + 6000 < world.time) + continue - var/turf/tr = get_turf(W) + var/turf/tr = get_turf(M) if (tr.z == sr.z && tr) var/direct = max(abs(tr.x - sr.x), abs(tr.y - sr.y)) if (direct < 20) @@ -188,8 +187,13 @@ user.show_message("\The [src] is recharging!") return var/atom/T = L[t1] + var/implantcheckmate = FALSE + if(isliving(T)) + var/mob/living/M = T + if(!locate(/obj/item/implant/tracking) in M.implants) //The user was too slow and let the target mob's tracking implant expire or get removed. + implantcheckmate = TRUE var/area/A = get_area(T) - if(A.noteleport) + if(A.noteleport || implantcheckmate) to_chat(user, "\The [src] is malfunctioning.") return current_location = get_turf(user) //Recheck. diff --git a/code/game/objects/items/theft_tools.dm b/code/game/objects/items/theft_tools.dm index 0c74f610df..b99be7e988 100644 --- a/code/game/objects/items/theft_tools.dm +++ b/code/game/objects/items/theft_tools.dm @@ -232,7 +232,7 @@ . = ..() if(!sliver) return - if(ismovableatom(O) && O != sliver) + if(proximity && ismovableatom(O) && O != sliver) Consume(O, user) /obj/item/hemostat/supermatter/throw_impact(atom/hit_atom) // no instakill supermatter javelins diff --git a/code/game/objects/items/tools/crowbar.dm b/code/game/objects/items/tools/crowbar.dm index 97375221d4..f891a48df6 100644 --- a/code/game/objects/items/tools/crowbar.dm +++ b/code/game/objects/items/tools/crowbar.dm @@ -31,7 +31,7 @@ name = "brass crowbar" desc = "A brass crowbar. It feels faintly warm to the touch." resistance_flags = FIRE_PROOF | ACID_PROOF - icon_state = "crowbar_brass" + icon_state = "crowbar_clock" toolspeed = 0.5 /obj/item/crowbar/bronze @@ -90,4 +90,12 @@ var/obj/item/wirecutters/power/cutjaws = new /obj/item/wirecutters/power(drop_location()) to_chat(user, "You attach the cutting jaws to [src].") qdel(src) - user.put_in_active_hand(cutjaws) \ No newline at end of file + user.put_in_active_hand(cutjaws) + +/obj/item/crowbar/advanced + name = "advanced crowbar" + desc = "A scientist's almost successful reproduction of an abductor's crowbar, it uses the same technology combined with a handle that can't quite hold it." + icon = 'icons/obj/advancedtools.dmi' + usesound = 'sound/weapons/sonic_jackhammer.ogg' + icon_state = "crowbar" + toolspeed = 0.2 \ No newline at end of file diff --git a/code/game/objects/items/tools/screwdriver.dm b/code/game/objects/items/tools/screwdriver.dm index e5808de088..6cbede78a8 100644 --- a/code/game/objects/items/tools/screwdriver.dm +++ b/code/game/objects/items/tools/screwdriver.dm @@ -81,7 +81,7 @@ name = "brass screwdriver" desc = "A screwdriver made of brass. The handle feels freezing cold." resistance_flags = FIRE_PROOF | ACID_PROOF - icon_state = "screwdriver_brass" + icon_state = "screwdriver_clock" item_state = "screwdriver_brass" toolspeed = 0.5 random_color = FALSE @@ -141,4 +141,14 @@ name = "powered screwdriver" desc = "An electrical screwdriver, designed to be both precise and quick." usesound = 'sound/items/drill_use.ogg' - toolspeed = 0.5 \ No newline at end of file + toolspeed = 0.5 + +/obj/item/screwdriver/advanced + name = "advanced screwdriver" + desc = "A classy silver screwdriver with an alien alloy tip, it works almost as well as the real thing." + icon = 'icons/obj/advancedtools.dmi' + icon_state = "screwdriver_a" + item_state = "screwdriver_nuke" + usesound = 'sound/items/pshoom.ogg' + toolspeed = 0.2 + random_color = FALSE \ No newline at end of file diff --git a/code/game/objects/items/tools/weldingtool.dm b/code/game/objects/items/tools/weldingtool.dm index 718035a9a5..fb38e4335e 100644 --- a/code/game/objects/items/tools/weldingtool.dm +++ b/code/game/objects/items/tools/weldingtool.dm @@ -360,7 +360,7 @@ name = "brass welding tool" desc = "A brass welder that seems to constantly refuel itself. It is faintly warm to the touch." resistance_flags = FIRE_PROOF | ACID_PROOF - icon_state = "brasswelder" + icon_state = "clockwelder" item_state = "brasswelder" /obj/item/weldingtool/bronze @@ -377,4 +377,18 @@ nextrefueltick = world.time + 10 reagents.add_reagent("welding_fuel", 1) +/obj/item/weldingtool/advanced + name = "advanced welding tool" + desc = "A modern welding tool combined with an alien welding tool, it never runs out of fuel and works almost as fast." + icon = 'icons/obj/advancedtools.dmi' + icon_state = "welder" + toolspeed = 0.2 + light_intensity = 0 + change_icons = 0 + +/obj/item/weldingtool/advanced/process() + if(get_fuel() <= max_fuel) + reagents.add_reagent("welding_fuel", 1) + ..() + #undef WELDER_FUEL_BURN_INTERVAL diff --git a/code/game/objects/items/tools/wirecutters.dm b/code/game/objects/items/tools/wirecutters.dm index 1a35196bd8..e40ae8bdc1 100644 --- a/code/game/objects/items/tools/wirecutters.dm +++ b/code/game/objects/items/tools/wirecutters.dm @@ -63,9 +63,9 @@ /obj/item/wirecutters/brass name = "brass wirecutters" - desc = "A pair of wirecutters made of brass. The handle feels freezing cold to the touch." + desc = "A pair of eloquent wirecutters made of brass. The handle feels freezing cold to the touch." resistance_flags = FIRE_PROOF | ACID_PROOF - icon_state = "cutters_brass" + icon_state = "cutters_clock" random_color = FALSE toolspeed = 0.5 @@ -82,7 +82,6 @@ icon = 'icons/obj/abductor.dmi' icon_state = "cutters" toolspeed = 0.1 - random_color = FALSE /obj/item/wirecutters/cyborg @@ -126,3 +125,11 @@ return else ..() + +/obj/item/wirecutters/advanced + name = "advanced wirecutters" + desc = "A set of reproduction alien wirecutters, they have a silver handle with an exceedingly sharp blade." + icon = 'icons/obj/advancedtools.dmi' + icon_state = "cutters" + toolspeed = 0.2 + random_color = FALSE \ No newline at end of file diff --git a/code/game/objects/items/tools/wrench.dm b/code/game/objects/items/tools/wrench.dm index 4fd99e9adf..462eb22aaa 100644 --- a/code/game/objects/items/tools/wrench.dm +++ b/code/game/objects/items/tools/wrench.dm @@ -32,7 +32,7 @@ name = "brass wrench" desc = "A brass wrench. It's faintly warm to the touch." resistance_flags = FIRE_PROOF | ACID_PROOF - icon_state = "wrench_brass" + icon_state = "wrench_clock" toolspeed = 0.5 /obj/item/wrench/bronze @@ -112,4 +112,12 @@ user.dust() - return OXYLOSS \ No newline at end of file + return OXYLOSS + +/obj/item/wrench/advanced + name = "advanced wrench" + desc = "A wrench that uses the same magnetic technology that abductor tools use, but slightly more ineffeciently." + icon = 'icons/obj/advancedtools.dmi' + icon_state = "wrench" + usesound = 'sound/effects/empulse.ogg' + toolspeed = 0.2 \ No newline at end of file diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index 9ac5261e5f..46fabea8b0 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -30,6 +30,7 @@ throw_speed = 3 throw_range = 7 force = 0 + total_mass = TOTAL_MASS_TINY_ITEM /* @@ -112,10 +113,6 @@ /obj/item/toy/syndicateballoon name = "syndicate balloon" desc = "There is a tag on the back that reads \"FUK NT!11!\"." - throwforce = 0 - throw_speed = 3 - throw_range = 7 - force = 0 icon = 'icons/obj/items_and_weapons.dmi' icon_state = "syndballoon" item_state = "syndballoon" @@ -225,6 +222,8 @@ w_class = WEIGHT_CLASS_SMALL attack_verb = list("attacked", "struck", "hit") var/hacked = FALSE + total_mass = 0.4 + var/total_mass_on = TOTAL_MASS_TOY_SWORD /obj/item/toy/sword/attack_self(mob/user) active = !( active ) @@ -274,6 +273,9 @@ else return ..() +/obj/item/toy/sword/getweight() + return (active ? total_mass_on : total_mass) || w_class *1.25 + /* * Foam armblade */ @@ -327,12 +329,13 @@ force_unwielded = 0 force_wielded = 0 attack_verb = list("attacked", "struck", "hit") + total_mass_on = TOTAL_MASS_TOY_SWORD /obj/item/twohanded/dualsaber/toy/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) - return 0 + return FALSE /obj/item/twohanded/dualsaber/toy/IsReflect()//Stops Toy Dualsabers from reflecting energy projectiles - return 0 + return FALSE /obj/item/toy/katana name = "replica katana" @@ -346,6 +349,7 @@ slot_flags = ITEM_SLOT_BELT | ITEM_SLOT_BACK force = 5 throwforce = 5 + total_mass = null w_class = WEIGHT_CLASS_NORMAL attack_verb = list("attacked", "slashed", "stabbed", "sliced") hitsound = 'sound/weapons/bladeslice.ogg' diff --git a/code/game/objects/items/trash.dm b/code/game/objects/items/trash.dm index 539a60986a..37ab948332 100644 --- a/code/game/objects/items/trash.dm +++ b/code/game/objects/items/trash.dm @@ -44,6 +44,10 @@ icon_state = "plate" resistance_flags = NONE +/obj/item/trash/plate/alt + desc = "Still some dip left. Sadly still just trash..." + icon_state = "plate1" + /obj/item/trash/pistachios name = "pistachios pack" icon_state = "pistachios_pack" diff --git a/code/game/objects/items/twohanded.dm b/code/game/objects/items/twohanded.dm index bf63a96f05..b1c2c36585 100644 --- a/code/game/objects/items/twohanded.dm +++ b/code/game/objects/items/twohanded.dm @@ -28,12 +28,14 @@ var/force_wielded = 0 var/wieldsound = null var/unwieldsound = null + var/slowdown_wielded = 0 + item_flags = SLOWS_WHILE_IN_HAND /obj/item/twohanded/proc/unwield(mob/living/carbon/user, show_message = TRUE) if(!wielded || !user) return wielded = 0 - if(force_unwielded) + if(!isnull(force_unwielded)) force = force_unwielded var/sf = findtext(name," (Wielded)") if(sf) @@ -55,7 +57,7 @@ var/obj/item/twohanded/offhand/O = user.get_inactive_held_item() if(O && istype(O)) O.unwield() - return + slowdown -= slowdown_wielded /obj/item/twohanded/proc/wield(mob/living/carbon/user) if(wielded) @@ -85,7 +87,7 @@ O.desc = "Your second grip on [src]." O.wielded = TRUE user.put_in_inactive_hand(O) - return + slowdown += slowdown_wielded /obj/item/twohanded/dropped(mob/user) . = ..() @@ -279,6 +281,7 @@ wieldsound = 'sound/weapons/saberon.ogg' unwieldsound = 'sound/weapons/saberoff.ogg' hitsound = "swing_hit" + var/hitsound_on = 'sound/weapons/blade1.ogg' armour_penetration = 35 item_color = "green" light_color = "#00ff00"//green @@ -290,8 +293,10 @@ var/hacked = FALSE var/brightness_on = 6 //TWICE AS BRIGHT AS A REGULAR ESWORD var/list/possible_colors = list("red", "blue", "green", "purple") - total_mass = 0.375 //Survival flashlights typically weigh around 5 ounces. - var/total_mass_on = 3.4 //The typical medieval sword, on the other hand, weighs roughly 3 pounds. //Values copied from the regular e-sword + var/list/rainbow_colors = list(LIGHT_COLOR_RED, LIGHT_COLOR_GREEN, LIGHT_COLOR_LIGHT_CYAN, LIGHT_COLOR_LAVENDER) + var/spinnable = TRUE + total_mass = 0.4 //Survival flashlights typically weigh around 5 ounces. + var/total_mass_on = 3.4 /obj/item/twohanded/dualsaber/suicide_act(mob/living/carbon/user) if(wielded) @@ -299,7 +304,7 @@ var/obj/item/bodypart/head/myhead = user.get_bodypart(BODY_ZONE_HEAD)//stole from chainsaw code var/obj/item/organ/brain/B = user.getorganslot(ORGAN_SLOT_BRAIN) - B.vital = FALSE//this cant possibly be a good idea + B.organ_flags &= ~ORGAN_VITAL //this cant possibly be a good idea var/randdir for(var/i in 1 to 24)//like a headless chicken! if(user.is_holding(src)) @@ -353,7 +358,7 @@ if(HAS_TRAIT(user, TRAIT_CLUMSY) && (wielded) && prob(40)) impale(user) return - if((wielded) && prob(50)) + if(spinnable && (wielded) && prob(50)) INVOKE_ASYNC(src, .proc/jedi_spin, user) /obj/item/twohanded/dualsaber/proc/jedi_spin(mob/living/user) @@ -406,11 +411,14 @@ /obj/item/twohanded/dualsaber/process() if(wielded) if(hacked) - light_color = pick(LIGHT_COLOR_RED, LIGHT_COLOR_GREEN, LIGHT_COLOR_LIGHT_CYAN, LIGHT_COLOR_LAVENDER) + rainbow_process() open_flame() else STOP_PROCESSING(SSobj, src) +/obj/item/twohanded/dualsaber/proc/rainbow_process() + light_color = pick(rainbow_colors) + /obj/item/twohanded/dualsaber/IsReflect() if(wielded) return 1 @@ -428,7 +436,8 @@ playsound(loc, hitsound, get_clamped_volume(), 1, -1) add_fingerprint(user) // Light your candles while spinning around the room - INVOKE_ASYNC(src, .proc/jedi_spin, user) + if(spinnable) + INVOKE_ASYNC(src, .proc/jedi_spin, user) /obj/item/twohanded/dualsaber/green possible_colors = list("green") @@ -478,6 +487,7 @@ armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 30) var/obj/item/grenade/explosive = null var/war_cry = "AAAAARGH!!!" + var/icon_prefix = "spearglass" /obj/item/twohanded/spear/Initialize() . = ..() @@ -520,7 +530,7 @@ if(explosive) icon_state = "spearbomb[wielded]" else - icon_state = "spearglass[wielded]" + icon_state = "[icon_prefix][wielded]" /obj/item/twohanded/spear/afterattack(atom/movable/AM, mob/user, proximity) . = ..() @@ -547,6 +557,13 @@ src.war_cry = input /obj/item/twohanded/spear/CheckParts(list/parts_list) + var/obj/item/shard/tip = locate() in parts_list + if (istype(tip, /obj/item/shard/plasma)) + force_wielded = 19 + force_unwielded = 11 + throwforce = 21 + icon_prefix = "spearplasma" + qdel(tip) var/obj/item/twohanded/spear/S = locate() in parts_list if(S) if(S.explosive) @@ -582,6 +599,8 @@ sharpness = IS_SHARP actions_types = list(/datum/action/item_action/startchainsaw) var/on = FALSE + tool_behaviour = TOOL_SAW + toolspeed = 0.5 /obj/item/twohanded/required/chainsaw/Initialize() . = ..() diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm index 48681c3d6d..4552e846ad 100644 --- a/code/game/objects/items/weaponry.dm +++ b/code/game/objects/items/weaponry.dm @@ -69,6 +69,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 max_integrity = 200 armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50) resistance_flags = FIRE_PROOF + total_mass = TOTAL_MASS_MEDIEVAL_WEAPON /obj/item/claymore/Initialize() . = ..() @@ -223,11 +224,12 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 max_integrity = 200 armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50) resistance_flags = FIRE_PROOF + total_mass = TOTAL_MASS_MEDIEVAL_WEAPON /obj/item/katana/cursed slot_flags = null -/obj/item/katana/Initialize() +/obj/item/katana/cursed/Initialize() . = ..() ADD_TRAIT(src, TRAIT_NODROP, CURSED_ITEM_TRAIT) @@ -253,7 +255,9 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 var/obj/item/twohanded/spear/S = new /obj/item/twohanded/spear remove_item_from_storage(user) - qdel(I) + if (!user.transferItemToLoc(I, S)) + return + S.CheckParts(list(I)) qdel(src) user.put_in_hands(S) @@ -431,6 +435,9 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 sharpness = IS_SHARP attack_verb = list("sawed", "torn", "cut", "chopped", "diced") hitsound = 'sound/weapons/chainsawhit.ogg' + total_mass = TOTAL_MASS_HAND_REPLACEMENT + tool_behaviour = TOOL_SAW + toolspeed = 1 /obj/item/mounted_chainsaw/Initialize() . = ..() @@ -510,6 +517,19 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 var/homerun_able = 0 total_mass = 2.7 //a regular wooden major league baseball bat weighs somewhere between 2 to 3.4 pounds, according to google +/obj/item/melee/baseball_bat/chaplain + name = "blessed baseball bat" + desc = "There ain't a cult in the league that can withstand a swatter." + force = 14 + throwforce = 14 + obj_flags = UNIQUE_RENAME + var/chaplain_spawnable = TRUE + total_mass = TOTAL_MASS_MEDIEVAL_WEAPON + +/obj/item/melee/baseball_bat/chaplain/Initialize() + . = ..() + AddComponent(/datum/component/anti_magic, TRUE, TRUE) + /obj/item/melee/baseball_bat/homerun name = "home run bat" desc = "This thing looks dangerous... Dangerously good at baseball, that is." @@ -560,6 +580,12 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 playsound(turf, 'sound/weapons/effects/batreflect2.ogg', 50, 1) return 1 +/obj/item/melee/baseball_bat/ablative/syndi + name = "syndicate major league bat" + desc = "A metal bat made by the syndicate for the major league team." + force = 18 //Spear damage... + throwforce = 30 + /obj/item/melee/flyswatter name = "flyswatter" desc = "Useful for killing insects of all sizes." diff --git a/code/game/objects/structures.dm b/code/game/objects/structures.dm index 5f21862c17..7526807eeb 100644 --- a/code/game/objects/structures.dm +++ b/code/game/objects/structures.dm @@ -8,6 +8,7 @@ var/climbable = FALSE var/mob/living/structureclimber var/broken = 0 //similar to machinery's stat BROKEN + layer = BELOW_OBJ_LAYER /obj/structure/Initialize() if (!armor) diff --git a/code/game/objects/structures/barsigns.dm b/code/game/objects/structures/barsigns.dm index 1ab28a33de..2093ae5660 100644 --- a/code/game/objects/structures/barsigns.dm +++ b/code/game/objects/structures/barsigns.dm @@ -112,12 +112,16 @@ /obj/structure/sign/barsign/emag_act(mob/user) + . = ..() if(broken || (obj_flags & EMAGGED)) to_chat(user, "Nothing interesting happens!") return obj_flags |= EMAGGED to_chat(user, "You emag the barsign. Takeover in progress...") - sleep(10 SECONDS) + addtimer(CALLBACK(src, .proc/syndie_bar_good), 10 SECONDS) + return TRUE + +/obj/structure/sign/barsign/proc/syndie_bar_good() set_sign(new /datum/barsign/hiddensigns/syndibarsign) req_access = list(ACCESS_SYNDICATE) diff --git a/code/game/objects/structures/beds_chairs/chair.dm b/code/game/objects/structures/beds_chairs/chair.dm index e944eb32da..dde9bce1bc 100644 --- a/code/game/objects/structures/beds_chairs/chair.dm +++ b/code/game/objects/structures/beds_chairs/chair.dm @@ -317,9 +317,6 @@ new stack_type(get_turf(loc)) qdel(src) - - - /obj/item/chair/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) if(attack_type == UNARMED_ATTACK && prob(hit_reaction_chance)) owner.visible_message("[owner] fends off [attack_text] with [src]!") @@ -338,7 +335,6 @@ C.Knockdown(20) smash(user) - /obj/item/chair/stool name = "stool" icon_state = "stool_toppled" @@ -352,6 +348,70 @@ item_state = "stool_bar" origin_type = /obj/structure/chair/stool/bar +////////////////////////// +//Brass & Bronze stools!// +////////////////////////// + +/obj/structure/chair/stool/bar/brass + name = "brass bar stool" + desc = "A brass bar stool with red silk for a pillow." + icon_state = "barbrass" + item_chair = /obj/item/chair/stool/bar/brass + buildstacktype = /obj/item/stack/tile/brass + buildstackamount = 1 + +/obj/structure/chair/stool/bar/bronze + name = "bronze bar stool" + desc = "A bronze bar stool with red silk for a pillow." + icon_state = "barbrass" + item_chair = /obj/item/chair/stool/bar/bronze + buildstacktype = /obj/item/stack/tile/bronze + buildstackamount = 1 + +/obj/structure/chair/stool/brass + name = "brass stool" + desc = "A brass stool with a silk top for comfort." + icon_state = "stoolbrass" + item_chair = /obj/item/chair/stool/brass + buildstacktype = /obj/item/stack/tile/brass + buildstackamount = 1 + +/obj/structure/chair/stool/bronze + name = "bronze stool" + desc = "A bronze stool with a silk top for comfort." + icon_state = "stoolbrass" + item_chair = /obj/item/chair/stool/bronze + buildstacktype = /obj/item/stack/tile/bronze + buildstackamount = 1 + +/obj/item/chair/stool/brass + name = "brass stool" + icon_state = "stoolbrass_toppled" + item_state = "stoolbrass" + origin_type = /obj/structure/chair/stool/brass + +/obj/item/chair/stool/bar/brass + name = "brass bar stool" + icon_state = "barbrass_toppled" + item_state = "stoolbrass_bar" + origin_type = /obj/structure/chair/stool/bar/brass + +/obj/item/chair/stool/bronze + name = "bronze stool" + icon_state = "stoolbrass_toppled" + item_state = "stoolbrass" + origin_type = /obj/structure/chair/stool/bronze + +/obj/item/chair/stool/bar/bronze + name = "bronze bar stool" + icon_state = "barbrass_toppled" + item_state = "stoolbrass_bar" + origin_type = /obj/structure/chair/stool/bar/bronze + +///////////////////////////////// +//End of Brass & Bronze stools!// +///////////////////////////////// + /obj/item/chair/stool/narsie_act() return //sturdy enough to ignore a god @@ -429,3 +489,19 @@ . = ..() if(has_gravity()) playsound(src, 'sound/machines/clockcult/integration_cog_install.ogg', 50, TRUE) + +/obj/structure/chair/sofa + name = "old ratty sofa" + icon_state = "sofamiddle" + icon = 'icons/obj/sofa.dmi' + buildstackamount = 1 + item_chair = null + +/obj/structure/chair/sofa/left + icon_state = "sofaend_left" + +/obj/structure/chair/sofa/right + icon_state = "sofaend_right" + +/obj/structure/chair/sofa/corner + icon_state = "sofacorner" \ No newline at end of file diff --git a/code/game/objects/structures/bedsheet_bin.dm b/code/game/objects/structures/bedsheet_bin.dm index b493f84240..1f7f0ab391 100644 --- a/code/game/objects/structures/bedsheet_bin.dm +++ b/code/game/objects/structures/bedsheet_bin.dm @@ -288,17 +288,19 @@ LINEN BINS resistance_flags = FLAMMABLE max_integrity = 70 var/amount = 10 + var/list/sheet_types = list(/obj/item/bedsheet) + var/static/allowed_sheets = list(/obj/item/bedsheet, /obj/item/reagent_containers/rag/towel) var/list/sheets = list() var/obj/item/hidden = null /obj/structure/bedsheetbin/examine(mob/user) ..() if(amount < 1) - to_chat(user, "There are no bed sheets in the bin.") + to_chat(user, "There are no sheets in the bin.") else if(amount == 1) - to_chat(user, "There is one bed sheet in the bin.") + to_chat(user, "There is one sheet in the bin.") else - to_chat(user, "There are [amount] bed sheets in the bin.") + to_chat(user, "There are [amount] sheets in the bin.") /obj/structure/bedsheetbin/update_icon() @@ -317,8 +319,9 @@ LINEN BINS ..() /obj/structure/bedsheetbin/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/bedsheet)) + if(is_type_in_list(I, allowed_sheets)) if(!user.transferItemToLoc(I, src)) + to_chat(user, "\The [I] is stuck to your hand, you cannot place it into the bin!") return sheets.Add(I) amount++ @@ -339,18 +342,19 @@ LINEN BINS . = ..() if(.) return - if(user.lying) + if(user.incapacitated()) return if(amount >= 1) amount-- - var/obj/item/bedsheet/B + var/obj/item/B if(sheets.len > 0) B = sheets[sheets.len] sheets.Remove(B) else - B = new /obj/item/bedsheet(loc) + var/chosen = pick(sheet_types) + B = new chosen B.forceMove(drop_location()) user.put_in_hands(B) @@ -362,19 +366,20 @@ LINEN BINS to_chat(user, "[hidden] falls out of [B]!") hidden = null - add_fingerprint(user) + /obj/structure/bedsheetbin/attack_tk(mob/user) if(amount >= 1) amount-- - var/obj/item/bedsheet/B + var/obj/item/B if(sheets.len > 0) B = sheets[sheets.len] sheets.Remove(B) else - B = new /obj/item/bedsheet(loc) + var/chosen = pick(sheet_types) + B = new chosen B.forceMove(drop_location()) to_chat(user, "You telekinetically remove [B] from [src].") @@ -384,5 +389,11 @@ LINEN BINS hidden.forceMove(drop_location()) hidden = null +/obj/structure/bedsheetbin/towel + desc = "It looks rather cosy. This one is designed to hold towels." + sheet_types = list(/obj/item/reagent_containers/rag/towel) - add_fingerprint(user) +/obj/structure/bedsheetbin/color + sheet_types = list(/obj/item/bedsheet, /obj/item/bedsheet/blue, /obj/item/bedsheet/green, /obj/item/bedsheet/orange, \ + /obj/item/bedsheet/purple, /obj/item/bedsheet/red, /obj/item/bedsheet/yellow, /obj/item/bedsheet/brown, \ + /obj/item/bedsheet/black) \ No newline at end of file diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index cf5b9ce197..8b0d410a72 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -4,7 +4,6 @@ icon = 'icons/obj/closet.dmi' icon_state = "generic" density = TRUE - layer = BELOW_OBJ_LAYER var/icon_door = null var/icon_door_override = FALSE //override to have open overlay use icon different to its base's var/secure = FALSE //secure locker or not, also used if overriding a non-secure locker with a secure door overlay to add fancy lights @@ -36,6 +35,9 @@ var/icon_welded = "welded" var/obj/item/electronics/airlock/lockerelectronics //Installed electronics var/lock_in_use = FALSE //Someone is doing some stuff with the lock here, better not proceed further + var/eigen_teleport = FALSE //If the closet leads to Mr Tumnus. + var/obj/structure/closet/eigen_target //Where you go to. + /obj/structure/closet/Initialize(mapload) . = ..() @@ -144,6 +146,8 @@ /obj/structure/closet/proc/togglelock(mob/living/user) add_fingerprint(user) + if(eigen_target) + return if(opened) return if(!can_lock(user)) @@ -186,7 +190,12 @@ if(contents.len >= storage_capacity) return -1 if(insertion_allowed(AM)) - AM.forceMove(src) + if(eigen_teleport) // For teleporting people with linked lockers. + do_teleport(AM, get_turf(eigen_target), 0) + if(eigen_target.opened == FALSE) + eigen_target.bust_open() + else + AM.forceMove(src) return TRUE else return FALSE @@ -292,7 +301,7 @@ if(!istype(S)) return var/brokenword = broken ? "broken " : null - user.visible_message("You begin removing the [brokenword]lock on [src]...", "[user] begins removing the [brokenword]lock on [src]...") + user.visible_message("[user] begins removing the [brokenword]lock on [src]...","You begin removing the [brokenword]lock on [src]...") playsound(loc, S.usesound, 50, 1) lock_in_use = TRUE if(!do_after(user, 100 * S.toolspeed, target = src)) @@ -339,6 +348,9 @@ to_chat(user, "You begin cutting \the [src] apart...") if(W.use_tool(src, user, 40, volume=50)) + if(eigen_teleport) + to_chat(user, "The unstable nature of \the [src] makes it impossible to cut!") + return if(!opened) return user.visible_message("[user] slices apart \the [src].", @@ -363,6 +375,9 @@ to_chat(user, "You begin [welded ? "unwelding":"welding"] \the [src]...") if(W.use_tool(src, user, 40, volume=50)) + if(eigen_teleport) + to_chat(user, "The unstable nature of \the [src] makes it impossible to weld!") + return if(opened) return welded = !welded @@ -525,17 +540,18 @@ dive_into(user) /obj/structure/closet/emag_act(mob/user) - if(secure && !broken) - user.visible_message("Sparks fly from [src]!", - "You scramble [src]'s lock, breaking it open!", - "You hear a faint electrical spark.") - playsound(src, "sparks", 50, 1) - broken = TRUE - locked = FALSE - if(!QDELETED(lockerelectronics)) - qdel(lockerelectronics) - lockerelectronics = null - update_icon() + . = ..() + if(!secure || broken) + return + user.visible_message("Sparks fly from [src]!", + "You scramble [src]'s lock, breaking it open!", + "You hear a faint electrical spark.") + playsound(src, "sparks", 50, 1) + broken = TRUE + locked = FALSE + if(!QDELETED(lockerelectronics)) + QDEL_NULL(lockerelectronics) + update_icon() /obj/structure/closet/get_remote_view_fullscreens(mob/user) if(user.stat == DEAD || !(user.sight & (SEEOBJS|SEEMOBS))) diff --git a/code/game/objects/structures/crates_lockers/closets/genpop.dm b/code/game/objects/structures/crates_lockers/closets/genpop.dm new file mode 100644 index 0000000000..80b64aaedc --- /dev/null +++ b/code/game/objects/structures/crates_lockers/closets/genpop.dm @@ -0,0 +1,117 @@ +/obj/structure/closet/secure_closet/genpop + desc = "It's a secure locker for inmates's personal belongings." + var/default_desc = "It's a secure locker for the storage inmates's personal belongings during their time in prison." + name = "prisoner closet" + var/default_name = "prisoner closet" + req_access = list(ACCESS_BRIG) + var/obj/item/card/id/prisoner/registered_id = null + icon_state = "prisoner" + locked = FALSE + anchored = TRUE + opened = TRUE + density = FALSE + +/obj/structure/closet/secure_closet/genpop/attackby(obj/item/W, mob/user, params) + if(!broken && locked && W == registered_id) //Prisoner opening + handle_prisoner_id(user) + return + + return ..() + +/obj/structure/closet/secure_closet/genpop/proc/handle_prisoner_id(mob/user) + var/obj/item/card/id/prisoner/prisoner_id = null + for(prisoner_id in user.held_items) + if(prisoner_id != registered_id) + prisoner_id = null + else + break + + if(!prisoner_id) + to_chat(user, "Access Denied.") + return FALSE + + qdel(registered_id) + registered_id = null + locked = FALSE + open(user) + desc = "It's a secure locker for prisoner effects." + to_chat(user, "You insert your prisoner id into \the [src] and it springs open!") + + return TRUE + +/obj/structure/closet/secure_closet/genpop/proc/handle_edit_sentence(mob/user) + var/prisoner_name = input(user, "Please input the name of the prisoner.", "Prisoner Name", registered_id.registered_name) as text|null + if(prisoner_name == null | !user.Adjacent(src)) + return FALSE + var/sentence_length = input(user, "Please input the length of their sentence in minutes (0 for perma).", "Sentence Length", registered_id.sentence) as num|null + if(sentence_length == null | !user.Adjacent(src)) + return FALSE + var/crimes = input(user, "Please input their crimes.", "Crimes", registered_id.crime) as text|null + if(crimes == null | !user.Adjacent(src)) + return FALSE + + registered_id.registered_name = prisoner_name + var/filteredsentlength = text2num(sentence_length) + registered_id.sentence = filteredsentlength ? (filteredsentlength MINUTES) + world.time : 0 + registered_id.crime = crimes + registered_id.update_label(prisoner_name, registered_id.assignment) + if(registered_id.sentence) + START_PROCESSING(SSobj, registered_id) + else + STOP_PROCESSING(SSobj, registered_id) + + name = "[default_name] ([prisoner_name])" + desc = "[default_desc] It contains the personal effects of [prisoner_name]." + + return TRUE + +/obj/structure/closet/secure_closet/genpop/togglelock(mob/living/user) + if(!allowed(user)) + return ..() + + if(!broken && locked && registered_id != null) + var/name = registered_id.registered_name + var/result = alert(user, "This locker currently contains [name]'s personal belongings ","Locker In Use","Reset","Amend ID", "Open") + if(!user.Adjacent(src)) + return + if(result == "Reset") + name = default_name + desc = default_desc + registered_id = null + if(result == "Open" | result == "Reset") + locked = FALSE + open(user) + if(result == "Amend ID") + handle_edit_sentence(user) + else + return ..() + +/obj/structure/closet/secure_closet/genpop/close(mob/living/user) + if(registered_id != null) + locked = TRUE + return ..() + +/obj/structure/closet/secure_closet/genpop/attack_hand(mob/user) + if(user.lying && get_dist(src, user) > 0) + return + + if(!broken && registered_id != null && registered_id in user.held_items) + handle_prisoner_id(user) + return + + if(!broken && opened && !locked && allowed(user) && !registered_id) //Genpop setup + + registered_id = new /obj/item/card/id/prisoner/(src.contents) + if(handle_edit_sentence(user)) + close(user) + locked = TRUE + update_icon() + registered_id.forceMove(src.loc) + new /obj/item/clothing/under/rank/prisoner(src.loc) + else + qdel(registered_id) + registered_id = null + + return + + ..() \ No newline at end of file diff --git a/code/game/objects/structures/crates_lockers/closets/job_closets.dm b/code/game/objects/structures/crates_lockers/closets/job_closets.dm index d2ab9ea6fb..b49d0a77d5 100644 --- a/code/game/objects/structures/crates_lockers/closets/job_closets.dm +++ b/code/game/objects/structures/crates_lockers/closets/job_closets.dm @@ -111,9 +111,9 @@ new /obj/item/clothing/accessory/pocketprotector/cosmetology(src) new /obj/item/clothing/under/rank/chaplain(src) new /obj/item/clothing/shoes/sneakers/black(src) - new /obj/item/clothing/suit/nun(src) + new /obj/item/clothing/suit/chaplain/nun(src) new /obj/item/clothing/head/nun_hood(src) - new /obj/item/clothing/suit/holidaypriest(src) + new /obj/item/clothing/suit/chaplain/holidaypriest(src) new /obj/item/storage/backpack/cultpack(src) new /obj/item/storage/fancy/candle_box(src) new /obj/item/storage/fancy/candle_box(src) 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 167823b9be..a7adafdad4 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm @@ -33,6 +33,7 @@ new /obj/item/extinguisher/advanced(src) new /obj/item/storage/photo_album/CE(src) new /obj/item/storage/lockbox/medal/engineering(src) + new /obj/item/construction/rcd/loaded/upgraded(src) /obj/structure/closet/secure_closet/engineering_electrical name = "electrical supplies locker" diff --git a/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm b/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm index 6e841bcd93..9dab3679fa 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm @@ -2,6 +2,24 @@ icon_state = "freezer" var/jones = FALSE +/obj/structure/closet/secure_closet/freezer/Destroy() + recursive_organ_check(src) + ..() + +/obj/structure/closet/secure_closet/freezer/Initialize() + ..() + recursive_organ_check(src) + +/obj/structure/closet/secure_closet/freezer/open(mob/living/user) + if(opened || !can_open(user)) //dupe check just so we don't let the organs decay when someone fails to open the locker + return FALSE + recursive_organ_check(src) + return ..() + +/obj/structure/closet/secure_closet/freezer/close(mob/living/user) + if(..()) //if we actually closed the locker + recursive_organ_check(src) + /obj/structure/closet/secure_closet/freezer/ex_act() if(!jones) jones = TRUE diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm index 6caa7d834b..23703c7891 100644 --- a/code/game/objects/structures/crates_lockers/crates.dm +++ b/code/game/objects/structures/crates_lockers/crates.dm @@ -99,6 +99,25 @@ name = "freezer" icon_state = "freezer" +//Snowflake organ freezer code +//Order is important, since we check source, we need to do the check whenever we have all the organs in the crate + +/obj/structure/closet/crate/freezer/open() + recursive_organ_check(src) + ..() + +/obj/structure/closet/crate/freezer/close() + ..() + recursive_organ_check(src) + +/obj/structure/closet/crate/freezer/Destroy() + recursive_organ_check(src) + ..() + +/obj/structure/closet/crate/freezer/Initialize() + . = ..() + recursive_organ_check(src) + /obj/structure/closet/crate/freezer/blood name = "blood freezer" desc = "A freezer containing packs of blood." diff --git a/code/game/objects/structures/dresser.dm b/code/game/objects/structures/dresser.dm index 8dc560b936..05e62c196f 100644 --- a/code/game/objects/structures/dresser.dm +++ b/code/game/objects/structures/dresser.dm @@ -79,4 +79,4 @@ var/n_color = input(H, "Choose your [garment_type]'\s color.", "Character Preference", default_color) as color|null if(!n_color || !H.canUseTopic(src, BE_CLOSE, FALSE, NO_TK)) return default_color - return sanitize_hexcolor(n_color, include_crunch= TRUE) + return sanitize_hexcolor(n_color, 3, FALSE, default_color) diff --git a/code/game/objects/structures/femur_breaker.dm b/code/game/objects/structures/femur_breaker.dm index 077eb25688..e3002a8fae 100644 --- a/code/game/objects/structures/femur_breaker.dm +++ b/code/game/objects/structures/femur_breaker.dm @@ -83,8 +83,9 @@ icon_state = "breaker_drop" /obj/structure/femur_breaker/proc/damage_leg(mob/living/carbon/human/H) - H.say("AAAAAAAAAAAAAAAAAAAAAAAAAAAHHHHHHHHHHHHHHHHHHH!!", forced = "femur broken") + H.emote("scream") H.apply_damage(150, BRUTE, pick(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)) + H.adjustBruteLoss(rand(5,20) + (max(0, H.health))) //Make absolutely sure they end up in crit, so that they can succumb if they wish. /obj/structure/femur_breaker/proc/raise_slat() slat_status = BREAKER_SLAT_RAISED @@ -171,4 +172,4 @@ #undef BREAKER_ACTIVATE_DELAY #undef BREAKER_WRENCH_DELAY #undef BREAKER_ACTION_INUSE -#undef BREAKER_ACTION_WRENCH \ No newline at end of file +#undef BREAKER_ACTION_WRENCH diff --git a/code/game/objects/structures/ghost_role_spawners.dm b/code/game/objects/structures/ghost_role_spawners.dm index 12827a0aba..b820e93c7b 100644 --- a/code/game/objects/structures/ghost_role_spawners.dm +++ b/code/game/objects/structures/ghost_role_spawners.dm @@ -45,7 +45,7 @@ death = FALSE anchored = FALSE density = FALSE - flavour_text = "You are an ash walker. Your tribe worships the Necropolis. The wastes are sacred ground, its monsters a blessed bounty. \ + flavour_text = "You are an ash walker. Your tribe worships the Necropolis. The wastes are sacred ground, its monsters a blessed bounty. You would never leave its beautiful expanse. \ You have seen lights in the distance... they foreshadow the arrival of outsiders that seek to tear apart the Necropolis and its domain. Fresh sacrifices for your nest." assignedrole = "Ash Walker" @@ -561,7 +561,7 @@ icon = 'icons/obj/machines/sleeper.dmi' icon_state = "sleeper" mob_name = "a space pirate" - mob_species = /datum/species/skeleton/pirate + mob_species = /datum/species/skeleton/space outfit = /datum/outfit/pirate/space roundstart = FALSE death = FALSE diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm index cd87075258..31bf9318ce 100644 --- a/code/game/objects/structures/girders.dm +++ b/code/game/objects/structures/girders.dm @@ -4,7 +4,6 @@ desc = "A large structural assembly made out of metal; It requires a layer of metal before it can be considered a wall." anchored = TRUE density = TRUE - layer = BELOW_OBJ_LAYER var/state = GIRDER_NORMAL var/girderpasschance = 20 // percentage chance that a projectile passes through the girder. var/can_displace = TRUE //If the girder can be moved around by wrenching it diff --git a/code/game/objects/structures/loom.dm b/code/game/objects/structures/loom.dm new file mode 100644 index 0000000000..c4e1968e59 --- /dev/null +++ b/code/game/objects/structures/loom.dm @@ -0,0 +1,21 @@ +//Loom, turns raw cotton and durathread into their respective fabrics. + +/obj/structure/loom + name = "loom" + desc = "A simple device used to weave cloth and other thread-based fabrics together into usable material." + icon = 'icons/obj/hydroponics/equipment.dmi' + icon_state = "loom" + density = TRUE + anchored = TRUE + +/obj/structure/loom/attackby(obj/item/stack/sheet/W, mob/user) + if(W.is_fabric && W.amount > 1) + user.show_message("You start weaving the [W.name] through the loom..", 1) + if(W.use_tool(src, user, W.pull_effort)) + new W.loom_result(drop_location()) + user.show_message("You weave the [W.name] into a workable fabric.", 1) + W.amount = (W.amount - 2) + if(W.amount < 1) + qdel(W) + else + user.show_message("You need a valid fabric and at least 2 of said fabric before using this.", 1) \ No newline at end of file diff --git a/code/game/objects/structures/mineral_doors.dm b/code/game/objects/structures/mineral_doors.dm index 13ca421daa..5733ea123c 100644 --- a/code/game/objects/structures/mineral_doors.dm +++ b/code/game/objects/structures/mineral_doors.dm @@ -6,6 +6,7 @@ density = TRUE anchored = TRUE opacity = TRUE + layer = CLOSED_DOOR_LAYER icon = 'icons/obj/doors/mineral_doors.dmi' icon_state = "metal" @@ -90,6 +91,7 @@ flick("[initial_state]opening",src) sleep(10) density = FALSE + layer = OPEN_DOOR_LAYER state = 1 air_update_turf(1) update_icon() @@ -111,6 +113,7 @@ density = TRUE set_opacity(TRUE) state = 0 + layer = initial(layer) air_update_turf(1) update_icon() isSwitchingStates = 0 diff --git a/code/game/objects/structures/morgue.dm b/code/game/objects/structures/morgue.dm index 09e5510d62..e7be30520e 100644 --- a/code/game/objects/structures/morgue.dm +++ b/code/game/objects/structures/morgue.dm @@ -31,6 +31,7 @@ GLOBAL_LIST_EMPTY(bodycontainers) //Let them act as spawnpoints for revenants an /obj/structure/bodycontainer/Initialize() . = ..() GLOB.bodycontainers += src + recursive_organ_check(src) /obj/structure/bodycontainer/Destroy() GLOB.bodycontainers -= src @@ -101,6 +102,7 @@ GLOBAL_LIST_EMPTY(bodycontainers) //Let them act as spawnpoints for revenants an /obj/structure/bodycontainer/deconstruct(disassembled = TRUE) new /obj/item/stack/sheet/metal (loc, 5) + recursive_organ_check(src) qdel(src) /obj/structure/bodycontainer/container_resist(mob/living/user) @@ -120,6 +122,7 @@ GLOBAL_LIST_EMPTY(bodycontainers) //Let them act as spawnpoints for revenants an open() /obj/structure/bodycontainer/proc/open() + recursive_organ_check(src) playsound(src.loc, 'sound/items/deconstruct.ogg', 50, 1) playsound(src, 'sound/effects/roll.ogg', 5, 1) var/turf/T = get_step(src, dir) @@ -130,10 +133,13 @@ GLOBAL_LIST_EMPTY(bodycontainers) //Let them act as spawnpoints for revenants an /obj/structure/bodycontainer/proc/close() playsound(src, 'sound/effects/roll.ogg', 5, 1) - playsound(src.loc, 'sound/items/deconstruct.ogg', 50, 1) + playsound(src, 'sound/items/deconstruct.ogg', 50, 1) for(var/atom/movable/AM in connected.loc) if(!AM.anchored || AM == connected) + if(ismob(AM) && !isliving(AM)) + continue AM.forceMove(src) + recursive_organ_check(src) update_icon() /obj/structure/bodycontainer/get_remote_view_fullscreens(mob/user) @@ -301,7 +307,7 @@ GLOBAL_LIST_EMPTY(crematoriums) /obj/structure/tray icon = 'icons/obj/stationobjs.dmi' density = TRUE - layer = BELOW_OBJ_LAYER + layer = TRAY_LAYER var/obj/structure/bodycontainer/connected = null anchored = TRUE pass_flags = LETPASSTHROW diff --git a/code/game/objects/structures/reflector.dm b/code/game/objects/structures/reflector.dm index 889cdab388..419502e2b0 100644 --- a/code/game/objects/structures/reflector.dm +++ b/code/game/objects/structures/reflector.dm @@ -5,7 +5,6 @@ desc = "A base for reflector assemblies." anchored = FALSE density = FALSE - layer = BELOW_OBJ_LAYER var/deflector_icon_state var/image/deflector_overlay var/finished = FALSE diff --git a/code/game/objects/structures/table_frames.dm b/code/game/objects/structures/table_frames.dm index e979d4f18e..f62bed878b 100644 --- a/code/game/objects/structures/table_frames.dm +++ b/code/game/objects/structures/table_frames.dm @@ -22,84 +22,22 @@ var/framestackamount = 2 /obj/structure/table_frame/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/wrench)) + if(I.tool_behaviour == TOOL_WRENCH) to_chat(user, "You start disassembling [src]...") I.play_tool_sound(src) if(I.use_tool(src, user, 30)) - playsound(src.loc, 'sound/items/deconstruct.ogg', 50, 1) + playsound(src.loc, 'sound/items/deconstruct.ogg', 50, TRUE) deconstruct(TRUE) - else if(istype(I, /obj/item/stack/sheet/plasteel)) - var/obj/item/stack/sheet/plasteel/P = I - if(P.get_amount() < 1) - to_chat(user, "You need one plasteel sheet to do this!") + return + + var/obj/item/stack/material = I + if (istype(I, /obj/item/stack) && material?.tableVariant) + if(material.get_amount() < 1) + to_chat(user, "You need one [material.name] sheet to do this!") return - to_chat(user, "You start adding [P] to [src]...") - if(do_after(user, 50, target = src) && P.use(1)) - make_new_table(/obj/structure/table/reinforced) - else if(istype(I, /obj/item/stack/sheet/metal)) - var/obj/item/stack/sheet/metal/M = I - if(M.get_amount() < 1) - to_chat(user, "You need one metal sheet to do this!") - return - to_chat(user, "You start adding [M] to [src]...") - if(do_after(user, 20, target = src) && M.use(1)) - make_new_table(/obj/structure/table) - else if(istype(I, /obj/item/stack/sheet/glass)) - var/obj/item/stack/sheet/glass/G = I - if(G.get_amount() < 1) - to_chat(user, "You need one glass sheet to do this!") - return - to_chat(user, "You start adding [G] to [src]...") - if(do_after(user, 20, target = src) && G.use(1)) - make_new_table(/obj/structure/table/glass) - else if(istype(I, /obj/item/stack/sheet/mineral/silver)) - var/obj/item/stack/sheet/mineral/silver/S = I - if(S.get_amount() < 1) - to_chat(user, "You need one silver sheet to do this!") - return - to_chat(user, "You start adding [S] to [src]...") - if(do_after(user, 20, target = src) && S.use(1)) - make_new_table(/obj/structure/table/optable) - else if(istype(I, /obj/item/stack/tile/carpet/black)) - var/obj/item/stack/tile/carpet/black/C = I - if(C.get_amount() < 1) - to_chat(user, "You need one black carpet sheet to do this!") - return - to_chat(user, "You start adding [C] to [src]...") - if(do_after(user, 20, target = src) && C.use(1)) - make_new_table(/obj/structure/table/wood/fancy/black) - else if(istype(I, /obj/item/stack/tile/carpet/blackred)) - var/obj/item/stack/tile/carpet/blackred/C = I - if(C.get_amount() < 1) - to_chat(user, "You need one red carpet sheet to do this!") - return - to_chat(user, "You start adding [C] to [src]...") - if(do_after(user, 20, target = src) && C.use(1)) - make_new_table(/obj/structure/table/wood/fancy/blackred) - else if(istype(I, /obj/item/stack/tile/carpet/monochrome)) - var/obj/item/stack/tile/carpet/monochrome/C = I - if(C.get_amount() < 1) - to_chat(user, "You need one monochrome carpet sheet to do this!") - return - to_chat(user, "You start adding [C] to [src]...") - if(do_after(user, 20, target = src) && C.use(1)) - make_new_table(/obj/structure/table/wood/fancy/monochrome) - else if(istype(I, /obj/item/stack/tile/carpet)) - var/obj/item/stack/tile/carpet/C = I - if(C.get_amount() < 1) - to_chat(user, "You need one carpet sheet to do this!") - return - to_chat(user, "You start adding [C] to [src]...") - if(do_after(user, 20, target = src) && C.use(1)) - make_new_table(/obj/structure/table/wood/fancy) - else if(istype(I, /obj/item/stack/tile/bronze)) - var/obj/item/stack/tile/bronze/B = I - if(B.get_amount() < 1) - to_chat(user, "You need one bronze sheet to do this!") - return - to_chat(user, "You start adding [B] to [src]...") - if(do_after(user, 20, target = src) && B.use(1)) - make_new_table(/obj/structure/table/bronze) + to_chat(user, "You start adding [material] to [src]...") + if(do_after(user, 20, target = src) && material.use(1)) + make_new_table(material.tableVariant) else return ..() @@ -135,23 +73,21 @@ resistance_flags = FLAMMABLE /obj/structure/table_frame/wood/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/stack/sheet/mineral/wood)) - var/obj/item/stack/sheet/mineral/wood/W = I - if(W.get_amount() < 1) - to_chat(user, "You need one wood sheet to do this!") - return - to_chat(user, "You start adding [W] to [src]...") - if(do_after(user, 20, target = src) && W.use(1)) - make_new_table(/obj/structure/table/wood) - return - else if(istype(I, /obj/item/stack/tile/carpet)) - var/obj/item/stack/tile/carpet/C = I - if(C.get_amount() < 1) - to_chat(user, "You need one carpet sheet to do this!") - return - to_chat(user, "You start adding [C] to [src]...") - if(do_after(user, 20, target = src) && C.use(1)) - make_new_table(/obj/structure/table/wood/poker) + if (istype(I, /obj/item/stack)) + var/obj/item/stack/material = I + var/toConstruct // stores the table variant + if(istype(I, /obj/item/stack/sheet/mineral/wood)) + toConstruct = /obj/structure/table/wood + else if(istype(I, /obj/item/stack/tile/carpet)) + toConstruct = /obj/structure/table/wood/poker + + if (toConstruct) + if(material.get_amount() < 1) + to_chat(user, "You need one [material.name] sheet to do this!") + return + to_chat(user, "You start adding [material] to [src]...") + if(do_after(user, 20, target = src) && material.use(1)) + make_new_table(toConstruct) else return ..() diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 8c29c1b2c5..b12a26cd00 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -21,6 +21,7 @@ anchored = TRUE layer = TABLE_LAYER climbable = TRUE + obj_flags = CAN_BE_HIT|SHOVABLE_ONTO pass_flags = LETPASSTHROW //You can throw objects over this, despite it's density.") var/frame = /obj/structure/table_frame var/framestack = /obj/item/stack/rods @@ -115,6 +116,9 @@ log_combat(user, pushed_mob, "placed") /obj/structure/table/proc/tablepush(mob/living/user, mob/living/pushed_mob) + if(HAS_TRAIT(user, TRAIT_PACIFISM)) + to_chat(user, "Throwing [pushed_mob] onto the table might hurt them!") + return var/added_passtable = FALSE if(!pushed_mob.pass_flags & PASSTABLE) added_passtable = TRUE @@ -125,14 +129,23 @@ if(pushed_mob.loc != loc) //Something prevented the tabling return pushed_mob.Knockdown(40) - pushed_mob.visible_message("[user] pushes [pushed_mob] onto [src].", \ - "[user] pushes [pushed_mob] onto [src].") - log_combat(user, pushed_mob, "pushed") + pushed_mob.visible_message("[user] slams [pushed_mob] onto [src]!", \ + "[user] slams you onto [src]!") + log_combat(user, pushed_mob, "tabled", null, "onto [src]") if(!ishuman(pushed_mob)) return var/mob/living/carbon/human/H = pushed_mob SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "table", /datum/mood_event/table) +/obj/structure/table/shove_act(mob/living/target, mob/living/user) + if(!target.resting) + target.Knockdown(SHOVE_KNOCKDOWN_TABLE) + user.visible_message("[user.name] shoves [target.name] onto \the [src]!", + "You shove [target.name] onto \the [src]!", null, COMBAT_MESSAGE_RANGE) + target.forceMove(src.loc) + log_combat(user, target, "shoved", "onto [src] (table)") + return TRUE + /obj/structure/table/attackby(obj/item/I, mob/user, params) if(!(flags_1 & NODECONSTRUCT_1)) if(istype(I, /obj/item/screwdriver) && deconstruction_ready) @@ -258,6 +271,53 @@ for(var/obj/item/shard/S in debris) S.color = NARSIE_WINDOW_COLOUR +/* + * Plasmaglass tables + */ +/obj/structure/table/plasmaglass + name = "plasmaglass table" + desc = "A glasstable, but it's pink and more sturdy. What will Nanotrasen design next with plasma?" + icon = 'icons/obj/smooth_structures/plasmaglass_table.dmi' + icon_state = "plasmaglass_table" + climbable = TRUE + buildstack = /obj/item/stack/sheet/plasmaglass + canSmoothWith = null + max_integrity = 270 + resistance_flags = ACID_PROOF + armor = list("melee" = 10, "bullet" = 5, "laser" = 0, "energy" = 0, "bomb" = 10, "bio" = 0, "rad" = 0, "fire" = 80, "acid" = 100) + var/list/debris = list() + +/obj/structure/table/plasmaglass/New() + . = ..() + debris += new frame + debris += new /obj/item/shard/plasma + +/obj/structure/table/plasmaglass/Destroy() + QDEL_LIST(debris) + . = ..() + +/obj/structure/table/plasmaglass/proc/check_break(mob/living/M) + return + +/obj/structure/table/plasmaglass/deconstruct(disassembled = TRUE, wrench_disassembly = 0) + if(!(flags_1 & NODECONSTRUCT_1)) + if(disassembled) + ..() + return + else + var/turf/T = get_turf(src) + playsound(T, "shatter", 50, 1) + for(var/X in debris) + var/atom/movable/AM = X + AM.forceMove(T) + debris -= AM + qdel(src) + +/obj/structure/table/plasmaglass/narsie_act() + color = NARSIE_WINDOW_COLOUR + for(var/obj/item/shard/S in debris) + S.color = NARSIE_WINDOW_COLOUR + /* * Wooden tables */ @@ -298,44 +358,83 @@ frame = /obj/structure/table_frame framestack = /obj/item/stack/rods buildstack = /obj/item/stack/tile/carpet - canSmoothWith = list(/obj/structure/table/wood/fancy, /obj/structure/table/wood/fancy/black, /obj/structure/table/wood/fancy/blackred, /obj/structure/table/wood/fancy/monochrome) + canSmoothWith = list(/obj/structure/table/wood/fancy, + /obj/structure/table/wood/fancy/black, + /obj/structure/table/wood/fancy/blackred, + /obj/structure/table/wood/fancy/monochrome, + /obj/structure/table/wood/fancy/blue, + /obj/structure/table/wood/fancy/cyan, + /obj/structure/table/wood/fancy/green, + /obj/structure/table/wood/fancy/orange, + /obj/structure/table/wood/fancy/purple, + /obj/structure/table/wood/fancy/red, + /obj/structure/table/wood/fancy/royalblack, + /obj/structure/table/wood/fancy/royalblue) + var/smooth_icon = 'icons/obj/smooth_structures/fancy_table.dmi' // see Initialize() -/obj/structure/table/wood/fancy/New() - // New() is used so that the /black subtype can override `icon` easily and - // the correct value will be used by the smoothing subsystem. +/obj/structure/table/wood/fancy/Initialize() . = ..() // Needs to be set dynamically because table smooth sprites are 32x34, // which the editor treats as a two-tile-tall object. The sprites are that // size so that the north/south corners look nice - examine the detail on // the sprites in the editor to see why. - icon = 'icons/obj/smooth_structures/fancy_table.dmi' + icon = smooth_icon /obj/structure/table/wood/fancy/black icon_state = "fancy_table_black" buildstack = /obj/item/stack/tile/carpet/black + smooth_icon = 'icons/obj/smooth_structures/fancy_table_black.dmi' /obj/structure/table/wood/fancy/blackred - icon = 'icons/obj/structures.dmi' - icon_state = "fancy_table_blackred" - buildstack = /obj/item/stack/tile/carpet/blackred - -/obj/structure/table/wood/fancy/blackred/New() - . = ..() - icon = 'icons/obj/smooth_structures/fancy_table_blackred.dmi' + icon_state = "fancy_table_blackred" + buildstack = /obj/item/stack/tile/carpet/blackred + smooth_icon = 'icons/obj/smooth_structures/fancy_table_blackred.dmi' /obj/structure/table/wood/fancy/monochrome - icon = 'icons/obj/structures.dmi' - icon_state = "fancy_table_monochrome" - buildstack = /obj/item/stack/tile/carpet/monochrome + icon_state = "fancy_table_monochrome" + buildstack = /obj/item/stack/tile/carpet/monochrome + smooth_icon = 'icons/obj/smooth_structures/fancy_table_monochrome.dmi' -/obj/structure/table/wood/fancy/monochrome/New() - . = ..() - icon = 'icons/obj/smooth_structures/fancy_table_monochrome.dmi' +/obj/structure/table/wood/fancy/blue + icon_state = "fancy_table_blue" + buildstack = /obj/item/stack/tile/carpet/blue + smooth_icon = 'icons/obj/smooth_structures/fancy_table_blue.dmi' + +/obj/structure/table/wood/fancy/cyan + icon_state = "fancy_table_cyan" + buildstack = /obj/item/stack/tile/carpet/cyan + smooth_icon = 'icons/obj/smooth_structures/fancy_table_cyan.dmi' + +/obj/structure/table/wood/fancy/green + icon_state = "fancy_table_green" + buildstack = /obj/item/stack/tile/carpet/green + smooth_icon = 'icons/obj/smooth_structures/fancy_table_green.dmi' + +/obj/structure/table/wood/fancy/orange + icon_state = "fancy_table_orange" + buildstack = /obj/item/stack/tile/carpet/orange + smooth_icon = 'icons/obj/smooth_structures/fancy_table_orange.dmi' + +/obj/structure/table/wood/fancy/purple + icon_state = "fancy_table_purple" + buildstack = /obj/item/stack/tile/carpet/purple + smooth_icon = 'icons/obj/smooth_structures/fancy_table_purple.dmi' + +/obj/structure/table/wood/fancy/red + icon_state = "fancy_table_red" + buildstack = /obj/item/stack/tile/carpet/red + smooth_icon = 'icons/obj/smooth_structures/fancy_table_red.dmi' + +/obj/structure/table/wood/fancy/royalblack + icon_state = "fancy_table_royalblack" + buildstack = /obj/item/stack/tile/carpet/royalblack + smooth_icon = 'icons/obj/smooth_structures/fancy_table_royalblack.dmi' + +/obj/structure/table/wood/fancy/royalblue + icon_state = "fancy_table_royalblue" + buildstack = /obj/item/stack/tile/carpet/royalblue + smooth_icon = 'icons/obj/smooth_structures/fancy_table_royalblue.dmi' -/obj/structure/table/wood/fancy/black/New() - . = ..() - // Ditto above. - icon = 'icons/obj/smooth_structures/fancy_table_black.dmi' /* * Reinforced tables */ diff --git a/code/game/objects/structures/transit_tubes/transit_tube_pod.dm b/code/game/objects/structures/transit_tubes/transit_tube_pod.dm index ee46538be1..392c802ed8 100644 --- a/code/game/objects/structures/transit_tubes/transit_tube_pod.dm +++ b/code/game/objects/structures/transit_tubes/transit_tube_pod.dm @@ -4,7 +4,6 @@ animate_movement = FORWARD_STEPS anchored = TRUE density = TRUE - layer = BELOW_OBJ_LAYER var/moving = 0 var/datum/gas_mixture/air_contents = new() diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index a26d57e3e1..9fc055c2ba 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -281,6 +281,8 @@ . += new /obj/effect/decal/cleanable/glass(location) if (reinf) . += new /obj/item/stack/rods(location, (fulltile ? 2 : 1)) + if (fulltile) + . += new /obj/item/shard(location) /obj/structure/window/proc/can_be_rotated(mob/user,rotation_type) if(anchored) @@ -409,6 +411,15 @@ glass_type = /obj/item/stack/sheet/plasmaglass rad_insulation = RAD_NO_INSULATION +/obj/structure/window/plasma/spawnDebris(location) + . = list() + . += new /obj/item/shard/plasma(location) + . += new /obj/effect/decal/cleanable/glass/plasma(location) + if (reinf) + . += new /obj/item/stack/rods(location, (fulltile ? 2 : 1)) + if (fulltile) + . += new /obj/item/shard/plasma(location) + /obj/structure/window/plasma/spawner/east dir = EAST diff --git a/code/game/sound.dm b/code/game/sound.dm index 5503c6103d..e7562476a8 100644 --- a/code/game/sound.dm +++ b/code/game/sound.dm @@ -182,6 +182,8 @@ soundin = pick('sound/voice/beepsky/god.ogg', 'sound/voice/beepsky/iamthelaw.ogg', 'sound/voice/beepsky/secureday.ogg', 'sound/voice/beepsky/radio.ogg', 'sound/voice/beepsky/insult.ogg', 'sound/voice/beepsky/creep.ogg') if("honkbot_e") soundin = pick('sound/items/bikehorn.ogg', 'sound/items/AirHorn2.ogg', 'sound/misc/sadtrombone.ogg', 'sound/items/AirHorn.ogg', 'sound/effects/reee.ogg', 'sound/items/WEEOO1.ogg', 'sound/voice/beepsky/iamthelaw.ogg', 'sound/voice/beepsky/creep.ogg','sound/magic/Fireball.ogg' ,'sound/effects/pray.ogg', 'sound/voice/hiss1.ogg','sound/machines/buzz-sigh.ogg', 'sound/machines/ping.ogg', 'sound/weapons/flashbang.ogg', 'sound/weapons/bladeslice.ogg') + if("goose") + soundin = pick('sound/creatures/goose1.ogg', 'sound/creatures/goose2.ogg', 'sound/creatures/goose3.ogg', 'sound/creatures/goose4.ogg') //START OF CIT CHANGES - adds random vore sounds if ("struggle_sound") soundin = pick( 'sound/vore/pred/struggle_01.ogg','sound/vore/pred/struggle_02.ogg','sound/vore/pred/struggle_03.ogg', diff --git a/code/game/turfs/simulated/floor.dm b/code/game/turfs/simulated/floor.dm index b00efc7ed6..194014b61a 100644 --- a/code/game/turfs/simulated/floor.dm +++ b/code/game/turfs/simulated/floor.dm @@ -236,6 +236,10 @@ return list("mode" = RCD_DECONSTRUCT, "delay" = 50, "cost" = 33) if(RCD_WINDOWGRILLE) return list("mode" = RCD_WINDOWGRILLE, "delay" = 10, "cost" = 4) + if(RCD_MACHINE) + return list("mode" = RCD_MACHINE, "delay" = 20, "cost" = 25) + if(RCD_COMPUTER) + return list("mode" = RCD_COMPUTER, "delay" = 20, "cost" = 25) return FALSE /turf/open/floor/rcd_act(mob/user, obj/item/construction/rcd/the_rcd, passed_mode) @@ -274,4 +278,20 @@ var/obj/structure/grille/G = new(src) G.anchored = TRUE return TRUE + if(RCD_MACHINE) + if(locate(/obj/structure/frame/machine) in src) + return FALSE + var/obj/structure/frame/machine/M = new(src) + M.state = 2 + M.icon_state = "box_1" + M.anchored = TRUE + return TRUE + if(RCD_COMPUTER) + if(locate(/obj/structure/frame/computer) in src) + return FALSE + var/obj/structure/frame/computer/C = new(src) + C.anchored = TRUE + C.setDir(the_rcd.computer_dir) + return TRUE + return FALSE diff --git a/code/game/turfs/simulated/floor/fancy_floor.dm b/code/game/turfs/simulated/floor/fancy_floor.dm index 7b45aa1fbb..ed6e279088 100644 --- a/code/game/turfs/simulated/floor/fancy_floor.dm +++ b/code/game/turfs/simulated/floor/fancy_floor.dm @@ -209,6 +209,46 @@ icon_state = "tile-carpet-monochrome" canSmoothWith = list(/turf/open/floor/carpet/black, /turf/open/floor/carpet/blackred, /turf/open/floor/carpet/monochrome) +/turf/open/floor/carpet/blue + icon = 'icons/turf/floors/carpet_blue.dmi' + floor_tile = /obj/item/stack/tile/carpet/blue + canSmoothWith = list(/turf/open/floor/carpet/blue) + +/turf/open/floor/carpet/cyan + icon = 'icons/turf/floors/carpet_cyan.dmi' + floor_tile = /obj/item/stack/tile/carpet/cyan + canSmoothWith = list(/turf/open/floor/carpet/cyan) + +/turf/open/floor/carpet/green + icon = 'icons/turf/floors/carpet_green.dmi' + floor_tile = /obj/item/stack/tile/carpet/green + canSmoothWith = list(/turf/open/floor/carpet/green) + +/turf/open/floor/carpet/orange + icon = 'icons/turf/floors/carpet_orange.dmi' + floor_tile = /obj/item/stack/tile/carpet/orange + canSmoothWith = list(/turf/open/floor/carpet/orange) + +/turf/open/floor/carpet/purple + icon = 'icons/turf/floors/carpet_purple.dmi' + floor_tile = /obj/item/stack/tile/carpet/purple + canSmoothWith = list(/turf/open/floor/carpet/purple) + +/turf/open/floor/carpet/red + icon = 'icons/turf/floors/carpet_red.dmi' + floor_tile = /obj/item/stack/tile/carpet/red + canSmoothWith = list(/turf/open/floor/carpet/red) + +/turf/open/floor/carpet/royalblack + icon = 'icons/turf/floors/carpet_royalblack.dmi' + floor_tile = /obj/item/stack/tile/carpet/royalblack + canSmoothWith = list(/turf/open/floor/carpet/royalblack) + +/turf/open/floor/carpet/royalblue + icon = 'icons/turf/floors/carpet_royalblue.dmi' + floor_tile = /obj/item/stack/tile/carpet/royalblue + canSmoothWith = list(/turf/open/floor/carpet/royalblue) + /turf/open/floor/carpet/narsie_act(force, ignore_mobs, probability = 20) . = (prob(probability) || force) for(var/I in src) diff --git a/code/game/turfs/simulated/wall/misc_walls.dm b/code/game/turfs/simulated/wall/misc_walls.dm index dfc6972578..8b63d60939 100644 --- a/code/game/turfs/simulated/wall/misc_walls.dm +++ b/code/game/turfs/simulated/wall/misc_walls.dm @@ -7,6 +7,7 @@ smooth = SMOOTH_MORE sheet_type = /obj/item/stack/sheet/runed_metal sheet_amount = 1 + explosion_block = 10 girder_type = /obj/structure/girder/cult /turf/closed/wall/mineral/cult/Initialize() @@ -49,7 +50,7 @@ /turf/closed/wall/clockwork name = "clockwork wall" desc = "A huge chunk of warm metal. The clanging of machinery emanates from within." - explosion_block = 2 + explosion_block = 5 hardness = 10 slicing_duration = 80 sheet_type = /obj/item/stack/tile/brass diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 7110ff4405..ebf6f6626c 100755 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -382,6 +382,19 @@ if(ismob(A) || .) A.ratvar_act() +//called on /datum/species/proc/altdisarm() +/turf/shove_act(mob/living/target, mob/living/user, pre_act = FALSE) + var/list/possibilities + for(var/obj/O in contents) + if(CHECK_BITFIELD(O.obj_flags, SHOVABLE_ONTO)) + LAZYADD(possibilities, O) + else if(!O.CanPass(target, src)) + return FALSE + if(possibilities) + var/obj/O = pick(possibilities) + return O.shove_act(target, user) + return FALSE + /turf/proc/get_smooth_underlay_icon(mutable_appearance/underlay_appearance, turf/asking_turf, adjacency_dir) underlay_appearance.icon = icon underlay_appearance.icon_state = icon_state @@ -452,16 +465,21 @@ /turf/AllowDrop() return TRUE -/turf/proc/add_vomit_floor(mob/living/carbon/M, toxvomit = NONE) +/turf/proc/add_vomit_floor(mob/living/M, toxvomit = NONE) + var/obj/effect/decal/cleanable/vomit/V = new /obj/effect/decal/cleanable/vomit(src, M.get_static_viruses()) - // If the vomit combined, apply toxicity and reagents to the old vomit + //if the vomit combined, apply toxicity and reagents to the old vomit if (QDELETED(V)) V = locate() in src // Make toxins and blazaam vomit look different if(toxvomit == VOMIT_PURPLE) V.icon_state = "vomitpurp_[pick(1,4)]" - else if(toxvomit == VOMIT_TOXIC) + else if (toxvomit == VOMIT_TOXIC) V.icon_state = "vomittox_[pick(1,4)]" + if (iscarbon(M)) + var/mob/living/carbon/C = M + if(C.reagents) + clear_reagents_to_vomit_pool(C,V) /proc/clear_reagents_to_vomit_pool(mob/living/carbon/M, obj/effect/decal/cleanable/vomit/V) M.reagents.trans_to(V, M.reagents.total_volume / 10) @@ -474,4 +492,4 @@ //Whatever happens after high temperature fire dies out or thermite reaction works. //Should return new turf /turf/proc/Melt() - return ScrapeAway() \ No newline at end of file + return ScrapeAway() diff --git a/code/game/world.dm b/code/game/world.dm index dedf822597..25b8c4d9f3 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -100,6 +100,7 @@ GLOBAL_VAR(restart_counter) GLOB.picture_log_directory = "data/picture_logs/[override_dir]" GLOB.world_game_log = "[GLOB.log_directory]/game.log" + GLOB.world_virus_log = "[GLOB.log_directory]/virus.log" GLOB.world_attack_log = "[GLOB.log_directory]/attack.log" GLOB.world_pda_log = "[GLOB.log_directory]/pda.log" GLOB.world_telecomms_log = "[GLOB.log_directory]/telecomms.log" @@ -137,7 +138,7 @@ GLOBAL_VAR(restart_counter) // but those are both private, so let's put the commit info in the runtime // log which is ultimately public. log_runtime(GLOB.revdata.get_log_message()) - + /world/Topic(T, addr, master, key) TGS_TOPIC //redirect to server tools if necessary @@ -270,7 +271,8 @@ GLOBAL_VAR(restart_counter) if (M.client) n++ - features += "[SSmapping.config.map_name]" //CIT CHANGE - makes the hub entry display the current map + if(SSmapping.config) // this just stops the runtime, honk. + features += "[SSmapping.config.map_name]" //CIT CHANGE - makes the hub entry display the current map if(get_security_level())//CIT CHANGE - makes the hub entry show the security level features += "[get_security_level()] alert" diff --git a/code/modules/VR/vr_human.dm b/code/modules/VR/vr_human.dm deleted file mode 100644 index 53a4bbe540..0000000000 --- a/code/modules/VR/vr_human.dm +++ /dev/null @@ -1,61 +0,0 @@ -/mob/living/carbon/human/virtual_reality - var/datum/mind/real_mind // where is my mind t. pixies - var/obj/machinery/vr_sleeper/vr_sleeper - var/datum/action/quit_vr/quit_action - -/mob/living/carbon/human/virtual_reality/Initialize() - . = ..() - quit_action = new() - quit_action.Grant(src) - -/mob/living/carbon/human/virtual_reality/death() - revert_to_reality() - ..() - -/mob/living/carbon/human/virtual_reality/Destroy() - revert_to_reality() - return ..() - -/mob/living/carbon/human/virtual_reality/Life() - . = ..() - if(real_mind) - var/mob/living/real_me = real_mind.current - if (real_me && real_me.stat == CONSCIOUS) - return - revert_to_reality(FALSE) - -/mob/living/carbon/human/virtual_reality/ghostize() - stack_trace("Ghostize was called on a virtual reality mob") - -/mob/living/carbon/human/virtual_reality/ghost() - set category = "OOC" - set name = "Ghost" - set desc = "Relinquish your life and enter the land of the dead." - revert_to_reality(FALSE) - -/mob/living/carbon/human/virtual_reality/proc/revert_to_reality(deathchecks = TRUE) - if(real_mind && mind) - real_mind.current.audiovisual_redirect = null - real_mind.current.ckey = ckey - real_mind.current.stop_sound_channel(CHANNEL_HEARTBEAT) - if(deathchecks && vr_sleeper) - if(vr_sleeper.you_die_in_the_game_you_die_for_real) - to_chat(real_mind, "You feel everything fading away...") - real_mind.current.death(0) - if(deathchecks && vr_sleeper) - vr_sleeper.vr_human = null - vr_sleeper = null - real_mind = null - -/datum/action/quit_vr - name = "Quit Virtual Reality" - icon_icon = 'icons/mob/actions/actions_vr.dmi' - button_icon_state = "logout" - -/datum/action/quit_vr/Trigger() - if(..()) - if(istype(owner, /mob/living/carbon/human/virtual_reality)) - var/mob/living/carbon/human/virtual_reality/VR = owner - VR.revert_to_reality(FALSE) - else - Remove(owner) diff --git a/code/modules/VR/vr_mob.dm b/code/modules/VR/vr_mob.dm new file mode 100644 index 0000000000..5c0cea9f60 --- /dev/null +++ b/code/modules/VR/vr_mob.dm @@ -0,0 +1,44 @@ +/mob/proc/build_virtual_character(mob/M) + mind_initialize() + if(!M) + return FALSE + name = M.name + real_name = M.real_name + mind.name = M.real_name + return TRUE + +/mob/living/carbon/build_virtual_character(mob/M) + . = ..() + if(!.) + return + if(iscarbon(M)) + var/mob/living/carbon/C = M + C.dna?.transfer_identity(src) + +/mob/living/carbon/human/build_virtual_character(mob/M, datum/outfit/outfit) + . = ..() + if(!.) + return + var/mob/living/carbon/human/H + if(ishuman(M)) + H = M + socks = H ? H.socks : random_socks() + socks_color = H ? H.socks_color : random_color() + undershirt = H ? H.undershirt : random_undershirt(M.gender) + shirt_color = H ? H.shirt_color : random_color() + underwear = H ? H.underwear : random_underwear(M.gender) + undie_color = H ? H.undie_color : random_color() + give_genitals(TRUE) + if(outfit) + var/datum/outfit/O = new outfit() + O.equip(src) + +/datum/action/quit_vr + name = "Quit Virtual Reality" + icon_icon = 'icons/mob/actions/actions_vr.dmi' + button_icon_state = "logout" + +/datum/action/quit_vr/Trigger() //this merely a trigger for /datum/component/virtual_reality + . = ..() + if(!.) + Remove(owner) diff --git a/code/modules/VR/vr_sleeper.dm b/code/modules/VR/vr_sleeper.dm index bfbf6b5b79..72cbdc1409 100644 --- a/code/modules/VR/vr_sleeper.dm +++ b/code/modules/VR/vr_sleeper.dm @@ -1,5 +1,3 @@ - - //Glorified teleporter that puts you in a new human body. // it's """VR""" /obj/machinery/vr_sleeper @@ -12,9 +10,10 @@ circuit = /obj/item/circuitboard/machine/vr_sleeper var/you_die_in_the_game_you_die_for_real = FALSE var/datum/effect_system/spark_spread/sparks - var/mob/living/carbon/human/virtual_reality/vr_human + var/mob/living/vr_mob + var/virtual_mob_type = /mob/living/carbon/human var/vr_category = "default" //Specific category of spawn points to pick from - var/allow_creating_vr_humans = TRUE //So you can have vr_sleepers that always spawn you as a specific person or 1 life/chance vr games + var/allow_creating_vr_mobs = TRUE //So you can have vr_sleepers that always spawn you as a specific person or 1 life/chance vr games var/only_current_user_can_interact = FALSE /obj/machinery/vr_sleeper/Initialize() @@ -44,7 +43,7 @@ /obj/machinery/vr_sleeper/Destroy() open_machine() - cleanup_vr_human() + cleanup_vr_mob() QDEL_NULL(sparks) return ..() @@ -54,23 +53,27 @@ only_current_user_can_interact = TRUE /obj/machinery/vr_sleeper/hugbox/emag_act(mob/user) - return + return SEND_SIGNAL(src, COMSIG_ATOM_EMAG_ACT) /obj/machinery/vr_sleeper/emag_act(mob/user) + . = ..() + if(!(obj_flags & EMAGGED)) + return + obj_flags |= EMAGGED you_die_in_the_game_you_die_for_real = TRUE sparks.start() addtimer(CALLBACK(src, .proc/emagNotify), 150) + return TRUE /obj/machinery/vr_sleeper/update_icon() icon_state = "[initial(icon_state)][state_open ? "-open" : ""]" /obj/machinery/vr_sleeper/open_machine() - if(!state_open) - if(vr_human) - vr_human.revert_to_reality(FALSE) - if(occupant) - SStgui.close_user_uis(occupant, src) - ..() + if(state_open) + return + if(occupant) + SStgui.close_user_uis(occupant, src) + return ..() /obj/machinery/vr_sleeper/MouseDrop_T(mob/target, mob/user) if(user.stat || user.lying || !Adjacent(user) || !user.Adjacent(target) || !iscarbon(target) || !user.IsAdvancedToolUser()) @@ -90,22 +93,20 @@ if("vr_connect") var/mob/living/carbon/human/human_occupant = occupant if(human_occupant && human_occupant.mind && usr == occupant) + to_chat(occupant, "Transferring to virtual reality...") - if(vr_human && vr_human.stat == CONSCIOUS && !vr_human.real_mind) - SStgui.close_user_uis(occupant, src) - human_occupant.audiovisual_redirect = vr_human - vr_human.real_mind = human_occupant.mind - vr_human.ckey = human_occupant.ckey - to_chat(vr_human, "Transfer successful! You are now playing as [vr_human] in VR!") + if(vr_mob && (!istype(vr_mob) || !vr_mob.InCritical()) && !vr_mob.GetComponent(/datum/component/virtual_reality)) + vr_mob.AddComponent(/datum/component/virtual_reality, human_occupant, src, you_die_in_the_game_you_die_for_real) + to_chat(vr_mob, "Transfer successful! You are now playing as [vr_mob] in VR!") else - if(allow_creating_vr_humans) + if(allow_creating_vr_mobs) to_chat(occupant, "Virtual avatar not found, attempting to create one...") var/obj/effect/landmark/vr_spawn/V = get_vr_spawnpoint() var/turf/T = get_turf(V) if(T) SStgui.close_user_uis(occupant, src) - build_virtual_human(occupant, T, V.vr_outfit) - to_chat(vr_human, "Transfer successful! You are now playing as [vr_human] in VR!") + new_player(occupant, T, V.vr_outfit) + to_chat(vr_mob, "Transfer successful! You are now playing as [vr_mob] in VR!") else to_chat(occupant, "Virtual world misconfigured, aborting transfer") else @@ -113,8 +114,8 @@ . = TRUE if("delete_avatar") if(!occupant || usr == occupant) - if(vr_human) - cleanup_vr_human() + if(vr_mob) + cleanup_vr_mob() else to_chat(usr, "The VR Sleeper's safeties prevent you from doing that.") . = TRUE @@ -127,19 +128,22 @@ /obj/machinery/vr_sleeper/ui_data(mob/user) var/list/data = list() - if(vr_human && !QDELETED(vr_human)) + if(vr_mob && !QDELETED(vr_mob)) data["can_delete_avatar"] = TRUE - var/status - switch(vr_human.stat) - if(CONSCIOUS) - status = "Conscious" - if(DEAD) - status = "Dead" - if(UNCONSCIOUS) - status = "Unconscious" - if(SOFT_CRIT) - status = "Barely Conscious" - data["vr_avatar"] = list("name" = vr_human.name, "status" = status, "health" = vr_human.health, "maxhealth" = vr_human.maxHealth) + data["vr_avatar"] = list("name" = vr_mob.name) + data["isliving"] = istype(vr_mob) + if(data["isliving"]) + var/status + switch(vr_mob.stat) + if(CONSCIOUS) + status = "Conscious" + if(DEAD) + status = "Dead" + if(UNCONSCIOUS) + status = "Unconscious" + if(SOFT_CRIT) + status = "Barely Conscious" + data["vr_avatar"] += list("status" = status, "health" = vr_mob.health, "maxhealth" = vr_mob.maxHealth) data["toggle_open"] = state_open data["emagged"] = you_die_in_the_game_you_die_for_real data["isoccupant"] = (user == occupant) @@ -153,40 +157,25 @@ for(var/obj/effect/landmark/vr_spawn/V in GLOB.landmarks_list) GLOB.vr_spawnpoints[V.vr_category] = V -/obj/machinery/vr_sleeper/proc/build_virtual_human(mob/living/carbon/human/H, location, var/datum/outfit/outfit, transfer = TRUE) - if(H) - cleanup_vr_human() - vr_human = new /mob/living/carbon/human/virtual_reality(location) - vr_human.mind_initialize() - vr_human.vr_sleeper = src - vr_human.real_mind = H.mind - H.dna.transfer_identity(vr_human) - vr_human.name = H.name - vr_human.real_name = H.real_name - vr_human.socks = H.socks - vr_human.socks_color = H.socks_color - vr_human.undershirt = H.undershirt - vr_human.shirt_color = H.shirt_color - vr_human.underwear = H.underwear - vr_human.undie_color = H.undie_color - vr_human.updateappearance(TRUE, TRUE, TRUE) - vr_human.give_genitals(TRUE) //CITADEL ADD - if(outfit) - var/datum/outfit/O = new outfit() - O.equip(vr_human) - if(transfer && H.mind) - SStgui.close_user_uis(H, src) - H.audiovisual_redirect = vr_human - vr_human.ckey = H.ckey +/obj/machinery/vr_sleeper/proc/new_player(mob/living/carbon/human/H, location, datum/outfit/outfit, transfer = TRUE) + if(!H) + return + cleanup_vr_mob() + vr_mob = new virtual_mob_type(location) + if(vr_mob.build_virtual_character(H, outfit)) + var/mob/living/carbon/human/vr_H = vr_mob + vr_H.updateappearance(TRUE, TRUE, TRUE) + if(!transfer || !H.mind) + return + vr_mob.AddComponent(/datum/component/virtual_reality, H, src, you_die_in_the_game_you_die_for_real) -/obj/machinery/vr_sleeper/proc/cleanup_vr_human() - if(vr_human) - vr_human.vr_sleeper = null // Prevents race condition where a new human could get created out of order and set to null. - QDEL_NULL(vr_human) +/obj/machinery/vr_sleeper/proc/cleanup_vr_mob() + if(vr_mob) + QDEL_NULL(vr_mob) /obj/machinery/vr_sleeper/proc/emagNotify() - if(vr_human) - vr_human.Dizzy(10) + if(vr_mob) + vr_mob.Dizzy(10) /obj/effect/landmark/vr_spawn //places you can spawn in VR, auto selected by the vr_sleeper during get_vr_spawnpoint() var/vr_category = "default" //So we can have specific sleepers, eg: "Basketball VR Sleeper", etc. @@ -218,6 +207,7 @@ color = "#00FF00" invisibility = INVISIBILITY_ABSTRACT var/area/vr_area + var/list/corpse_party /obj/effect/vr_clean_master/Initialize() . = ..() @@ -230,7 +220,8 @@ qdel(casing) for(var/obj/effect/decal/cleanable/C in vr_area) qdel(C) - for (var/mob/living/carbon/human/virtual_reality/H in vr_area) - if (H.stat == DEAD && !H.vr_sleeper && !H.real_mind) - qdel(H) + for (var/A in corpse_party) + var/mob/M = A + if(get_area(M) == vr_area && M.stat == DEAD) + qdel(M) addtimer(CALLBACK(src, .proc/clean_up), 3 MINUTES) diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index b400f44b98..555c35980d 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -423,6 +423,25 @@ if(GLOB.master_mode == "secret") dat += "(Force Secret Mode)
" + if(GLOB.master_mode == "dynamic") + if(SSticker.current_state <= GAME_STATE_PREGAME) + dat += "(Force Roundstart Rulesets)
" + if (GLOB.dynamic_forced_roundstart_ruleset.len > 0) + for(var/datum/dynamic_ruleset/roundstart/rule in GLOB.dynamic_forced_roundstart_ruleset) + dat += {"-> [rule.name] <-
"} + dat += "(Clear Rulesets)
" + dat += "(Dynamic mode options)
" + else if (SSticker.IsRoundInProgress()) + dat += "(Force Next Latejoin Ruleset)
" + if (SSticker && SSticker.mode && istype(SSticker.mode,/datum/game_mode/dynamic)) + var/datum/game_mode/dynamic/mode = SSticker.mode + if (mode.forced_latejoin_rule) + dat += {"-> [mode.forced_latejoin_rule.name] <-
"} + dat += "(Execute Midround Ruleset!)
" + dat += "
" + if(SSticker.IsRoundInProgress()) + dat += "(Game Mode Panel)
" + dat += {"
Create Object
@@ -839,6 +858,44 @@ browser.set_content(dat.Join()) browser.open() +/datum/admins/proc/dynamic_mode_options(mob/user) + var/dat = {" +

Dynamic Mode Options


+
+

Common options

+ All these options can be changed midround.
+
+ Force extended: - Option is [GLOB.dynamic_forced_extended ? "ON" : "OFF"]. +
This will force the round to be extended. No rulesets will be drafted.
+
+ No stacking: - Option is [GLOB.dynamic_no_stacking ? "ON" : "OFF"]. +
Unless the threat goes above [GLOB.dynamic_stacking_limit], only one "round-ender" ruleset will be drafted.
+
+ Classic secret mode: - Option is [GLOB.dynamic_classic_secret ? "ON" : "OFF"]. +
Only one roundstart ruleset will be drafted. Only traitors and minor roles will latespawn.
+
+
+ Forced threat level: Current value : [GLOB.dynamic_forced_threat_level]. +
The value threat is set to if it is higher than -1.
+
+ High population limit: Current value : [GLOB.dynamic_high_pop_limit]. +
The threshold at which "high population override" will be in effect.
+
+ Stacking threeshold: Current value : [GLOB.dynamic_stacking_limit]. +
The threshold at which "round-ender" rulesets will stack. A value higher than 100 ensure this never happens.
+

Advanced parameters

+ Curve centre: -> [GLOB.dynamic_curve_centre] <-
+ Curve width: -> [GLOB.dynamic_curve_width] <-
+ Latejoin injection delay:
+ Minimum: -> [GLOB.dynamic_latejoin_delay_min / 60 / 10] <- Minutes
+ Maximum: -> [GLOB.dynamic_latejoin_delay_max / 60 / 10] <- Minutes
+ Midround injection delay:
+ Minimum: -> [GLOB.dynamic_midround_delay_min / 60 / 10] <- Minutes
+ Maximum: -> [GLOB.dynamic_midround_delay_max / 60 / 10] <- Minutes
+ "} + + user << browse(dat, "window=dyn_mode_options;size=900x650") + /datum/admins/proc/create_or_modify_area() set category = "Debug" set name = "Create or modify area" diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index ac1ae51f69..626fa7f66f 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -169,6 +169,7 @@ GLOBAL_LIST_INIT(admin_verbs_debug, world.AVerbsDebug()) /client/proc/cmd_display_overlay_log, /client/proc/reload_configuration, /datum/admins/proc/create_or_modify_area, + /client/proc/generate_wikichem_list //DO NOT PRESS UNLESS YOU WANT SUPERLAG ) GLOBAL_PROTECT(admin_verbs_possess) GLOBAL_LIST_INIT(admin_verbs_possess, list(/proc/possess, /proc/release)) diff --git a/code/modules/admin/create_mob.dm b/code/modules/admin/create_mob.dm index f66cda42dc..cff7faadd8 100644 --- a/code/modules/admin/create_mob.dm +++ b/code/modules/admin/create_mob.dm @@ -34,8 +34,10 @@ H.dna.features["frills"] = pick(GLOB.frills_list) H.dna.features["spines"] = pick(GLOB.spines_list) H.dna.features["body_markings"] = pick(GLOB.body_markings_list) - H.dna.features["moth_wings"] = pick(GLOB.moth_wings_list) + H.dna.features["insect_wings"] = pick(GLOB.insect_wings_list) + H.dna.features["deco_wings"] = pick(GLOB.deco_wings_list) + H.dna.features["insect_fluff"] = pick(GLOB.insect_fluffs_list) H.update_body() H.update_hair() - H.update_body_parts() \ No newline at end of file + H.update_body_parts() diff --git a/code/modules/admin/fun_balloon.dm b/code/modules/admin/fun_balloon.dm index da811a1974..81050e6eae 100644 --- a/code/modules/admin/fun_balloon.dm +++ b/code/modules/admin/fun_balloon.dm @@ -61,7 +61,7 @@ to_chat(body, "Your mob has been taken over by a ghost!") message_admins("[key_name_admin(C)] has taken control of ([key_name_admin(body)])") body.ghostize(0) - body.key = C.key + C.transfer_ckey(body) new /obj/effect/temp_visual/gravpush(get_turf(body)) /obj/effect/fun_balloon/sentience/emergency_shuttle diff --git a/code/modules/admin/secrets.dm b/code/modules/admin/secrets.dm index 7d74387c43..58fd627c74 100644 --- a/code/modules/admin/secrets.dm +++ b/code/modules/admin/secrets.dm @@ -458,7 +458,7 @@ SSblackbox.record_feedback("nested tally", "admin_secrets_fun_used", 1, list("Mass Braindamage")) for(var/mob/living/carbon/human/H in GLOB.player_list) to_chat(H, "You suddenly feel stupid.") - H.adjustBrainLoss(60, 80) + H.adjustOrganLoss(ORGAN_SLOT_BRAIN, 60, 80) message_admins("[key_name_admin(usr)] made everybody retarded") if("eagles")//SCRAW @@ -744,7 +744,7 @@ var/mob/chosen = players[1] if (chosen.client) chosen.client.prefs.copy_to(spawnedMob) - spawnedMob.key = chosen.key + chosen.transfer_ckey(spawnedMob) players -= chosen if (ishuman(spawnedMob) && ispath(humanoutfit, /datum/outfit)) var/mob/living/carbon/human/H = spawnedMob diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index d881044757..b0b9190556 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -291,6 +291,11 @@ else if(href_list["editrights"]) edit_rights_topic(href_list) + else if(href_list["gamemode_panel"]) + if(!check_rights(R_ADMIN)) + return + SSticker.mode.admin_panel() + else if(href_list["call_shuttle"]) if(!check_rights(R_ADMIN)) return @@ -1342,6 +1347,291 @@ else if(href_list["f_secret"]) return HandleFSecret() + + else if(href_list["f_dynamic_roundstart"]) + if(!check_rights(R_ADMIN)) + return + if(SSticker && SSticker.mode) + return alert(usr, "The game has already started.", null, null, null, null) + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode.", null, null, null, null) + var/roundstart_rules = list() + for (var/rule in subtypesof(/datum/dynamic_ruleset/roundstart)) + var/datum/dynamic_ruleset/roundstart/newrule = new rule() + roundstart_rules[newrule.name] = newrule + var/added_rule = input(usr,"What ruleset do you want to force? This will bypass threat level and population restrictions.", "Rigging Roundstart", null) as null|anything in roundstart_rules + if (added_rule) + GLOB.dynamic_forced_roundstart_ruleset += roundstart_rules[added_rule] + log_admin("[key_name(usr)] set [added_rule] to be a forced roundstart ruleset.") + message_admins("[key_name(usr)] set [added_rule] to be a forced roundstart ruleset.", 1) + Game() + + else if(href_list["f_dynamic_roundstart_clear"]) + if(!check_rights(R_ADMIN)) + return + GLOB.dynamic_forced_roundstart_ruleset = list() + Game() + log_admin("[key_name(usr)] cleared the rigged roundstart rulesets. The mode will pick them as normal.") + message_admins("[key_name(usr)] cleared the rigged roundstart rulesets. The mode will pick them as normal.", 1) + + else if(href_list["f_dynamic_roundstart_remove"]) + if(!check_rights(R_ADMIN)) + return + var/datum/dynamic_ruleset/roundstart/rule = locate(href_list["f_dynamic_roundstart_remove"]) + GLOB.dynamic_forced_roundstart_ruleset -= rule + Game() + log_admin("[key_name(usr)] removed [rule] from the forced roundstart rulesets.") + message_admins("[key_name(usr)] removed [rule] from the forced roundstart rulesets.", 1) + + else if(href_list["f_dynamic_latejoin"]) + if(!check_rights(R_ADMIN)) + return + if(!SSticker || !SSticker.mode) + return alert(usr, "The game must start first.", null, null, null, null) + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + var/latejoin_rules = list() + for (var/rule in subtypesof(/datum/dynamic_ruleset/latejoin)) + var/datum/dynamic_ruleset/latejoin/newrule = new rule() + latejoin_rules[newrule.name] = newrule + var/added_rule = input(usr,"What ruleset do you want to force upon the next latejoiner? This will bypass threat level and population restrictions.", "Rigging Latejoin", null) as null|anything in latejoin_rules + if (added_rule) + var/datum/game_mode/dynamic/mode = SSticker.mode + mode.forced_latejoin_rule = latejoin_rules[added_rule] + log_admin("[key_name(usr)] set [added_rule] to proc on the next latejoin.") + message_admins("[key_name(usr)] set [added_rule] to proc on the next latejoin.", 1) + Game() + + else if(href_list["f_dynamic_latejoin_clear"]) + if(!check_rights(R_ADMIN)) + return + if (SSticker && SSticker.mode && istype(SSticker.mode,/datum/game_mode/dynamic)) + var/datum/game_mode/dynamic/mode = SSticker.mode + mode.forced_latejoin_rule = null + Game() + log_admin("[key_name(usr)] cleared the forced latejoin ruleset.") + message_admins("[key_name(usr)] cleared the forced latejoin ruleset.", 1) + + else if(href_list["f_dynamic_midround"]) + if(!check_rights(R_ADMIN)) + return + if(!SSticker || !SSticker.mode) + return alert(usr, "The game must start first.", null, null, null, null) + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + var/midround_rules = list() + for (var/rule in subtypesof(/datum/dynamic_ruleset/midround)) + var/datum/dynamic_ruleset/midround/newrule = new rule() + midround_rules[newrule.name] = rule + var/added_rule = input(usr,"What ruleset do you want to force right now? This will bypass threat level and population restrictions.", "Execute Ruleset", null) as null|anything in midround_rules + if (added_rule) + var/datum/game_mode/dynamic/mode = SSticker.mode + log_admin("[key_name(usr)] executed the [added_rule] ruleset.") + message_admins("[key_name(usr)] executed the [added_rule] ruleset.", 1) + mode.picking_specific_rule(midround_rules[added_rule],1) + + else if (href_list["f_dynamic_options"]) + if(!check_rights(R_ADMIN)) + return + + if(SSticker && SSticker.mode) + return alert(usr, "The game has already started.", null, null, null, null) + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + + dynamic_mode_options(usr) + + else if(href_list["f_dynamic_roundstart_centre"]) + if(!check_rights(R_ADMIN)) + return + if(SSticker && SSticker.mode) + return alert(usr, "The game has already started.", null, null, null, null) + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + + var/new_centre = input(usr,"Change the centre of the dynamic mode threat curve. A negative value will give a more peaceful round ; a positive value, a round with higher threat. Any number between -5 and +5 is allowed.", "Change curve centre", null) as num + if (new_centre < -5 || new_centre > 5) + return alert(usr, "Only values between -5 and +5 are allowed.", null, null, null, null) + + log_admin("[key_name(usr)] changed the distribution curve center to [new_centre].") + message_admins("[key_name(usr)] changed the distribution curve center to [new_centre]", 1) + GLOB.dynamic_curve_centre = new_centre + dynamic_mode_options(usr) + + else if(href_list["f_dynamic_roundstart_width"]) + if(!check_rights(R_ADMIN)) + return + if(SSticker && SSticker.mode) + return alert(usr, "The game has already started.", null, null, null, null) + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + + var/new_width = input(usr,"Change the width of the dynamic mode threat curve. A higher value will favour extreme rounds ; a lower value, a round closer to the average. Any Number between 0.5 and 4 are allowed.", "Change curve width", null) as num + if (new_width < 0.5 || new_width > 4) + return alert(usr, "Only values between 0.5 and +2.5 are allowed.", null, null, null, null) + + log_admin("[key_name(usr)] changed the distribution curve width to [new_width].") + message_admins("[key_name(usr)] changed the distribution curve width to [new_width]", 1) + GLOB.dynamic_curve_width = new_width + dynamic_mode_options(usr) + + else if(href_list["f_dynamic_roundstart_latejoin_min"]) + if(!check_rights(R_ADMIN)) + return + if(SSticker && SSticker.mode) + return alert(usr, "The game has already started.", null, null, null, null) + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + var/new_min = input(usr,"Change the minimum delay of latejoin injection in minutes.", "Change latejoin injection delay minimum", null) as num + if(new_min <= 0) + return alert(usr, "The minimum can't be zero or lower.", null, null, null, null) + if((new_min MINUTES) > GLOB.dynamic_latejoin_delay_max) + return alert(usr, "The minimum must be lower than the maximum.", null, null, null, null) + + log_admin("[key_name(usr)] changed the latejoin injection minimum delay to [new_min] minutes.") + message_admins("[key_name(usr)] changed the latejoin injection minimum delay to [new_min] minutes", 1) + GLOB.dynamic_latejoin_delay_min = (new_min MINUTES) + dynamic_mode_options(usr) + + else if(href_list["f_dynamic_roundstart_latejoin_max"]) + if(!check_rights(R_ADMIN)) + return + if(SSticker && SSticker.mode) + return alert(usr, "The game has already started.", null, null, null, null) + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + var/new_max = input(usr,"Change the maximum delay of latejoin injection in minutes.", "Change latejoin injection delay maximum", null) as num + if(new_max <= 0) + return alert(usr, "The maximum can't be zero or lower.", null, null, null, null) + if((new_max MINUTES) < GLOB.dynamic_latejoin_delay_min) + return alert(usr, "The maximum must be higher than the minimum.", null, null, null, null) + + log_admin("[key_name(usr)] changed the latejoin injection maximum delay to [new_max] minutes.") + message_admins("[key_name(usr)] changed the latejoin injection maximum delay to [new_max] minutes", 1) + GLOB.dynamic_latejoin_delay_max = (new_max MINUTES) + dynamic_mode_options(usr) + + else if(href_list["f_dynamic_roundstart_midround_min"]) + if(!check_rights(R_ADMIN)) + return + if(SSticker && SSticker.mode) + return alert(usr, "The game has already started.", null, null, null, null) + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + var/new_min = input(usr,"Change the minimum delay of midround injection in minutes.", "Change midround injection delay minimum", null) as num + if(new_min <= 0) + return alert(usr, "The minimum can't be zero or lower.", null, null, null, null) + if((new_min MINUTES) > GLOB.dynamic_midround_delay_max) + return alert(usr, "The minimum must be lower than the maximum.", null, null, null, null) + + log_admin("[key_name(usr)] changed the midround injection minimum delay to [new_min] minutes.") + message_admins("[key_name(usr)] changed the midround injection minimum delay to [new_min] minutes", 1) + GLOB.dynamic_midround_delay_min = (new_min MINUTES) + dynamic_mode_options(usr) + + else if(href_list["f_dynamic_roundstart_midround_max"]) + if(!check_rights(R_ADMIN)) + return + if(SSticker && SSticker.mode) + return alert(usr, "The game has already started.", null, null, null, null) + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + var/new_max = input(usr,"Change the maximum delay of midround injection in minutes.", "Change midround injection delay maximum", null) as num + if(new_max <= 0) + return alert(usr, "The maximum can't be zero or lower.", null, null, null, null) + if((new_max MINUTES) > GLOB.dynamic_midround_delay_max) + return alert(usr, "The maximum must be higher than the minimum.", null, null, null, null) + + log_admin("[key_name(usr)] changed the midround injection maximum delay to [new_max] minutes.") + message_admins("[key_name(usr)] changed the midround injection maximum delay to [new_max] minutes", 1) + GLOB.dynamic_midround_delay_max = (new_max MINUTES) + dynamic_mode_options(usr) + + else if(href_list["f_dynamic_force_extended"]) + if(!check_rights(R_ADMIN)) + return + + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + + GLOB.dynamic_forced_extended = !GLOB.dynamic_forced_extended + log_admin("[key_name(usr)] set 'forced_extended' to [GLOB.dynamic_forced_extended].") + message_admins("[key_name(usr)] set 'forced_extended' to [GLOB.dynamic_forced_extended].") + dynamic_mode_options(usr) + + else if(href_list["f_dynamic_no_stacking"]) + if(!check_rights(R_ADMIN)) + return + + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + + GLOB.dynamic_no_stacking = !GLOB.dynamic_no_stacking + log_admin("[key_name(usr)] set 'no_stacking' to [GLOB.dynamic_no_stacking].") + message_admins("[key_name(usr)] set 'no_stacking' to [GLOB.dynamic_no_stacking].") + dynamic_mode_options(usr) + + else if(href_list["f_dynamic_classic_secret"]) + if(!check_rights(R_ADMIN)) + return + + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + + GLOB.dynamic_classic_secret = !GLOB.dynamic_classic_secret + log_admin("[key_name(usr)] set 'classic_secret' to [GLOB.dynamic_classic_secret].") + message_admins("[key_name(usr)] set 'classic_secret' to [GLOB.dynamic_classic_secret].") + dynamic_mode_options(usr) + + else if(href_list["f_dynamic_stacking_limit"]) + if(!check_rights(R_ADMIN)) + return + + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + + GLOB.dynamic_stacking_limit = input(usr,"Change the threat limit at which round-endings rulesets will start to stack.", "Change stacking limit", null) as num + log_admin("[key_name(usr)] set 'stacking_limit' to [GLOB.dynamic_stacking_limit].") + message_admins("[key_name(usr)] set 'stacking_limit' to [GLOB.dynamic_stacking_limit].") + dynamic_mode_options(usr) + + else if(href_list["f_dynamic_high_pop_limit"]) + if(!check_rights(R_ADMIN)) + return + + if(SSticker && SSticker.mode) + return alert(usr, "The game has already started.", null, null, null, null) + + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + + var/new_value = input(usr, "Enter the high-pop override threshold for dynamic mode.", "High pop override") as num + if (new_value < 0) + return alert(usr, "Only positive values allowed!", null, null, null, null) + GLOB.dynamic_high_pop_limit = new_value + + log_admin("[key_name(usr)] set 'high_pop_limit' to [GLOB.dynamic_high_pop_limit].") + message_admins("[key_name(usr)] set 'high_pop_limit' to [GLOB.dynamic_high_pop_limit].") + dynamic_mode_options(usr) + + else if(href_list["f_dynamic_forced_threat"]) + if(!check_rights(R_ADMIN)) + return + + if(SSticker && SSticker.mode) + return alert(usr, "The game has already started.", null, null, null, null) + + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + + var/new_value = input(usr, "Enter the forced threat level for dynamic mode.", "Forced threat level") as num + if (new_value > 100) + return alert(usr, "The value must be be under 100.", null, null, null, null) + GLOB.dynamic_forced_threat_level = new_value + + log_admin("[key_name(usr)] set 'forced_threat_level' to [GLOB.dynamic_forced_threat_level].") + message_admins("[key_name(usr)] set 'forced_threat_level' to [GLOB.dynamic_forced_threat_level].") + dynamic_mode_options(usr) else if(href_list["c_mode2"]) if(!check_rights(R_ADMIN|R_SERVER)) @@ -1752,7 +2042,7 @@ if(DEAD) status = "Dead" health_description = "Status = [status]" - health_description += "
Oxy: [L.getOxyLoss()] - Tox: [L.getToxLoss()] - Fire: [L.getFireLoss()] - Brute: [L.getBruteLoss()] - Clone: [L.getCloneLoss()] - Brain: [L.getBrainLoss()] - Stamina: [L.getStaminaLoss()]" + health_description += "
Oxy: [L.getOxyLoss()] - Tox: [L.getToxLoss()] - Fire: [L.getFireLoss()] - Brute: [L.getBruteLoss()] - Clone: [L.getCloneLoss()] - Brain: [L.getOrganLoss(ORGAN_SLOT_BRAIN)] - Stamina: [L.getStaminaLoss()]" else health_description = "This mob type has no health to speak of." diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm index 91fdc78d20..4e58a9cba5 100644 --- a/code/modules/admin/verbs/adminhelp.dm +++ b/code/modules/admin/verbs/adminhelp.dm @@ -413,9 +413,9 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) dat += "CLOSED" else dat += "UNKNOWN" - dat += "
[GLOB.TAB][TicketHref("Refresh", ref_src)][GLOB.TAB][TicketHref("Re-Title", ref_src, "retitle")]" + dat += "[FOURSPACES][TicketHref("Refresh", ref_src)][FOURSPACES][TicketHref("Re-Title", ref_src, "retitle")]" if(state != AHELP_ACTIVE) - dat += "[GLOB.TAB][TicketHref("Reopen", ref_src, "reopen")]" + dat += "[FOURSPACES][TicketHref("Reopen", ref_src, "reopen")]" dat += "

Opened at: [GAMETIMESTAMP("hh:mm:ss", closed_at)] (Approx [DisplayTimeText(world.time - opened_at)] ago)" if(closed_at) dat += "
Closed at: [GAMETIMESTAMP("hh:mm:ss", closed_at)] (Approx [DisplayTimeText(world.time - closed_at)] ago)" @@ -423,7 +423,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) if(initiator) dat += "Actions: [FullMonty(ref_src)]
" else - dat += "DISCONNECTED[GLOB.TAB][ClosureLinks(ref_src)]
" + dat += "DISCONNECTED[FOURSPACES][ClosureLinks(ref_src)]
" dat += "
Log:

" for(var/I in _interactions) dat += "[I]
" diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index e15613c43d..53fdb315b5 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -306,7 +306,7 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention) var/mob/living/silicon/pai/pai = new(card) pai.name = input(choice, "Enter your pAI name:", "pAI Name", "Personal AI") as text pai.real_name = pai.name - pai.key = choice.key + choice.transfer_ckey(pai) card.setPersonality(pai) for(var/datum/paiCandidate/candidate in SSpai.candidates) if(candidate.key == choice.key) diff --git a/code/modules/admin/verbs/modifyvariables.dm b/code/modules/admin/verbs/modifyvariables.dm index 5b74ae7c5b..e70ea1c1b3 100644 --- a/code/modules/admin/verbs/modifyvariables.dm +++ b/code/modules/admin/verbs/modifyvariables.dm @@ -534,7 +534,7 @@ GLOBAL_PROTECT(VVpixelmovement) if (prompt != "Continue") return FALSE return TRUE - + /client/proc/modify_variables(atom/O, param_var_name = null, autodetect_class = 0) if(!check_rights(R_VAREDIT)) @@ -545,7 +545,7 @@ GLOBAL_PROTECT(VVpixelmovement) var/var_value if(param_var_name) - if(!param_var_name in O.vars) + if(!(param_var_name in O.vars)) to_chat(src, "A variable with this name ([param_var_name]) doesn't exist in this datum ([O])") return variable = param_var_name diff --git a/code/modules/admin/verbs/one_click_antag.dm b/code/modules/admin/verbs/one_click_antag.dm index d9732818bd..09a8f692d8 100644 --- a/code/modules/admin/verbs/one_click_antag.dm +++ b/code/modules/admin/verbs/one_click_antag.dm @@ -412,7 +412,7 @@ //Spawn the body var/mob/living/carbon/human/ERTOperative = new ertemplate.mobtype(spawnloc) chosen_candidate.client.prefs.copy_to(ERTOperative) - ERTOperative.key = chosen_candidate.key + chosen_candidate.transfer_ckey(ERTOperative) if(ertemplate.enforce_human || ERTOperative.dna.species.dangerous_existence) // Don't want any exploding plasmemes ERTOperative.set_species(/datum/species/human) diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index a725399b0f..246ccb1d07 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -384,7 +384,7 @@ Traitors and the like can also be revived with the previous role mostly intact. //Now to give them their mind back. G_found.mind.transfer_to(new_xeno) //be careful when doing stuff like this! I've already checked the mind isn't in use - new_xeno.key = G_found.key + G_found.transfer_ckey(new_xeno, FALSE) to_chat(new_xeno, "You have been fully respawned. Enjoy the game.") var/msg = "[key_name_admin(usr)] has respawned [new_xeno.key] as a filthy xeno." message_admins(msg) @@ -397,7 +397,7 @@ Traitors and the like can also be revived with the previous role mostly intact. var/mob/living/carbon/monkey/new_monkey = new SSjob.SendToLateJoin(new_monkey) G_found.mind.transfer_to(new_monkey) //be careful when doing stuff like this! I've already checked the mind isn't in use - new_monkey.key = G_found.key + G_found.transfer_ckey(new_monkey, FALSE) to_chat(new_monkey, "You have been fully respawned. Enjoy the game.") var/msg = "[key_name_admin(usr)] has respawned [new_monkey.key] as a filthy xeno." message_admins(msg) @@ -437,7 +437,7 @@ Traitors and the like can also be revived with the previous role mostly intact. if(!new_character.mind.assigned_role) new_character.mind.assigned_role = "Assistant"//If they somehow got a null assigned role. - new_character.key = G_found.key + G_found.transfer_ckey(new_character, FALSE) /* The code below functions with the assumption that the mob is already a traitor if they have a special role. @@ -1264,7 +1264,7 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits target.electrocution_animation(40) to_chat(target, "The gods have punished you for your sins!") if(ADMIN_PUNISHMENT_BRAINDAMAGE) - target.adjustBrainLoss(199, 199) + target.adjustOrganLoss(ORGAN_SLOT_BRAIN, 199, 199) if(ADMIN_PUNISHMENT_GIB) target.gib(FALSE) if(ADMIN_PUNISHMENT_BSA) diff --git a/code/modules/antagonists/_common/antag_datum.dm b/code/modules/antagonists/_common/antag_datum.dm index aa91af1dd8..42719e28bd 100644 --- a/code/modules/antagonists/_common/antag_datum.dm +++ b/code/modules/antagonists/_common/antag_datum.dm @@ -15,7 +15,7 @@ GLOBAL_LIST_EMPTY(antagonists) var/antag_memory = ""//These will be removed with antag datum var/antag_moodlet //typepath of moodlet that the mob will gain with their status var/can_hijack = HIJACK_NEUTRAL //If these antags are alone on shuttle hijack happens. - + //Antag panel properties var/show_in_antagpanel = TRUE //This will hide adding this antag type in antag panel, use only for internal subtypes that shouldn't be added directly but still show if possessed by mind var/antagpanel_category = "Uncategorized" //Antagpanel will display these together, REQUIRED @@ -87,7 +87,7 @@ GLOBAL_LIST_EMPTY(antagonists) to_chat(owner, "Your mob has been taken over by a ghost! Appeal your job ban if you want to avoid this in the future!") message_admins("[key_name_admin(C)] has taken control of ([key_name_admin(owner.current)]) to replace a jobbaned player.") owner.current.ghostize(0) - owner.current.key = C.key + C.transfer_ckey(owner.current, FALSE) /datum/antagonist/proc/on_removal() remove_innate_effects() diff --git a/code/modules/antagonists/abductor/abductor.dm b/code/modules/antagonists/abductor/abductor.dm index 8e29b38fe1..e8d30e8dbe 100644 --- a/code/modules/antagonists/abductor/abductor.dm +++ b/code/modules/antagonists/abductor/abductor.dm @@ -26,7 +26,7 @@ sub_role = "Scientist" outfit = /datum/outfit/abductor/scientist landmark_type = /obj/effect/landmark/abductor/scientist - greet_text = "Use your stealth technology and equipment to incapacitate humans for your scientist to retrieve." + greet_text = "Use your experimental console and surgical equipment to monitor your agent and experiment upon abducted humans." show_in_antagpanel = TRUE /datum/antagonist/abductor/create_team(datum/team/abductor_team/new_team) @@ -40,22 +40,24 @@ return team /datum/antagonist/abductor/on_gain() - owner.special_role = "[name] [sub_role]" - owner.assigned_role = "[name] [sub_role]" - owner.objectives += team.objectives + owner.special_role = "[name]" + owner.assigned_role = "[name]" + objectives += team.objectives finalize_abductor() + ADD_TRAIT(owner, TRAIT_ABDUCTOR_TRAINING, ABDUCTOR_ANTAGONIST) return ..() /datum/antagonist/abductor/on_removal() - owner.objectives -= team.objectives if(owner.current) to_chat(owner.current,"You are no longer the [owner.special_role]!") owner.special_role = null + REMOVE_TRAIT(owner, TRAIT_ABDUCTOR_TRAINING, ABDUCTOR_ANTAGONIST) return ..() /datum/antagonist/abductor/greet() to_chat(owner.current, "You are the [owner.special_role]!") to_chat(owner.current, "With the help of your teammate, kidnap and experiment on station crew members!") + to_chat(owner.current, "Try not to disturb the habitat, it could lead to dead specimens.") to_chat(owner.current, "[greet_text]") owner.announce_objectives() @@ -63,6 +65,7 @@ //Equip var/mob/living/carbon/human/H = owner.current H.set_species(/datum/species/abductor) + H.real_name = "[team.name] [sub_role]" H.equipOutfit(outfit) @@ -74,11 +77,15 @@ update_abductor_icons_added(owner,"abductor") -/datum/antagonist/abductor/scientist/finalize_abductor() - ..() - var/mob/living/carbon/human/H = owner.current - var/datum/species/abductor/A = H.dna.species - A.scientist = TRUE +/datum/antagonist/abductor/scientist/on_gain() + ADD_TRAIT(owner, TRAIT_ABDUCTOR_SCIENTIST_TRAINING, ABDUCTOR_ANTAGONIST) + ADD_TRAIT(owner, TRAIT_SURGEON, ABDUCTOR_ANTAGONIST) + . = ..() + +/datum/antagonist/abductor/scientist/on_removal() + REMOVE_TRAIT(owner, TRAIT_ABDUCTOR_SCIENTIST_TRAINING, ABDUCTOR_ANTAGONIST) + REMOVE_TRAIT(owner, TRAIT_SURGEON, ABDUCTOR_ANTAGONIST) + . = ..() /datum/antagonist/abductor/admin_add(datum/mind/new_owner,mob/admin) var/list/current_teams = list() @@ -92,8 +99,8 @@ else return new_owner.add_antag_datum(src) - log_admin("[key_name(usr)] made [key_name(new_owner.current)] [name] on [choice]!") - message_admins("[key_name_admin(usr)] made [key_name_admin(new_owner.current)] [name] on [choice] !") + log_admin("[key_name(usr)] made [key_name(new_owner)] [name] on [choice]!") + message_admins("[key_name_admin(usr)] made [key_name_admin(new_owner)] [name] on [choice] !") /datum/antagonist/abductor/get_admin_commands() . = ..() @@ -146,7 +153,7 @@ result += "The abductors of [name] were:" for(var/datum/mind/abductor_mind in members) result += printplayer(abductor_mind) - result += printobjectives(abductor_mind) + result += printobjectives(objectives) return "
[result.Join("
")]
" @@ -171,7 +178,6 @@ var/objtype = (prob(75) ? /datum/objective/abductee/random : pick(subtypesof(/datum/objective/abductee/) - /datum/objective/abductee/random)) var/datum/objective/abductee/O = new objtype() objectives += O - owner.objectives += objectives /datum/antagonist/abductee/apply_innate_effects(mob/living/mob_override) update_abductor_icons_added(mob_override ? mob_override.mind : owner,"abductee") @@ -213,4 +219,4 @@ /datum/antagonist/proc/update_abductor_icons_removed(datum/mind/alien_mind) var/datum/atom_hud/antag/hud = GLOB.huds[ANTAG_HUD_ABDUCTOR] hud.leave_hud(alien_mind.current) - set_antag_hud(alien_mind.current, null) \ No newline at end of file + set_antag_hud(alien_mind.current, null) diff --git a/code/modules/antagonists/abductor/equipment/abduction_gear.dm b/code/modules/antagonists/abductor/equipment/abduction_gear.dm index 1573204d88..ed26b894d9 100644 --- a/code/modules/antagonists/abductor/equipment/abduction_gear.dm +++ b/code/modules/antagonists/abductor/equipment/abduction_gear.dm @@ -132,22 +132,26 @@ /obj/item/abductor icon = 'icons/obj/abductor.dmi' -/obj/item/abductor/proc/AbductorCheck(user) - if(isabductor(user)) +/obj/item/abductor/proc/AbductorCheck(mob/user) + if(HAS_TRAIT(user, TRAIT_ABDUCTOR_TRAINING)) + return TRUE + if (istype(user) && user.mind && HAS_TRAIT(user.mind, TRAIT_ABDUCTOR_TRAINING)) return TRUE to_chat(user, "You can't figure how this works!") return FALSE -/obj/item/abductor/proc/ScientistCheck(user) - if(!AbductorCheck(user)) - return FALSE +/obj/item/abductor/proc/ScientistCheck(mob/user) + var/training = HAS_TRAIT(user, TRAIT_ABDUCTOR_TRAINING) || (user.mind && HAS_TRAIT(user.mind, TRAIT_ABDUCTOR_TRAINING)) + var/sci_training = HAS_TRAIT(user, TRAIT_ABDUCTOR_SCIENTIST_TRAINING) || (user.mind && HAS_TRAIT(user.mind, TRAIT_ABDUCTOR_SCIENTIST_TRAINING)) - var/mob/living/carbon/human/H = user - var/datum/species/abductor/S = H.dna.species - if(S.scientist) - return TRUE - to_chat(user, "You're not trained to use this!") - return FALSE + if(training && !sci_training) + to_chat(user, "You're not trained to use this!") + . = FALSE + else if(!training && !sci_training) + to_chat(user, "You can't figure how this works!") + . = FALSE + else + . = TRUE /obj/item/abductor/gizmo name = "science tool" @@ -683,7 +687,7 @@ Congratulations! You are now trained for invasive xenobiology research!"} desc = "Abduct with style - spiky style. Prevents digital tracking." icon_state = "alienhelmet" item_state = "alienhelmet" - blockTracking = 1 + blockTracking = TRUE flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR // Operating Table / Beds / Lockers diff --git a/code/modules/antagonists/abductor/equipment/abduction_outfits.dm b/code/modules/antagonists/abductor/equipment/abduction_outfits.dm index a69c8fdeff..7e03bbf57a 100644 --- a/code/modules/antagonists/abductor/equipment/abduction_outfits.dm +++ b/code/modules/antagonists/abductor/equipment/abduction_outfits.dm @@ -52,5 +52,5 @@ /datum/outfit/abductor/scientist/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) ..() if(!visualsOnly) - var/obj/item/implant/abductor/beamplant = new /obj/item/implant/abductor(H) + var/obj/item/implant/abductor/beamplant = new beamplant.implant(H) diff --git a/code/modules/antagonists/abductor/equipment/abduction_surgery.dm b/code/modules/antagonists/abductor/equipment/abduction_surgery.dm index 819dbafd6a..98164de099 100644 --- a/code/modules/antagonists/abductor/equipment/abduction_surgery.dm +++ b/code/modules/antagonists/abductor/equipment/abduction_surgery.dm @@ -1,5 +1,5 @@ /datum/surgery/organ_extraction - name = "experimental dissection" + name = "experimental organ replacement" steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/incise, /datum/surgery_step/extract_organ, /datum/surgery_step/gland_insert) possible_locs = list(BODY_ZONE_CHEST) ignore_clothes = 1 diff --git a/code/modules/antagonists/abductor/equipment/gland.dm b/code/modules/antagonists/abductor/equipment/gland.dm index 8a3ff2186a..a35cbbf0e4 100644 --- a/code/modules/antagonists/abductor/equipment/gland.dm +++ b/code/modules/antagonists/abductor/equipment/gland.dm @@ -5,6 +5,7 @@ icon_state = "gland" status = ORGAN_ROBOTIC beating = TRUE + var/true_name = "baseline placebo referencer" var/cooldown_low = 300 var/cooldown_high = 300 var/next_activation = 0 @@ -16,6 +17,11 @@ var/mind_control_duration = 1800 var/active_mind_control = FALSE +/obj/item/organ/heart/gland/examine(mob/user) + . = ..() + if((user.mind && HAS_TRAIT(user.mind, TRAIT_ABDUCTOR_SCIENTIST_TRAINING)) || isobserver(user)) + to_chat(user, "It is \a [true_name].") + /obj/item/organ/heart/gland/proc/ownerCheck() if(ishuman(owner)) return TRUE @@ -42,19 +48,19 @@ /obj/item/organ/heart/gland/proc/mind_control(command, mob/living/user) if(!ownerCheck() || !mind_control_uses || active_mind_control) - return + return FALSE mind_control_uses-- to_chat(owner, "You suddenly feel an irresistible compulsion to follow an order...") to_chat(owner, "[command]") active_mind_control = TRUE - log_admin("[key_name(user)] sent an abductor mind control message to [key_name(owner)]: [command]") + message_admins("[key_name(user)] sent an abductor mind control message to [key_name(owner)]: [command]") update_gland_hud() addtimer(CALLBACK(src, .proc/clear_mind_control), mind_control_duration) /obj/item/organ/heart/gland/proc/clear_mind_control() if(!ownerCheck() || !active_mind_control) - return + return FALSE to_chat(owner, "You feel the compulsion fade, and you completely forget about your previous orders.") active_mind_control = FALSE @@ -95,6 +101,7 @@ return /obj/item/organ/heart/gland/heals + true_name = "coherency harmonizer" cooldown_low = 200 cooldown_high = 400 uses = -1 @@ -109,6 +116,7 @@ owner.adjustOxyLoss(-20) /obj/item/organ/heart/gland/slime + true_name = "gastric animation galvanizer" cooldown_low = 600 cooldown_high = 1200 uses = -1 @@ -130,6 +138,7 @@ Slime.Leader = owner /obj/item/organ/heart/gland/mindshock + true_name = "neural crosstalk uninhibitor" cooldown_low = 400 cooldown_high = 700 uses = -1 @@ -151,11 +160,12 @@ if(2) to_chat(H, "You hear an annoying buzz in your head.") H.confused += 15 - H.adjustBrainLoss(10, 160) + H.adjustOrganLoss(ORGAN_SLOT_BRAIN, 10, 160) if(3) H.hallucination += 60 /obj/item/organ/heart/gland/pop + true_name = "anthropmorphic translocator" cooldown_low = 900 cooldown_high = 1800 uses = -1 @@ -167,10 +177,11 @@ /obj/item/organ/heart/gland/pop/activate() to_chat(owner, "You feel unlike yourself.") randomize_human(owner) - var/species = pick(list(/datum/species/human, /datum/species/lizard, /datum/species/moth, /datum/species/fly)) + var/species = pick(list(/datum/species/human, /datum/species/lizard, /datum/species/insect, /datum/species/fly)) owner.set_species(species) /obj/item/organ/heart/gland/ventcrawling + true_name = "pliant cartilage enabler" cooldown_low = 1800 cooldown_high = 2400 uses = 1 @@ -183,6 +194,7 @@ owner.ventcrawler = VENTCRAWLER_ALWAYS /obj/item/organ/heart/gland/viral + true_name = "contamination incubator" cooldown_low = 1800 cooldown_high = 2400 uses = 1 @@ -217,6 +229,7 @@ return A /obj/item/organ/heart/gland/trauma + true_name = "white matter randomiser" cooldown_low = 800 cooldown_high = 1200 uses = 5 @@ -235,6 +248,7 @@ owner.gain_trauma_type(BRAIN_TRAUMA_MILD, rand(TRAUMA_RESILIENCE_BASIC, TRAUMA_RESILIENCE_LOBOTOMY)) /obj/item/organ/heart/gland/spiderman + true_name = "araneae cloister accelerator" cooldown_low = 450 cooldown_high = 900 uses = -1 @@ -249,6 +263,7 @@ S.directive = "Protect your nest inside [owner.real_name]." /obj/item/organ/heart/gland/egg + true_name = "roe/enzymatic synthesizer" cooldown_low = 300 cooldown_high = 400 uses = -1 @@ -264,6 +279,7 @@ new /obj/item/reagent_containers/food/snacks/egg/gland(T) /obj/item/organ/heart/gland/electric + true_name = "electron accumulator/discharger" cooldown_low = 800 cooldown_high = 1200 uses = -1 @@ -289,6 +305,7 @@ playsound(get_turf(owner), 'sound/magic/lightningshock.ogg', 50, 1) /obj/item/organ/heart/gland/chem + true_name = "intrinsic pharma-provider" cooldown_low = 50 cooldown_high = 50 uses = -1 @@ -315,6 +332,7 @@ ..() /obj/item/organ/heart/gland/plasma + true_name = "effluvium sanguine-synonym emitter" cooldown_low = 1200 cooldown_high = 1800 uses = -1 diff --git a/code/modules/antagonists/abductor/machinery/camera.dm b/code/modules/antagonists/abductor/machinery/camera.dm index 41cfa6a954..00e48cb1c7 100644 --- a/code/modules/antagonists/abductor/machinery/camera.dm +++ b/code/modules/antagonists/abductor/machinery/camera.dm @@ -55,8 +55,7 @@ actions += set_droppoint_action /obj/machinery/computer/camera_advanced/abductor/proc/IsScientist(mob/living/carbon/human/H) - var/datum/species/abductor/S = H.dna.species - return S.scientist + return HAS_TRAIT(H, TRAIT_ABDUCTOR_SCIENTIST_TRAINING) /datum/action/innate/teleport_in name = "Send To" diff --git a/code/modules/antagonists/abductor/machinery/console.dm b/code/modules/antagonists/abductor/machinery/console.dm index 46d69ba9bb..9a9b1a6ba0 100644 --- a/code/modules/antagonists/abductor/machinery/console.dm +++ b/code/modules/antagonists/abductor/machinery/console.dm @@ -28,7 +28,7 @@ . = ..() if(.) return - if(!isabductor(user)) + if(!HAS_TRAIT(user, TRAIT_ABDUCTOR_TRAINING) && !HAS_TRAIT(user.mind, TRAIT_ABDUCTOR_TRAINING)) to_chat(user, "You start mashing alien buttons at random!") if(do_after(user,100, target = src)) TeleporterSend() diff --git a/code/modules/antagonists/abductor/machinery/pad.dm b/code/modules/antagonists/abductor/machinery/pad.dm index 1cb95fbf05..ab636f7d0e 100644 --- a/code/modules/antagonists/abductor/machinery/pad.dm +++ b/code/modules/antagonists/abductor/machinery/pad.dm @@ -53,4 +53,4 @@ . = ..() var/datum/effect_system/spark_spread/S = new S.set_up(10,0,loc) - S.start() \ No newline at end of file + S.start() diff --git a/code/modules/antagonists/blob/blob/powers.dm b/code/modules/antagonists/blob/blob/powers.dm index 9e915ee0fa..e49d186362 100644 --- a/code/modules/antagonists/blob/blob/powers.dm +++ b/code/modules/antagonists/blob/blob/powers.dm @@ -172,7 +172,7 @@ blobber.adjustHealth(blobber.maxHealth * 0.5) blob_mobs += blobber var/mob/dead/observer/C = pick(candidates) - blobber.key = C.key + C.transfer_ckey(blobber) SEND_SOUND(blobber, sound('sound/effects/blobattack.ogg')) SEND_SOUND(blobber, sound('sound/effects/attackblob.ogg')) to_chat(blobber, "You are a blobbernaut!") diff --git a/code/modules/antagonists/changeling/changeling.dm b/code/modules/antagonists/changeling/changeling.dm index 252e2b5cbe..b6e3d66c35 100644 --- a/code/modules/antagonists/changeling/changeling.dm +++ b/code/modules/antagonists/changeling/changeling.dm @@ -83,7 +83,7 @@ if(istype(C)) var/obj/item/organ/brain/B = C.getorganslot(ORGAN_SLOT_BRAIN) if(B && (B.decoy_override != initial(B.decoy_override))) - B.vital = TRUE + B.organ_flags |= ORGAN_VITAL B.decoy_override = FALSE remove_changeling_powers() . = ..() @@ -340,7 +340,7 @@ if(istype(C)) var/obj/item/organ/brain/B = C.getorganslot(ORGAN_SLOT_BRAIN) if(B) - B.vital = FALSE + B.organ_flags &= ~ORGAN_VITAL B.decoy_override = TRUE update_changeling_icons_added() return diff --git a/code/modules/antagonists/changeling/powers/mutations.dm b/code/modules/antagonists/changeling/powers/mutations.dm index 99d8ae797b..c428c56d45 100644 --- a/code/modules/antagonists/changeling/powers/mutations.dm +++ b/code/modules/antagonists/changeling/powers/mutations.dm @@ -161,11 +161,13 @@ throwforce = 0 //Just to be on the safe side throw_range = 0 throw_speed = 0 + armour_penetration = 20 hitsound = 'sound/weapons/bladeslice.ogg' attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") sharpness = IS_SHARP var/can_drop = FALSE var/fake = FALSE + total_mass = TOTAL_MASS_HAND_REPLACEMENT /obj/item/melee/arm_blade/Initialize(mapload,silent,synthetic) . = ..() diff --git a/code/modules/antagonists/changeling/powers/regenerate.dm b/code/modules/antagonists/changeling/powers/regenerate.dm index a1f8e1ef9b..1b27fa9694 100644 --- a/code/modules/antagonists/changeling/powers/regenerate.dm +++ b/code/modules/antagonists/changeling/powers/regenerate.dm @@ -35,7 +35,7 @@ B = new C.dna.species.mutant_brain() else B = new() - B.vital = FALSE + B.organ_flags &= ~ORGAN_VITAL B.decoy_override = TRUE B.Insert(C) if(ishuman(user)) diff --git a/code/modules/antagonists/changeling/powers/strained_muscles.dm b/code/modules/antagonists/changeling/powers/strained_muscles.dm index baeed8b0b2..081b1181dc 100644 --- a/code/modules/antagonists/changeling/powers/strained_muscles.dm +++ b/code/modules/antagonists/changeling/powers/strained_muscles.dm @@ -5,7 +5,7 @@ name = "Strained Muscles" desc = "We evolve the ability to reduce the acid buildup in our muscles, allowing us to move much faster." helptext = "The strain will make us tired, and we will rapidly become fatigued. Standard weight restrictions, like hardsuits, still apply. Cannot be used in lesser form." - chemical_cost = 0 + chemical_cost = 15 dna_cost = 1 req_human = 1 var/stacks = 0 //Increments every 5 seconds; damage increases over time @@ -15,13 +15,16 @@ action_background_icon_state = "bg_ling" /obj/effect/proc_holder/changeling/strained_muscles/sting_action(mob/living/carbon/user) + var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling) active = !active if(active) to_chat(user, "Our muscles tense and strengthen.") + changeling.chem_recharge_slowdown += 0.5 else REMOVE_TRAIT(user, TRAIT_GOTTAGOFAST, "changeling_muscles") to_chat(user, "Our muscles relax.") - if(stacks >= 10) + changeling.chem_recharge_slowdown -= 0.5 + if(stacks >= 20) to_chat(user, "We collapse in exhaustion.") user.Knockdown(60) user.emote("gasp") @@ -31,6 +34,7 @@ return TRUE /obj/effect/proc_holder/changeling/strained_muscles/proc/muscle_loop(mob/living/carbon/user) + var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling) while(active) ADD_TRAIT(user, TRAIT_GOTTAGOFAST, "changeling_muscles") if(user.stat != CONSCIOUS || user.staminaloss >= 90) @@ -38,13 +42,14 @@ to_chat(user, "Our muscles relax without the energy to strengthen them.") user.Knockdown(40) REMOVE_TRAIT(user, TRAIT_GOTTAGOFAST, "changeling_muscles") + changeling.chem_recharge_slowdown -= 0.5 break stacks++ //user.take_bodypart_damage(stacks * 0.03, 0) - user.staminaloss += stacks * 1.3 //At first the changeling may regenerate stamina fast enough to nullify fatigue, but it will stack + user.adjustStaminaLoss(stacks*1.3) //At first the changeling may regenerate stamina fast enough to nullify fatigue, but it will stack - if(stacks == 11) //Warning message that the stacks are getting too high + if(stacks == 10) //Warning message that the stacks are getting too high to_chat(user, "Our legs are really starting to hurt...") sleep(40) diff --git a/code/modules/antagonists/clockcult/clock_effects/clock_sigils.dm b/code/modules/antagonists/clockcult/clock_effects/clock_sigils.dm index 97d7f0c128..2018067b77 100644 --- a/code/modules/antagonists/clockcult/clock_effects/clock_sigils.dm +++ b/code/modules/antagonists/clockcult/clock_effects/clock_sigils.dm @@ -349,7 +349,7 @@ to_chat(L, "Your physical form has been taken over by another soul due to your inactivity! Ahelp if you wish to regain your form!") message_admins("[key_name_admin(C)] has taken control of ([key_name_admin(L)]) to replace an inactive clock cultist.") L.ghostize(0) - L.key = C.key + C.transfer_ckey(L, FALSE) var/obj/effect/temp_visual/ratvar/sigil/vitality/V = new /obj/effect/temp_visual/ratvar/sigil/vitality(get_turf(src)) animate(V, alpha = 0, transform = matrix()*2, time = 8) playsound(L, 'sound/magic/staff_healing.ogg', 50, 1) diff --git a/code/modules/antagonists/clockcult/clock_items/clockwork_armor.dm b/code/modules/antagonists/clockcult/clock_items/clockwork_armor.dm index 54027266e5..88cf420420 100644 --- a/code/modules/antagonists/clockcult/clock_items/clockwork_armor.dm +++ b/code/modules/antagonists/clockcult/clock_items/clockwork_armor.dm @@ -50,7 +50,7 @@ to_chat(user, "The helmet tries to drive a spike through your head as you scramble to remove it!") user.emote("scream") user.apply_damage(30, BRUTE, BODY_ZONE_HEAD) - user.adjustBrainLoss(30) + user.adjustOrganLoss(ORGAN_SLOT_BRAIN, 30) addtimer(CALLBACK(user, /mob/living.proc/dropItemToGround, src, TRUE), 1) //equipped happens before putting stuff on(but not before picking items up), 1). thus, we need to wait for it to be on before forcing it off. /obj/item/clothing/head/helmet/clockwork/mob_can_equip(mob/M, mob/equipper, slot, disable_warning = 0) @@ -69,7 +69,7 @@ heat_protection = CHEST|GROIN|LEGS resistance_flags = FIRE_PROOF | ACID_PROOF armor = list("melee" = 60, "bullet" = 70, "laser" = -25, "energy" = 0, "bomb" = 60, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100) - allowed = list(/obj/item/clockwork, /obj/item/clothing/glasses/wraith_spectacles, /obj/item/clothing/glasses/judicial_visor, /obj/item/mmi/posibrain/soul_vessel, /obj/item/reagent_containers/food/drinks/holyoil) + allowed = list(/obj/item/clockwork, /obj/item/clothing/glasses/wraith_spectacles, /obj/item/clothing/glasses/judicial_visor, /obj/item/mmi/posibrain/soul_vessel, /obj/item/reagent_containers/food/drinks/bottle/holyoil) /obj/item/clothing/suit/armor/clockwork/Initialize() . = ..() diff --git a/code/modules/antagonists/clockcult/clock_items/construct_chassis.dm b/code/modules/antagonists/clockcult/clock_items/construct_chassis.dm index 12af249bee..2be0fdde11 100644 --- a/code/modules/antagonists/clockcult/clock_items/construct_chassis.dm +++ b/code/modules/antagonists/clockcult/clock_items/construct_chassis.dm @@ -55,7 +55,7 @@ pre_spawn() visible_message(creation_message) var/mob/living/construct = new construct_type(get_turf(src)) - construct.key = user.key + user.transfer_ckey(construct, FALSE) post_spawn(construct) qdel(user) qdel(src) diff --git a/code/modules/antagonists/clockcult/clock_scriptures/scripture_applications.dm b/code/modules/antagonists/clockcult/clock_scriptures/scripture_applications.dm index da499065d7..3d467350ff 100644 --- a/code/modules/antagonists/clockcult/clock_scriptures/scripture_applications.dm +++ b/code/modules/antagonists/clockcult/clock_scriptures/scripture_applications.dm @@ -119,3 +119,33 @@ var/datum/clockwork_scripture/create_object/construct/clockwork_marauder/CM = new() CM.recent_marauders-- qdel(CM) + +//Summon Neovgre: Summon a very powerful combat mech that explodes when destroyed for massive damage. +/datum/clockwork_scripture/create_object/summon_arbiter + descname = "Powerful Assault Mech" + name = "Summon Neovgre, the Anima Bulwark" + desc = "Calls forth the mighty Anima Bulwark, a weapon of unmatched power,\ + mech with superior defensive and offensive capabilities. It will \ + steadily regenerate HP and triple its regeneration speed while standing \ + on a clockwork tile. It will automatically draw power from nearby sigils of \ + transmission should the need arise. Its Arbiter laser cannon can decimate foes \ + from a range and is capable of smashing through any barrier presented to it. \ + Be warned, choosing to pilot Neovgre is a lifetime commitment, once you are \ + in you cannot leave and when it is destroyed it will explode catastrophically with you inside." + invocations = list("By the strength of the alloy...!!", "...call forth the Arbiter!!") + channel_time = 200 // This is a strong fucking weapon, 20 seconds channel time is getting off light I tell ya. + power_cost = 75000 //75 KW + usage_tip = "Neovgre is a powerful mech that will crush your enemies!" + invokers_required = 5 + multiple_invokers_used = TRUE + object_path = /obj/mecha/combat/neovgre + tier = SCRIPTURE_APPLICATION + primary_component = BELLIGERENT_EYE + sort_priority = 2 + creator_message = "Neovgre, the Anima Bulwark towers over you... your enemies reckoning has come." + +/datum/clockwork_scripture/create_object/summon_arbiter/check_special_requirements() + if(GLOB.neovgre_exists) + to_chat(invoker, "\"You've already got one...\"") + return FALSE + return ..() diff --git a/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm b/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm index 510c279f3c..82c1291433 100644 --- a/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm +++ b/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm @@ -216,6 +216,9 @@ if(is_reebe(invoker.z)) to_chat(invoker, "You're already at Reebe.") return + if(!isturf(invoker.loc)) + to_chat(invoker, "You must be visible to return!") + return return TRUE /datum/clockwork_scripture/abscond/recital() @@ -224,7 +227,7 @@ . = ..() /datum/clockwork_scripture/abscond/scripture_effects() - var/mob/living/pulled_mob = invoker.pulling && isliving(invoker.pulling) && get_clockwork_power(ABSCOND_ABDUCTION_COST) + var/mob/living/pulled_mob = (invoker.pulling && isliving(invoker.pulling) && get_clockwork_power(ABSCOND_ABDUCTION_COST)) ? invoker.pulling : null var/turf/T if(GLOB.ark_of_the_clockwork_justiciar) T = get_step(GLOB.ark_of_the_clockwork_justiciar, SOUTH) diff --git a/code/modules/antagonists/clockcult/clock_structures/ark_of_the_clockwork_justicar.dm b/code/modules/antagonists/clockcult/clock_structures/ark_of_the_clockwork_justicar.dm index 4cf7c1ba60..f735d6bb29 100644 --- a/code/modules/antagonists/clockcult/clock_structures/ark_of_the_clockwork_justicar.dm +++ b/code/modules/antagonists/clockcult/clock_structures/ark_of_the_clockwork_justicar.dm @@ -131,12 +131,10 @@ if(!M || !M.current) continue if(isliving(M.current) && M.current.stat != DEAD) - var/turf/t_turf - if(isAI(M.current)) - t_turf = isAI(M.current) ? get_step(get_step(src, NORTH),NORTH) : get_turf(src) // AI too fat, must make sure it always ends up a 2 tiles north instead of on the ark. - do_teleport(M, t_turf, channel = TELEPORT_CHANNEL_CULT, forced = TRUE) - M.current.overlay_fullscreen("flash", /obj/screen/fullscreen/flash) - M.current.clear_fullscreen("flash", 5) + var/turf/t_turf = isAI(M.current) ? get_step(get_step(src, NORTH),NORTH) : get_turf(src) // AI too fat, must make sure it always ends up a 2 tiles north instead of on the ark. + do_teleport(M.current, t_turf, channel = TELEPORT_CHANNEL_CULT, forced = TRUE) + M.current.overlay_fullscreen("flash", /obj/screen/fullscreen/flash) + M.current.clear_fullscreen("flash", 5) playsound(src, 'sound/magic/clockwork/invoke_general.ogg', 50, FALSE) recalls_remaining-- recalling = FALSE diff --git a/code/modules/antagonists/clockcult/clock_structures/eminence_spire.dm b/code/modules/antagonists/clockcult/clock_structures/eminence_spire.dm index 05f3ca5917..c01c7f0f57 100644 --- a/code/modules/antagonists/clockcult/clock_structures/eminence_spire.dm +++ b/code/modules/antagonists/clockcult/clock_structures/eminence_spire.dm @@ -64,7 +64,7 @@ message_admins("Admin [key_name_admin(user)] directly became the Eminence of the cult!") log_admin("Admin [key_name(user)] made themselves the Eminence.") var/mob/camera/eminence/eminence = new(get_turf(src)) - eminence.key = user.key + user.transfer_ckey(eminence, FALSE) hierophant_message("Ratvar has directly assigned the Eminence!") for(var/mob/M in servants_and_ghosts()) M.playsound_local(M, 'sound/machines/clockcult/eminence_selected.ogg', 50, FALSE) @@ -138,7 +138,7 @@ playsound(src, 'sound/machines/clockcult/ark_damage.ogg', 50, FALSE) var/mob/camera/eminence/eminence = new(get_turf(src)) eminence_nominee = pick(candidates) - eminence.key = eminence_nominee.key + eminence_nominee.transfer_ckey(eminence) hierophant_message("A ghost has ascended into the Eminence!") for(var/mob/M in servants_and_ghosts()) M.playsound_local(M, 'sound/machines/clockcult/eminence_selected.ogg', 50, FALSE) diff --git a/code/modules/antagonists/clockcult/clock_structures/heralds_beacon.dm b/code/modules/antagonists/clockcult/clock_structures/heralds_beacon.dm index 7654c0203b..3a461b7745 100644 --- a/code/modules/antagonists/clockcult/clock_structures/heralds_beacon.dm +++ b/code/modules/antagonists/clockcult/clock_structures/heralds_beacon.dm @@ -78,7 +78,7 @@ return voters += user.key else - if(!user.key in voters) + if(!(user.key in voters)) return voters -= user.key var/votes_left = votes_needed - voters.len diff --git a/code/modules/antagonists/clockcult/clock_structures/ratvar_the_clockwork_justicar.dm b/code/modules/antagonists/clockcult/clock_structures/ratvar_the_clockwork_justicar.dm index 9341a7ee6a..c17885315f 100644 --- a/code/modules/antagonists/clockcult/clock_structures/ratvar_the_clockwork_justicar.dm +++ b/code/modules/antagonists/clockcult/clock_structures/ratvar_the_clockwork_justicar.dm @@ -45,7 +45,7 @@ return FALSE var/mob/living/simple_animal/drone/cogscarab/ratvar/R = new/mob/living/simple_animal/drone/cogscarab/ratvar(get_turf(src)) R.visible_message("[R] forms, and its eyes blink open, glowing bright red!") - R.key = O.key + O.transfer_ckey(R, FALSE) /obj/structure/destructible/clockwork/massive/ratvar/Bump(atom/A) var/turf/T = get_turf(A) diff --git a/code/modules/antagonists/clockcult/clock_structures/traps/steam_vent.dm b/code/modules/antagonists/clockcult/clock_structures/traps/steam_vent.dm index 8d65574987..6aede1592e 100644 --- a/code/modules/antagonists/clockcult/clock_structures/traps/steam_vent.dm +++ b/code/modules/antagonists/clockcult/clock_structures/traps/steam_vent.dm @@ -7,7 +7,6 @@ break_message = "The vent snaps and collapses!" max_integrity = 100 density = FALSE - layer = BELOW_OBJ_LAYER /obj/structure/destructible/clockwork/trap/steam_vent/activate() opacity = !opacity diff --git a/code/modules/antagonists/clockcult/clock_structures/wall_gear.dm b/code/modules/antagonists/clockcult/clock_structures/wall_gear.dm index fb8397eed7..32b1b61dd1 100644 --- a/code/modules/antagonists/clockcult/clock_structures/wall_gear.dm +++ b/code/modules/antagonists/clockcult/clock_structures/wall_gear.dm @@ -5,7 +5,6 @@ unanchored_icon = "wall_gear" climbable = TRUE max_integrity = 100 - layer = BELOW_OBJ_LAYER construction_value = 3 desc = "A massive brass gear. You could probably secure or unsecure it with a wrench, or just climb over it." break_message = "The gear breaks apart into shards of alloy!" diff --git a/code/modules/antagonists/cult/blood_magic.dm b/code/modules/antagonists/cult/blood_magic.dm index f58ffc56d2..fc4d945d51 100644 --- a/code/modules/antagonists/cult/blood_magic.dm +++ b/code/modules/antagonists/cult/blood_magic.dm @@ -4,6 +4,7 @@ desc = "Prepare blood magic by carving runes into your flesh. This rite is most effective with an empowering rune" var/list/spells = list() var/channeling = FALSE + var/holy_dispel = FALSE /datum/action/innate/cult/blood_magic/Grant() ..() @@ -33,6 +34,9 @@ B.button.moved = B.button.screen_loc /datum/action/innate/cult/blood_magic/Activate() + if(holy_dispel) + to_chat(owner, "Holy water currently scours your body, nullifying the power of the rites!") + return var/rune = FALSE var/limit = RUNELESS_MAX_BLOODCHARGE for(var/obj/effect/rune/empower/R in range(1, owner)) @@ -64,7 +68,7 @@ qdel(nullify_spell) return BS = possible_spells[entered_spell_name] - if(QDELETED(src) || owner.incapacitated() || !BS || (rune && !(locate(/obj/effect/rune/empower) in range(1, owner))) || (spells.len >= limit)) + if(QDELETED(src) || owner.incapacitated() || !BS || holy_dispel || (rune && !(locate(/obj/effect/rune/empower) in range(1, owner))) || (spells.len >= limit)) return to_chat(owner,"You begin to carve unnatural symbols into your flesh!") SEND_SOUND(owner, sound('sound/weapons/slice.ogg',0,1,10)) @@ -73,7 +77,7 @@ else to_chat(owner, "You are already invoking blood magic!") return - if(do_after(owner, 100 - rune*60, target = owner)) + if(do_after(owner, 100 - rune*60, target = owner) && !holy_dispel) if(ishuman(owner)) var/mob/living/carbon/human/H = owner H.bleed(40 - rune*32) @@ -644,6 +648,11 @@ desc = "A spell that will absorb blood from anything you touch.
Touching cultists and constructs can heal them.
Clicking the hand will potentially let you focus the spell into something stronger." color = "#7D1717" +/obj/item/melee/blood_magic/manipulator/examine(mob/user) + . = ..() + if(iscultist(user)) + to_chat(user, "The [name] currently has [uses] blood charges left.") + /obj/item/melee/blood_magic/manipulator/afterattack(atom/target, mob/living/carbon/human/user, proximity) if(proximity) if(ishuman(target)) @@ -655,15 +664,15 @@ if(H.stat == DEAD) to_chat(user,"Only a revive rune can bring back the dead!") return - if(H.blood_volume < BLOOD_VOLUME_SAFE) - var/restore_blood = BLOOD_VOLUME_SAFE - H.blood_volume + if(H.blood_volume < (BLOOD_VOLUME_SAFE*H.blood_ratio)) + var/restore_blood = (BLOOD_VOLUME_SAFE*H.blood_ratio) - H.blood_volume if(uses*2 < restore_blood) H.blood_volume += uses*2 to_chat(user,"You use the last of your blood rites to restore what blood you could!") uses = 0 return ..() else - H.blood_volume = BLOOD_VOLUME_SAFE + H.blood_volume = (BLOOD_VOLUME_SAFE*H.blood_ratio) uses -= round(restore_blood/2) to_chat(user,"Your blood rites have restored [H == user ? "your" : "[H.p_their()]"] blood to safe levels!") var/overall_damage = H.getBruteLoss() + H.getFireLoss() + H.getToxLoss() + H.getOxyLoss() @@ -678,9 +687,9 @@ if(ratio>1) ratio = 1 uses -= round(overall_damage) - H.visible_message("[H] is fully healed by [H==user ? "[H.p_their()]":"[H]'s"]'s blood magic!") + H.visible_message("[H] is fully healed by [H==user ? "[H.p_their()]":"[user]'s"] blood magic!") else - H.visible_message("[H] is partially healed by [H==user ? "[H.p_their()]":"[H]'s"] blood magic.") + H.visible_message("[H] is partially healed by [H==user ? "[H.p_their()]":"[user]'s"] blood magic.") uses = 0 ratio *= -1 H.adjustOxyLoss((overall_damage*ratio) * (H.getOxyLoss() / overall_damage), 0) @@ -698,7 +707,7 @@ if(H.cultslurring) to_chat(user,"[H.p_their(TRUE)] blood has been tainted by an even stronger form of blood magic, it's no use to us like this!") return - if(H.blood_volume > BLOOD_VOLUME_SAFE) + if(H.blood_volume > (BLOOD_VOLUME_SAFE*H.blood_ratio)) H.blood_volume -= 100 uses += 50 user.Beam(H,icon_state="drainbeam",time=10) @@ -762,7 +771,7 @@ switch(choice) if("Blood Spear (150)") if(uses < 150) - to_chat(user, "You need 200 charges to perform this rite.") + to_chat(user, "You need 150 charges to perform this rite.") else uses -= 150 var/turf/T = get_turf(user) @@ -778,7 +787,7 @@ "A [rite.name] materializes at your feet.") if("Blood Bolt Barrage (300)") if(uses < 300) - to_chat(user, "You need 400 charges to perform this rite.") + to_chat(user, "You need 300 charges to perform this rite.") else var/obj/rite = new /obj/item/gun/ballistic/shotgun/boltaction/enchanted/arcane_barrage/blood() uses -= 300 @@ -790,7 +799,7 @@ qdel(rite) if("Blood Beam (500)") if(uses < 500) - to_chat(user, "You need 600 charges to perform this rite.") + to_chat(user, "You need 500 charges to perform this rite.") else var/obj/rite = new /obj/item/blood_beam() uses -= 500 @@ -799,4 +808,4 @@ to_chat(user, "Your hands glow with POWER OVERWHELMING!!!") else to_chat(user, "You need a free hand for this rite!") - qdel(rite) \ No newline at end of file + qdel(rite) diff --git a/code/modules/antagonists/cult/cult_items.dm b/code/modules/antagonists/cult/cult_items.dm index dc2c29eb6d..10759afcd0 100644 --- a/code/modules/antagonists/cult/cult_items.dm +++ b/code/modules/antagonists/cult/cult_items.dm @@ -105,7 +105,6 @@ inhand_x_dimension = 64 inhand_y_dimension = 64 actions_types = list() - item_flags = SLOWS_WHILE_IN_HAND var/datum/action/innate/dash/cult/jaunt var/datum/action/innate/cult/spin2win/linked_action var/spinning = FALSE @@ -667,6 +666,7 @@ righthand_file = 'icons/mob/inhands/weapons/polearms_righthand.dmi' slot_flags = 0 force = 17 + force_unwielded = 17 force_wielded = 24 throwforce = 40 throw_speed = 2 diff --git a/code/modules/antagonists/cult/cult_structures.dm b/code/modules/antagonists/cult/cult_structures.dm index 64d57c2f94..0dd6b08c4d 100644 --- a/code/modules/antagonists/cult/cult_structures.dm +++ b/code/modules/antagonists/cult/cult_structures.dm @@ -73,6 +73,10 @@ animate(src, color = previouscolor, time = 8) addtimer(CALLBACK(src, /atom/proc/update_atom_colour), 8) +/obj/structure/destructible/cult/proc/check_menu(mob/living/user) + if(!user || user.incapacitated() || !iscultist(user) || !anchored || cooldowntime > world.time) + return FALSE + return TRUE /obj/structure/destructible/cult/talisman name = "altar" @@ -80,9 +84,18 @@ icon_state = "talismanaltar" break_message = "The altar shatters, leaving only the wailing of the damned!" -/obj/structure/destructible/cult/talisman/attack_hand(mob/living/user) + var/static/image/radial_whetstone = image(icon = 'icons/obj/kitchen.dmi', icon_state = "cult_sharpener") + var/static/image/radial_shell = image(icon = 'icons/obj/wizard.dmi', icon_state = "construct-cult") + var/static/image/radial_unholy_water = image(icon = 'icons/obj/drinks.dmi', icon_state = "holyflask") + +/obj/structure/destructible/cult/talisman/Initialize() . = ..() - if(.) + radial_unholy_water.color = "#333333" + +/obj/structure/destructible/cult/talisman/ui_interact(mob/user) + . = ..() + + if(!user.canUseTopic(src, TRUE)) return if(!iscultist(user)) to_chat(user, "You're pretty sure you know exactly what this is used for and you can't seem to touch it.") @@ -91,22 +104,27 @@ to_chat(user, "You need to anchor [src] to the floor with your dagger first.") return if(cooldowntime > world.time) - to_chat(user, "The magic in [src] is weak, it will be ready to use again in [DisplayTimeText(cooldowntime - world.time)].") + to_chat(user, "The magic in [src] is weak, it will be ready to use again in [DisplayTimeText(cooldowntime - world.time)].") return - var/choice = alert(user,"You study the schematics etched into the altar...",,"Eldritch Whetstone","Construct Shell","Flask of Unholy Water") - var/list/pickedtype = list() + + to_chat(user, "You study the schematics etched into the altar...") + + var/list/options = list("Eldritch Whetstone" = radial_whetstone, "Construct Shell" = radial_shell, "Flask of Unholy Water" = radial_unholy_water) + var/choice = show_radial_menu(user, src, options, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = TRUE, tooltips = TRUE) + + var/reward switch(choice) if("Eldritch Whetstone") - pickedtype += /obj/item/sharpener/cult + reward = /obj/item/sharpener/cult if("Construct Shell") - pickedtype += /obj/structure/constructshell + reward = /obj/structure/constructshell if("Flask of Unholy Water") - pickedtype += /obj/item/reagent_containers/glass/beaker/unholywater - if(src && !QDELETED(src) && anchored && pickedtype && Adjacent(user) && !user.incapacitated() && iscultist(user) && cooldowntime <= world.time) + reward = /obj/item/reagent_containers/glass/beaker/unholywater + + if(!QDELETED(src) && reward && check_menu(user)) cooldowntime = world.time + 2400 - for(var/N in pickedtype) - new N(get_turf(src)) - to_chat(user, "You kneel before the altar and your faith is rewarded with the [choice]!") + new reward(get_turf(src)) + to_chat(user, "You kneel before the altar and your faith is rewarded with the [choice]!") /obj/structure/destructible/cult/forge name = "daemon forge" @@ -116,9 +134,14 @@ light_color = LIGHT_COLOR_LAVA break_message = "The force breaks apart into shards with a howling scream!" -/obj/structure/destructible/cult/forge/attack_hand(mob/living/user) + var/static/image/radial_flagellant = image(icon = 'icons/obj/clothing/suits.dmi', icon_state = "cultrobes") + var/static/image/radial_shielded = image(icon = 'icons/obj/clothing/suits.dmi', icon_state = "cult_armor") + var/static/image/radial_mirror = image(icon = 'icons/obj/items_and_weapons.dmi', icon_state = "mirror_shield") + +/obj/structure/destructible/cult/forge/ui_interact(mob/user) . = ..() - if(.) + + if(!user.canUseTopic(src, TRUE)) return if(!iscultist(user)) to_chat(user, "The heat radiating from [src] pushes you back.") @@ -129,24 +152,26 @@ if(cooldowntime > world.time) to_chat(user, "The magic in [src] is weak, it will be ready to use again in [DisplayTimeText(cooldowntime - world.time)].") return - var/choice - if(user.mind.has_antag_datum(/datum/antagonist/cult/master)) - choice = alert(user,"You study the schematics etched into the forge...",,"Shielded Robe","Flagellant's Robe","Mirror Shield") - else - choice = alert(user,"You study the schematics etched into the forge...",,"Shielded Robe","Flagellant's Robe","Mirror Shield") - var/list/pickedtype = list() + + to_chat(user, "You study the schematics etched into the forge...") + + + var/list/options = list("Shielded Robe" = radial_shielded, "Flagellant's Robe" = radial_flagellant, "Mirror Shield" = radial_mirror) + var/choice = show_radial_menu(user, src, options, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = TRUE, tooltips = TRUE) + + var/reward switch(choice) if("Shielded Robe") - pickedtype += /obj/item/clothing/suit/hooded/cultrobes/cult_shield + reward = /obj/item/clothing/suit/hooded/cultrobes/cult_shield if("Flagellant's Robe") - pickedtype += /obj/item/clothing/suit/hooded/cultrobes/berserker + reward = /obj/item/clothing/suit/hooded/cultrobes/berserker if("Mirror Shield") - pickedtype += /obj/item/shield/mirror - if(src && !QDELETED(src) && anchored && pickedtype && Adjacent(user) && !user.incapacitated() && iscultist(user) && cooldowntime <= world.time) + reward = /obj/item/shield/mirror + + if(!QDELETED(src) && reward && check_menu(user)) cooldowntime = world.time + 2400 - for(var/N in pickedtype) - new N(get_turf(src)) - to_chat(user, "You work the forge as dark knowledge guides your hands, creating the [choice]!") + new reward(get_turf(src)) + to_chat(user, "You work the forge as dark knowledge guides your hands, creating the [choice]!") @@ -188,7 +213,7 @@ var/mob/living/simple_animal/M = L if(M.health < M.maxHealth) M.adjustHealth(-3) - if(ishuman(L) && L.blood_volume < BLOOD_VOLUME_NORMAL) + if(ishuman(L) && L.blood_volume < (BLOOD_VOLUME_NORMAL * L.blood_ratio)) L.blood_volume += 1.0 CHECK_TICK if(last_corrupt <= world.time) @@ -234,9 +259,14 @@ light_color = LIGHT_COLOR_FIRE break_message = "The books and tomes of the archives burn into ash as the desk shatters!" -/obj/structure/destructible/cult/tome/attack_hand(mob/living/user) + var/static/image/radial_blindfold = image(icon = 'icons/obj/clothing/glasses.dmi', icon_state = "blindfold") + var/static/image/radial_curse = image(icon = 'icons/obj/cult.dmi', icon_state ="shuttlecurse") + var/static/image/radial_veilwalker = image(icon = 'icons/obj/cult.dmi', icon_state ="shifter") + +/obj/structure/destructible/cult/tome/ui_interact(mob/user) . = ..() - if(.) + + if(!user.canUseTopic(src, TRUE)) return if(!iscultist(user)) to_chat(user, "These books won't open and it hurts to even try and read the covers.") @@ -247,21 +277,27 @@ if(cooldowntime > world.time) to_chat(user, "The magic in [src] is weak, it will be ready to use again in [DisplayTimeText(cooldowntime - world.time)].") return - var/choice = alert(user,"You flip through the black pages of the archives...",,"Zealot's Blindfold","Shuttle Curse","Veil Walker Set") - var/list/pickedtype = list() + + to_chat(user, "You flip through the black pages of the archives...") + + var/list/options = list("Zealot's Blindfold" = radial_blindfold, "Shuttle Curse" = radial_curse, "Veil Walker Set" = radial_veilwalker) + var/choice = show_radial_menu(user, src, options, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = TRUE, tooltips = TRUE) + + var/reward switch(choice) if("Zealot's Blindfold") - pickedtype += /obj/item/clothing/glasses/hud/health/night/cultblind + reward = /obj/item/clothing/glasses/hud/health/night/cultblind if("Shuttle Curse") - pickedtype += /obj/item/shuttle_curse + reward = /obj/item/shuttle_curse if("Veil Walker Set") - pickedtype += /obj/item/cult_shift - pickedtype += /obj/item/flashlight/flare/culttorch - if(src && !QDELETED(src) && anchored && pickedtype.len && Adjacent(user) && !user.incapacitated() && iscultist(user) && cooldowntime <= world.time) + reward = /obj/effect/spawner/bundle/veil_walker + if(!QDELETED(src) && reward && check_menu(user)) cooldowntime = world.time + 2400 - for(var/N in pickedtype) - new N(get_turf(src)) - to_chat(user, "You summon the [choice] from the archives!") + new reward(get_turf(src)) + to_chat(user, "You summon the [choice] from the archives!") + +/obj/effect/spawner/bundle/veil_walker + items = list(/obj/item/cult_shift, /obj/item/flashlight/flare/culttorch) /obj/effect/gateway name = "gateway" diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm index bbab86729b..2e233d26e4 100644 --- a/code/modules/antagonists/cult/runes.dm +++ b/code/modules/antagonists/cult/runes.dm @@ -61,8 +61,8 @@ Runes can either be invoked by one's self or with many different cultists. Each if(do_after(user, 15, target = src)) to_chat(user, "You carefully erase the [lowertext(cultist_name)] rune.") qdel(src) - else if(istype(I, /obj/item/nullrod)) - user.say("BEGONE FOUL MAGIKS!!", forced = "nullrod") + else if(istype(I, /obj/item/storage/book/bible) || istype(I, /obj/item/nullrod)) + user.say("BEGONE FOUL MAGICKS!!", forced = "bible") to_chat(user, "You disrupt the magic of [src] with [I].") qdel(src) @@ -185,9 +185,6 @@ structure_check() searches for nearby cultist structures required for the invoca color = RUNE_COLOR_OFFER req_cultists = 1 rune_in_use = FALSE - var/mob/living/currentconversionman - var/conversiontimeout - var/conversionresult /obj/effect/rune/convert/do_invoke_glow() return @@ -233,37 +230,18 @@ structure_check() searches for nearby cultist structures required for the invoca addtimer(CALLBACK(src, /atom/proc/update_atom_colour), 5) Cult_team.check_size() // Triggers the eye glow or aura effects if the cult has grown large enough relative to the crew rune_in_use = FALSE + /obj/effect/rune/convert/proc/do_convert(mob/living/convertee, list/invokers) if(invokers.len < 2) for(var/M in invokers) - to_chat(M, "You need at least two invokers to convert [convertee]!") + to_chat(M, "You need at least two invokers to convert [convertee]!") log_game("Offer rune failed - tried conversion with one invoker") return 0 - if(convertee.anti_magic_check(TRUE, TRUE)) + if(convertee.anti_magic_check(TRUE, TRUE, FALSE, 0)) //Not chargecost because it can be spammed for(var/M in invokers) to_chat(M, "Something is shielding [convertee]'s mind!") log_game("Offer rune failed - convertee had anti-magic") return 0 - to_chat(convertee, "The world goes red. All at once you are aware of an evil, eldritch truth taking roots into your mind.\n\ - Click here to become a follower of Nar'sie, or suffer a fate worse than death.") - INVOKE_ASYNC(src, .proc/optinalert, convertee) - currentconversionman = convertee - conversiontimeout = world.time + (14 SECONDS) - convertee.Stun(140) - ADD_TRAIT(convertee, TRAIT_MUTE, "conversionrune") - flash_color(convertee, list("#960000", "#960000", "#960000", rgb(0,0,0)), 50) - conversionresult = FALSE - while(world.time < conversiontimeout && convertee && !conversionresult) - stoplag(1) - currentconversionman = null - if(!convertee) - return FALSE - REMOVE_TRAIT(convertee, TRAIT_MUTE, "conversionrune") - if(get_turf(convertee) != get_turf(src)) - return FALSE - if(!conversionresult) - do_sacrifice(convertee, invokers, TRUE) - return FALSE var/brutedamage = convertee.getBruteLoss() var/burndamage = convertee.getFireLoss() if(brutedamage || burndamage) @@ -275,6 +253,8 @@ structure_check() searches for nearby cultist structures required for the invoca SSticker.mode.add_cultist(convertee.mind, 1) new /obj/item/melee/cultblade/dagger(get_turf(src)) convertee.mind.special_role = ROLE_CULTIST + to_chat(convertee, "Your blood pulses. Your head throbs. The world goes red. All at once you are aware of a horrible, horrible, truth. The veil of reality has been ripped away \ + and something evil takes root.") to_chat(convertee, "Assist your new compatriots in their dark dealings. Your goal is theirs, and theirs is yours. You serve the Geometer above all else. Bring it back.\ ") if(ishuman(convertee)) @@ -284,18 +264,7 @@ structure_check() searches for nearby cultist structures required for the invoca H.cultslurring = 0 return 1 -/obj/effect/rune/convert/proc/optinalert(mob/living/convertee) - var/alert = alert(convertee, "Will you embrace the Geometer of Blood or perish in futile resistance?", "Choose your own fate", "Join the Blood Cult", "Suffer a horrible demise") - if(alert == "Join the Blood Cult") - signmeup(convertee) - -/obj/effect/rune/convert/proc/signmeup(mob/living/convertee) - if(currentconversionman == usr) - conversionresult = TRUE - else - to_chat(usr, "Your fate has already been set in stone.") - -/obj/effect/rune/convert/proc/do_sacrifice(mob/living/sacrificial, list/invokers, force_a_sac) +/obj/effect/rune/convert/proc/do_sacrifice(mob/living/sacrificial, list/invokers) var/mob/living/first_invoker = invokers[1] if(!first_invoker) return FALSE @@ -305,7 +274,7 @@ structure_check() searches for nearby cultist structures required for the invoca var/big_sac = FALSE - if(!force_a_sac && (((ishuman(sacrificial) || iscyborg(sacrificial)) && sacrificial.stat != DEAD) || C.cult_team.is_sacrifice_target(sacrificial.mind)) && invokers.len < 3) + if((((ishuman(sacrificial) || iscyborg(sacrificial)) && sacrificial.stat != DEAD) || C.cult_team.is_sacrifice_target(sacrificial.mind)) && invokers.len < 3) for(var/M in invokers) to_chat(M, "[sacrificial] is too greatly linked to the world! You need three acolytes!") log_game("Offer rune failed - not enough acolytes and target is living or sac target") @@ -345,10 +314,6 @@ structure_check() searches for nearby cultist structures required for the invoca sacrificial.gib() return TRUE -/obj/effect/rune/convert/Topic(href, href_list) - if(href_list["signmeup"]) - signmeup(usr) - /obj/effect/rune/empower cultist_name = "Empower" cultist_desc = "allows cultists to prepare greater amounts of blood magic at far less of a cost." @@ -433,12 +398,12 @@ structure_check() searches for nearby cultist structures required for the invoca continue if(!A.anchored) movedsomething = TRUE - if(do_teleport(A, T, forceMove = TRUE, channel = TELEPORT_CHANNEL_CULT)) + if(do_teleport(A, target, forceMove = TRUE, channel = TELEPORT_CHANNEL_CULT)) movesuccess = TRUE if(movedsomething) ..() if(moveuserlater) - if(do_teleport(user, T, channel = TELEPORT_CHANNEL_CULT)) + if(do_teleport(user, target, channel = TELEPORT_CHANNEL_CULT)) movesuccess = TRUE if(movesuccess) visible_message("There is a sharp crack of inrushing air, and everything above the rune disappears!", null, "You hear a sharp crack.") @@ -610,7 +575,7 @@ structure_check() searches for nearby cultist structures required for the invoca to_chat(mob_to_revive.mind, "Your physical form has been taken over by another soul due to your inactivity! Ahelp if you wish to regain your form.") message_admins("[key_name_admin(C)] has taken control of ([key_name_admin(mob_to_revive)]) to replace an AFK player.") mob_to_revive.ghostize(0) - mob_to_revive.key = C.key + C.transfer_ckey(mob_to_revive, FALSE) else fail_invoke() return @@ -905,7 +870,7 @@ structure_check() searches for nearby cultist structures required for the invoca visible_message("A cloud of red mist forms above [src], and from within steps... a [new_human.gender == FEMALE ? "wo":""]man.") to_chat(user, "Your blood begins flowing into [src]. You must remain in place and conscious to maintain the forms of those summoned. This will hurt you slowly but surely...") var/obj/structure/emergency_shield/invoker/N = new(T) - new_human.key = ghost_to_spawn.key + ghost_to_spawn.transfer_ckey(new_human, FALSE) SSticker.mode.add_cultist(new_human.mind, 0) to_chat(new_human, "You are a servant of the Geometer. You have been made semi-corporeal by the cult of Nar'Sie, and you are to serve them at all costs.") diff --git a/code/modules/antagonists/devil/devil.dm b/code/modules/antagonists/devil/devil.dm index 3f2bd003a3..dc649025d2 100644 --- a/code/modules/antagonists/devil/devil.dm +++ b/code/modules/antagonists/devil/devil.dm @@ -539,10 +539,10 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master", var/list/parts = list() parts += "The devil's true name is: [truename]" parts += "The devil's bans were:" - parts += "[GLOB.TAB][GLOB.lawlorify[LORE][ban]]" - parts += "[GLOB.TAB][GLOB.lawlorify[LORE][bane]]" - parts += "[GLOB.TAB][GLOB.lawlorify[LORE][obligation]]" - parts += "[GLOB.TAB][GLOB.lawlorify[LORE][banish]]" + parts += "[FOURSPACES][GLOB.lawlorify[LORE][ban]]" + parts += "[FOURSPACES][GLOB.lawlorify[LORE][bane]]" + parts += "[FOURSPACES][GLOB.lawlorify[LORE][obligation]]" + parts += "[FOURSPACES][GLOB.lawlorify[LORE][banish]]" return parts.Join("
") /datum/antagonist/devil/roundend_report() diff --git a/code/modules/antagonists/devil/true_devil/_true_devil.dm b/code/modules/antagonists/devil/true_devil/_true_devil.dm index 1df81a797b..afe439f02c 100644 --- a/code/modules/antagonists/devil/true_devil/_true_devil.dm +++ b/code/modules/antagonists/devil/true_devil/_true_devil.dm @@ -146,7 +146,7 @@ /mob/living/carbon/true_devil/attack_ghost(mob/dead/observer/user as mob) if(ascended || user.mind.soulOwner == src.mind) var/mob/living/simple_animal/imp/S = new(get_turf(loc)) - S.key = user.key + user.transfer_ckey(S, FALSE) S.mind.assigned_role = "Imp" S.mind.special_role = "Imp" var/datum/objective/newobjective = new diff --git a/code/modules/antagonists/disease/disease_abilities.dm b/code/modules/antagonists/disease/disease_abilities.dm index 07cd3030b1..dc2249006c 100644 --- a/code/modules/antagonists/disease/disease_abilities.dm +++ b/code/modules/antagonists/disease/disease_abilities.dm @@ -5,25 +5,48 @@ is currently following. */ GLOBAL_LIST_INIT(disease_ability_singletons, list( - new /datum/disease_ability/action/cough(), - new /datum/disease_ability/action/sneeze(), - new /datum/disease_ability/action/infect(), - new /datum/disease_ability/symptom/cough(), - new /datum/disease_ability/symptom/sneeze(),\ - new /datum/disease_ability/symptom/hallucigen(), - new /datum/disease_ability/symptom/choking(), - new /datum/disease_ability/symptom/confusion(), - new /datum/disease_ability/symptom/youth(), - new /datum/disease_ability/symptom/vomit(), - new /datum/disease_ability/symptom/voice_change(), - new /datum/disease_ability/symptom/visionloss(), - new /datum/disease_ability/symptom/viraladaptation(), - new /datum/disease_ability/symptom/vitiligo(), - new /datum/disease_ability/symptom/sensory_restoration(), - new /datum/disease_ability/symptom/itching(), - new /datum/disease_ability/symptom/weight_loss(), - new /datum/disease_ability/symptom/metabolism_heal(), - new /datum/disease_ability/symptom/coma_heal() + new /datum/disease_ability/action/cough, + new /datum/disease_ability/action/sneeze, + new /datum/disease_ability/action/infect, + new /datum/disease_ability/symptom/mild/cough, + new /datum/disease_ability/symptom/mild/sneeze, + new /datum/disease_ability/symptom/medium/shedding, + new /datum/disease_ability/symptom/medium/beard, + new /datum/disease_ability/symptom/medium/hallucigen, + new /datum/disease_ability/symptom/medium/choking, + new /datum/disease_ability/symptom/medium/confusion, + new /datum/disease_ability/symptom/medium/vomit, + new /datum/disease_ability/symptom/medium/voice_change, + new /datum/disease_ability/symptom/medium/visionloss, + new /datum/disease_ability/symptom/medium/deafness, + new /datum/disease_ability/symptom/powerful/narcolepsy, + new /datum/disease_ability/symptom/medium/fever, + new /datum/disease_ability/symptom/medium/shivering, + new /datum/disease_ability/symptom/medium/headache, + new /datum/disease_ability/symptom/medium/nano_boost, + new /datum/disease_ability/symptom/medium/nano_destroy, + new /datum/disease_ability/symptom/medium/viraladaptation, + new /datum/disease_ability/symptom/medium/viralevolution, + new /datum/disease_ability/symptom/medium/vitiligo, + new /datum/disease_ability/symptom/medium/revitiligo, + new /datum/disease_ability/symptom/medium/itching, + new /datum/disease_ability/symptom/medium/heal/weight_loss, + new /datum/disease_ability/symptom/medium/heal/sensory_restoration, + new /datum/disease_ability/symptom/medium/heal/mind_restoration, + new /datum/disease_ability/symptom/powerful/fire, + new /datum/disease_ability/symptom/powerful/flesh_eating, +// new /datum/disease_ability/symptom/powerful/genetic_mutation, + new /datum/disease_ability/symptom/powerful/inorganic_adaptation, + new /datum/disease_ability/symptom/powerful/heal/starlight, + new /datum/disease_ability/symptom/powerful/heal/oxygen, + new /datum/disease_ability/symptom/powerful/heal/chem, + new /datum/disease_ability/symptom/powerful/heal/metabolism, + new /datum/disease_ability/symptom/powerful/heal/dark, + new /datum/disease_ability/symptom/powerful/heal/water, + new /datum/disease_ability/symptom/powerful/heal/plasma, + new /datum/disease_ability/symptom/powerful/heal/radiation, + new /datum/disease_ability/symptom/powerful/heal/coma, + new /datum/disease_ability/symptom/powerful/youth )) /datum/disease_ability @@ -54,7 +77,13 @@ GLOBAL_LIST_INIT(disease_ability_singletons, list( stage_speed += initial(S.stage_speed) transmittable += initial(S.transmittable) threshold_block += "

[initial(S.threshold_desc)]" - stat_block = "Resistance: [resistance]
Stealth: [stealth]
Stage Speed: [stage_speed]
Transmissibility: [transmittable]

" + stat_block = "Resistance: [resistance]
Stealth: [stealth]
Stage Speed: [stage_speed]
Transmissibility: [transmittable]

" + if(symptoms.len == 1) //lazy boy's dream + name = initial(S.name) + if(short_desc == "") + short_desc = initial(S.desc) + if(long_desc == "") + long_desc = initial(S.desc) /datum/disease_ability/proc/CanBuy(mob/camera/disease/D) if(world.time < D.next_adaptation_time) @@ -77,8 +106,10 @@ GLOBAL_LIST_INIT(disease_ability_singletons, list( for(var/T in symptoms) var/datum/symptom/S = new T() SD.symptoms += S + S.OnAdd(SD) if(SD.processing) - S.Start(SD) + if(S.Start(SD)) + S.next_activation = world.time + rand(S.symptom_delay_min * 10, S.symptom_delay_max * 10) SD.Refresh() for(var/T in actions) var/datum/action/A = new T() @@ -105,6 +136,7 @@ GLOBAL_LIST_INIT(disease_ability_singletons, list( var/datum/symptom/S = locate(T) in SD.symptoms if(S) SD.symptoms -= S + S.OnRemove(SD) if(SD.processing) S.End(SD) qdel(S) @@ -152,8 +184,9 @@ GLOBAL_LIST_INIT(disease_ability_singletons, list( return FALSE to_chat(D, "You force [L.real_name] to cough.") L.emote("cough") - var/datum/disease/advance/sentient_disease/SD = D.hosts[L] - SD.spread(2) + if(L.CanSpreadAirborneDisease()) //don't spread germs if they covered their mouth + var/datum/disease/advance/sentient_disease/SD = D.hosts[L] + SD.spread(2) StartCooldown() return TRUE @@ -185,11 +218,12 @@ GLOBAL_LIST_INIT(disease_ability_singletons, list( return FALSE to_chat(D, "You force [L.real_name] to sneeze.") L.emote("sneeze") - var/datum/disease/advance/sentient_disease/SD = D.hosts[L] + if(L.CanSpreadAirborneDisease()) //don't spread germs if they covered their mouth + var/datum/disease/advance/sentient_disease/SD = D.hosts[L] - for(var/mob/living/M in oview(4, SD.affected_mob)) - if(is_A_facing_B(SD.affected_mob, M) && disease_air_spread_walk(get_turf(SD.affected_mob), get_turf(M))) - M.AirborneContractDisease(SD, TRUE) + for(var/mob/living/M in oview(4, SD.affected_mob)) + if(is_A_facing_B(SD.affected_mob, M) && disease_air_spread_walk(get_turf(SD.affected_mob), get_turf(M))) + M.AirborneContractDisease(SD, TRUE) StartCooldown() return TRUE @@ -235,154 +269,192 @@ GLOBAL_LIST_INIT(disease_ability_singletons, list( StartCooldown() return TRUE -//passive symptom abilities +/*******************BASE SYMPTOM TYPES*******************/ +// cost is for convenience and can be changed. If you're changing req_tot_points then don't use the subtype... +//healing costs more so you have to techswitch from naughty disease otherwise we'd have friendly disease for easy greentext (no fun!) -/datum/disease_ability/symptom/cough - name = "Involuntary Coughing" - symptoms = list(/datum/symptom/cough) +/datum/disease_ability/symptom/mild cost = 2 required_total_points = 4 + category = "Symptom (Weak)" + +/datum/disease_ability/symptom/medium + cost = 4 + required_total_points = 8 + category = "Symptom" + +/datum/disease_ability/symptom/medium/heal + cost = 5 + category = "Symptom (+)" + +/datum/disease_ability/symptom/powerful + cost = 4 + required_total_points = 16 + category = "Symptom (Strong)" + +/datum/disease_ability/symptom/powerful/heal + cost = 8 + category = "Symptom (Strong+)" + + +/******MILD******/ + +/datum/disease_ability/symptom/mild/cough + name = "Involuntary Coughing" + symptoms = list(/datum/symptom/cough) short_desc = "Cause victims to cough intermittently." long_desc = "Cause victims to cough intermittently, spreading your infection if your transmissibility is high." -/datum/disease_ability/symptom/sneeze +/datum/disease_ability/symptom/mild/sneeze name = "Involuntary Sneezing" symptoms = list(/datum/symptom/sneeze) - cost = 2 - required_total_points = 4 short_desc = "Cause victims to sneeze intermittently." long_desc = "Cause victims to sneeze intermittently, spreading your infection and also increasing transmissibility and resistance, at the cost of stealth." -/datum/disease_ability/symptom/beard - //I don't think I need to justify the fact that this is the best symptom - name = "Beard Growth" - symptoms = list(/datum/symptom/beard) - cost = 1 - required_total_points = 8 - short_desc = "Cause all victims to grow a luscious beard." - long_desc = "Cause all victims to grow a luscious beard. Decreases stats slightly. Ineffective against Santa Claus." +/******MEDIUM******/ -/datum/disease_ability/symptom/hallucigen - name = "Hallucinations" +/datum/disease_ability/symptom/medium/shedding + symptoms = list(/datum/symptom/shedding) + +/datum/disease_ability/symptom/medium/beard + symptoms = list(/datum/symptom/beard) + short_desc = "Cause all victims to grow a luscious beard." + long_desc = "Cause all victims to grow a luscious beard. Ineffective against Santa Claus." + +/datum/disease_ability/symptom/medium/hallucigen symptoms = list(/datum/symptom/hallucigen) - cost = 4 - required_total_points = 8 short_desc = "Cause victims to hallucinate." long_desc = "Cause victims to hallucinate. Decreases stats, especially resistance." - -/datum/disease_ability/symptom/choking - name = "Choking" +/datum/disease_ability/symptom/medium/choking symptoms = list(/datum/symptom/choking) - cost = 4 - required_total_points = 8 short_desc = "Cause victims to choke." long_desc = "Cause victims to choke, threatening asphyxiation. Decreases stats, especially transmissibility." - -/datum/disease_ability/symptom/confusion - name = "Confusion" +/datum/disease_ability/symptom/medium/confusion symptoms = list(/datum/symptom/confusion) - cost = 4 - required_total_points = 8 short_desc = "Cause victims to become confused." long_desc = "Cause victims to become confused intermittently." - -/datum/disease_ability/symptom/youth - name = "Eternal Youth" - symptoms = list(/datum/symptom/youth) - cost = 4 - required_total_points = 8 - short_desc = "Cause victims to become eternally young." - long_desc = "Cause victims to become eternally young. Provides boosts to all stats except transmissibility." - - -/datum/disease_ability/symptom/vomit - name = "Vomiting" +/datum/disease_ability/symptom/medium/vomit symptoms = list(/datum/symptom/vomit) - cost = 4 - required_total_points = 8 short_desc = "Cause victims to vomit." long_desc = "Cause victims to vomit. Slightly increases transmissibility. Vomiting also also causes the victims to lose nutrition and removes some toxin damage." - -/datum/disease_ability/symptom/voice_change - name = "Voice Changing" +/datum/disease_ability/symptom/medium/voice_change symptoms = list(/datum/symptom/voice_change) - cost = 4 - required_total_points = 8 short_desc = "Change the voice of victims." long_desc = "Change the voice of victims, causing confusion in communications." - -/datum/disease_ability/symptom/visionloss - name = "Vision Loss" +/datum/disease_ability/symptom/medium/visionloss symptoms = list(/datum/symptom/visionloss) - cost = 4 - required_total_points = 8 short_desc = "Damage the eyes of victims, eventually causing blindness." long_desc = "Damage the eyes of victims, eventually causing blindness. Decreases all stats." +/datum/disease_ability/symptom/medium/deafness + symptoms = list(/datum/symptom/deafness) -/datum/disease_ability/symptom/viraladaptation - name = "Self-Adaptation" +/datum/disease_ability/symptom/medium/fever + symptoms = list(/datum/symptom/fever) + +/datum/disease_ability/symptom/medium/shivering + symptoms = list(/datum/symptom/shivering) + +/datum/disease_ability/symptom/medium/headache + symptoms = list(/datum/symptom/headache) + +/datum/disease_ability/symptom/medium/nano_boost + symptoms = list(/datum/symptom/nano_boost) + +/datum/disease_ability/symptom/medium/nano_destroy + symptoms = list(/datum/symptom/nano_destroy) + +/datum/disease_ability/symptom/medium/viraladaptation symptoms = list(/datum/symptom/viraladaptation) - cost = 4 - required_total_points = 8 short_desc = "Cause your infection to become more resistant to detection and eradication." long_desc = "Cause your infection to mimic the function of normal body cells, becoming much harder to spot and to eradicate, but reducing its speed." +/datum/disease_ability/symptom/medium/viralevolution + symptoms = list(/datum/symptom/viralevolution) -/datum/disease_ability/symptom/vitiligo - name = "Skin Paleness" +/datum/disease_ability/symptom/medium/vitiligo symptoms = list(/datum/symptom/vitiligo) - cost = 1 - required_total_points = 8 - short_desc = "Cause victims to become pale." - long_desc = "Cause victims to become pale. Decreases all stats." +/datum/disease_ability/symptom/medium/revitiligo + symptoms = list(/datum/symptom/revitiligo) -/datum/disease_ability/symptom/sensory_restoration - name = "Sensory Restoration" - symptoms = list(/datum/symptom/sensory_restoration) - cost = 4 - required_total_points = 8 - short_desc = "Regenerate eye and ear damage of victims." - long_desc = "Regenerate eye and ear damage of victims." - - -/datum/disease_ability/symptom/itching - name = "Itching" +/datum/disease_ability/symptom/medium/itching symptoms = list(/datum/symptom/itching) - cost = 4 - required_total_points = 8 short_desc = "Cause victims to itch." long_desc = "Cause victims to itch, increasing all stats except stealth." - -/datum/disease_ability/symptom/weight_loss - name = "Weight Loss" +/datum/disease_ability/symptom/medium/heal/weight_loss symptoms = list(/datum/symptom/weight_loss) - cost = 4 - required_total_points = 8 short_desc = "Cause victims to lose weight." long_desc = "Cause victims to lose weight, and make it almost impossible for them to gain nutrition from food. Reduced nutrition allows your infection to spread more easily from hosts, especially by sneezing." +/datum/disease_ability/symptom/medium/heal/sensory_restoration + symptoms = list(/datum/symptom/sensory_restoration) + short_desc = "Regenerate eye and ear damage of victims." + long_desc = "Regenerate eye and ear damage of victims." -/datum/disease_ability/symptom/metabolism_heal - name = "Metabolic Boost" +/datum/disease_ability/symptom/medium/heal/mind_restoration + symptoms = list(/datum/symptom/mind_restoration) + +/******POWERFUL******/ + +/datum/disease_ability/symptom/powerful/fire + symptoms = list(/datum/symptom/fire) + +/datum/disease_ability/symptom/powerful/flesh_eating + symptoms = list(/datum/symptom/flesh_eating) + +/* +/datum/disease_ability/symptom/powerful/genetic_mutation + symptoms = list(/datum/symptom/genetic_mutation) + cost = 8 +*/ + +/datum/disease_ability/symptom/powerful/inorganic_adaptation + symptoms = list(/datum/symptom/inorganic_adaptation) + +/datum/disease_ability/symptom/powerful/narcolepsy + symptoms = list(/datum/symptom/narcolepsy) + +/datum/disease_ability/symptom/powerful/youth + symptoms = list(/datum/symptom/youth) + short_desc = "Cause victims to become eternally young." + long_desc = "Cause victims to become eternally young. Provides boosts to all stats except transmissibility." + +/****HEALING SUBTYPE****/ + +/datum/disease_ability/symptom/powerful/heal/starlight + symptoms = list(/datum/symptom/heal/starlight) + +/datum/disease_ability/symptom/powerful/heal/oxygen + symptoms = list(/datum/symptom/oxygen) + +/datum/disease_ability/symptom/powerful/heal/chem + symptoms = list(/datum/symptom/heal/chem) + +/datum/disease_ability/symptom/powerful/heal/metabolism symptoms = list(/datum/symptom/heal/metabolism) - cost = 4 - required_total_points = 16 short_desc = "Increase the metabolism of victims, causing them to process chemicals and grow hungry faster." long_desc = "Increase the metabolism of victims, causing them to process chemicals twice as fast and grow hungry more quickly." +/datum/disease_ability/symptom/powerful/heal/dark + symptoms = list(/datum/symptom/heal/darkness) -/datum/disease_ability/symptom/coma_heal - name = "Regenerative Coma" +/datum/disease_ability/symptom/powerful/heal/water + symptoms = list(/datum/symptom/heal/water) + +/datum/disease_ability/symptom/powerful/heal/plasma + symptoms = list(/datum/symptom/heal/plasma) + +/datum/disease_ability/symptom/powerful/heal/radiation + symptoms = list(/datum/symptom/heal/radiation) + +/datum/disease_ability/symptom/powerful/heal/coma symptoms = list(/datum/symptom/heal/coma) - cost = 8 - required_total_points = 16 short_desc = "Cause victims to fall into a healing coma when hurt." long_desc = "Cause victims to fall into a healing coma when hurt." diff --git a/code/modules/antagonists/disease/disease_disease.dm b/code/modules/antagonists/disease/disease_disease.dm index 21d0381982..c37abefab0 100644 --- a/code/modules/antagonists/disease/disease_disease.dm +++ b/code/modules/antagonists/disease/disease_disease.dm @@ -51,7 +51,8 @@ if(cures.len) return var/list/not_used = advance_cures.Copy() - cures = list(pick_n_take(not_used), pick_n_take(not_used)) + not_used.Cut(1, 6) // Removes the first five tiers of cures. + cures = list(pick(pick_n_take(not_used)), pick(pick_n_take(not_used))) // Get the cure name from the cure_id var/datum/reagent/D1 = GLOB.chemical_reagents_list[cures[1]] diff --git a/code/modules/antagonists/disease/disease_event.dm b/code/modules/antagonists/disease/disease_event.dm index 7183ed5455..385cee998b 100644 --- a/code/modules/antagonists/disease/disease_event.dm +++ b/code/modules/antagonists/disease/disease_event.dm @@ -18,7 +18,7 @@ var/mob/dead/observer/selected = pick_n_take(candidates) var/mob/camera/disease/virus = new /mob/camera/disease(SSmapping.get_station_center()) - virus.key = selected.key + selected.transfer_ckey(virus, FALSE) INVOKE_ASYNC(virus, /mob/camera/disease/proc/pick_name) message_admins("[ADMIN_LOOKUPFLW(virus)] has been made into a sentient disease by an event.") log_game("[key_name(virus)] was spawned as a sentient disease by an event.") diff --git a/code/modules/antagonists/disease/disease_mob.dm b/code/modules/antagonists/disease/disease_mob.dm index 4d378af724..49c34131fc 100644 --- a/code/modules/antagonists/disease/disease_mob.dm +++ b/code/modules/antagonists/disease/disease_mob.dm @@ -18,7 +18,7 @@ the new instance inside the host to be updated to the template's stats. layer = BELOW_MOB_LAYER lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE sight = SEE_SELF|SEE_THRU - initial_language_holder = /datum/language_holder/empty + initial_language_holder = /datum/language_holder/universal var/freemove = TRUE var/freemove_end = 0 @@ -43,7 +43,7 @@ the new instance inside the host to be updated to the template's stats. var/move_delay = 1 var/next_adaptation_time = 0 - var/adaptation_cooldown = 1200 + var/adaptation_cooldown = 600 var/list/purchased_abilities var/list/unpurchased_abilities @@ -118,10 +118,28 @@ the new instance inside the host to be updated to the template's stats. follow_next(Dir & NORTHWEST) last_move_tick = world.time +/mob/camera/disease/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode) + . = ..() + var/atom/movable/to_follow = speaker + if(radio_freq) + var/atom/movable/virtualspeaker/V = speaker + to_follow = V.source + var/link + if(to_follow in hosts) + link = FOLLOW_LINK(src, to_follow) + else + link = "" + // Recompose the message, because it's scrambled by default + message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode) + to_chat(src, "[link] [message]") + + /mob/camera/disease/mind_initialize() . = ..() if(!mind.has_antag_datum(/datum/antagonist/disease)) mind.add_antag_datum(/datum/antagonist/disease) + var/datum/atom_hud/medsensor = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED] + medsensor.add_hud_to(src) /mob/camera/disease/proc/pick_name() var/static/list/taken_names @@ -247,9 +265,12 @@ the new instance inside the host to be updated to the template's stats. if(!move_listener) move_listener = L.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/follow_mob))) else - L.TakeComponent(move_listener) - if(QDELING(move_listener)) - move_listener = null + if(L) + L.TakeComponent(move_listener) + if(QDELING(move_listener)) + move_listener = null + else + QDEL_NULL(move_listener) follow_mob() /mob/camera/disease/proc/follow_next(reverse = FALSE) diff --git a/code/modules/antagonists/ert/ert.dm b/code/modules/antagonists/ert/ert.dm index 53f8aa2da1..bb24af4f7a 100644 --- a/code/modules/antagonists/ert/ert.dm +++ b/code/modules/antagonists/ert/ert.dm @@ -36,30 +36,42 @@ /datum/antagonist/ert/security // kinda handled by the base template but here for completion -/datum/antagonist/ert/security/red +/datum/antagonist/ert/security/amber outfit = /datum/outfit/ert/security/alert +/datum/antagonist/ert/security/red + outfit = /datum/outfit/ert/security/alert/red + /datum/antagonist/ert/engineer role = "Engineer" outfit = /datum/outfit/ert/engineer -/datum/antagonist/ert/engineer/red +/datum/antagonist/ert/engineer/amber outfit = /datum/outfit/ert/engineer/alert +/datum/antagonist/ert/engineer/red + outfit = /datum/outfit/ert/engineer/alert/red + /datum/antagonist/ert/medic role = "Medical Officer" outfit = /datum/outfit/ert/medic -/datum/antagonist/ert/medic/red +/datum/antagonist/ert/medic/amber outfit = /datum/outfit/ert/medic/alert +/datum/antagonist/ert/medic/red + outfit = /datum/outfit/ert/medic/alert/red + /datum/antagonist/ert/commander role = "Commander" outfit = /datum/outfit/ert/commander -/datum/antagonist/ert/commander/red +/datum/antagonist/ert/commander/amber outfit = /datum/outfit/ert/commander/alert +/datum/antagonist/ert/commander/red + outfit = /datum/outfit/ert/commander/alert/red + /datum/antagonist/ert/deathsquad name = "Deathsquad Trooper" outfit = /datum/outfit/death_commando diff --git a/code/modules/antagonists/greybois/greybois.dm b/code/modules/antagonists/greybois/greybois.dm new file mode 100644 index 0000000000..b5e18045e8 --- /dev/null +++ b/code/modules/antagonists/greybois/greybois.dm @@ -0,0 +1,23 @@ +/datum/antagonist/greybois + name = "Emergency Assistant" + show_name_in_check_antagonists = TRUE + show_in_antagpanel = FALSE + var/mission = "Assist the station." + var/datum/outfit/outfit = /datum/outfit/ert/greybois + +/datum/antagonist/greybois/greygod + outfit = /datum/outfit/ert/greybois/greygod + +/datum/antagonist/greybois/greet() + to_chat(owner, "You are an Emergency Assistant.") + to_chat(owner, "Central Command is sending you to [station_name()] with the task: [mission]") + +/datum/antagonist/greybois/on_gain() + equipERT() + . = ..() + +/datum/antagonist/greybois/proc/equipERT() + var/mob/living/carbon/human/H = owner.current + if(!istype(H)) + return + H.equipOutfit(outfit) diff --git a/code/modules/antagonists/nukeop/equipment/nuclear_challenge.dm b/code/modules/antagonists/nukeop/equipment/nuclear_challenge.dm index b274283621..779dfb43a7 100644 --- a/code/modules/antagonists/nukeop/equipment/nuclear_challenge.dm +++ b/code/modules/antagonists/nukeop/equipment/nuclear_challenge.dm @@ -1,10 +1,12 @@ #define CHALLENGE_TELECRYSTALS 280 #define PLAYER_SCALING 1.5 #define CHALLENGE_TIME_LIMIT 3000 -#define CHALLENGE_MIN_PLAYERS 50 +#define CHALLENGE_PLAYERS_TARGET 50 //target players population. anything below is a malus to the challenge tc bonus. +#define TELECRYSTALS_MALUS_SCALING 1 //the higher the value, the bigger the malus. #define CHALLENGE_SHUTTLE_DELAY 15000 // 25 minutes, so the ops have at least 5 minutes before the shuttle is callable. GLOBAL_LIST_EMPTY(jam_on_wardec) +GLOBAL_VAR_INIT(war_declared, FALSE) /obj/item/nuclear_challenge name = "Declaration of War (Challenge Mode)" @@ -62,10 +64,15 @@ GLOBAL_LIST_EMPTY(jam_on_wardec) for(var/obj/machinery/computer/camera_advanced/shuttle_docker/D in GLOB.jam_on_wardec) D.jammed = TRUE + GLOB.war_declared = TRUE var/list/nukeops = get_antag_minds(/datum/antagonist/nukeop) var/actual_players = GLOB.joined_player_list.len - nukeops.len + var/tc_malus = 0 + if(actual_players < CHALLENGE_PLAYERS_TARGET) + tc_malus = FLOOR(((CHALLENGE_TELECRYSTALS / CHALLENGE_PLAYERS_TARGET) * (CHALLENGE_PLAYERS_TARGET - actual_players)) * TELECRYSTALS_MALUS_SCALING, 1) + + new uplink_type(get_turf(user), user.key, CHALLENGE_TELECRYSTALS - tc_malus + CEILING(PLAYER_SCALING * actual_players, 1)) - new uplink_type(get_turf(user), user.key, CHALLENGE_TELECRYSTALS + CEILING(PLAYER_SCALING * actual_players, 1)) CONFIG_SET(number/shuttle_refuel_delay, max(CONFIG_GET(number/shuttle_refuel_delay), CHALLENGE_SHUTTLE_DELAY)) SSblackbox.record_feedback("amount", "nuclear_challenge_mode", 1) @@ -76,11 +83,6 @@ GLOBAL_LIST_EMPTY(jam_on_wardec) to_chat(user, "You are already in the process of declaring war! Make your mind up.") return FALSE - var/list/nukeops = get_antag_minds(/datum/antagonist/nukeop) - var/actual_players = GLOB.joined_player_list.len - nukeops.len - if(actual_players < CHALLENGE_MIN_PLAYERS) - to_chat(user, "The enemy crew is too small to be worth declaring war on.") - return FALSE if(!user.onSyndieBase()) to_chat(user, "You have to be at your base to use this.") return FALSE @@ -99,5 +101,6 @@ GLOBAL_LIST_EMPTY(jam_on_wardec) #undef CHALLENGE_TELECRYSTALS #undef CHALLENGE_TIME_LIMIT -#undef CHALLENGE_MIN_PLAYERS +#undef CHALLENGE_PLAYERS_TARGET +#undef TELECRYSTALS_MALUS_SCALING #undef CHALLENGE_SHUTTLE_DELAY diff --git a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm index ade5458765..add3c1d9b0 100644 --- a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm +++ b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm @@ -373,6 +373,11 @@ S.switch_mode_to(TRACK_INFILTRATOR) countdown.start() set_security_level("delta") + + if(GLOB.war_declared) + var/area/A = get_area(src) + priority_announce("Alert: Unexpected increase in radiation levels near [A.name] ([src.x],[src.y],[src.z]). Please send an authorized radiation specialist to investigate.", "Sensory Nuclear Indexer Telemetry Calculation Helper") + else detonation_timer = null set_security_level(previous_level) diff --git a/code/modules/antagonists/overthrow/overthrow.dm b/code/modules/antagonists/overthrow/overthrow.dm index 2f08824c0b..075b9f13bc 100644 --- a/code/modules/antagonists/overthrow/overthrow.dm +++ b/code/modules/antagonists/overthrow/overthrow.dm @@ -107,9 +107,9 @@ /datum/antagonist/overthrow/proc/equip_overthrow() if(!owner || !owner.current || !ishuman(owner.current)) // only equip existing human overthrow members. This excludes the AI, in particular. return - var/obj/item/implant/storage/S = locate(/obj/item/implant/storage) in owner.current + var/obj/item/implant/storage/S = locate(/obj/item/implant/storage) in owner.current.implants if(!S) - S = new(owner.current) + S = new S.implant(owner.current) var/I = pick(possible_useful_items) if(ispath(I)) // in case some admin decides to fuck the list up for fun diff --git a/code/modules/antagonists/revenant/revenant.dm b/code/modules/antagonists/revenant/revenant.dm index 87794993a7..f380fa68e9 100644 --- a/code/modules/antagonists/revenant/revenant.dm +++ b/code/modules/antagonists/revenant/revenant.dm @@ -377,14 +377,15 @@ /obj/item/ectoplasm/revenant/proc/reform() if(QDELETED(src) || QDELETED(revenant) || inert) return - var/key_of_revenant + var/key_of_revenant = FALSE message_admins("Revenant ectoplasm was left undestroyed for 1 minute and is reforming into a new revenant.") forceMove(drop_location()) //In case it's in a backpack or someone's hand revenant.forceMove(loc) if(old_key) for(var/mob/M in GLOB.dead_mob_list) if(M.client && M.client.key == old_key) //Only recreates the mob if the mob the client is in is dead - key_of_revenant = old_key + M.transfer_ckey(revenant.key, FALSE) + key_of_revenant = TRUE break if(!key_of_revenant) message_admins("The new revenant's old client either could not be found or is in a new, living mob - grabbing a random candidate instead...") @@ -396,22 +397,21 @@ visible_message("[src] settles down and seems lifeless.") return var/mob/dead/observer/C = pick(candidates) - key_of_revenant = C.key - if(!key_of_revenant) + C.transfer_ckey(revenant.key, FALSE) + if(!revenant.key) qdel(revenant) message_admins("No ckey was found for the new revenant. Oh well!") inert = TRUE visible_message("[src] settles down and seems lifeless.") return - message_admins("[key_of_revenant] has been [old_key == key_of_revenant ? "re":""]made into a revenant by reforming ectoplasm.") - log_game("[key_of_revenant] was [old_key == key_of_revenant ? "re":""]made as a revenant by reforming ectoplasm.") + message_admins("[key_of_revenant] has been [old_key == revenant.key ? "re":""]made into a revenant by reforming ectoplasm.") + log_game("[key_of_revenant] was [old_key == revenant.key ? "re":""]made as a revenant by reforming ectoplasm.") visible_message("[src] suddenly rises into the air before fading away.") revenant.essence = essence revenant.essence_regen_cap = essence revenant.death_reset() - revenant.key = key_of_revenant revenant = null qdel(src) diff --git a/code/modules/antagonists/revenant/revenant_blight.dm b/code/modules/antagonists/revenant/revenant_blight.dm index 7037ecae86..89d8de283a 100644 --- a/code/modules/antagonists/revenant/revenant_blight.dm +++ b/code/modules/antagonists/revenant/revenant_blight.dm @@ -11,9 +11,9 @@ viable_mobtypes = list(/mob/living/carbon/human) disease_flags = CURABLE permeability_mod = 1 - severity = DISEASE_SEVERITY_HARMFUL - var/stagedamage = 0 //Highest stage reached. + severity = DISEASE_SEVERITY_DANGEROUS var/finalstage = 0 //Because we're spawning off the cure in the final stage, we need to check if we've done the final stage's effects. + var/datum/mood_event/revenant_blight/depression /datum/disease/revblight/cure() if(affected_mob) @@ -21,12 +21,13 @@ if(affected_mob.dna && affected_mob.dna.species) affected_mob.dna.species.handle_mutant_bodyparts(affected_mob) affected_mob.dna.species.handle_hair(affected_mob) - to_chat(affected_mob, "You feel better.") + SEND_SIGNAL(affected_mob, COMSIG_CLEAR_MOOD_EVENT, "rev_blight") ..() /datum/disease/revblight/stage_act() if(!finalstage) - if(affected_mob.lying && prob(stage*6)) + if(affected_mob.lying && prob(stage*4)) + to_chat(affected_mob, "You feel better.") cure() return if(prob(stage*3)) @@ -34,10 +35,6 @@ affected_mob.confused += 8 affected_mob.adjustStaminaLoss(8) new /obj/effect/temp_visual/revenant(affected_mob.loc) - if(stagedamage < stage) - stagedamage++ - affected_mob.adjustToxLoss(stage*2) //should, normally, do about 30 toxin damage. - new /obj/effect/temp_visual/revenant(affected_mob.loc) if(prob(45)) affected_mob.adjustStaminaLoss(stage) ..() //So we don't increase a stage before applying the stage damage. @@ -46,9 +43,13 @@ if(prob(5)) affected_mob.emote("pale") if(3) + if(!depression) + depression = SEND_SIGNAL(affected_mob, COMSIG_ADD_MOOD_EVENT, "rev_blight", /datum/mood_event/revenant_blight) + SEND_SIGNAL(affected_mob, COMSIG_DECREASE_SANITY, 0.12, SANITY_CRAZY) if(prob(10)) affected_mob.emote(pick("pale","shiver")) if(4) + SEND_SIGNAL(affected_mob, COMSIG_DECREASE_SANITY, 0.18, SANITY_CRAZY) if(prob(15)) affected_mob.emote(pick("pale","shiver","cries")) if(5) @@ -56,12 +57,18 @@ finalstage = TRUE to_chat(affected_mob, "You feel like [pick("nothing's worth it anymore", "nobody ever needed your help", "nothing you did mattered", "everything you tried to do was worthless")].") affected_mob.adjustStaminaLoss(45) - new /obj/effect/temp_visual/revenant(affected_mob.loc) - if(affected_mob.dna && affected_mob.dna.species) + if(affected_mob.dna?.species) affected_mob.dna.species.handle_mutant_bodyparts(affected_mob,"#1d2953") affected_mob.dna.species.handle_hair(affected_mob,"#1d2953") affected_mob.visible_message("[affected_mob] looks terrifyingly gaunt...", "You suddenly feel like your skin is wrong...") affected_mob.add_atom_colour("#1d2953", TEMPORARY_COLOUR_PRIORITY) - addtimer(CALLBACK(src, .proc/cure), 100) - else - return + new /obj/effect/temp_visual/revenant(affected_mob.loc) + addtimer(CALLBACK(src, .proc/curses), 150) + +/datum/disease/revblight/proc/curses() + if(QDELETED(affected_mob)) + return + affected_mob.playsound_local(affected_mob, 'sound/effects/curse5.ogg', 40, 1, -1) + to_chat(affected_mob, "You sense the terrific curse of a vengeful ghost befall upon you...") + affected_mob.apply_necropolis_curse(null, 7 MINUTES) //Once the blight has done its course without being cured beforehand, it will cast a necrocurse to compensate how underpowered it's. + cure() diff --git a/code/modules/antagonists/revenant/revenant_spawn_event.dm b/code/modules/antagonists/revenant/revenant_spawn_event.dm index c9a892cd64..cb534b6613 100644 --- a/code/modules/antagonists/revenant/revenant_spawn_event.dm +++ b/code/modules/antagonists/revenant/revenant_spawn_event.dm @@ -52,7 +52,7 @@ return MAP_ERROR var/mob/living/simple_animal/revenant/revvie = new(pick(spawn_locs)) - revvie.key = selected.key + selected.transfer_ckey(revvie, FALSE) message_admins("[ADMIN_LOOKUPFLW(revvie)] has been made into a revenant by an event.") log_game("[key_name(revvie)] was spawned as a revenant by an event.") spawned_mobs += revvie diff --git a/code/modules/antagonists/slaughter/slaughter.dm b/code/modules/antagonists/slaughter/slaughter.dm index 4f31346136..03a176b054 100644 --- a/code/modules/antagonists/slaughter/slaughter.dm +++ b/code/modules/antagonists/slaughter/slaughter.dm @@ -80,6 +80,7 @@ desc = "Still it beats furiously, emanating an aura of utter hate." icon = 'icons/obj/surgery.dmi' icon_state = "demon_heart-on" + decay_factor = 0 /obj/item/organ/heart/demon/update_icon() return //always beating visually diff --git a/code/modules/antagonists/traitor/IAA/internal_affairs.dm b/code/modules/antagonists/traitor/IAA/internal_affairs.dm index 051bf74705..f2e6566e8f 100644 --- a/code/modules/antagonists/traitor/IAA/internal_affairs.dm +++ b/code/modules/antagonists/traitor/IAA/internal_affairs.dm @@ -244,10 +244,12 @@ to_chat(owner.current, "Your target has been framed for [crime], and you have been tasked with eliminating them to prevent them defending themselves in court.") to_chat(owner.current, "Any damage you cause will be a further embarrassment to Nanotrasen, so you have no limits on collateral damage.") to_chat(owner.current, " You have been provided with a standard uplink to accomplish your task. ") + to_chat(owner.current, "By no means reveal that you, or any other NT employees, are undercover agents.") else to_chat(owner.current, "Your target is suspected of [crime], and you have been tasked with eliminating them by any means necessary to avoid a costly and embarrassing public trial.") to_chat(owner.current, "While you have a license to kill, unneeded property damage or loss of employee life will lead to your contract being terminated.") to_chat(owner.current, "For the sake of plausible deniability, you have been equipped with an array of captured Syndicate weaponry available via uplink.") + to_chat(owner.current, "By no means reveal that you, or any other NT employees, are undercover agents.") to_chat(owner.current, "Finally, watch your back. Your target has friends in high places, and intel suggests someone may have taken out a contract of their own to protect them.") owner.announce_objectives() diff --git a/code/modules/antagonists/valentines/valentine.dm b/code/modules/antagonists/valentines/valentine.dm index 31e69b32c2..21e54374a4 100644 --- a/code/modules/antagonists/valentines/valentine.dm +++ b/code/modules/antagonists/valentines/valentine.dm @@ -27,6 +27,7 @@ var/mob/living/L = owner L.remove_status_effect(STATUS_EFFECT_INLOVE) + /datum/antagonist/valentine/greet() to_chat(owner, "You're on a date with [date.name]! Protect [date.p_them()] at all costs. This takes priority over all other loyalties.") @@ -42,4 +43,21 @@ if(objectives_complete) return "[owner.name] protected [owner.p_their()] date" else - return "[owner.name] date failed!" \ No newline at end of file + return "[owner.name] date failed!" + +//Just so it's distinct, basically. +/datum/antagonist/valentine/chem/greet() + to_chat(owner, "You're in love with [date.name]! Protect [date.p_them()] at all costs. This takes priority over all other loyalties.") + +/datum/antagonist/valentine/chem/roundend_report() + var/objectives_complete = TRUE + if(owner.objectives.len) + for(var/datum/objective/objective in owner.objectives) + if(!objective.check_completion()) + objectives_complete = FALSE + break + + if(objectives_complete) + return "[owner.name] protected [owner.p_their()] love: [date.name]! What a cutie!" + else + return "[owner.name] date failed!" diff --git a/code/modules/antagonists/wizard/equipment/artefact.dm b/code/modules/antagonists/wizard/equipment/artefact.dm index 08e00ea0f4..57488a6722 100644 --- a/code/modules/antagonists/wizard/equipment/artefact.dm +++ b/code/modules/antagonists/wizard/equipment/artefact.dm @@ -198,7 +198,7 @@ to_chat(user, "This artifact can only affect three undead at a time!") return - M.set_species(/datum/species/skeleton, icon_update=0) + M.set_species(/datum/species/skeleton/space, icon_update=0) M.revive(full_heal = 1, admin_revive = 1) spooky_scaries |= M to_chat(M, "You have been revived by [user.real_name]!") @@ -405,8 +405,12 @@ var/breakout = 0 while(breakout < 50) if(!T) - break + end_effect(user) + return var/turf/potential_T = find_safe_turf() + if(!potential_T) + end_effect(user) + return if(T.z != potential_T.z || abs(get_dist_euclidian(potential_T,T)) > 50 - breakout) do_teleport(user, potential_T, channel = TELEPORT_CHANNEL_MAGIC) user.canmove = 0 diff --git a/code/modules/antagonists/wizard/equipment/soulstone.dm b/code/modules/antagonists/wizard/equipment/soulstone.dm index 40551ae2fc..1df8e43316 100644 --- a/code/modules/antagonists/wizard/equipment/soulstone.dm +++ b/code/modules/antagonists/wizard/equipment/soulstone.dm @@ -218,7 +218,7 @@ newstruct.master = stoner var/datum/action/innate/seek_master/SM = new() SM.Grant(newstruct) - newstruct.key = target.key + target.transfer_ckey(newstruct) var/obj/screen/alert/bloodsense/BS if(newstruct.mind && ((stoner && iscultist(stoner)) || cultoverride) && SSticker && SSticker.mode) SSticker.mode.add_cultist(newstruct.mind, 0) @@ -243,7 +243,7 @@ S.canmove = FALSE//Can't move out of the soul stone S.name = "Shade of [T.real_name]" S.real_name = "Shade of [T.real_name]" - S.key = T.key + T.transfer_ckey(S) S.language_holder = U.language_holder.copy(S) if(U) S.faction |= "[REF(U)]" //Add the master as a faction, allowing inter-mob cooperation diff --git a/code/modules/antagonists/wizard/wizard.dm b/code/modules/antagonists/wizard/wizard.dm index e6cae518b6..8a20a81555 100644 --- a/code/modules/antagonists/wizard/wizard.dm +++ b/code/modules/antagonists/wizard/wizard.dm @@ -245,7 +245,7 @@ if(!istype(M)) return - var/obj/item/implant/exile/Implant = new/obj/item/implant/exile(M) + var/obj/item/implant/exile/Implant = new Implant.implant(M) /datum/antagonist/wizard/academy/create_objectives() diff --git a/code/modules/assembly/flash.dm b/code/modules/assembly/flash.dm index b1aa63c242..186eb1b024 100644 --- a/code/modules/assembly/flash.dm +++ b/code/modules/assembly/flash.dm @@ -12,6 +12,7 @@ crit_fail = FALSE //Is the flash burnt out? light_color = LIGHT_COLOR_WHITE light_power = FLASH_LIGHT_POWER + var/flashing_overlay = "flash-f" var/times_used = 0 //Number of times it's been used. var/burnout_resistance = 0 var/last_used = 0 //last world.time it was used. @@ -36,8 +37,8 @@ add_overlay("flashburnt") attached_overlays += "flashburnt" if(flash) - add_overlay("flash-f") - attached_overlays += "flash-f" + add_overlay(flashing_overlay) + attached_overlays += flashing_overlay addtimer(CALLBACK(src, .proc/update_icon), 5) if(holder) holder.update_icon() @@ -313,3 +314,50 @@ /obj/item/assembly/flash/shield/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) activate() return ..() + +//ported from tg - check to make sure it can't appear where it's not supposed to. +/obj/item/assembly/flash/hypnotic + desc = "A modified flash device, programmed to emit a sequence of subliminal flashes that can send a vulnerable target into a hypnotic trance." + flashing_overlay = "flash-hypno" //I cannot find this icon no matter how hard I look in tg, so I might just make my own. + light_color = LIGHT_COLOR_PINK + cooldown = 20 + +/obj/item/assembly/flash/hypnotic/burn_out() + return + +/obj/item/assembly/flash/hypnotic/flash_carbon(mob/living/carbon/M, mob/user, power = 15, targeted = TRUE, generic_message = FALSE) + if(!istype(M)) + return + if(user) + log_combat(user, M, "[targeted? "hypno-flashed(targeted)" : "hypno-flashed(AOE)"]", src) + else //caused by emp/remote signal + M.log_message("was [targeted? "hypno-flashed(targeted)" : "hypno-flashed(AOE)"]",LOG_ATTACK) + if(generic_message && M != user) + to_chat(M, "[src] emits a soothing light...") + if(targeted) + if(M.flash_act(1, 1)) + var/hypnosis = FALSE + if(M.hypnosis_vulnerable()) + hypnosis = TRUE + if(user) + user.visible_message("[user] blinds [M] with the flash!", "You hypno-flash [M]!") + + if(!hypnosis) + to_chat(M, "The light makes you feel oddly relaxed...") + M.confused += min(M.confused + 10, 20) + M.dizziness += min(M.dizziness + 10, 20) + M.drowsyness += min(M.drowsyness + 10, 20) + M.apply_status_effect(STATUS_EFFECT_PACIFY, 100) + else + M.apply_status_effect(/datum/status_effect/trance, 200, TRUE) + + else if(user) + user.visible_message("[user] fails to blind [M] with the flash!", "You fail to hypno-flash [M]!") + else + to_chat(M, "[src] fails to blind you!") + + else if(M.flash_act()) + to_chat(M, "Such a pretty light...") + M.confused += min(M.confused + 4, 20) + M.dizziness += min(M.dizziness + 4, 20) + M.drowsyness += min(M.drowsyness + 4, 20) diff --git a/code/modules/atmospherics/gasmixtures/reactions.dm b/code/modules/atmospherics/gasmixtures/reactions.dm index 5ad97fb7c8..f9c831a65a 100644 --- a/code/modules/atmospherics/gasmixtures/reactions.dm +++ b/code/modules/atmospherics/gasmixtures/reactions.dm @@ -210,9 +210,9 @@ return cached_results["fire"] ? REACTING : NO_REACTION -//fusion: a terrible idea that was fun but broken. Now reworked to be less broken and more interesting. Again (and again, and again) +//fusion: a terrible idea that was fun but broken. Now reworked to be less broken and more interesting. Again (and again, and again). Again! //Fusion Rework Counter: Please increment this if you make a major overhaul to this system again. -//5 reworks +//6 reworks /datum/gas_reaction/fusion exclude = FALSE @@ -220,100 +220,79 @@ name = "Plasmic Fusion" id = "fusion" -//Since fusion isn't really intended to happen in successive chains, the requirements are very high /datum/gas_reaction/fusion/init_reqs() min_requirements = list( "TEMP" = FUSION_TEMPERATURE_THRESHOLD, - "ENER" = FUSION_ENERGY_THRESHOLD, + /datum/gas/tritium = FUSION_TRITIUM_MOLES_USED, /datum/gas/plasma = FUSION_MOLE_THRESHOLD, - /datum/gas/tritium = FUSION_MOLE_THRESHOLD - ) + /datum/gas/carbon_dioxide = FUSION_MOLE_THRESHOLD) /datum/gas_reaction/fusion/react(datum/gas_mixture/air, datum/holder) var/list/cached_gases = air.gases - var/temperature = air.temperature - if(!air.analyzer_results) - air.analyzer_results = new - var/list/cached_scan_results = air.analyzer_results var/turf/open/location if (istype(holder,/datum/pipeline)) //Find the tile the reaction is occuring on, or a random part of the network if it's a pipenet. var/datum/pipeline/fusion_pipenet = holder location = get_turf(pick(fusion_pipenet.members)) else location = get_turf(holder) - + if(!air.analyzer_results) + air.analyzer_results = new + var/list/cached_scan_results = air.analyzer_results var/old_heat_capacity = air.heat_capacity() - var/reaction_energy = 0 - - var/mediation = FUSION_MEDIATION_FACTOR*(air.heat_capacity()-(cached_gases[/datum/gas/plasma]*GLOB.meta_gas_specific_heats[/datum/gas/plasma]))/(air.total_moles()-cached_gases[/datum/gas/plasma]) //This is the average specific heat of the mixture,not including plasma. - - var/gases_fused = air.total_moles() - cached_gases[/datum/gas/plasma] - var/plasma_differential = (cached_gases[/datum/gas/plasma] - gases_fused) / air.total_moles() - var/reaction_efficiency = FUSION_EFFICIENCY_BASE ** -((plasma_differential ** 2) / FUSION_EFFICIENCY_DIVISOR) //https://www.desmos.com/calculator/6jjx3vdrvx - + var/reaction_energy = 0 //Reaction energy can be negative or positive, for both exothermic and endothermic reactions. + var/initial_plasma = cached_gases[/datum/gas/plasma] + var/initial_carbon = cached_gases[/datum/gas/carbon_dioxide] + var/scale_factor = (air.volume)/(PI) //We scale it down by volume/Pi because for fusion conditions, moles roughly = 2*volume, but we want it to be based off something constant between reactions. + var/toroidal_size = (2*PI)+TORADIANS(arctan((air.volume-TOROID_VOLUME_BREAKEVEN)/TOROID_VOLUME_BREAKEVEN)) //The size of the phase space hypertorus var/gas_power = 0 + var/list/gas_fusion_powers = GLOB.meta_gas_fusions for (var/gas_id in cached_gases) - gas_power += reaction_efficiency * (GLOB.meta_gas_fusions[gas_id]*cached_gases[gas_id]) + gas_power += (gas_fusion_powers[gas_id]*cached_gases[gas_id]) + var/instability = MODULUS((gas_power*INSTABILITY_GAS_POWER_FACTOR)**2,toroidal_size) //Instability effects how chaotic the behavior of the reaction is + cached_scan_results[id] = instability//used for analyzer feedback - var/power_ratio = gas_power/mediation - cached_scan_results[id] = power_ratio //used for analyzer feedback + var/plasma = (initial_plasma-FUSION_MOLE_THRESHOLD)/(scale_factor) //We have to scale the amounts of carbon and plasma down a significant amount in order to show the chaotic dynamics we want + var/carbon = (initial_carbon-FUSION_MOLE_THRESHOLD)/(scale_factor) //We also subtract out the threshold amount to make it harder for fusion to burn itself out. - for (var/gas_id in cached_gases) //and now we fuse - cached_gases[gas_id] = 0 + //The reaction is a specific form of the Kicked Rotator system, which displays chaotic behavior and can be used to model particle interactions. + plasma = MODULUS(plasma - (instability*sin(TODEGREES(carbon))), toroidal_size) + carbon = MODULUS(carbon - plasma, toroidal_size) - var/radiation_power = (FUSION_RADIATION_FACTOR * power_ratio) / (power_ratio + FUSION_RADIATION_CONSTANT) //https://www.desmos.com/calculator/4i1f296phl - var/zap_power = ((FUSION_ZAP_POWER_ASYMPTOTE * power_ratio) / (power_ratio + FUSION_ZAP_POWER_CONSTANT)) + FUSION_ZAP_POWER_BASE //https://www.desmos.com/calculator/n0zkdpxnrr - var/do_explosion = FALSE - var/zap_range //these ones are set later - var/fusion_prepare_to_die_edition_rng - if (power_ratio > FUSION_SUPER_TIER_THRESHOLD) //power ratio 50+: SUPER TIER. The gases become so energized that they fuse into a ton of tritium, which is pretty nice! Until you consider the fact that everything just exploded, the canister is probably going to break and you're irradiated. - reaction_energy += gases_fused * FUSION_RELEASE_ENERGY_SUPER * (power_ratio / FUSION_ENERGY_DIVISOR_SUPER) - cached_gases[/datum/gas/tritium] += gases_fused * FUSION_GAS_CREATION_FACTOR_TRITIUM //60% of the gas is converted to energy, 40% to trit - fusion_prepare_to_die_edition_rng = 100 //Wait a minute.. - do_explosion = TRUE - zap_range = FUSION_ZAP_RANGE_SUPER + cached_gases[/datum/gas/plasma] = plasma*scale_factor + FUSION_MOLE_THRESHOLD //Scales the gases back up + cached_gases[/datum/gas/carbon_dioxide] = carbon*scale_factor + FUSION_MOLE_THRESHOLD + var/delta_plasma = initial_plasma - cached_gases[/datum/gas/plasma] - else if (power_ratio > FUSION_HIGH_TIER_THRESHOLD) //power ratio 20-50; High tier. The reaction is so energized that it fuses into a small amount of stimulum, and some pluoxium. Very dangerous, but super cool and super useful. - reaction_energy += gases_fused * FUSION_RELEASE_ENERGY_HIGH * (power_ratio / FUSION_ENERGY_DIVISOR_HIGH) - cached_gases[/datum/gas/stimulum] += gases_fused * FUSION_GAS_CREATION_FACTOR_STIM //40% of the gas is converted to energy, 60% to stim and pluox - cached_gases[/datum/gas/pluoxium] += gases_fused * FUSION_GAS_CREATION_FACTOR_PLUOX - fusion_prepare_to_die_edition_rng = power_ratio //Now we're getting into dangerous territory - do_explosion = TRUE - zap_range = FUSION_ZAP_RANGE_HIGH - - else if (power_ratio > FUSION_MID_TIER_THRESHOLD) //power_ratio 5 to 20; Mediation is overpowered, fusion reaction starts to break down. - reaction_energy += gases_fused * FUSION_RELEASE_ENERGY_MID * (power_ratio / FUSION_ENERGY_DIVISOR_MID) - cached_gases[/datum/gas/nitryl] += gases_fused * FUSION_GAS_CREATION_FACTOR_NITRYL //20% of the gas is converted to energy, 80% to nitryl and N2O - cached_gases[/datum/gas/nitrous_oxide] += gases_fused * FUSION_GAS_CREATION_FACTOR_N2O - fusion_prepare_to_die_edition_rng = power_ratio * FUSION_MID_TIER_RAD_PROB_FACTOR //Still unlikely, but don't stand next to the reaction unprotected - zap_range = FUSION_ZAP_RANGE_MID - - else //power ratio 0 to 5; Gas power is overpowered. Fusion isn't nearly as powerful. - reaction_energy += gases_fused * FUSION_RELEASE_ENERGY_LOW * (power_ratio / FUSION_ENERGY_DIVISOR_LOW) - cached_gases[/datum/gas/bz] += gases_fused * FUSION_GAS_CREATION_FACTOR_BZ //10% of the gas is converted to energy, 90% to BZ and CO2 - cached_gases[/datum/gas/carbon_dioxide] += gases_fused * FUSION_GAS_CREATION_FACTOR_CO2 - fusion_prepare_to_die_edition_rng = power_ratio * FUSION_LOW_TIER_RAD_PROB_FACTOR //Low, but still something to look out for - zap_range = FUSION_ZAP_RANGE_LOW - - //All the deadly consequences of fusion, consolidated for your viewing pleasure - if (location) - if(prob(fusion_prepare_to_die_edition_rng)) //Some.. permanent effects - if(do_explosion) - explosion(location, 0, 0, 5, power_ratio, TRUE, TRUE) //large shockwave, the actual radius is quite small - people will recognize that you're doing fusion - radiation_pulse(location, radiation_power) //You mean causing a super-tier fusion reaction in the halls is a bad idea? - SSresearch.science_tech.add_point_type(TECHWEB_POINT_TYPE_DEFAULT, 30000)//The science is cool though. - playsound(location, 'sound/effects/supermatter.ogg', 100, 0) - else - playsound(location, 'sound/effects/phasein.ogg', 75, 0) - //These will always happen, so be prepared - tesla_zap(location, zap_range, zap_power, TESLA_FUSION_FLAGS) //larpers beware - location.fire_nuclear_particles(power_ratio) //see code/modules/projectile/energy/nuclear_particle.dm + reaction_energy += delta_plasma*PLASMA_BINDING_ENERGY //Energy is gained or lost corresponding to the creation or destruction of mass. + if(instability < FUSION_INSTABILITY_ENDOTHERMALITY) + reaction_energy = max(reaction_energy,0) //Stable reactions don't end up endothermic. + else if (reaction_energy < 0) + reaction_energy *= (instability-FUSION_INSTABILITY_ENDOTHERMALITY)**0.5 + if(air.thermal_energy() + reaction_energy < 0) //No using energy that doesn't exist. + cached_gases[/datum/gas/plasma] = initial_plasma + cached_gases[/datum/gas/carbon_dioxide] = initial_carbon + return NO_REACTION + cached_gases[/datum/gas/tritium] -= FUSION_TRITIUM_MOLES_USED + //The decay of the tritium and the reaction's energy produces waste gases, different ones depending on whether the reaction is endo or exothermic if(reaction_energy > 0) + cached_gases[/datum/gas/oxygen] += FUSION_TRITIUM_MOLES_USED*(reaction_energy*FUSION_TRITIUM_CONVERSION_COEFFICIENT) + cached_gases[/datum/gas/nitrous_oxide] += FUSION_TRITIUM_MOLES_USED*(reaction_energy*FUSION_TRITIUM_CONVERSION_COEFFICIENT) + else + cached_gases[/datum/gas/bz] += FUSION_TRITIUM_MOLES_USED*(reaction_energy*-FUSION_TRITIUM_CONVERSION_COEFFICIENT) + cached_gases[/datum/gas/nitryl] += FUSION_TRITIUM_MOLES_USED*(reaction_energy*-FUSION_TRITIUM_CONVERSION_COEFFICIENT) + + if(reaction_energy) + if(location) + var/particle_chance = ((PARTICLE_CHANCE_CONSTANT)/(reaction_energy-PARTICLE_CHANCE_CONSTANT)) + 1//Asymptopically approaches 100% as the energy of the reaction goes up. + if(prob(PERCENT(particle_chance))) + location.fire_nuclear_particle() + var/rad_power = max((FUSION_RAD_COEFFICIENT/instability) + FUSION_RAD_MAX,0) + radiation_pulse(location,rad_power) + var/new_heat_capacity = air.heat_capacity() if(new_heat_capacity > MINIMUM_HEAT_CAPACITY) - air.temperature = max(((temperature*old_heat_capacity + reaction_energy)/new_heat_capacity),TCMB) + air.temperature = CLAMP(((air.temperature*old_heat_capacity + reaction_energy)/new_heat_capacity),TCMB,INFINITY) return REACTING /datum/gas_reaction/nitrylformation //The formation of nitryl. Endothermic. Requires N2O as a catalyst. @@ -364,15 +343,10 @@ var/list/cached_gases = air.gases var/temperature = air.temperature var/pressure = air.return_pressure() - var/old_heat_capacity = air.heat_capacity() var/reaction_efficency = min(1/((pressure/(0.1*ONE_ATMOSPHERE))*(max(cached_gases[/datum/gas/plasma]/cached_gases[/datum/gas/nitrous_oxide],1))),cached_gases[/datum/gas/nitrous_oxide],cached_gases[/datum/gas/plasma]/2) var/energy_released = 2*reaction_efficency*FIRE_CARBON_ENERGY_RELEASED - if(cached_gases[/datum/gas/miasma] && cached_gases[/datum/gas/miasma] > 0) - energy_released /= cached_gases[/datum/gas/miasma]*0.1 - if(cached_gases[/datum/gas/bz] && cached_gases[/datum/gas/bz] > 0) - energy_released *= cached_gases[/datum/gas/bz]*0.1 - if ((cached_gases[/datum/gas/nitrous_oxide] - reaction_efficency < 0 )|| (cached_gases[/datum/gas/plasma] - (2*reaction_efficency) < 0)) //Shouldn't produce gas from nothing. + if ((cached_gases[/datum/gas/nitrous_oxide] - reaction_efficency < 0 )|| (cached_gases[/datum/gas/plasma] - (2*reaction_efficency) < 0) || energy_released <= 0) //Shouldn't produce gas from nothing. return NO_REACTION cached_gases[/datum/gas/bz] += reaction_efficency if(reaction_efficency == cached_gases[/datum/gas/nitrous_oxide]) @@ -381,7 +355,7 @@ cached_gases[/datum/gas/nitrous_oxide] -= reaction_efficency cached_gases[/datum/gas/plasma] -= 2*reaction_efficency - SSresearch.science_tech.add_point_type(TECHWEB_POINT_TYPE_DEFAULT, (reaction_efficency**0.5)*BZ_RESEARCH_AMOUNT) + SSresearch.science_tech.add_point_type(TECHWEB_POINT_TYPE_DEFAULT, min((reaction_efficency**2)*BZ_RESEARCH_SCALE),BZ_RESEARCH_MAX_AMOUNT) if(energy_released > 0) var/new_heat_capacity = air.heat_capacity() @@ -477,4 +451,4 @@ //Possibly burning a bit of organic matter through maillard reaction, so a *tiny* bit more heat would be understandable air.temperature += cleaned_air * 0.002 - SSresearch.science_tech.add_point_type(TECHWEB_POINT_TYPE_DEFAULT, cleaned_air*MIASMA_RESEARCH_AMOUNT)//Turns out the burning of miasma is kinda interesting to scientists \ No newline at end of file + SSresearch.science_tech.add_point_type(TECHWEB_POINT_TYPE_DEFAULT, cleaned_air*MIASMA_RESEARCH_AMOUNT)//Turns out the burning of miasma is kinda interesting to scientists diff --git a/code/modules/atmospherics/machinery/airalarm.dm b/code/modules/atmospherics/machinery/airalarm.dm index 3bf54a1178..6ca25c0d80 100644 --- a/code/modules/atmospherics/machinery/airalarm.dm +++ b/code/modules/atmospherics/machinery/airalarm.dm @@ -1,880 +1,882 @@ -/datum/tlv - var/min2 - var/min1 - var/max1 - var/max2 - -/datum/tlv/New(min2 as num, min1 as num, max1 as num, max2 as num) - if(min2) src.min2 = min2 - if(min1) src.min1 = min1 - if(max1) src.max1 = max1 - if(max2) src.max2 = max2 - -/datum/tlv/proc/get_danger_level(val as num) - if(max2 != -1 && val >= max2) - return 2 - if(min2 != -1 && val <= min2) - return 2 - if(max1 != -1 && val >= max1) - return 1 - if(min1 != -1 && val <= min1) - return 1 - return 0 - -/datum/tlv/no_checks - min2 = -1 - min1 = -1 - max1 = -1 - max2 = -1 - -/datum/tlv/dangerous - min2 = -1 - min1 = -1 - max1 = 0.2 - max2 = 0.5 - -/obj/item/electronics/airalarm - name = "air alarm electronics" - icon_state = "airalarm_electronics" - -/obj/item/wallframe/airalarm - name = "air alarm frame" - desc = "Used for building Air Alarms." - icon = 'icons/obj/monitors.dmi' - icon_state = "alarm_bitem" - result_path = /obj/machinery/airalarm - -#define AALARM_MODE_SCRUBBING 1 -#define AALARM_MODE_VENTING 2 //makes draught -#define AALARM_MODE_PANIC 3 //like siphon, but stronger (enables widenet) -#define AALARM_MODE_REPLACEMENT 4 //sucks off all air, then refill and swithes to scrubbing -#define AALARM_MODE_OFF 5 -#define AALARM_MODE_FLOOD 6 //Emagged mode; turns off scrubbers and pressure checks on vents -#define AALARM_MODE_SIPHON 7 //Scrubbers suck air -#define AALARM_MODE_CONTAMINATED 8 //Turns on all filtering and widenet scrubbing. -#define AALARM_MODE_REFILL 9 //just like normal, but with triple the air output - -#define AALARM_REPORT_TIMEOUT 100 - -#define AALARM_OVERLAY_OFF "alarm_off" -#define AALARM_OVERLAY_GREEN "alarm_green" -#define AALARM_OVERLAY_WARN "alarm_amber" -#define AALARM_OVERLAY_DANGER "alarm_red" - -/obj/machinery/airalarm - name = "air alarm" - desc = "A machine that monitors atmosphere levels. Goes off if the area is dangerous." - icon = 'icons/obj/monitors.dmi' - icon_state = "alarm0" - use_power = IDLE_POWER_USE - idle_power_usage = 4 - active_power_usage = 8 - power_channel = ENVIRON - req_access = list(ACCESS_ATMOSPHERICS) - max_integrity = 250 - integrity_failure = 80 - armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 100, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = 90, "acid" = 30) - resistance_flags = FIRE_PROOF - - var/danger_level = 0 - var/mode = AALARM_MODE_SCRUBBING - - var/locked = TRUE - var/aidisabled = 0 - var/shorted = 0 - var/buildstage = 2 // 2 = complete, 1 = no wires, 0 = circuit gone - var/brightness_on = 1 - - var/frequency = FREQ_ATMOS_CONTROL - var/alarm_frequency = FREQ_ATMOS_ALARMS - var/datum/radio_frequency/radio_connection - - var/list/TLV = list( // Breathable air. - "pressure" = new/datum/tlv(ONE_ATMOSPHERE * 0.8, ONE_ATMOSPHERE* 0.9, ONE_ATMOSPHERE * 1.1, ONE_ATMOSPHERE * 1.2), // kPa - "temperature" = new/datum/tlv(T0C, T0C+10, T0C+40, T0C+66), - /datum/gas/oxygen = new/datum/tlv(16, 19, 135, 140), // Partial pressure, kpa - /datum/gas/nitrogen = new/datum/tlv(-1, -1, 1000, 1000), - /datum/gas/carbon_dioxide = new/datum/tlv(-1, -1, 5, 10), - /datum/gas/miasma = new/datum/tlv/(-1, -1, 2, 5), - /datum/gas/plasma = new/datum/tlv/dangerous, - /datum/gas/nitrous_oxide = new/datum/tlv/dangerous, - /datum/gas/bz = new/datum/tlv/dangerous, - /datum/gas/hypernoblium = new/datum/tlv(-1, -1, 1000, 1000), // Hyper-Noblium is inert and nontoxic - /datum/gas/water_vapor = new/datum/tlv/dangerous, - /datum/gas/tritium = new/datum/tlv/dangerous, - /datum/gas/stimulum = new/datum/tlv(-1, -1, 1000, 1000), // Stimulum has only positive effects - /datum/gas/nitryl = new/datum/tlv/dangerous, - /datum/gas/pluoxium = new/datum/tlv(-1, -1, 1000, 1000) // Unlike oxygen, pluoxium does not fuel plasma/tritium fires - ) - -/obj/machinery/airalarm/server // No checks here. - TLV = list( - "pressure" = new/datum/tlv/no_checks, - "temperature" = new/datum/tlv/no_checks, - /datum/gas/oxygen = new/datum/tlv/no_checks, - /datum/gas/nitrogen = new/datum/tlv/no_checks, - /datum/gas/carbon_dioxide = new/datum/tlv/no_checks, - /datum/gas/miasma = new/datum/tlv/no_checks, - /datum/gas/plasma = new/datum/tlv/no_checks, - /datum/gas/nitrous_oxide = new/datum/tlv/no_checks, - /datum/gas/bz = new/datum/tlv/no_checks, - /datum/gas/hypernoblium = new/datum/tlv/no_checks, - /datum/gas/water_vapor = new/datum/tlv/no_checks, - /datum/gas/tritium = new/datum/tlv/no_checks, - /datum/gas/stimulum = new/datum/tlv/no_checks, - /datum/gas/nitryl = new/datum/tlv/no_checks, - /datum/gas/pluoxium = new/datum/tlv/no_checks - ) - -/obj/machinery/airalarm/kitchen_cold_room // Copypasta: to check temperatures. - TLV = list( - "pressure" = new/datum/tlv(ONE_ATMOSPHERE * 0.8, ONE_ATMOSPHERE* 0.9, ONE_ATMOSPHERE * 1.1, ONE_ATMOSPHERE * 1.2), // kPa - "temperature" = new/datum/tlv(T0C-73.15, T0C-63.15, T0C, T0C+10), - /datum/gas/oxygen = new/datum/tlv(16, 19, 135, 140), // Partial pressure, kpa - /datum/gas/nitrogen = new/datum/tlv(-1, -1, 1000, 1000), - /datum/gas/carbon_dioxide = new/datum/tlv(-1, -1, 5, 10), - /datum/gas/miasma = new/datum/tlv/(-1, -1, 2, 5), - /datum/gas/plasma = new/datum/tlv/dangerous, - /datum/gas/nitrous_oxide = new/datum/tlv/dangerous, - /datum/gas/bz = new/datum/tlv/dangerous, - /datum/gas/hypernoblium = new/datum/tlv(-1, -1, 1000, 1000), // Hyper-Noblium is inert and nontoxic - /datum/gas/water_vapor = new/datum/tlv/dangerous, - /datum/gas/tritium = new/datum/tlv/dangerous, - /datum/gas/stimulum = new/datum/tlv(-1, -1, 1000, 1000), // Stimulum has only positive effects - /datum/gas/nitryl = new/datum/tlv/dangerous, - /datum/gas/pluoxium = new/datum/tlv(-1, -1, 1000, 1000) // Unlike oxygen, pluoxium does not fuel plasma/tritium fires - ) - -/obj/machinery/airalarm/unlocked - locked = FALSE - -/obj/machinery/airalarm/engine - name = "engine air alarm" - locked = FALSE - req_access = null - req_one_access = list(ACCESS_ATMOSPHERICS, ACCESS_ENGINE) - -/obj/machinery/airalarm/mixingchamber - name = "chamber air alarm" - locked = FALSE - req_access = null - req_one_access = list(ACCESS_ATMOSPHERICS, ACCESS_TOX, ACCESS_TOX_STORAGE) - -/obj/machinery/airalarm/all_access - name = "all-access air alarm" - desc = "This particular atmos control unit appears to have no access restrictions." - locked = FALSE - req_access = null - req_one_access = null - -/obj/machinery/airalarm/syndicate //general syndicate access - req_access = list(ACCESS_SYNDICATE) - -/obj/machinery/airalarm/directional/north //Pixel offsets get overwritten on New() - dir = SOUTH - pixel_y = 24 - -/obj/machinery/airalarm/directional/south - dir = NORTH - pixel_y = -24 - -/obj/machinery/airalarm/directional/east - dir = WEST - pixel_x = 24 - -/obj/machinery/airalarm/directional/west - dir = EAST - pixel_x = -24 - -//all air alarms in area are connected via magic -/area - var/list/air_vent_names = list() - var/list/air_scrub_names = list() - var/list/air_vent_info = list() - var/list/air_scrub_info = list() - -/obj/machinery/airalarm/Initialize(mapload, ndir, nbuild) - . = ..() - wires = new /datum/wires/airalarm(src) - - if(ndir) - setDir(ndir) - - if(nbuild) - buildstage = 0 - panel_open = TRUE - pixel_x = (dir & 3)? 0 : (dir == 4 ? -24 : 24) - pixel_y = (dir & 3)? (dir == 1 ? -24 : 24) : 0 - - if(name == initial(name)) - name = "[get_area_name(src)] Air Alarm" - - power_change() - set_frequency(frequency) - -/obj/machinery/airalarm/Destroy() - SSradio.remove_object(src, frequency) - qdel(wires) - wires = null - return ..() - -/obj/machinery/airalarm/examine(mob/user) - . = ..() - switch(buildstage) - if(0) - to_chat(user, "It is missing air alarm electronics.") - if(1) - to_chat(user, "It is missing wiring.") - if(2) - to_chat(user, "Alt-click to [locked ? "unlock" : "lock"] the interface.") - -/obj/machinery/airalarm/ui_status(mob/user) - if(user.has_unlimited_silicon_privilege && aidisabled) - to_chat(user, "AI control has been disabled.") - else if(!shorted) - return ..() - return UI_CLOSE - -/obj/machinery/airalarm/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) - if(!ui) - ui = new(user, src, ui_key, "airalarm", name, 440, 650, master_ui, state) - ui.open() - -/obj/machinery/airalarm/ui_data(mob/user) - var/data = list( - "locked" = locked, - "siliconUser" = user.has_unlimited_silicon_privilege, - "emagged" = (obj_flags & EMAGGED ? 1 : 0), - "danger_level" = danger_level, - ) - - var/area/A = get_area(src) - data["atmos_alarm"] = A.atmosalm - data["fire_alarm"] = A.fire - - var/turf/T = get_turf(src) - var/datum/gas_mixture/environment = T.return_air() - var/datum/tlv/cur_tlv - - data["environment_data"] = list() - var/pressure = environment.return_pressure() - cur_tlv = TLV["pressure"] - data["environment_data"] += list(list( - "name" = "Pressure", - "value" = pressure, - "unit" = "kPa", - "danger_level" = cur_tlv.get_danger_level(pressure) - )) - var/temperature = environment.temperature - cur_tlv = TLV["temperature"] - data["environment_data"] += list(list( - "name" = "Temperature", - "value" = temperature, - "unit" = "K ([round(temperature - T0C, 0.1)]C)", - "danger_level" = cur_tlv.get_danger_level(temperature) - )) - var/total_moles = environment.total_moles() - var/partial_pressure = R_IDEAL_GAS_EQUATION * environment.temperature / environment.volume - for(var/gas_id in environment.gases) - if(!(gas_id in TLV)) // We're not interested in this gas, it seems. - continue - cur_tlv = TLV[gas_id] - data["environment_data"] += list(list( - "name" = GLOB.meta_gas_names[gas_id], - "value" = environment.gases[gas_id] / total_moles * 100, - "unit" = "%", - "danger_level" = cur_tlv.get_danger_level(environment.gases[gas_id] * partial_pressure) - )) - - if(!locked || user.has_unlimited_silicon_privilege) - data["vents"] = list() - for(var/id_tag in A.air_vent_names) - var/long_name = A.air_vent_names[id_tag] - var/list/info = A.air_vent_info[id_tag] - if(!info || info["frequency"] != frequency) - continue - data["vents"] += list(list( - "id_tag" = id_tag, - "long_name" = sanitize(long_name), - "power" = info["power"], - "checks" = info["checks"], - "excheck" = info["checks"]&1, - "incheck" = info["checks"]&2, - "direction" = info["direction"], - "external" = info["external"], - "internal" = info["internal"], - "extdefault"= (info["external"] == ONE_ATMOSPHERE), - "intdefault"= (info["internal"] == 0) - )) - data["scrubbers"] = list() - for(var/id_tag in A.air_scrub_names) - var/long_name = A.air_scrub_names[id_tag] - var/list/info = A.air_scrub_info[id_tag] - if(!info || info["frequency"] != frequency) - continue - data["scrubbers"] += list(list( - "id_tag" = id_tag, - "long_name" = sanitize(long_name), - "power" = info["power"], - "scrubbing" = info["scrubbing"], - "widenet" = info["widenet"], - "filter_types" = info["filter_types"] - )) - data["mode"] = mode - data["modes"] = list() - data["modes"] += list(list("name" = "Filtering - Scrubs out contaminants", "mode" = AALARM_MODE_SCRUBBING, "selected" = mode == AALARM_MODE_SCRUBBING, "danger" = 0)) - data["modes"] += list(list("name" = "Contaminated - Scrubs out ALL contaminants quickly","mode" = AALARM_MODE_CONTAMINATED, "selected" = mode == AALARM_MODE_CONTAMINATED, "danger" = 0)) - data["modes"] += list(list("name" = "Draught - Siphons out air while replacing", "mode" = AALARM_MODE_VENTING, "selected" = mode == AALARM_MODE_VENTING, "danger" = 0)) - data["modes"] += list(list("name" = "Refill - Triple vent output", "mode" = AALARM_MODE_REFILL, "selected" = mode == AALARM_MODE_REFILL, "danger" = 1)) - data["modes"] += list(list("name" = "Cycle - Siphons air before replacing", "mode" = AALARM_MODE_REPLACEMENT, "selected" = mode == AALARM_MODE_REPLACEMENT, "danger" = 1)) - data["modes"] += list(list("name" = "Siphon - Siphons air out of the room", "mode" = AALARM_MODE_SIPHON, "selected" = mode == AALARM_MODE_SIPHON, "danger" = 1)) - data["modes"] += list(list("name" = "Panic Siphon - Siphons air out of the room quickly","mode" = AALARM_MODE_PANIC, "selected" = mode == AALARM_MODE_PANIC, "danger" = 1)) - data["modes"] += list(list("name" = "Off - Shuts off vents and scrubbers", "mode" = AALARM_MODE_OFF, "selected" = mode == AALARM_MODE_OFF, "danger" = 0)) - if(obj_flags & EMAGGED) - data["modes"] += list(list("name" = "Flood - Shuts off scrubbers and opens vents", "mode" = AALARM_MODE_FLOOD, "selected" = mode == AALARM_MODE_FLOOD, "danger" = 1)) - - var/datum/tlv/selected - var/list/thresholds = list() - - selected = TLV["pressure"] - thresholds += list(list("name" = "Pressure", "settings" = list())) - thresholds[thresholds.len]["settings"] += list(list("env" = "pressure", "val" = "min2", "selected" = selected.min2)) - thresholds[thresholds.len]["settings"] += list(list("env" = "pressure", "val" = "min1", "selected" = selected.min1)) - thresholds[thresholds.len]["settings"] += list(list("env" = "pressure", "val" = "max1", "selected" = selected.max1)) - thresholds[thresholds.len]["settings"] += list(list("env" = "pressure", "val" = "max2", "selected" = selected.max2)) - - selected = TLV["temperature"] - thresholds += list(list("name" = "Temperature", "settings" = list())) - thresholds[thresholds.len]["settings"] += list(list("env" = "temperature", "val" = "min2", "selected" = selected.min2)) - thresholds[thresholds.len]["settings"] += list(list("env" = "temperature", "val" = "min1", "selected" = selected.min1)) - thresholds[thresholds.len]["settings"] += list(list("env" = "temperature", "val" = "max1", "selected" = selected.max1)) - thresholds[thresholds.len]["settings"] += list(list("env" = "temperature", "val" = "max2", "selected" = selected.max2)) - - for(var/gas_id in GLOB.meta_gas_names) - if(!(gas_id in TLV)) // We're not interested in this gas, it seems. - continue - selected = TLV[gas_id] - thresholds += list(list("name" = GLOB.meta_gas_names[gas_id], "settings" = list())) - thresholds[thresholds.len]["settings"] += list(list("env" = gas_id, "val" = "min2", "selected" = selected.min2)) - thresholds[thresholds.len]["settings"] += list(list("env" = gas_id, "val" = "min1", "selected" = selected.min1)) - thresholds[thresholds.len]["settings"] += list(list("env" = gas_id, "val" = "max1", "selected" = selected.max1)) - thresholds[thresholds.len]["settings"] += list(list("env" = gas_id, "val" = "max2", "selected" = selected.max2)) - - data["thresholds"] = thresholds - return data - -/obj/machinery/airalarm/ui_act(action, params) - if(..() || buildstage != 2) - return - if((locked && !usr.has_unlimited_silicon_privilege) || (usr.has_unlimited_silicon_privilege && aidisabled)) - return - var/device_id = params["id_tag"] - switch(action) - if("lock") - if(usr.has_unlimited_silicon_privilege && !wires.is_cut(WIRE_IDSCAN)) - locked = !locked - . = TRUE - if("power", "toggle_filter", "widenet", "scrubbing") - send_signal(device_id, list("[action]" = params["val"]), usr) - . = TRUE - if("excheck") - send_signal(device_id, list("checks" = text2num(params["val"])^1), usr) - . = TRUE - if("incheck") - send_signal(device_id, list("checks" = text2num(params["val"])^2), usr) - . = TRUE - if("set_external_pressure", "set_internal_pressure") - var/area/A = get_area(src) - var/target = input("New target pressure:", name, A.air_vent_info[device_id][(action == "set_external_pressure" ? "external" : "internal")]) as num|null - if(!isnull(target) && !..()) - send_signal(device_id, list("[action]" = target), usr) - . = TRUE - if("reset_external_pressure") - send_signal(device_id, list("reset_external_pressure"), usr) - . = TRUE - if("reset_internal_pressure") - send_signal(device_id, list("reset_internal_pressure"), usr) - . = TRUE - if("threshold") - var/env = params["env"] - if(text2path(env)) - env = text2path(env) - - var/name = params["var"] - var/datum/tlv/tlv = TLV[env] - if(isnull(tlv)) - return - var/value = input("New [name] for [env]:", name, tlv.vars[name]) as num|null - if(!isnull(value) && !..()) - if(value < 0) - tlv.vars[name] = -1 - else - tlv.vars[name] = round(value, 0.01) - investigate_log(" treshold value for [env]:[name] was set to [value] by [key_name(usr)]",INVESTIGATE_ATMOS) - . = TRUE - if("mode") - mode = text2num(params["mode"]) - investigate_log("was turned to [get_mode_name(mode)] mode by [key_name(usr)]",INVESTIGATE_ATMOS) - apply_mode() - . = TRUE - if("alarm") - var/area/A = get_area(src) - if(A.atmosalert(2, src)) - post_alert(2) - . = TRUE - if("reset") - var/area/A = get_area(src) - if(A.atmosalert(0, src)) - post_alert(0) - . = TRUE - update_icon() - -/obj/machinery/airalarm/proc/reset(wire) - switch(wire) - if(WIRE_POWER) - if(!wires.is_cut(WIRE_POWER)) - shorted = FALSE - update_icon() - if(WIRE_AI) - if(!wires.is_cut(WIRE_AI)) - aidisabled = FALSE - - -/obj/machinery/airalarm/proc/shock(mob/user, prb) - if((stat & (NOPOWER))) // unpowered, no shock - return 0 - if(!prob(prb)) - return 0 //you lucked out, no shock for you - var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread - s.set_up(5, 1, src) - s.start() //sparks always. - if (electrocute_mob(user, get_area(src), src, 1, TRUE)) - return 1 - else - return 0 - -/obj/machinery/airalarm/proc/refresh_all() - var/area/A = get_area(src) - for(var/id_tag in A.air_vent_names) - var/list/I = A.air_vent_info[id_tag] - if(I && I["timestamp"] + AALARM_REPORT_TIMEOUT / 2 > world.time) - continue - send_signal(id_tag, list("status")) - for(var/id_tag in A.air_scrub_names) - var/list/I = A.air_scrub_info[id_tag] - if(I && I["timestamp"] + AALARM_REPORT_TIMEOUT / 2 > world.time) - continue - send_signal(id_tag, list("status")) - -/obj/machinery/airalarm/proc/set_frequency(new_frequency) - SSradio.remove_object(src, frequency) - frequency = new_frequency - radio_connection = SSradio.add_object(src, frequency, RADIO_TO_AIRALARM) - -/obj/machinery/airalarm/proc/send_signal(target, list/command, mob/user)//sends signal 'command' to 'target'. Returns 0 if no radio connection, 1 otherwise - if(!radio_connection) - return 0 - - var/datum/signal/signal = new(command) - signal.data["tag"] = target - signal.data["sigtype"] = "command" - signal.data["user"] = user - radio_connection.post_signal(src, signal, RADIO_FROM_AIRALARM) - - return 1 - -/obj/machinery/airalarm/proc/get_mode_name(mode_value) - switch(mode_value) - if(AALARM_MODE_SCRUBBING) - return "Filtering" - if(AALARM_MODE_CONTAMINATED) - return "Contaminated" - if(AALARM_MODE_VENTING) - return "Draught" - if(AALARM_MODE_REFILL) - return "Refill" - if(AALARM_MODE_PANIC) - return "Panic Siphon" - if(AALARM_MODE_REPLACEMENT) - return "Cycle" - if(AALARM_MODE_SIPHON) - return "Siphon" - if(AALARM_MODE_OFF) - return "Off" - if(AALARM_MODE_FLOOD) - return "Flood" - -/obj/machinery/airalarm/proc/apply_mode() - var/area/A = get_area(src) - switch(mode) - if(AALARM_MODE_SCRUBBING) - for(var/device_id in A.air_scrub_names) - send_signal(device_id, list( - "power" = 1, - "set_filters" = list(/datum/gas/carbon_dioxide, /datum/gas/miasma), - "scrubbing" = 1, - "widenet" = 0, - )) - for(var/device_id in A.air_vent_names) - send_signal(device_id, list( - "power" = 1, - "checks" = 1, - "set_external_pressure" = ONE_ATMOSPHERE - )) - if(AALARM_MODE_CONTAMINATED) - for(var/device_id in A.air_scrub_names) - send_signal(device_id, list( - "power" = 1, - "set_filters" = list( - /datum/gas/carbon_dioxide, - /datum/gas/miasma, - /datum/gas/plasma, - /datum/gas/water_vapor, - /datum/gas/hypernoblium, - /datum/gas/nitrous_oxide, - /datum/gas/nitryl, - /datum/gas/tritium, - /datum/gas/bz, - /datum/gas/stimulum, - /datum/gas/pluoxium - ), - "scrubbing" = 1, - "widenet" = 1, - )) - for(var/device_id in A.air_vent_names) - send_signal(device_id, list( - "power" = 1, - "checks" = 1, - "set_external_pressure" = ONE_ATMOSPHERE - )) - if(AALARM_MODE_VENTING) - for(var/device_id in A.air_scrub_names) - send_signal(device_id, list( - "power" = 1, - "widenet" = 0, - "scrubbing" = 0 - )) - for(var/device_id in A.air_vent_names) - send_signal(device_id, list( - "power" = 1, - "checks" = 1, - "set_external_pressure" = ONE_ATMOSPHERE*2 - )) - if(AALARM_MODE_REFILL) - for(var/device_id in A.air_scrub_names) - send_signal(device_id, list( - "power" = 1, - "set_filters" = list(/datum/gas/carbon_dioxide, /datum/gas/miasma), - "scrubbing" = 1, - "widenet" = 0, - )) - for(var/device_id in A.air_vent_names) - send_signal(device_id, list( - "power" = 1, - "checks" = 1, - "set_external_pressure" = ONE_ATMOSPHERE * 3 - )) - if(AALARM_MODE_PANIC, - AALARM_MODE_REPLACEMENT) - for(var/device_id in A.air_scrub_names) - send_signal(device_id, list( - "power" = 1, - "widenet" = 1, - "scrubbing" = 0 - )) - for(var/device_id in A.air_vent_names) - send_signal(device_id, list( - "power" = 0 - )) - if(AALARM_MODE_SIPHON) - for(var/device_id in A.air_scrub_names) - send_signal(device_id, list( - "power" = 1, - "widenet" = 0, - "scrubbing" = 0 - )) - for(var/device_id in A.air_vent_names) - send_signal(device_id, list( - "power" = 0 - )) - - if(AALARM_MODE_OFF) - for(var/device_id in A.air_scrub_names) - send_signal(device_id, list( - "power" = 0 - )) - for(var/device_id in A.air_vent_names) - send_signal(device_id, list( - "power" = 0 - )) - if(AALARM_MODE_FLOOD) - for(var/device_id in A.air_scrub_names) - send_signal(device_id, list( - "power" = 0 - )) - for(var/device_id in A.air_vent_names) - send_signal(device_id, list( - "power" = 1, - "checks" = 2, - "set_internal_pressure" = 0 - )) - -/obj/machinery/airalarm/update_icon() - set_light(0) - cut_overlays() - SSvis_overlays.remove_vis_overlay(src, managed_vis_overlays) - if(stat & NOPOWER) - icon_state = "alarm0" - return - - if(stat & BROKEN) - icon_state = "alarmx" - return - - if(panel_open) - switch(buildstage) - if(2) - icon_state = "alarmx" - if(1) - icon_state = "alarm_b2" - if(0) - icon_state = "alarm_b1" - return - - icon_state = "alarm1" - var/overlay_state = AALARM_OVERLAY_OFF - var/area/A = get_area(src) - switch(max(danger_level, A.atmosalm)) - if(0) - add_overlay(AALARM_OVERLAY_GREEN) - overlay_state = AALARM_OVERLAY_GREEN - light_color = LIGHT_COLOR_GREEN - set_light(brightness_on) - if(1) - add_overlay(AALARM_OVERLAY_WARN) - overlay_state = AALARM_OVERLAY_WARN - light_color = LIGHT_COLOR_LAVA - set_light(brightness_on) - if(2) - add_overlay(AALARM_OVERLAY_DANGER) - overlay_state = AALARM_OVERLAY_DANGER - light_color = LIGHT_COLOR_RED - set_light(brightness_on) - - SSvis_overlays.add_vis_overlay(src, icon, overlay_state, ABOVE_LIGHTING_LAYER, ABOVE_LIGHTING_PLANE, dir) - update_light() - -/obj/machinery/airalarm/process() - if((stat & (NOPOWER|BROKEN)) || shorted) - return - - var/turf/location = get_turf(src) - if(!location) - return - - var/datum/tlv/cur_tlv - - var/datum/gas_mixture/environment = location.return_air() - var/list/env_gases = environment.gases - var/partial_pressure = R_IDEAL_GAS_EQUATION * environment.temperature / environment.volume - - cur_tlv = TLV["pressure"] - var/environment_pressure = environment.return_pressure() - var/pressure_dangerlevel = cur_tlv.get_danger_level(environment_pressure) - - cur_tlv = TLV["temperature"] - var/temperature_dangerlevel = cur_tlv.get_danger_level(environment.temperature) - - var/gas_dangerlevel = 0 - for(var/gas_id in env_gases) - if(!(gas_id in TLV)) // We're not interested in this gas, it seems. - continue - cur_tlv = TLV[gas_id] - gas_dangerlevel = max(gas_dangerlevel, cur_tlv.get_danger_level(env_gases[gas_id] * partial_pressure)) - - GAS_GARBAGE_COLLECT(environment.gases) - - var/old_danger_level = danger_level - danger_level = max(pressure_dangerlevel, temperature_dangerlevel, gas_dangerlevel) - - if(old_danger_level != danger_level) - apply_danger_level() - if(mode == AALARM_MODE_REPLACEMENT && environment_pressure < ONE_ATMOSPHERE * 0.05) - mode = AALARM_MODE_SCRUBBING - apply_mode() - - return - - -/obj/machinery/airalarm/proc/post_alert(alert_level) - var/datum/radio_frequency/frequency = SSradio.return_frequency(alarm_frequency) - - if(!frequency) - return - - var/datum/signal/alert_signal = new(list( - "zone" = get_area_name(src), - "type" = "Atmospheric" - )) - if(alert_level==2) - alert_signal.data["alert"] = "severe" - else if (alert_level==1) - alert_signal.data["alert"] = "minor" - else if (alert_level==0) - alert_signal.data["alert"] = "clear" - - frequency.post_signal(src, alert_signal, range = -1) - -/obj/machinery/airalarm/proc/apply_danger_level() - var/area/A = get_area(src) - - var/new_area_danger_level = 0 - for(var/obj/machinery/airalarm/AA in A) - if (!(AA.stat & (NOPOWER|BROKEN)) && !AA.shorted) - new_area_danger_level = max(new_area_danger_level,AA.danger_level) - if(A.atmosalert(new_area_danger_level,src)) //if area was in normal state or if area was in alert state - post_alert(new_area_danger_level) - - update_icon() - -/obj/machinery/airalarm/attackby(obj/item/W, mob/user, params) - switch(buildstage) - if(2) - if(istype(W, /obj/item/wirecutters) && panel_open && wires.is_all_cut()) - W.play_tool_sound(src) - to_chat(user, "You cut the final wires.") - new /obj/item/stack/cable_coil(loc, 5) - buildstage = 1 - update_icon() - return - else if(istype(W, /obj/item/screwdriver)) // Opening that Air Alarm up. - W.play_tool_sound(src) - panel_open = !panel_open - to_chat(user, "The wires have been [panel_open ? "exposed" : "unexposed"].") - update_icon() - return - else if(istype(W, /obj/item/card/id) || istype(W, /obj/item/pda))// trying to unlock the interface with an ID card - togglelock(user) - else if(panel_open && is_wire_tool(W)) - wires.interact(user) - return - if(1) - if(istype(W, /obj/item/crowbar)) - user.visible_message("[user.name] removes the electronics from [src.name].",\ - "You start prying out the circuit...") - W.play_tool_sound(src) - if (W.use_tool(src, user, 20)) - if (buildstage == 1) - to_chat(user, "You remove the air alarm electronics.") - new /obj/item/electronics/airalarm( src.loc ) - playsound(src.loc, 'sound/items/deconstruct.ogg', 50, 1) - buildstage = 0 - update_icon() - return - - if(istype(W, /obj/item/stack/cable_coil)) - var/obj/item/stack/cable_coil/cable = W - if(cable.get_amount() < 5) - to_chat(user, "You need five lengths of cable to wire the air alarm!") - return - user.visible_message("[user.name] wires the air alarm.", \ - "You start wiring the air alarm...") - if (do_after(user, 20, target = src)) - if (cable.get_amount() >= 5 && buildstage == 1) - cable.use(5) - to_chat(user, "You wire the air alarm.") - wires.repair() - aidisabled = 0 - locked = FALSE - mode = 1 - shorted = 0 - post_alert(0) - buildstage = 2 - update_icon() - return - if(0) - if(istype(W, /obj/item/electronics/airalarm)) - if(user.temporarilyRemoveItemFromInventory(W)) - to_chat(user, "You insert the circuit.") - buildstage = 1 - update_icon() - qdel(W) - return - - if(istype(W, /obj/item/electroadaptive_pseudocircuit)) - var/obj/item/electroadaptive_pseudocircuit/P = W - if(!P.adapt_circuit(user, 25)) - return - user.visible_message("[user] fabricates a circuit and places it into [src].", \ - "You adapt an air alarm circuit and slot it into the assembly.") - buildstage = 1 - update_icon() - return - - if(istype(W, /obj/item/wrench)) - to_chat(user, "You detach \the [src] from the wall.") - W.play_tool_sound(src) - new /obj/item/wallframe/airalarm( user.loc ) - qdel(src) - return - - return ..() - -/obj/machinery/airalarm/AltClick(mob/user) - ..() - if(!user.canUseTopic(src, !issilicon(user)) || !isturf(loc)) - return - else - togglelock(user) - -/obj/machinery/airalarm/proc/togglelock(mob/living/user) - if(stat & (NOPOWER|BROKEN)) - to_chat(user, "It does nothing!") - else - if(src.allowed(usr) && !wires.is_cut(WIRE_IDSCAN)) - locked = !locked - updateUsrDialog() - to_chat(user, "You [ locked ? "lock" : "unlock"] the air alarm interface.") - else - to_chat(user, "Access denied.") - return - -/obj/machinery/airalarm/power_change() - ..() - if(stat & NOPOWER) - set_light(0) - update_icon() - -/obj/machinery/airalarm/emag_act(mob/user) - if(obj_flags & EMAGGED) - return - obj_flags |= EMAGGED - visible_message("Sparks fly out of [src]!", "You emag [src], disabling its safeties.") - playsound(src, "sparks", 50, 1) - -/obj/machinery/airalarm/obj_break(damage_flag) - ..() - update_icon() - set_light(0) - -/obj/machinery/airalarm/deconstruct(disassembled = TRUE) - if(!(flags_1 & NODECONSTRUCT_1)) - new /obj/item/stack/sheet/metal(loc, 2) - var/obj/item/I = new /obj/item/electronics/airalarm(loc) - if(!disassembled) - I.obj_integrity = I.max_integrity * 0.5 - new /obj/item/stack/cable_coil(loc, 3) - qdel(src) - -#undef AALARM_MODE_SCRUBBING -#undef AALARM_MODE_VENTING -#undef AALARM_MODE_PANIC -#undef AALARM_MODE_REPLACEMENT -#undef AALARM_MODE_OFF -#undef AALARM_MODE_FLOOD -#undef AALARM_MODE_SIPHON -#undef AALARM_MODE_CONTAMINATED -#undef AALARM_MODE_REFILL -#undef AALARM_REPORT_TIMEOUT +/datum/tlv + var/min2 + var/min1 + var/max1 + var/max2 + +/datum/tlv/New(min2 as num, min1 as num, max1 as num, max2 as num) + if(min2) src.min2 = min2 + if(min1) src.min1 = min1 + if(max1) src.max1 = max1 + if(max2) src.max2 = max2 + +/datum/tlv/proc/get_danger_level(val as num) + if(max2 != -1 && val >= max2) + return 2 + if(min2 != -1 && val <= min2) + return 2 + if(max1 != -1 && val >= max1) + return 1 + if(min1 != -1 && val <= min1) + return 1 + return 0 + +/datum/tlv/no_checks + min2 = -1 + min1 = -1 + max1 = -1 + max2 = -1 + +/datum/tlv/dangerous + min2 = -1 + min1 = -1 + max1 = 0.2 + max2 = 0.5 + +/obj/item/electronics/airalarm + name = "air alarm electronics" + icon_state = "airalarm_electronics" + +/obj/item/wallframe/airalarm + name = "air alarm frame" + desc = "Used for building Air Alarms." + icon = 'icons/obj/monitors.dmi' + icon_state = "alarm_bitem" + result_path = /obj/machinery/airalarm + +#define AALARM_MODE_SCRUBBING 1 +#define AALARM_MODE_VENTING 2 //makes draught +#define AALARM_MODE_PANIC 3 //like siphon, but stronger (enables widenet) +#define AALARM_MODE_REPLACEMENT 4 //sucks off all air, then refill and swithes to scrubbing +#define AALARM_MODE_OFF 5 +#define AALARM_MODE_FLOOD 6 //Emagged mode; turns off scrubbers and pressure checks on vents +#define AALARM_MODE_SIPHON 7 //Scrubbers suck air +#define AALARM_MODE_CONTAMINATED 8 //Turns on all filtering and widenet scrubbing. +#define AALARM_MODE_REFILL 9 //just like normal, but with triple the air output + +#define AALARM_REPORT_TIMEOUT 100 + +#define AALARM_OVERLAY_OFF "alarm_off" +#define AALARM_OVERLAY_GREEN "alarm_green" +#define AALARM_OVERLAY_WARN "alarm_amber" +#define AALARM_OVERLAY_DANGER "alarm_red" + +/obj/machinery/airalarm + name = "air alarm" + desc = "A machine that monitors atmosphere levels. Goes off if the area is dangerous." + icon = 'icons/obj/monitors.dmi' + icon_state = "alarm0" + use_power = IDLE_POWER_USE + idle_power_usage = 4 + active_power_usage = 8 + power_channel = ENVIRON + req_access = list(ACCESS_ATMOSPHERICS) + max_integrity = 250 + integrity_failure = 80 + armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 100, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = 90, "acid" = 30) + resistance_flags = FIRE_PROOF + + var/danger_level = 0 + var/mode = AALARM_MODE_SCRUBBING + + var/locked = TRUE + var/aidisabled = 0 + var/shorted = 0 + var/buildstage = 2 // 2 = complete, 1 = no wires, 0 = circuit gone + var/brightness_on = 1 + + var/frequency = FREQ_ATMOS_CONTROL + var/alarm_frequency = FREQ_ATMOS_ALARMS + var/datum/radio_frequency/radio_connection + + var/list/TLV = list( // Breathable air. + "pressure" = new/datum/tlv(ONE_ATMOSPHERE * 0.8, ONE_ATMOSPHERE* 0.9, ONE_ATMOSPHERE * 1.1, ONE_ATMOSPHERE * 1.2), // kPa + "temperature" = new/datum/tlv(T0C, T0C+10, T0C+40, T0C+66), + /datum/gas/oxygen = new/datum/tlv(16, 19, 135, 140), // Partial pressure, kpa + /datum/gas/nitrogen = new/datum/tlv(-1, -1, 1000, 1000), + /datum/gas/carbon_dioxide = new/datum/tlv(-1, -1, 5, 10), + /datum/gas/miasma = new/datum/tlv/(-1, -1, 2, 5), + /datum/gas/plasma = new/datum/tlv/dangerous, + /datum/gas/nitrous_oxide = new/datum/tlv/dangerous, + /datum/gas/bz = new/datum/tlv/dangerous, + /datum/gas/hypernoblium = new/datum/tlv(-1, -1, 1000, 1000), // Hyper-Noblium is inert and nontoxic + /datum/gas/water_vapor = new/datum/tlv/dangerous, + /datum/gas/tritium = new/datum/tlv/dangerous, + /datum/gas/stimulum = new/datum/tlv(-1, -1, 1000, 1000), // Stimulum has only positive effects + /datum/gas/nitryl = new/datum/tlv/dangerous, + /datum/gas/pluoxium = new/datum/tlv(-1, -1, 1000, 1000) // Unlike oxygen, pluoxium does not fuel plasma/tritium fires + ) + +/obj/machinery/airalarm/server // No checks here. + TLV = list( + "pressure" = new/datum/tlv/no_checks, + "temperature" = new/datum/tlv/no_checks, + /datum/gas/oxygen = new/datum/tlv/no_checks, + /datum/gas/nitrogen = new/datum/tlv/no_checks, + /datum/gas/carbon_dioxide = new/datum/tlv/no_checks, + /datum/gas/miasma = new/datum/tlv/no_checks, + /datum/gas/plasma = new/datum/tlv/no_checks, + /datum/gas/nitrous_oxide = new/datum/tlv/no_checks, + /datum/gas/bz = new/datum/tlv/no_checks, + /datum/gas/hypernoblium = new/datum/tlv/no_checks, + /datum/gas/water_vapor = new/datum/tlv/no_checks, + /datum/gas/tritium = new/datum/tlv/no_checks, + /datum/gas/stimulum = new/datum/tlv/no_checks, + /datum/gas/nitryl = new/datum/tlv/no_checks, + /datum/gas/pluoxium = new/datum/tlv/no_checks + ) + +/obj/machinery/airalarm/kitchen_cold_room // Copypasta: to check temperatures. + TLV = list( + "pressure" = new/datum/tlv(ONE_ATMOSPHERE * 0.8, ONE_ATMOSPHERE* 0.9, ONE_ATMOSPHERE * 1.1, ONE_ATMOSPHERE * 1.2), // kPa + "temperature" = new/datum/tlv(T0C-73.15, T0C-63.15, T0C, T0C+10), + /datum/gas/oxygen = new/datum/tlv(16, 19, 135, 140), // Partial pressure, kpa + /datum/gas/nitrogen = new/datum/tlv(-1, -1, 1000, 1000), + /datum/gas/carbon_dioxide = new/datum/tlv(-1, -1, 5, 10), + /datum/gas/miasma = new/datum/tlv/(-1, -1, 2, 5), + /datum/gas/plasma = new/datum/tlv/dangerous, + /datum/gas/nitrous_oxide = new/datum/tlv/dangerous, + /datum/gas/bz = new/datum/tlv/dangerous, + /datum/gas/hypernoblium = new/datum/tlv(-1, -1, 1000, 1000), // Hyper-Noblium is inert and nontoxic + /datum/gas/water_vapor = new/datum/tlv/dangerous, + /datum/gas/tritium = new/datum/tlv/dangerous, + /datum/gas/stimulum = new/datum/tlv(-1, -1, 1000, 1000), // Stimulum has only positive effects + /datum/gas/nitryl = new/datum/tlv/dangerous, + /datum/gas/pluoxium = new/datum/tlv(-1, -1, 1000, 1000) // Unlike oxygen, pluoxium does not fuel plasma/tritium fires + ) + +/obj/machinery/airalarm/unlocked + locked = FALSE + +/obj/machinery/airalarm/engine + name = "engine air alarm" + locked = FALSE + req_access = null + req_one_access = list(ACCESS_ATMOSPHERICS, ACCESS_ENGINE) + +/obj/machinery/airalarm/mixingchamber + name = "chamber air alarm" + locked = FALSE + req_access = null + req_one_access = list(ACCESS_ATMOSPHERICS, ACCESS_TOX, ACCESS_TOX_STORAGE) + +/obj/machinery/airalarm/all_access + name = "all-access air alarm" + desc = "This particular atmos control unit appears to have no access restrictions." + locked = FALSE + req_access = null + req_one_access = null + +/obj/machinery/airalarm/syndicate //general syndicate access + req_access = list(ACCESS_SYNDICATE) + +/obj/machinery/airalarm/directional/north //Pixel offsets get overwritten on New() + dir = SOUTH + pixel_y = 24 + +/obj/machinery/airalarm/directional/south + dir = NORTH + pixel_y = -24 + +/obj/machinery/airalarm/directional/east + dir = WEST + pixel_x = 24 + +/obj/machinery/airalarm/directional/west + dir = EAST + pixel_x = -24 + +//all air alarms in area are connected via magic +/area + var/list/air_vent_names = list() + var/list/air_scrub_names = list() + var/list/air_vent_info = list() + var/list/air_scrub_info = list() + +/obj/machinery/airalarm/Initialize(mapload, ndir, nbuild) + . = ..() + wires = new /datum/wires/airalarm(src) + + if(ndir) + setDir(ndir) + + if(nbuild) + buildstage = 0 + panel_open = TRUE + pixel_x = (dir & 3)? 0 : (dir == 4 ? -24 : 24) + pixel_y = (dir & 3)? (dir == 1 ? -24 : 24) : 0 + + if(name == initial(name)) + name = "[get_area_name(src)] Air Alarm" + + power_change() + set_frequency(frequency) + +/obj/machinery/airalarm/Destroy() + SSradio.remove_object(src, frequency) + qdel(wires) + wires = null + return ..() + +/obj/machinery/airalarm/examine(mob/user) + . = ..() + switch(buildstage) + if(0) + to_chat(user, "It is missing air alarm electronics.") + if(1) + to_chat(user, "It is missing wiring.") + if(2) + to_chat(user, "Alt-click to [locked ? "unlock" : "lock"] the interface.") + +/obj/machinery/airalarm/ui_status(mob/user) + if(user.has_unlimited_silicon_privilege && aidisabled) + to_chat(user, "AI control has been disabled.") + else if(!shorted) + return ..() + return UI_CLOSE + +/obj/machinery/airalarm/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ + datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "airalarm", name, 440, 650, master_ui, state) + ui.open() + +/obj/machinery/airalarm/ui_data(mob/user) + var/data = list( + "locked" = locked, + "siliconUser" = user.has_unlimited_silicon_privilege, + "emagged" = (obj_flags & EMAGGED ? 1 : 0), + "danger_level" = danger_level, + ) + + var/area/A = get_area(src) + data["atmos_alarm"] = A.atmosalm + data["fire_alarm"] = A.fire + + var/turf/T = get_turf(src) + var/datum/gas_mixture/environment = T.return_air() + var/datum/tlv/cur_tlv + + data["environment_data"] = list() + var/pressure = environment.return_pressure() + cur_tlv = TLV["pressure"] + data["environment_data"] += list(list( + "name" = "Pressure", + "value" = pressure, + "unit" = "kPa", + "danger_level" = cur_tlv.get_danger_level(pressure) + )) + var/temperature = environment.temperature + cur_tlv = TLV["temperature"] + data["environment_data"] += list(list( + "name" = "Temperature", + "value" = temperature, + "unit" = "K ([round(temperature - T0C, 0.1)]C)", + "danger_level" = cur_tlv.get_danger_level(temperature) + )) + var/total_moles = environment.total_moles() + var/partial_pressure = R_IDEAL_GAS_EQUATION * environment.temperature / environment.volume + for(var/gas_id in environment.gases) + if(!(gas_id in TLV)) // We're not interested in this gas, it seems. + continue + cur_tlv = TLV[gas_id] + data["environment_data"] += list(list( + "name" = GLOB.meta_gas_names[gas_id], + "value" = environment.gases[gas_id] / total_moles * 100, + "unit" = "%", + "danger_level" = cur_tlv.get_danger_level(environment.gases[gas_id] * partial_pressure) + )) + + if(!locked || user.has_unlimited_silicon_privilege) + data["vents"] = list() + for(var/id_tag in A.air_vent_names) + var/long_name = A.air_vent_names[id_tag] + var/list/info = A.air_vent_info[id_tag] + if(!info || info["frequency"] != frequency) + continue + data["vents"] += list(list( + "id_tag" = id_tag, + "long_name" = sanitize(long_name), + "power" = info["power"], + "checks" = info["checks"], + "excheck" = info["checks"]&1, + "incheck" = info["checks"]&2, + "direction" = info["direction"], + "external" = info["external"], + "internal" = info["internal"], + "extdefault"= (info["external"] == ONE_ATMOSPHERE), + "intdefault"= (info["internal"] == 0) + )) + data["scrubbers"] = list() + for(var/id_tag in A.air_scrub_names) + var/long_name = A.air_scrub_names[id_tag] + var/list/info = A.air_scrub_info[id_tag] + if(!info || info["frequency"] != frequency) + continue + data["scrubbers"] += list(list( + "id_tag" = id_tag, + "long_name" = sanitize(long_name), + "power" = info["power"], + "scrubbing" = info["scrubbing"], + "widenet" = info["widenet"], + "filter_types" = info["filter_types"] + )) + data["mode"] = mode + data["modes"] = list() + data["modes"] += list(list("name" = "Filtering - Scrubs out contaminants", "mode" = AALARM_MODE_SCRUBBING, "selected" = mode == AALARM_MODE_SCRUBBING, "danger" = 0)) + data["modes"] += list(list("name" = "Contaminated - Scrubs out ALL contaminants quickly","mode" = AALARM_MODE_CONTAMINATED, "selected" = mode == AALARM_MODE_CONTAMINATED, "danger" = 0)) + data["modes"] += list(list("name" = "Draught - Siphons out air while replacing", "mode" = AALARM_MODE_VENTING, "selected" = mode == AALARM_MODE_VENTING, "danger" = 0)) + data["modes"] += list(list("name" = "Refill - Triple vent output", "mode" = AALARM_MODE_REFILL, "selected" = mode == AALARM_MODE_REFILL, "danger" = 1)) + data["modes"] += list(list("name" = "Cycle - Siphons air before replacing", "mode" = AALARM_MODE_REPLACEMENT, "selected" = mode == AALARM_MODE_REPLACEMENT, "danger" = 1)) + data["modes"] += list(list("name" = "Siphon - Siphons air out of the room", "mode" = AALARM_MODE_SIPHON, "selected" = mode == AALARM_MODE_SIPHON, "danger" = 1)) + data["modes"] += list(list("name" = "Panic Siphon - Siphons air out of the room quickly","mode" = AALARM_MODE_PANIC, "selected" = mode == AALARM_MODE_PANIC, "danger" = 1)) + data["modes"] += list(list("name" = "Off - Shuts off vents and scrubbers", "mode" = AALARM_MODE_OFF, "selected" = mode == AALARM_MODE_OFF, "danger" = 0)) + if(obj_flags & EMAGGED) + data["modes"] += list(list("name" = "Flood - Shuts off scrubbers and opens vents", "mode" = AALARM_MODE_FLOOD, "selected" = mode == AALARM_MODE_FLOOD, "danger" = 1)) + + var/datum/tlv/selected + var/list/thresholds = list() + + selected = TLV["pressure"] + thresholds += list(list("name" = "Pressure", "settings" = list())) + thresholds[thresholds.len]["settings"] += list(list("env" = "pressure", "val" = "min2", "selected" = selected.min2)) + thresholds[thresholds.len]["settings"] += list(list("env" = "pressure", "val" = "min1", "selected" = selected.min1)) + thresholds[thresholds.len]["settings"] += list(list("env" = "pressure", "val" = "max1", "selected" = selected.max1)) + thresholds[thresholds.len]["settings"] += list(list("env" = "pressure", "val" = "max2", "selected" = selected.max2)) + + selected = TLV["temperature"] + thresholds += list(list("name" = "Temperature", "settings" = list())) + thresholds[thresholds.len]["settings"] += list(list("env" = "temperature", "val" = "min2", "selected" = selected.min2)) + thresholds[thresholds.len]["settings"] += list(list("env" = "temperature", "val" = "min1", "selected" = selected.min1)) + thresholds[thresholds.len]["settings"] += list(list("env" = "temperature", "val" = "max1", "selected" = selected.max1)) + thresholds[thresholds.len]["settings"] += list(list("env" = "temperature", "val" = "max2", "selected" = selected.max2)) + + for(var/gas_id in GLOB.meta_gas_names) + if(!(gas_id in TLV)) // We're not interested in this gas, it seems. + continue + selected = TLV[gas_id] + thresholds += list(list("name" = GLOB.meta_gas_names[gas_id], "settings" = list())) + thresholds[thresholds.len]["settings"] += list(list("env" = gas_id, "val" = "min2", "selected" = selected.min2)) + thresholds[thresholds.len]["settings"] += list(list("env" = gas_id, "val" = "min1", "selected" = selected.min1)) + thresholds[thresholds.len]["settings"] += list(list("env" = gas_id, "val" = "max1", "selected" = selected.max1)) + thresholds[thresholds.len]["settings"] += list(list("env" = gas_id, "val" = "max2", "selected" = selected.max2)) + + data["thresholds"] = thresholds + return data + +/obj/machinery/airalarm/ui_act(action, params) + if(..() || buildstage != 2) + return + if((locked && !usr.has_unlimited_silicon_privilege) || (usr.has_unlimited_silicon_privilege && aidisabled)) + return + var/device_id = params["id_tag"] + switch(action) + if("lock") + if(usr.has_unlimited_silicon_privilege && !wires.is_cut(WIRE_IDSCAN)) + locked = !locked + . = TRUE + if("power", "toggle_filter", "widenet", "scrubbing") + send_signal(device_id, list("[action]" = params["val"]), usr) + . = TRUE + if("excheck") + send_signal(device_id, list("checks" = text2num(params["val"])^1), usr) + . = TRUE + if("incheck") + send_signal(device_id, list("checks" = text2num(params["val"])^2), usr) + . = TRUE + if("set_external_pressure", "set_internal_pressure") + var/area/A = get_area(src) + var/target = input("New target pressure:", name, A.air_vent_info[device_id][(action == "set_external_pressure" ? "external" : "internal")]) as num|null + if(!isnull(target) && !..()) + send_signal(device_id, list("[action]" = target), usr) + . = TRUE + if("reset_external_pressure") + send_signal(device_id, list("reset_external_pressure"), usr) + . = TRUE + if("reset_internal_pressure") + send_signal(device_id, list("reset_internal_pressure"), usr) + . = TRUE + if("threshold") + var/env = params["env"] + if(text2path(env)) + env = text2path(env) + + var/name = params["var"] + var/datum/tlv/tlv = TLV[env] + if(isnull(tlv)) + return + var/value = input("New [name] for [env]:", name, tlv.vars[name]) as num|null + if(!isnull(value) && !..()) + if(value < 0) + tlv.vars[name] = -1 + else + tlv.vars[name] = round(value, 0.01) + investigate_log(" treshold value for [env]:[name] was set to [value] by [key_name(usr)]",INVESTIGATE_ATMOS) + . = TRUE + if("mode") + mode = text2num(params["mode"]) + investigate_log("was turned to [get_mode_name(mode)] mode by [key_name(usr)]",INVESTIGATE_ATMOS) + apply_mode() + . = TRUE + if("alarm") + var/area/A = get_area(src) + if(A.atmosalert(2, src)) + post_alert(2) + . = TRUE + if("reset") + var/area/A = get_area(src) + if(A.atmosalert(0, src)) + post_alert(0) + . = TRUE + update_icon() + +/obj/machinery/airalarm/proc/reset(wire) + switch(wire) + if(WIRE_POWER) + if(!wires.is_cut(WIRE_POWER)) + shorted = FALSE + update_icon() + if(WIRE_AI) + if(!wires.is_cut(WIRE_AI)) + aidisabled = FALSE + + +/obj/machinery/airalarm/proc/shock(mob/user, prb) + if((stat & (NOPOWER))) // unpowered, no shock + return 0 + if(!prob(prb)) + return 0 //you lucked out, no shock for you + var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread + s.set_up(5, 1, src) + s.start() //sparks always. + if (electrocute_mob(user, get_area(src), src, 1, TRUE)) + return 1 + else + return 0 + +/obj/machinery/airalarm/proc/refresh_all() + var/area/A = get_area(src) + for(var/id_tag in A.air_vent_names) + var/list/I = A.air_vent_info[id_tag] + if(I && I["timestamp"] + AALARM_REPORT_TIMEOUT / 2 > world.time) + continue + send_signal(id_tag, list("status")) + for(var/id_tag in A.air_scrub_names) + var/list/I = A.air_scrub_info[id_tag] + if(I && I["timestamp"] + AALARM_REPORT_TIMEOUT / 2 > world.time) + continue + send_signal(id_tag, list("status")) + +/obj/machinery/airalarm/proc/set_frequency(new_frequency) + SSradio.remove_object(src, frequency) + frequency = new_frequency + radio_connection = SSradio.add_object(src, frequency, RADIO_TO_AIRALARM) + +/obj/machinery/airalarm/proc/send_signal(target, list/command, mob/user)//sends signal 'command' to 'target'. Returns 0 if no radio connection, 1 otherwise + if(!radio_connection) + return 0 + + var/datum/signal/signal = new(command) + signal.data["tag"] = target + signal.data["sigtype"] = "command" + signal.data["user"] = user + radio_connection.post_signal(src, signal, RADIO_FROM_AIRALARM) + + return 1 + +/obj/machinery/airalarm/proc/get_mode_name(mode_value) + switch(mode_value) + if(AALARM_MODE_SCRUBBING) + return "Filtering" + if(AALARM_MODE_CONTAMINATED) + return "Contaminated" + if(AALARM_MODE_VENTING) + return "Draught" + if(AALARM_MODE_REFILL) + return "Refill" + if(AALARM_MODE_PANIC) + return "Panic Siphon" + if(AALARM_MODE_REPLACEMENT) + return "Cycle" + if(AALARM_MODE_SIPHON) + return "Siphon" + if(AALARM_MODE_OFF) + return "Off" + if(AALARM_MODE_FLOOD) + return "Flood" + +/obj/machinery/airalarm/proc/apply_mode() + var/area/A = get_area(src) + switch(mode) + if(AALARM_MODE_SCRUBBING) + for(var/device_id in A.air_scrub_names) + send_signal(device_id, list( + "power" = 1, + "set_filters" = list(/datum/gas/carbon_dioxide, /datum/gas/miasma), + "scrubbing" = 1, + "widenet" = 0, + )) + for(var/device_id in A.air_vent_names) + send_signal(device_id, list( + "power" = 1, + "checks" = 1, + "set_external_pressure" = ONE_ATMOSPHERE + )) + if(AALARM_MODE_CONTAMINATED) + for(var/device_id in A.air_scrub_names) + send_signal(device_id, list( + "power" = 1, + "set_filters" = list( + /datum/gas/carbon_dioxide, + /datum/gas/miasma, + /datum/gas/plasma, + /datum/gas/water_vapor, + /datum/gas/hypernoblium, + /datum/gas/nitrous_oxide, + /datum/gas/nitryl, + /datum/gas/tritium, + /datum/gas/bz, + /datum/gas/stimulum, + /datum/gas/pluoxium + ), + "scrubbing" = 1, + "widenet" = 1, + )) + for(var/device_id in A.air_vent_names) + send_signal(device_id, list( + "power" = 1, + "checks" = 1, + "set_external_pressure" = ONE_ATMOSPHERE + )) + if(AALARM_MODE_VENTING) + for(var/device_id in A.air_scrub_names) + send_signal(device_id, list( + "power" = 1, + "widenet" = 0, + "scrubbing" = 0 + )) + for(var/device_id in A.air_vent_names) + send_signal(device_id, list( + "power" = 1, + "checks" = 1, + "set_external_pressure" = ONE_ATMOSPHERE*2 + )) + if(AALARM_MODE_REFILL) + for(var/device_id in A.air_scrub_names) + send_signal(device_id, list( + "power" = 1, + "set_filters" = list(/datum/gas/carbon_dioxide, /datum/gas/miasma), + "scrubbing" = 1, + "widenet" = 0, + )) + for(var/device_id in A.air_vent_names) + send_signal(device_id, list( + "power" = 1, + "checks" = 1, + "set_external_pressure" = ONE_ATMOSPHERE * 3 + )) + if(AALARM_MODE_PANIC, + AALARM_MODE_REPLACEMENT) + for(var/device_id in A.air_scrub_names) + send_signal(device_id, list( + "power" = 1, + "widenet" = 1, + "scrubbing" = 0 + )) + for(var/device_id in A.air_vent_names) + send_signal(device_id, list( + "power" = 0 + )) + if(AALARM_MODE_SIPHON) + for(var/device_id in A.air_scrub_names) + send_signal(device_id, list( + "power" = 1, + "widenet" = 0, + "scrubbing" = 0 + )) + for(var/device_id in A.air_vent_names) + send_signal(device_id, list( + "power" = 0 + )) + + if(AALARM_MODE_OFF) + for(var/device_id in A.air_scrub_names) + send_signal(device_id, list( + "power" = 0 + )) + for(var/device_id in A.air_vent_names) + send_signal(device_id, list( + "power" = 0 + )) + if(AALARM_MODE_FLOOD) + for(var/device_id in A.air_scrub_names) + send_signal(device_id, list( + "power" = 0 + )) + for(var/device_id in A.air_vent_names) + send_signal(device_id, list( + "power" = 1, + "checks" = 2, + "set_internal_pressure" = 0 + )) + +/obj/machinery/airalarm/update_icon() + set_light(0) + cut_overlays() + SSvis_overlays.remove_vis_overlay(src, managed_vis_overlays) + if(stat & NOPOWER) + icon_state = "alarm0" + return + + if(stat & BROKEN) + icon_state = "alarmx" + return + + if(panel_open) + switch(buildstage) + if(2) + icon_state = "alarmx" + if(1) + icon_state = "alarm_b2" + if(0) + icon_state = "alarm_b1" + return + + icon_state = "alarm1" + var/overlay_state = AALARM_OVERLAY_OFF + var/area/A = get_area(src) + switch(max(danger_level, A.atmosalm)) + if(0) + add_overlay(AALARM_OVERLAY_GREEN) + overlay_state = AALARM_OVERLAY_GREEN + light_color = LIGHT_COLOR_GREEN + set_light(brightness_on) + if(1) + add_overlay(AALARM_OVERLAY_WARN) + overlay_state = AALARM_OVERLAY_WARN + light_color = LIGHT_COLOR_LAVA + set_light(brightness_on) + if(2) + add_overlay(AALARM_OVERLAY_DANGER) + overlay_state = AALARM_OVERLAY_DANGER + light_color = LIGHT_COLOR_RED + set_light(brightness_on) + + SSvis_overlays.add_vis_overlay(src, icon, overlay_state, ABOVE_LIGHTING_LAYER, ABOVE_LIGHTING_PLANE, dir) + update_light() + +/obj/machinery/airalarm/process() + if((stat & (NOPOWER|BROKEN)) || shorted) + return + + var/turf/location = get_turf(src) + if(!location) + return + + var/datum/tlv/cur_tlv + + var/datum/gas_mixture/environment = location.return_air() + var/list/env_gases = environment.gases + var/partial_pressure = R_IDEAL_GAS_EQUATION * environment.temperature / environment.volume + + cur_tlv = TLV["pressure"] + var/environment_pressure = environment.return_pressure() + var/pressure_dangerlevel = cur_tlv.get_danger_level(environment_pressure) + + cur_tlv = TLV["temperature"] + var/temperature_dangerlevel = cur_tlv.get_danger_level(environment.temperature) + + var/gas_dangerlevel = 0 + for(var/gas_id in env_gases) + if(!(gas_id in TLV)) // We're not interested in this gas, it seems. + continue + cur_tlv = TLV[gas_id] + gas_dangerlevel = max(gas_dangerlevel, cur_tlv.get_danger_level(env_gases[gas_id] * partial_pressure)) + + GAS_GARBAGE_COLLECT(environment.gases) + + var/old_danger_level = danger_level + danger_level = max(pressure_dangerlevel, temperature_dangerlevel, gas_dangerlevel) + + if(old_danger_level != danger_level) + apply_danger_level() + if(mode == AALARM_MODE_REPLACEMENT && environment_pressure < ONE_ATMOSPHERE * 0.05) + mode = AALARM_MODE_SCRUBBING + apply_mode() + + return + + +/obj/machinery/airalarm/proc/post_alert(alert_level) + var/datum/radio_frequency/frequency = SSradio.return_frequency(alarm_frequency) + + if(!frequency) + return + + var/datum/signal/alert_signal = new(list( + "zone" = get_area_name(src), + "type" = "Atmospheric" + )) + if(alert_level==2) + alert_signal.data["alert"] = "severe" + else if (alert_level==1) + alert_signal.data["alert"] = "minor" + else if (alert_level==0) + alert_signal.data["alert"] = "clear" + + frequency.post_signal(src, alert_signal, range = -1) + +/obj/machinery/airalarm/proc/apply_danger_level() + var/area/A = get_area(src) + + var/new_area_danger_level = 0 + for(var/obj/machinery/airalarm/AA in A) + if (!(AA.stat & (NOPOWER|BROKEN)) && !AA.shorted) + new_area_danger_level = max(new_area_danger_level,AA.danger_level) + if(A.atmosalert(new_area_danger_level,src)) //if area was in normal state or if area was in alert state + post_alert(new_area_danger_level) + + update_icon() + +/obj/machinery/airalarm/attackby(obj/item/W, mob/user, params) + switch(buildstage) + if(2) + if(istype(W, /obj/item/wirecutters) && panel_open && wires.is_all_cut()) + W.play_tool_sound(src) + to_chat(user, "You cut the final wires.") + new /obj/item/stack/cable_coil(loc, 5) + buildstage = 1 + update_icon() + return + else if(istype(W, /obj/item/screwdriver)) // Opening that Air Alarm up. + W.play_tool_sound(src) + panel_open = !panel_open + to_chat(user, "The wires have been [panel_open ? "exposed" : "unexposed"].") + update_icon() + return + else if(istype(W, /obj/item/card/id) || istype(W, /obj/item/pda))// trying to unlock the interface with an ID card + togglelock(user) + else if(panel_open && is_wire_tool(W)) + wires.interact(user) + return + if(1) + if(istype(W, /obj/item/crowbar)) + user.visible_message("[user.name] removes the electronics from [src.name].",\ + "You start prying out the circuit...") + W.play_tool_sound(src) + if (W.use_tool(src, user, 20)) + if (buildstage == 1) + to_chat(user, "You remove the air alarm electronics.") + new /obj/item/electronics/airalarm( src.loc ) + playsound(src.loc, 'sound/items/deconstruct.ogg', 50, 1) + buildstage = 0 + update_icon() + return + + if(istype(W, /obj/item/stack/cable_coil)) + var/obj/item/stack/cable_coil/cable = W + if(cable.get_amount() < 5) + to_chat(user, "You need five lengths of cable to wire the air alarm!") + return + user.visible_message("[user.name] wires the air alarm.", \ + "You start wiring the air alarm...") + if (do_after(user, 20, target = src)) + if (cable.get_amount() >= 5 && buildstage == 1) + cable.use(5) + to_chat(user, "You wire the air alarm.") + wires.repair() + aidisabled = 0 + locked = FALSE + mode = 1 + shorted = 0 + post_alert(0) + buildstage = 2 + update_icon() + return + if(0) + if(istype(W, /obj/item/electronics/airalarm)) + if(user.temporarilyRemoveItemFromInventory(W)) + to_chat(user, "You insert the circuit.") + buildstage = 1 + update_icon() + qdel(W) + return + + if(istype(W, /obj/item/electroadaptive_pseudocircuit)) + var/obj/item/electroadaptive_pseudocircuit/P = W + if(!P.adapt_circuit(user, 25)) + return + user.visible_message("[user] fabricates a circuit and places it into [src].", \ + "You adapt an air alarm circuit and slot it into the assembly.") + buildstage = 1 + update_icon() + return + + if(istype(W, /obj/item/wrench)) + to_chat(user, "You detach \the [src] from the wall.") + W.play_tool_sound(src) + new /obj/item/wallframe/airalarm( user.loc ) + qdel(src) + return + + return ..() + +/obj/machinery/airalarm/AltClick(mob/user) + ..() + if(!user.canUseTopic(src, !issilicon(user)) || !isturf(loc)) + return + else + togglelock(user) + +/obj/machinery/airalarm/proc/togglelock(mob/living/user) + if(stat & (NOPOWER|BROKEN)) + to_chat(user, "It does nothing!") + else + if(src.allowed(usr) && !wires.is_cut(WIRE_IDSCAN)) + locked = !locked + updateUsrDialog() + to_chat(user, "You [ locked ? "lock" : "unlock"] the air alarm interface.") + else + to_chat(user, "Access denied.") + return + +/obj/machinery/airalarm/power_change() + ..() + if(stat & NOPOWER) + set_light(0) + update_icon() + +/obj/machinery/airalarm/emag_act(mob/user) + . = ..() + if(obj_flags & EMAGGED) + return + obj_flags |= EMAGGED + visible_message("Sparks fly out of [src]!", "You emag [src], disabling its safeties.") + playsound(src, "sparks", 50, 1) + return TRUE + +/obj/machinery/airalarm/obj_break(damage_flag) + ..() + update_icon() + set_light(0) + +/obj/machinery/airalarm/deconstruct(disassembled = TRUE) + if(!(flags_1 & NODECONSTRUCT_1)) + new /obj/item/stack/sheet/metal(loc, 2) + var/obj/item/I = new /obj/item/electronics/airalarm(loc) + if(!disassembled) + I.obj_integrity = I.max_integrity * 0.5 + new /obj/item/stack/cable_coil(loc, 3) + qdel(src) + +#undef AALARM_MODE_SCRUBBING +#undef AALARM_MODE_VENTING +#undef AALARM_MODE_PANIC +#undef AALARM_MODE_REPLACEMENT +#undef AALARM_MODE_OFF +#undef AALARM_MODE_FLOOD +#undef AALARM_MODE_SIPHON +#undef AALARM_MODE_CONTAMINATED +#undef AALARM_MODE_REFILL +#undef AALARM_REPORT_TIMEOUT diff --git a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm index 35b30107d8..ccd13d8d4a 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm @@ -394,6 +394,21 @@ . = TRUE update_icon() +/obj/machinery/atmospherics/components/unary/cryo_cell/CtrlClick(mob/user) + if(user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK) && !state_open) + on = !on + update_icon() + return ..() + +/obj/machinery/atmospherics/components/unary/cryo_cell/AltClick(mob/user) + if(user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK)) + if(state_open) + close_machine() + else + open_machine() + update_icon() + return ..() + /obj/machinery/atmospherics/components/unary/cryo_cell/update_remote_sight(mob/living/user) return // we don't see the pipe network while inside cryo. diff --git a/code/modules/awaymissions/capture_the_flag.dm b/code/modules/awaymissions/capture_the_flag.dm index fcfdd7c455..84f08197b4 100644 --- a/code/modules/awaymissions/capture_the_flag.dm +++ b/code/modules/awaymissions/capture_the_flag.dm @@ -24,7 +24,6 @@ armour_penetration = 1000 resistance_flags = INDESTRUCTIBLE anchored = TRUE - item_flags = SLOWS_WHILE_IN_HAND var/team = WHITE_TEAM var/reset_cooldown = 0 var/anyonecanpickup = TRUE diff --git a/code/modules/awaymissions/mission_code/Academy.dm b/code/modules/awaymissions/mission_code/Academy.dm index 57d8420fa8..b7b21bbb9b 100644 --- a/code/modules/awaymissions/mission_code/Academy.dm +++ b/code/modules/awaymissions/mission_code/Academy.dm @@ -133,7 +133,7 @@ var/mob/dead/observer/C = pick(candidates) message_admins("[ADMIN_LOOKUPFLW(C)] was spawned as Wizard Academy Defender") current_wizard.ghostize() // on the off chance braindead defender gets back in - current_wizard.key = C.key + C.transfer_ckey(current_wizard, FALSE) /obj/structure/academy_wizard_spawner/proc/summon_wizard() var/turf/T = src.loc @@ -210,8 +210,6 @@ if(4) //Destroy Equipment for (var/obj/item/I in user) - if (istype(I, /obj/item/implant)) - continue qdel(I) if(5) //Monkeying @@ -274,7 +272,7 @@ if(LAZYLEN(candidates)) var/mob/dead/observer/C = pick(candidates) message_admins("[ADMIN_LOOKUPFLW(C)] was spawned as Dice Servant") - H.key = C.key + C.transfer_ckey(H, FALSE) var/obj/effect/proc_holder/spell/targeted/summonmob/S = new S.target_mob = H diff --git a/code/modules/cargo/bounties/assistant.dm b/code/modules/cargo/bounties/assistant.dm index cf4efaa8c6..4edcb04e8f 100644 --- a/code/modules/cargo/bounties/assistant.dm +++ b/code/modules/cargo/bounties/assistant.dm @@ -1,46 +1,46 @@ /datum/bounty/item/assistant/strange_object name = "Strange Object" description = "Nanotrasen has taken an interest in strange objects. Find one in maint, and ship it off to CentCom right away." - reward = 1200 + reward = 600 wanted_types = list(/obj/item/relic) /datum/bounty/item/assistant/scooter name = "Scooter" description = "Nanotrasen has determined walking to be wasteful. Ship a scooter to CentCom to speed operations up." - reward = 1080 // the mat hoffman + reward = 850 // the mat hoffman wanted_types = list(/obj/vehicle/ridden/scooter) include_subtypes = FALSE /datum/bounty/item/assistant/skateboard name = "Skateboard" description = "Nanotrasen has determined walking to be wasteful. Ship a skateboard to CentCom to speed operations up." - reward = 900 // the tony hawk + reward = 700 // the tony hawk wanted_types = list(/obj/vehicle/ridden/scooter/skateboard) /datum/bounty/item/assistant/stunprod name = "Stunprod" description = "CentCom demands a stunprod to use against dissidents. Craft one, then ship it." - reward = 1300 + reward = 800 wanted_types = list(/obj/item/melee/baton/cattleprod) /datum/bounty/item/assistant/soap name = "Soap" description = "Soap has gone missing from CentCom's bathrooms and nobody knows who took it. Replace it and be the hero CentCom needs." - reward = 2000 + reward = 1000 required_count = 3 wanted_types = list(/obj/item/soap) /datum/bounty/item/assistant/spear name = "Spears" description = "CentCom's security forces are going through budget cuts. You will be paid if you ship a set of spears." - reward = 2000 + reward = 1000 required_count = 5 wanted_types = list(/obj/item/twohanded/spear) /datum/bounty/item/assistant/toolbox name = "Toolboxes" description = "There's an absence of robustness at Central Command. Hurry up and ship some toolboxes as a solution." - reward = 2000 + reward = 1000 required_count = 6 wanted_types = list(/obj/item/storage/toolbox) @@ -53,81 +53,81 @@ /datum/bounty/item/assistant/clown_box name = "Clown Box" description = "The universe needs laughter. Stamp cardboard with a clown stamp and ship it out." - reward = 1500 + reward = 750 wanted_types = list(/obj/item/storage/box/clown) /datum/bounty/item/assistant/cheesiehonkers name = "Cheesie Honkers" description = "Apparently the company that makes Cheesie Honkers is going out of business soon. CentCom wants to stock up before it happens!" - reward = 1200 + reward = 1000 required_count = 3 wanted_types = list(/obj/item/reagent_containers/food/snacks/cheesiehonkers) /datum/bounty/item/assistant/baseball_bat name = "Baseball Bat" description = "Baseball fever is going on at CentCom! Be a dear and ship them some baseball bats, so that management can live out their childhood dream." - reward = 2000 + reward = 1000 required_count = 5 wanted_types = list(/obj/item/melee/baseball_bat) /datum/bounty/item/assistant/extendohand name = "Extendo-Hand" description = "Commander Betsy is getting old, and can't bend over to get the telescreen remote anymore. Management has requested an extendo-hand to help her out." - reward = 2500 + reward = 1250 wanted_types = list(/obj/item/extendohand) /datum/bounty/item/assistant/donut name = "Donuts" description = "CentCom's security forces are facing heavy losses against the Syndicate. Ship donuts to raise morale." - reward = 3000 + reward = 2000 required_count = 10 wanted_types = list(/obj/item/reagent_containers/food/snacks/donut) /datum/bounty/item/assistant/donkpocket name = "Donk-Pockets" description = "Consumer safety recall: Warning. Donk-Pockets manufactured in the past year contain hazardous lizard biomatter. Return units to CentCom immediately." - reward = 3000 + reward = 1000 required_count = 10 wanted_types = list(/obj/item/reagent_containers/food/snacks/donkpocket) /datum/bounty/item/assistant/briefcase name = "Briefcase" description = "Central Command will be holding a business convention this year. Ship a few briefcases in support." - reward = 2500 + reward = 1500 required_count = 5 wanted_types = list(/obj/item/storage/briefcase, /obj/item/storage/secure/briefcase) /datum/bounty/item/assistant/sunglasses name = "Sunglasses" description = "A famous blues duo is passing through the sector, but they've lost their shades and they can't perform. Ship new sunglasses to CentCom to rectify this." - reward = 3000 + reward = 1000 required_count = 2 wanted_types = list(/obj/item/clothing/glasses/sunglasses) /datum/bounty/item/assistant/monkey_hide name = "Monkey Hide" description = "One of the scientists at CentCom is interested in testing products on monkey skin. Your mission is to acquire monkey's hide and ship it." - reward = 1500 + reward = 500 wanted_types = list(/obj/item/stack/sheet/animalhide/monkey) /datum/bounty/item/assistant/shard name = "Shards" description = "A killer clown has been stalking CentCom, and staff have been unable to catch her because she's not wearing shoes. Please ship some shards so that a booby trap can be constructed." - reward = 1500 + reward = 500 required_count = 15 wanted_types = list(/obj/item/shard) /datum/bounty/item/assistant/comfy_chair name = "Comfy Chairs" description = "Commander Pat is unhappy with his chair. He claims it hurts his back. Ship some alternatives out to humor him." - reward = 1500 + reward = 900 required_count = 5 wanted_types = list(/obj/structure/chair/comfy) /datum/bounty/item/assistant/geranium name = "Geraniums" description = "Commander Zot has the hots for Commander Zena. Send a shipment of geraniums - her favorite flower - and he'll happily reward you." - reward = 4000 + reward = 1000 required_count = 3 wanted_types = list(/obj/item/reagent_containers/food/snacks/grown/poppy/geranium) @@ -142,7 +142,7 @@ /datum/bounty/item/assistant/shadyjims name = "Shady Jim's" description = "There's an irate officer at CentCom demanding that he receive a box of Shady Jim's cigarettes. Please ship one. He's starting to make threats." - reward = 500 + reward = 750 wanted_types = list(/obj/item/storage/fancy/cigarettes/cigpack_shadyjims) /datum/bounty/item/assistant/potted_plants diff --git a/code/modules/cargo/bounties/botany.dm b/code/modules/cargo/bounties/botany.dm index 34906b321a..754de480cd 100644 --- a/code/modules/cargo/bounties/botany.dm +++ b/code/modules/cargo/bounties/botany.dm @@ -1,5 +1,5 @@ /datum/bounty/item/botany - reward = 5000 + reward = 1200 var/datum/bounty/item/botany/multiplier = 0 //adds bonus reward money; increased for higher tier or rare mutations var/datum/bounty/item/botany/bonus_desc //for adding extra flavor text to bounty descriptions var/datum/bounty/item/botany/foodtype = "meal" //same here @@ -64,7 +64,7 @@ multiplier = 4 //hush money bonus_desc = "Do not mention this shipment to security." foodtype = "\"meal\"" - + /datum/bounty/item/botany/cannabis_white name = "Lifeweed Leaves" wanted_types = list(/obj/item/reagent_containers/food/snacks/grown/cannabis/white) diff --git a/code/modules/cargo/bounties/chef.dm b/code/modules/cargo/bounties/chef.dm index b9d9ebc184..719a2d10a5 100644 --- a/code/modules/cargo/bounties/chef.dm +++ b/code/modules/cargo/bounties/chef.dm @@ -1,34 +1,34 @@ /datum/bounty/item/chef/birthday_cake name = "Birthday Cake" description = "Nanotrasen's birthday is coming up! Ship them a birthday cake to celebrate!" - reward = 4000 + reward = 1000 wanted_types = list(/obj/item/reagent_containers/food/snacks/store/cake/birthday, /obj/item/reagent_containers/food/snacks/cakeslice/birthday) /datum/bounty/item/chef/soup name = "Soup" description = "To quell the homeless uprising, Nanotrasen will be serving soup to all underpaid workers. Ship any type of soup." - reward = 3000 + reward = 700 required_count = 3 wanted_types = list(/obj/item/reagent_containers/food/snacks/soup) /datum/bounty/item/chef/popcorn name = "Popcorn Bags" description = "Upper management wants to host a movie night. Ship bags of popcorn for the occasion." - reward = 3000 + reward = 800 required_count = 3 wanted_types = list(/obj/item/reagent_containers/food/snacks/popcorn) /datum/bounty/item/chef/onionrings name = "Onion Rings" description = "Nanotrasen is remembering Saturn day. Ship onion rings to show the station's support." - reward = 3000 + reward = 800 required_count = 3 wanted_types = list(/obj/item/reagent_containers/food/snacks/onionrings) /datum/bounty/item/chef/icecreamsandwich name = "Ice Cream Sandwiches" description = "Upper management has been screaming non-stop for ice cream. Please send some." - reward = 4000 + reward = 800 required_count = 3 wanted_types = list(/obj/item/reagent_containers/food/snacks/icecreamsandwich) @@ -36,7 +36,7 @@ name = "Bread" description = "Problems with central planning have led to bread prices skyrocketing. Ship some bread to ease tensions." reward = 1000 - wanted_types = list(/obj/item/reagent_containers/food/snacks/store/bread, /obj/item/reagent_containers/food/snacks/breadslice, /obj/item/reagent_containers/food/snacks/bun, /obj/item/reagent_containers/food/snacks/pizzabread, /obj/item/reagent_containers/food/snacks/rawpastrybase) + wanted_types = list(/obj/item/reagent_containers/food/snacks/store/bread, /obj/item/reagent_containers/food/snacks/breadslice, /obj/item/reagent_containers/food/snacks/bun, /obj/item/reagent_containers/food/snacks/pizzabread, /obj/item/reagent_containers/food/snacks/rawpastrybase) /datum/bounty/item/chef/pie name = "Pie" @@ -47,21 +47,21 @@ /datum/bounty/item/chef/salad name = "Salad or Rice Bowls" description = "CentCom management is going on a health binge. Your order is to ship salad or rice bowls." - reward = 3000 + reward = 1200 required_count = 3 wanted_types = list(/obj/item/reagent_containers/food/snacks/salad) /datum/bounty/item/chef/carrotfries name = "Carrot Fries" description = "Night sight can mean life or death! A shipment of carrot fries is the order." - reward = 3500 + reward = 1300 required_count = 3 wanted_types = list(/obj/item/reagent_containers/food/snacks/carrotfries) /datum/bounty/item/chef/superbite name = "Super Bite Burger" description = "Commander Tubbs thinks he can set a competitive eating world record. All he needs is a super bite burger shipped to him." - reward = 12000 + reward = 1800 wanted_types = list(/obj/item/reagent_containers/food/snacks/burger/superbite) /datum/bounty/item/chef/poppypretzel @@ -73,19 +73,19 @@ /datum/bounty/item/chef/cubancarp name = "Cuban Carp" description = "To celebrate the birth of Castro XXVII, ship one cuban carp to CentCom." - reward = 8000 + reward = 3000 wanted_types = list(/obj/item/reagent_containers/food/snacks/cubancarp) /datum/bounty/item/chef/hotdog name = "Hot Dog" description = "Nanotrasen is conducting taste tests to determine the best hot dog recipe. Ship your station's version to participate." - reward = 8000 + reward = 4000 wanted_types = list(/obj/item/reagent_containers/food/snacks/hotdog) /datum/bounty/item/chef/eggplantparm name = "Eggplant Parmigianas" description = "A famous singer will be arriving at CentCom, and their contract demands that they only be served Eggplant Parmigiana. Ship some, please!" - reward = 3500 + reward = 2500 required_count = 3 wanted_types = list(/obj/item/reagent_containers/food/snacks/eggplantparm) @@ -99,33 +99,33 @@ /datum/bounty/item/chef/chawanmushi name = "Chawanmushi" description = "Nanotrasen wants to improve relations with its sister company, Japanotrasen. Ship Chawanmushi immediately." - reward = 8000 + reward = 5000 wanted_types = list(/obj/item/reagent_containers/food/snacks/chawanmushi) /datum/bounty/item/chef/kebab name = "Kebabs" description = "Remove all kebab from station you are best food. Ship to CentCom to remove from the premises." - reward = 3500 + reward = 1500 required_count = 3 wanted_types = list(/obj/item/reagent_containers/food/snacks/kebab) /datum/bounty/item/chef/soylentgreen name = "Soylent Green" description = "CentCom has heard wonderful things about the product 'Soylent Green', and would love to try some. If you endulge them, expect a pleasant bonus." - reward = 5000 + reward = 4000 wanted_types = list(/obj/item/reagent_containers/food/snacks/soylentgreen) /datum/bounty/item/chef/pancakes name = "Pancakes" description = "Here at Nanotrasen we consider employees to be family. And you know what families love? Pancakes. Ship a baker's dozen." - reward = 5000 + reward = 4000 required_count = 13 wanted_types = list(/datum/crafting_recipe/food/pancakes) /datum/bounty/item/chef/nuggies name = "Chicken Nuggets" description = "The vice president's son won't shut up about chicken nuggies. Would you mind shipping some?" - reward = 4000 + reward = 2500 required_count = 6 wanted_types = list(/obj/item/reagent_containers/food/snacks/nugget) diff --git a/code/modules/cargo/bounties/engineering.dm b/code/modules/cargo/bounties/engineering.dm index e10d48f3bf..1f16788c4d 100644 --- a/code/modules/cargo/bounties/engineering.dm +++ b/code/modules/cargo/bounties/engineering.dm @@ -14,10 +14,10 @@ return FALSE return T.air_contents.gases[gas_type] >= moles_required -/datum/bounty/item/engineering/gas/nitryl_tank - name = "Full Tank of Nitryl" - description = "The non-human staff of Station 88 has been volunteered to test performance enhancing drugs. Ship them a tank full of Nitryl so they can get started." - gas_type = /datum/gas/nitryl +//datum/bounty/item/engineering/gas/nitryl_tank +// name = "Full Tank of Nitryl" +// description = "The non-human staff of Station 88 has been volunteered to test performance enhancing drugs. Ship them a tank full of Nitryl so they can get started." +// gas_type = /datum/gas/nitryl /datum/bounty/item/engineering/gas/tritium_tank name = "Full Tank of Tritium" @@ -27,18 +27,67 @@ /datum/bounty/item/engineering/pacman name = "P.A.C.M.A.N.-type portable generator" description = "A neighboring station had a problem with their SMES, and now need something to power their communications console. Can you send them a P.AC.M.A.N.?" - reward = 3500 //2500 for the cargo one + reward = 1500 //2500 for the cargo one wanted_types = list(/obj/machinery/power/port_gen/pacman) /datum/bounty/item/engineering/canisters name = "Gas Canisters" description = "After a recent debacle in a nearby sector, 10 gas canisters are needed for containing an experimental aerosol before it kills all the local fauna." - reward = 5000 + reward = 3000 required_count = 10 //easy to make wanted_types = list(/obj/machinery/portable_atmospherics/canister) +/datum/bounty/item/engineering/microwave + name = "Microwaves" + description = "Due to a shortage of microwaves, our chefs are incapable of keeping up with our sheer volume of orders. We need at least three microwaves to keep up with our crew's dietary habits." + reward = 1000 + required_count = 3 + wanted_types = list(/obj/machinery/microwave) + +/datum/bounty/item/engineering/hydroponicstrays + name = "Hydroponics Tray" + description = "The garden has become a hot spot of late, they need a few more hydroponics tray to grow more flowers." + reward = 1500 + required_count = 5 + wanted_types = list(/obj/machinery/hydroponics) + +/datum/bounty/item/engineering/rcd + name = "Spare RCD" + description = "Construction and repairs to are shuttles are going slowly. As it turns out, we're a little short on RCDs, can you send us a few?" + reward = 1500 + required_count = 3 + wanted_types = list(/obj/item/construction/rcd) + +/datum/bounty/item/engineering/rpd + name = "Spare RPD" + description = "Our Atmospheric Technicians are still living in the past, relying on stationary pipe dispensers to produce the pipes necessary to accomplish their strenuous tasks. They could use an upgrade. Could you send us some Rapid Pipe Dispensers?" + reward = 2500 + required_count = 3 + wanted_types = list(/obj/item/pipe_dispenser) + +/datum/bounty/item/engineering/heaters + name = "Space Heaters" + description = "The kitchen freezer was left open and now the whole place is frozen solid! We need a few space heaters to warm it back up before anyone gets hungry." + reward = 3000 + required_count = 5 + wanted_types = list(/obj/machinery/space_heater) + +/datum/bounty/item/engineering/arcadetrail + name = "Orion Trail Arcade Games" + description = "The staff have nothing to do when off-work. Can you send us some Orion Trail games to play?" + reward = 1500 + required_count = 5 + wanted_types = list(/obj/machinery/computer/arcade/orion_trail) + +/datum/bounty/item/engineering/arcadebattle + name = "Battle Arcade Games" + description = "The staff have nothing to do when off-work. Can you send us some Battle Arcade games to play?" + reward = 1500 + required_count = 5 + wanted_types = list(/obj/machinery/computer/arcade/battle) + /datum/bounty/item/engineering/energy_ball name = "Contained Tesla Ball" description = "Station 24 is being overrun by hordes of angry Mothpeople. They are requesting the ultimate bug zapper." - reward = 75000 //requires 14k credits of purchases, not to mention cooperation with engineering/heads of staff to set up inside the cramped shuttle + reward = 50000 //requires 14k credits of purchases, not to mention cooperation with engineering/heads of staff to set up inside the cramped shuttle wanted_types = list(/obj/singularity/energy_ball) diff --git a/code/modules/cargo/bounties/medical.dm b/code/modules/cargo/bounties/medical.dm index 3129051754..22964e1fb7 100644 --- a/code/modules/cargo/bounties/medical.dm +++ b/code/modules/cargo/bounties/medical.dm @@ -7,34 +7,34 @@ /datum/bounty/item/medical/lung name = "Lungs" description = "A recent explosion at Central Command has left multiple staff with punctured lungs. Ship spare lungs to be rewarded." - reward = 10000 + reward = 3000 required_count = 3 wanted_types = list(/obj/item/organ/lungs) /datum/bounty/item/medical/appendix name = "Appendix" description = "Chef Gibb of Central Command wants to prepare a meal using a very special delicacy: an appendix. If you ship one, he'll pay." - reward = 5000 //there are no synthetic appendixes + reward = 3500 //there are no synthetic appendixes wanted_types = list(/obj/item/organ/appendix) /datum/bounty/item/medical/ears name = "Ears" description = "Multiple staff at Station 12 have been left deaf due to unauthorized clowning. Ship them new ears." - reward = 10000 + reward = 5000 required_count = 3 wanted_types = list(/obj/item/organ/ears) /datum/bounty/item/medical/liver name = "Livers" description = "Multiple high-ranking CentCom diplomats have been hospitalized with liver failure after a recent meeting with Third Soviet Union ambassadors. Help us out, will you?" - reward = 10000 + reward = 5500 required_count = 3 wanted_types = list(/obj/item/organ/liver) /datum/bounty/item/medical/eye name = "Organic Eyes" description = "Station 5's Research Director Willem is requesting a few pairs of non-robotic eyes. Don't ask questions, just ship them." - reward = 10000 + reward = 3000 required_count = 3 wanted_types = list(/obj/item/organ/eyes) exclude_types = list(/obj/item/organ/eyes/robotic) @@ -42,7 +42,7 @@ /datum/bounty/item/medical/tongue name = "Tongues" description = "A recent attack by Mime extremists has left staff at Station 23 speechless. Ship some spare tongues." - reward = 10000 + reward = 4500 required_count = 3 wanted_types = list(/obj/item/organ/tongue) @@ -79,7 +79,7 @@ required_count = 200 wanted_types = (L,/datum/reagent/blood) if(istype(L,/datum/reagent/blood)) - wanted_types += L + wanted_types += L /datum/bounty/item/medical/bloodu //Dosnt work do to how blood is yet* name = "U-Type Blood" @@ -88,40 +88,40 @@ required_count = 200 wanted_types = (U,/datum/reagent/blood) if(istype(U,/datum/reagent/blood)) - wanted_types += U + wanted_types += U */ /datum/bounty/item/medical/surgery name = "Surgery tool implants" description = "Our medical interns keep dropping their Shambler's Juice while they're performing open heart surgery. One of them even had the audacity to say he only had two hands!" - reward = 10000 + reward = 7000 required_count = 3 wanted_types = list(/obj/item/organ/cyberimp/arm/surgery) /datum/bounty/item/medical/chemmaker name = "Portable Chem Dispenser" description = "After a new chemist mixed up some water and a banana, we lost our only chem dispenser. Please send us a replacement and you will be compensated." - reward = 7000 + reward = 5000 wanted_types = list(/obj/machinery/chem_dispenser) /datum/bounty/item/medical/advhealthscaner name = "Advanced Health Analyzer" description = "A ERT Medical unit needs the new 'advanced health analyzer', for a mission at a Station 4. Can you send some?." - reward = 4000 + reward = 3000 required_count = 5 wanted_types = list(/obj/item/healthanalyzer/advanced) /datum/bounty/item/medical/wallmounts name = "Defibrillator wall mounts" description = "New Space OSHA regulation state that are new cloning medical wing needs a few 'Easy to access defibrillartors'. Can you send a few before we get a lawsuit?" - reward = 5000 + reward = 2000 required_count = 3 wanted_types = list(/obj/machinery/defibrillator_mount) /datum/bounty/item/medical/defibrillator name = "New defibillators" description = "After years of storge are defibrillator units have become more liabilities then we want. Please send us some new ones to replace these old ones." - reward = 5000 + reward = 2250 required_count = 5 wanted_types = list(/obj/item/defibrillator) diff --git a/code/modules/cargo/bounties/mining.dm b/code/modules/cargo/bounties/mining.dm index 51d93f83b5..1f3266af62 100644 --- a/code/modules/cargo/bounties/mining.dm +++ b/code/modules/cargo/bounties/mining.dm @@ -8,58 +8,58 @@ /datum/bounty/item/mining/goliath_boat name = "Goliath Hide Boat" description = "Commander Menkov wants to participate in the annual Lavaland Regatta. He is asking your shipwrights to build the swiftest boat known to man." - reward = 10000 + reward = 5500 wanted_types = list(/obj/vehicle/ridden/lavaboat) /datum/bounty/item/mining/bone_oar name = "Bone Oars" description = "Commander Menkov requires oars to participate in the annual Lavaland Regatta. Ship a pair over." - reward = 4000 + reward = 2000 required_count = 2 wanted_types = list(/obj/item/oar) /datum/bounty/item/mining/bone_axe name = "Bone Axe" description = "Station 12 has had their fire axes stolen by marauding clowns. Ship them a bone axe as a replacement." - reward = 7500 + reward = 3500 wanted_types = list(/obj/item/twohanded/fireaxe/boneaxe) /datum/bounty/item/mining/bone_armor name = "Bone Armor" description = "Station 14 has volunteered their lizard crew for ballistic armor testing. Ship over some bone armor." - reward = 5000 + reward = 2000 wanted_types = list(/obj/item/clothing/suit/armor/bone) /datum/bounty/item/mining/skull_helmet name = "Skull Helmet" description = "Station 42's Head of Security has her birthday tomorrow! We want to suprise her with a fashionable skull helmet." - reward = 4000 + reward = 2000 wanted_types = list(/obj/item/clothing/head/helmet/skull) /datum/bounty/item/mining/bone_talisman name = "Bone Talismans" description = "Station 14's Research Director claims that pagan bone talismans protect their wearer. Ship them a few so they can start testing." - reward = 7500 + reward = 3500 required_count = 3 wanted_types = list(/obj/item/clothing/accessory/talisman) /datum/bounty/item/mining/bone_dagger name = "Bone Daggers" description = "Central Command's canteen is undergoing budget cuts. Ship over some bone daggers so our Chef can keep working." - reward = 5000 + reward = 1000 required_count = 3 wanted_types = list(/obj/item/kitchen/knife/combat/bone) /datum/bounty/item/mining/basalt name = "Artificial Basalt Tiles" description = "Central Command's Ash Walker exhibit needs to be expanded again, we just need some more basalt flooring." - reward = 5000 + reward = 2200 required_count = 60 wanted_types = list(/obj/item/stack/tile/basalt) /datum/bounty/item/mining/fruit name = "Cactus Fruit" description = "Central Command's Ash Walker habitat needs more fauna, send us some local fruit seeds!" - reward = 2000 + reward = 1000 required_count = 1 wanted_types = list(/obj/item/seeds/lavaland/cactus) diff --git a/code/modules/cargo/bounties/reagent.dm b/code/modules/cargo/bounties/reagent.dm index 3f458e2b12..5137d0a6f3 100644 --- a/code/modules/cargo/bounties/reagent.dm +++ b/code/modules/cargo/bounties/reagent.dm @@ -109,19 +109,18 @@ datum/bounty/reagent/complex_drink/New() /datum/reagent/consumable/ethanol/patron,\ /datum/reagent/consumable/ethanol/quadruple_sec,\ /datum/reagent/consumable/ethanol/quintuple_sec,\ - /datum/reagent/consumable/bluecherryshake,\ /datum/reagent/consumable/doctor_delight,\ /datum/reagent/consumable/ethanol/silencer) - + var/reagent_type = pick(possible_reagents) wanted_reagent = new reagent_type name = wanted_reagent.name description = "CentCom is offering a reward for talented mixologists. Ship a container of [name] to claim the prize." - reward += rand(0, 4) * 500 + reward += rand(0, 4) * 300 /datum/bounty/reagent/chemical name = "Chemical" - reward = 4000 + reward = 2750 required_volume = 30 datum/bounty/reagent/chemical/New() diff --git a/code/modules/cargo/bounties/science.dm b/code/modules/cargo/bounties/science.dm index 2ac79f6ee8..6102d8d685 100644 --- a/code/modules/cargo/bounties/science.dm +++ b/code/modules/cargo/bounties/science.dm @@ -1,116 +1,116 @@ /datum/bounty/item/science/boh name = "Bag of Holding" description = "Nanotrasen would make good use of high-capacity backpacks. If you have any, please ship them." - reward = 10000 + reward = 5000 wanted_types = list(/obj/item/storage/backpack/holding) /datum/bounty/item/science/tboh name = "Trash Bag of Holding" description = "Nanotrasen would make good use of high-capacity trash bags. If you have any, please ship them." - reward = 10000 + reward = 3000 wanted_types = list(/obj/item/storage/backpack/holding) /datum/bounty/item/science/bluespace_syringe name = "Bluespace Syringe" description = "Nanotrasen would make good use of high-capacity syringes. If you have any, please ship them." - reward = 10000 + reward = 1500 wanted_types = list(/obj/item/reagent_containers/syringe/bluespace) /datum/bounty/item/science/bluespace_body_bag name = "Bluespace Body Bag" description = "Nanotrasen would make good use of high-capacity body bags. If you have any, please ship them." - reward = 10000 + reward = 5000 wanted_types = list(/obj/item/bodybag/bluespace) /datum/bounty/item/science/nightvision_goggles name = "Night Vision Goggles" description = "An electrical storm has busted all the lights at CentCom. While management is waiting for replacements, perhaps some night vision goggles can be shipped?" - reward = 10000 + reward = 1000 wanted_types = list(/obj/item/clothing/glasses/night, /obj/item/clothing/glasses/meson/night, /obj/item/clothing/glasses/hud/health/night, /obj/item/clothing/glasses/hud/security/night, /obj/item/clothing/glasses/hud/diagnostic/night) /datum/bounty/item/science/experimental_welding_tool name = "Experimental Welding Tool" description = "A recent accident has left most of CentCom's welding tools exploded. Ship replacements to be rewarded." - reward = 10000 + reward = 5000 required_count = 3 wanted_types = list(/obj/item/weldingtool/experimental) /datum/bounty/item/science/cryostasis_beaker name = "Cryostasis Beaker" description = "Chemists at Central Command have discovered a new chemical that can only be held in cryostasis beakers. The only problem is they don't have any! Rectify this to receive payment." - reward = 10000 + reward = 2000 wanted_types = list(/obj/item/reagent_containers/glass/beaker/noreact) /datum/bounty/item/science/diamond_drill name = "Diamond Mining Drill" description = "Central Command is willing to pay three months salary in exchange for one diamond mining drill." - reward = 15000 + reward = 5500 wanted_types = list(/obj/item/pickaxe/drill/diamonddrill, /obj/item/mecha_parts/mecha_equipment/drill/diamonddrill) /datum/bounty/item/science/floor_buffer name = "Floor Buffer Upgrade" description = "One of CentCom's janitors made a small fortune betting on carp races. Now they'd like to commission an upgrade to their floor buffer." - reward = 10000 + reward = 3000 wanted_types = list(/obj/item/janiupgrade) /datum/bounty/item/science/advanced_mop name = "Advanced Mop" description = "Excuse me. I'd like to request $17 for a push broom rebristling. Either that, or an advanced mop." - reward = 10000 + reward = 3000 wanted_types = list(/obj/item/mop/advanced) /datum/bounty/item/science/advanced_egun name = "Advanced Energy Gun" description = "With the price of rechargers on the rise, upper management is interested in purchasing guns that are self-powered. If you ship one, they'll pay." - reward = 10000 + reward = 1800 wanted_types = list(/obj/item/gun/energy/e_gun/nuclear) /datum/bounty/item/science/bscells name = "Bluespace Power Cells" description = "Someone in upper management keeps using the excuse that his tablet battery dies when he's in the middle of work. This will be the last time he doesn't have his presentation, I swear to -" - reward = 7000 + reward = 3000 required_count = 10 //Easy to make wanted_types = list(/obj/item/stock_parts/cell/bluespace) /datum/bounty/item/science/t4manip name = "Femto-Manipulators" description = "One of our Chief Engineers has OCD. Can you send us some femto-manipulators so he stops complaining that his ID doesn't fit perfectly in the PDA slot?" - reward = 7000 + reward = 2000 required_count = 20 //Easy to make wanted_types = list(/obj/item/stock_parts/manipulator/femto) /datum/bounty/item/science/t4bins name = "Bluespace Matter Bins" description = "The local Janitorial union has gone on strike. Can you send us some bluespace bins so we don't have to take out our own trash?" - reward = 7000 + reward = 2000 required_count = 20 //Easy to make wanted_types = list(/obj/item/stock_parts/matter_bin/bluespace) /datum/bounty/item/science/t4capacitor name = "Quadratic Capacitor" description = "One of our linguists doesn't understand why they're called Quadratic capacitors. Can you give him a few so he leaves us alone about it?" - reward = 7000 + reward = 2000 required_count = 20 //Easy to make wanted_types = list(/obj/item/stock_parts/capacitor/quadratic) /datum/bounty/item/science/t4triphasic name = "Triphasic Scanning Module" description = "One of our scientists got into the liberty caps and is demanding new scanning modules so he can talk to ghosts. At this point we just want him out of our office." - reward = 7000 + reward = 2000 required_count = 20 //Easy to make wanted_types = list(/obj/item/stock_parts/scanning_module/triphasic) /datum/bounty/item/science/t4microlaser name = "Quad-Ultra Micro-Laser" description = "The cats on Vega 9 are breeding out of control. We need something to corral them into one area so we can saturation bomb it." - reward = 7000 + reward = 2000 required_count = 20 //Easy to make wanted_types = list(/obj/item/stock_parts/micro_laser/quadultra) /datum/bounty/item/science/fakecrystals name = "synthetic bluespace crystals" description = "Don't, uh, tell anyone, but one of our BSA arrays might have had a little... accident. Send us some bluespace crystals so we can recalibrate it before anyone realizes. The whole set uses artificial bluespace crystals, so we need and not any other type of bluespace crystals..." - reward = 10000 + reward = 8000 required_count = 5 wanted_types = list(/obj/item/stack/ore/bluespace_crystal/artificial) exclude_types = list(/obj/item/stack/ore/bluespace_crystal, diff --git a/code/modules/cargo/bounties/security.dm b/code/modules/cargo/bounties/security.dm index cae8d10c61..6ed86cd4b7 100644 --- a/code/modules/cargo/bounties/security.dm +++ b/code/modules/cargo/bounties/security.dm @@ -1,54 +1,54 @@ /datum/bounty/item/security/riotshotgun name = "Riot Shotguns" description = "Hooligans have boarded CentCom! Ship riot shotguns quick, or things are going to get dirty." - reward = 5000 + reward = 2500 required_count = 2 wanted_types = list(/obj/item/gun/ballistic/shotgun/riot) /datum/bounty/item/security/recharger name = "Rechargers" description = "Nanotrasen military academy is conducting marksmanship exercises. They request that rechargers be shipped." - reward = 2000 + reward = 1700 required_count = 3 wanted_types = list(/obj/machinery/recharger) /datum/bounty/item/security/practice name = "Practice Laser Gun" description = "Nanotrasen Military Academy is conducting routine marksmanship exercises. The clown hid all the practice lasers, and we're not using live weapons after last time." - reward = 3000 + reward = 1500 required_count = 3 wanted_types = list(/obj/item/gun/energy/laser/practice) /datum/bounty/item/security/flashshield name = "Strobe Shield" description = "One of our Emergency Response Agents thinks there's vampires in a local station. Send him something to help with his fear of the dark and protect him, too." - reward = 5000 + reward = 3000 wanted_types = list(/obj/item/assembly/flash/shield) /datum/bounty/item/security/sechuds name = "Sec HUDs" description = "Nanotrasen military academy has started to train officers how to use Sec HUDs to the fullest affect. Please send spare Sec HUDs so we can teach the men." - reward = 3000 + reward = 1250 required_count = 5 wanted_types = list(/obj/item/clothing/glasses/hud/security) /datum/bounty/item/security/techslugs name = "Tech Slugs" description = "Nanotrasen Military Academy is conducting an ammo loading and use lessons, on the new 'Tech Slugs'. Problem is we don't have any, please fix this..." - reward = 7500 + reward = 3500 required_count = 15 wanted_types = list(/obj/item/ammo_casing/shotgun/techshell) -/datum/bounty/item/security/WT550 +/datum/bounty/item/security/wt550 name = "Spare WT-550 clips" description = "Nanotrasen Military Academy's ammunition is running low, please send in spare ammo for practice." - reward = 7500 + reward = 1500 required_count = 5 wanted_types = list(/obj/item/ammo_box/magazine/wt550m9) /datum/bounty/item/security/pins name = "Test range firing pins" description = "Nanotrasen Military Academy just got a new set of guns, sadly they didn't come with any pins. Can you send us some Test range locked firing pins?" - reward = 5000 + reward = 2750 required_count = 3 wanted_types = list(/obj/item/firing_pin/test_range) diff --git a/code/modules/cargo/bounties/slime.dm b/code/modules/cargo/bounties/slime.dm index 4aa0797c70..f52f995a27 100644 --- a/code/modules/cargo/bounties/slime.dm +++ b/code/modules/cargo/bounties/slime.dm @@ -1,10 +1,10 @@ /datum/bounty/item/slime - reward = 3000 + reward = 1950 /datum/bounty/item/slime/New() ..() description = "Nanotrasen's science lead is hunting for the rare and exotic [name]. A bounty has been offered for finding it." - reward += rand(0, 4) * 500 + reward += rand(0, 4) * 250 /datum/bounty/item/slime/green name = "Green Slime Extract" diff --git a/code/modules/cargo/bounties/special.dm b/code/modules/cargo/bounties/special.dm index adffaf999a..be91b1d8aa 100644 --- a/code/modules/cargo/bounties/special.dm +++ b/code/modules/cargo/bounties/special.dm @@ -1,14 +1,14 @@ /datum/bounty/item/alien_organs name = "Alien Organs" description = "Nanotrasen is interested in studying Xenomorph biology. Ship a set of organs to be thoroughly compensated." - reward = 25000 + reward = 13500 required_count = 3 wanted_types = list(/obj/item/organ/brain/alien, /obj/item/organ/alien, /obj/item/organ/body_egg/alien_embryo) /datum/bounty/item/syndicate_documents name = "Syndicate Documents" description = "Intel regarding the syndicate is highly prized at CentCom. If you find syndicate documents, ship them. You could save lives." - reward = 15000 + reward = 10000 wanted_types = list(/obj/item/documents/syndicate, /obj/item/documents/photocopy) /datum/bounty/item/syndicate_documents/applies_to(obj/O) @@ -22,15 +22,15 @@ /datum/bounty/item/adamantine name = "Adamantine" description = "Nanotrasen's anomalous materials division is in desparate need for Adamantine. Send them a large shipment and we'll make it worth your while." - reward = 35000 + reward = 15000 required_count = 10 wanted_types = list(/obj/item/stack/sheet/mineral/adamantine) /datum/bounty/more_bounties name = "More Bounties" description = "Complete enough bounties and CentCom will issue new ones!" - reward = 3 // number of bounties - var/required_bounties = 5 + reward = 8 // number of bounties + var/required_bounties = 3 /datum/bounty/more_bounties/can_claim() return ..() && completed_bounty_count() >= required_bounties diff --git a/code/modules/cargo/bounties/virus.dm b/code/modules/cargo/bounties/virus.dm index 8f078a2668..938ac7708d 100644 --- a/code/modules/cargo/bounties/virus.dm +++ b/code/modules/cargo/bounties/virus.dm @@ -1,5 +1,5 @@ /datum/bounty/virus - reward = 5000 + reward = 3000 var/shipped = FALSE var/stat_value = 0 var/stat_name = "" @@ -11,7 +11,7 @@ stat_value *= -1 name = "Virus ([stat_name] of [stat_value])" description = "Nanotrasen is interested in a virus with a [stat_name] stat of exactly [stat_value]. Central Command will pay handsomely for such a virus." - reward += rand(0, 4) * 500 + reward += rand(0, 4) * 400 /datum/bounty/virus/completion_string() return shipped ? "Shipped" : "Not Shipped" diff --git a/code/modules/cargo/console.dm b/code/modules/cargo/console.dm index b5b9a616d0..1a607b4b96 100644 --- a/code/modules/cargo/console.dm +++ b/code/modules/cargo/console.dm @@ -36,6 +36,7 @@ cat |= EXPORT_EMAG /obj/machinery/computer/cargo/emag_act(mob/user) + . = ..() if(obj_flags & EMAGGED) return user.visible_message("[user] swipes a suspicious card through [src]!", @@ -48,6 +49,8 @@ var/obj/item/circuitboard/computer/cargo/board = circuit board.contraband = TRUE board.obj_flags |= EMAGGED + req_access = list() + return TRUE /obj/machinery/computer/cargo/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) diff --git a/code/modules/cargo/exports.dm b/code/modules/cargo/exports.dm index b7550465d9..9a99f201b3 100644 --- a/code/modules/cargo/exports.dm +++ b/code/modules/cargo/exports.dm @@ -1,6 +1,6 @@ /* How it works: The shuttle arrives at CentCom dock and calls sell(), which recursively loops through all the shuttle contents that are unanchored. - + Each object in the loop is checked for applies_to() of various export datums, except the invalid ones. */ @@ -31,7 +31,7 @@ Credit dupes that require a lot of manual work shouldn't be removed, unless they setupExports() var/list/contents = AM.GetAllContents() - + var/datum/export_report/report = external_report if(!report) //If we don't have any longer transaction going on report = new @@ -58,7 +58,7 @@ Credit dupes that require a lot of manual work shouldn't be removed, unless they var/unit_name = "" // Unit name. Only used in "Received [total_amount] [name]s [message]." message var/message = "" var/cost = 100 // Cost of item, in cargo credits. Must not alow for infinite price dupes, see above. - var/k_elasticity = 1/30 //coefficient used in marginal price calculation that roughly corresponds to the inverse of price elasticity, or "quantity elasticity" + var/k_elasticity = 1/20 //coefficient used in marginal price calculation that roughly corresponds to the inverse of price elasticity, or "quantity elasticity" - CIT EDIT 30 - > 20 var/list/export_types = list() // Type of the exported object. If none, the export datum is considered base type. var/include_subtypes = TRUE // Set to FALSE to make the datum apply only to a strict type. var/list/exclude_types = list() // Types excluded from export @@ -125,9 +125,9 @@ Credit dupes that require a lot of manual work shouldn't be removed, unless they if(amount <=0 || the_cost <=0) return FALSE - + report.total_value[src] += the_cost - + if(istype(O, /datum/export/material)) report.total_amount[src] += amount*MINERAL_MATERIAL_AMOUNT else @@ -148,7 +148,7 @@ Credit dupes that require a lot of manual work shouldn't be removed, unless they var/total_value = ex.total_value[src] var/total_amount = ex.total_amount[src] - + var/msg = "[total_value] credits: Received [total_amount] " if(total_value > 0) msg = "+" + msg diff --git a/code/modules/cargo/exports/gear.dm b/code/modules/cargo/exports/gear.dm index 125e0f708b..7ff14df04c 100644 --- a/code/modules/cargo/exports/gear.dm +++ b/code/modules/cargo/exports/gear.dm @@ -1,83 +1,800 @@ /datum/export/gear + include_subtypes = FALSE + +//blanket +/datum/export/gear/hat + cost = 3 + unit_name = "clothing" + export_types = list(/obj/item/clothing) + include_subtypes = TRUE + +//Hats + +//Blanket +/datum/export/gear/hat + cost = 5 + unit_name = "hat" + export_types = list(/obj/item/clothing/head) + include_subtypes = TRUE /datum/export/gear/sec_helmet - cost = 100 + cost = 70 unit_name = "helmet" export_types = list(/obj/item/clothing/head/helmet/sec) -/datum/export/gear/sec_armor - cost = 100 - unit_name = "armor vest" - export_types = list(/obj/item/clothing/suit/armor/vest) +/datum/export/gear/sec_soft + cost = 50 + unit_name = "soft sec cap" + export_types = list(/obj/item/clothing/head/soft/sec) -/datum/export/gear/riot_shield - cost = 100 - unit_name = "riot shield" - export_types = list(/obj/item/shield/riot) +/datum/export/gear/sec_helmetalt + cost = 50 + unit_name = "bullet proof helmet" + export_types = list(/obj/item/clothing/head/helmet/alt) +/datum/export/gear/sec_helmetold + cost = 10 + unit_name = "old helmet" + export_types = list(/obj/item/clothing/head/helmet/old) + +/datum/export/gear/sec_helmetblue + cost = 75 + unit_name = "blue helmet" + export_types = list(/obj/item/clothing/head/helmet/blueshirt) + +/datum/export/gear/sec_helmetriot + cost = 100 + unit_name = "riot helmet" + export_types = list(/obj/item/clothing/head/helmet/riot) + +/datum/export/gear/sec_helmet_light + cost = 20 + unit_name = "justice helmet" + export_types = list(/obj/item/clothing/head/helmet/justice/escape) + include_subtypes = TRUE + +/datum/export/gear/syndicate_helmetswat + cost = 250 + unit_name = "syndicate helmet" + export_types = list(/obj/item/clothing/head/helmet/swat) + +/datum/export/gear/sec_helmetswat + cost = 150 + unit_name = "swat helmet" + export_types = list(/obj/item/clothing/head/helmet/swat/nanotrasen) + +/datum/export/gear/thunder_helmet + cost = 120 + unit_name = "thunder dome helmet" + export_types = list(/obj/item/clothing/head/helmet/thunderdome) + +/datum/export/gear/roman_real + cost = 30 + unit_name = "roman helmet" + export_types = list(/obj/item/clothing/head/helmet/roman) + +/datum/export/gear/roman_realalt + cost = 60 + unit_name = "legionnaire helmet" + export_types = list(/obj/item/clothing/head/helmet/roman/legionnaire) + +/datum/export/gear/roman_fake + cost = 10 + unit_name = "toy roman helmet" + export_types = list(/obj/item/clothing/head/helmet/roman/fake) + +/datum/export/gear/roman_fakealt + cost = 20 + unit_name = "toy legionnaire helmet" + export_types = list(/obj/item/clothing/head/helmet/roman/legionnaire/fake) + +/datum/export/gear/ash_walker_helm + cost = 70 + unit_name = "gladiator helmet" + export_types = list(/obj/item/clothing/head/helmet/gladiator) + +/datum/export/gear/lasertag + cost = 30 //Has armor + unit_name = "lasertag helmet" + export_types = list(/obj/item/clothing/head/helmet/redtaghelm) + +/datum/export/gear/lasertag/blue + export_types = list(/obj/item/clothing/head/helmet/bluetaghelm) + +/datum/export/gear/knight_helmet + cost = 200 + k_elasticity = 1/5 //Rare, dont flood it + unit_name = "knight helmet" + export_types = list(/obj/item/clothing/head/helmet/knight, /obj/item/clothing/head/helmet/knight/blue, /obj/item/clothing/head/helmet/knight/yellow, /obj/item/clothing/head/helmet/knight/red) + +/datum/export/gear/skull_hat + cost = 70 + k_elasticity = 1/15 //Its just a skull + unit_name = "skull" + export_types = list(/obj/item/clothing/head/helmet/skull) + +/datum/export/gear/durathread_helm + cost = 100 + k_elasticity = 1/15 + unit_name = "durathread hat" + export_types = list(/obj/item/clothing/head/helmet/durathread, /obj/item/clothing/head/beret/durathread, /obj/item/clothing/head/beanie/durathread) + +/datum/export/gear/hard_hats + cost = 50 + unit_name = "hard hat" + export_types = list(/obj/item/clothing/head/hardhat, /obj/item/clothing/head/hardhat/orange, /obj/item/clothing/head/hardhat/white, /obj/item/clothing/head/hardhat/dblue) + +/datum/export/gear/atmos_helm + cost = 200 //Armored, fire proof, light, and presser proof + unit_name = "atmos hard hat" + export_types = list(/obj/item/clothing/head/hardhat/atmos) + +/datum/export/gear/crowns + cost = 350 //Armored, gold 300cr of gold to make so give them 50 more for working + k_elasticity = 1/5 //Anti-floods + unit_name = "crown" + export_types = list(/obj/item/clothing/head/crown, /obj/item/clothing/head/crown/fancy) + +/datum/export/gear/cchat + cost = 40 + unit_name = "centcom hat" + export_types = list(/obj/item/clothing/head/centhat) + +/datum/export/gear/caphat + cost = 150 + unit_name = "command hat" + export_types = list(/obj/item/clothing/head/caphat, /obj/item/clothing/head/caphat/parade, /obj/item/clothing/head/caphat/beret) + +/datum/export/gear/hophat + cost = 130 + unit_name = "hop hat" + export_types = list(/obj/item/clothing/head/hopcap, /obj/item/clothing/head/hopcap/beret) + +/datum/export/gear/dechat + cost = 75 + k_elasticity = 1/8 //Anti-floods + unit_name = "fedora" + export_types = list(/obj/item/clothing/head/fedora/det_hat, /obj/item/clothing/head/fedora/curator, /obj/item/clothing/head/fedora) + +/datum/export/gear/hoshat + cost = 140 + unit_name = "hos hat" + export_types = list(/obj/item/clothing/head/HoS, /obj/item/clothing/head/HoS/beret, /obj/item/clothing/head/beret/sec/navyhos) + +/datum/export/gear/syndahoshat + cost = 300 + unit_name = "syndicate command hat" + export_types = list(/obj/item/clothing/head/HoS/syndicate, /obj/item/clothing/head/HoS/beret/syndicate) + +/datum/export/gear/wardenhat + cost = 90 + unit_name = "warden hat" + export_types = list(/obj/item/clothing/head/warden, /obj/item/clothing/head/warden/drill, /obj/item/clothing/head/beret/sec/navywarden) + +/datum/export/gear/sechats + cost = 60 + unit_name = "sec beret" + export_types = list(/obj/item/clothing/head/beret/sec, /obj/item/clothing/head/beret/sec/navyofficer) + +/datum/export/gear/berets + cost = 30 + unit_name = "beret" + export_types = list(/obj/item/clothing/head/beret/qm, /obj/item/clothing/head/beret/rd, /obj/item/clothing/head/beret/cmo, /obj/item/clothing/head/beret) + +/datum/export/gear/berets + cost = 30 + unit_name = "beret" + export_types = list(/obj/item/clothing/head/beret/qm, /obj/item/clothing/head/beret/rd, /obj/item/clothing/head/beret/cmo, /obj/item/clothing/head/beret) + +/datum/export/gear/collectable + cost = 500 + unit_name = "collectable hat" + k_elasticity = 1/10 //dont flood these + export_types = list(/obj/item/clothing/head/collectable) + include_subtypes = TRUE + +/datum/export/gear/fancyhats + cost = 75 + unit_name = "fancy hat" + k_elasticity = 1/10 //dont flood these + export_types = list(/obj/item/clothing/head/that, /obj/item/clothing/head/bowler, /obj/item/clothing/head/lizard, /obj/item/clothing/head/canada) + +/datum/export/gear/welders + cost = 30 + unit_name = "welder helm" + k_elasticity = 1/20 //dont flood these + export_types = list(/obj/item/clothing/head/welding) + +/datum/export/gear/magichat //Magic as is Antags-Wiz/Cults + cost = 450 + unit_name = "magic hat" + export_types = list(/obj/item/clothing/head/wizard, /obj/item/clothing/head/culthood, /obj/item/clothing/head/magus, /obj/item/clothing/head/helmet/clockwork) + exclude_types = list(/obj/item/clothing/head/wizard/fake, /obj/item/clothing/head/wizard/marisa/fake) + include_subtypes = TRUE + +//Shoes + +//Blanket +/datum/export/gear/shoes + cost = 1 //Really dont want to sell EVERY SHOE EVER - yet* + unit_name = "shoes" + export_types = list(/obj/item/clothing/shoes) + include_subtypes = TRUE + +/datum/export/gear/clown_shoesmk + cost = 600 + unit_name = "mk-honk prototype shoes" + export_types = list(/obj/item/clothing/shoes/clown_shoes/banana_shoes) + +/datum/export/gear/magboots + cost = 50 + unit_name = "magboots" + export_types = list(/obj/item/clothing/shoes/magboots, /obj/item/clothing/shoes/magboots/atmos) + +/datum/export/gear/nosellboots + cost = -5000 //We DONT want scew antags + unit_name = "error shipment stolen" + export_types = list(/obj/item/clothing/shoes/magboots/advance, /obj/item/clothing/shoes/magboots/deathsquad) + +/datum/export/gear/syndamagboots + cost = 250 + unit_name = "blood redmagboots" + export_types = list(/obj/item/clothing/shoes/magboots/syndie) + +/datum/export/gear/combatboots + cost = 30 + unit_name = "combat boots" + export_types = list(/obj/item/clothing/shoes/combat) + +/datum/export/gear/swatboots + cost = 45 + unit_name = "swat boots" + export_types = list(/obj/item/clothing/shoes/combat/swat) + +/datum/export/gear/galoshes + cost = 50 + unit_name = "galoshes" + export_types = list(/obj/item/clothing/shoes/galoshes, /obj/item/clothing/shoes/galoshes/dry) + +/datum/export/gear/clown + cost = 10 + unit_name = "clown shoes" + export_types = list(/obj/item/clothing/shoes/clown_shoes, /obj/item/clothing/shoes/clown_shoes/jester) + +/datum/export/gear/dressshoes + cost = 10 + unit_name = "dress shoes" + export_types = list(/obj/item/clothing/shoes/laceup, /obj/item/clothing/shoes/singerb, /obj/item/clothing/shoes/singery) + +/datum/export/gear/working + cost = 15 + unit_name = "boots" + export_types = list(/obj/item/clothing/shoes/jackboots/fast, /obj/item/clothing/shoes/winterboots, /obj/item/clothing/shoes/jackboots, /obj/item/clothing/shoes/workboots, /obj/item/clothing/shoes/workboots/mining) + +/datum/export/gear/hopboots + cost = 350 //costs 1000 credits for miners to get + unit_name = "jump boots" + export_types = list(/obj/item/clothing/shoes/bhop) + +/datum/export/gear/magicboots //Magic as in Antag - Wiz/Cults + cost = 450 + unit_name = "magic shoes" + export_types = list(/obj/item/clothing/shoes/sandal/marisa, /obj/item/clothing/shoes/sandal/magic, /obj/item/clothing/shoes/cult, /obj/item/clothing/shoes/clockwork, /obj/item/clothing/shoes/clown_shoes/taeclowndo, /obj/item/clothing/shoes/sandal/slippers) + include_subtypes = TRUE + +//Headsets/Ears + +//Blanket +/datum/export/gear/ears + cost = 2 //We dont want to sell every headset ever + unit_name = "ear gear" + export_types = list(/obj/item/clothing/ears, /obj/item/radio/headset) + include_subtypes = TRUE + +//Gloves + +//Blanket +/datum/export/gear/gloves + cost = 4 //Glove crafting can be done + unit_name = "gloves" + export_types = list(/obj/item/clothing/gloves) + include_subtypes = TRUE + +/datum/export/gear/boxing + cost = 10 //Padding as well as a weapon + unit_name = "boxing gloves" + export_types = list(/obj/item/clothing/gloves/boxing) + include_subtypes = TRUE + +/datum/export/gear/combatgloves + cost = 80 + unit_name = "combat gloves" + export_types = list(/obj/item/clothing/gloves/combat, /obj/item/clothing/gloves/rapid, /obj/item/clothing/gloves/krav_maga) + include_subtypes = TRUE + +/datum/export/gear/bonegloves + cost = 30 + unit_name = "bone bracers" + export_types = list(/obj/item/clothing/gloves/bracer) + +/datum/export/gear/yellowgloves + cost = 50 + unit_name = "insulated gloves" + export_types = list(/obj/item/clothing/gloves/color/yellow, /obj/item/clothing/gloves/color/red/insulated) + +/datum/export/gear/leathergloves + cost = 20 + unit_name = "leather gloves" + export_types = list(/obj/item/clothing/gloves/botanic_leather) + +/datum/export/gear/fancy + cost = 25 + unit_name = "fancy gloves" + export_types = list(/obj/item/clothing/gloves/color/black, /obj/item/clothing/gloves/color/captain, /obj/item/clothing/gloves/color/white) + +/datum/export/gear/magicgloves//Magic as in Antag - Wiz/Cults + cost = 400 + unit_name = "magic gloves" + export_types = list(/obj/item/clothing/gloves/clockwork) + include_subtypes = TRUE + +//Ties/neck + +//Blanket +/datum/export/gear/neck + cost = 5 //Fancy! + unit_name = "neck based gear" + export_types = list(/obj/item/clothing/neck) + include_subtypes = TRUE + +/datum/export/gear/collar + cost = 7 + unit_name = "collar" + export_types = list(/obj/item/clothing/neck/petcollar) + include_subtypes = TRUE + +/datum/export/gear/bling + cost = 15 //Needs a coin + unit_name = "gold plated necklace" + export_types = list(/obj/item/clothing/neck/necklace/dope) + +//masks + +//Blanket +/datum/export/gear/masks + cost = 3 //Mostly just fake stuff and clowngear + unit_name = "face gear" + export_types = list(/obj/item/clothing/mask) + include_subtypes = TRUE + +/datum/export/gear/gasmask + cost = 4 + unit_name = "gas mask" + export_types = list(/obj/item/clothing/mask/gas, /obj/item/clothing/mask/gas/glass) + +/datum/export/gear/minermask + cost = 10 + unit_name = "armored mask" + export_types = list(/obj/item/clothing/mask/gas/welding, /obj/item/clothing/mask/gas/explorer, /obj/item/clothing/mask/gas/syndicate) + +/datum/export/gear/sechailer + cost = 6 + unit_name = "sec hailer" + export_types = list(/obj/item/clothing/mask/gas/sechailer) + include_subtypes = TRUE /datum/export/gear/mask/breath cost = 2 unit_name = "breath mask" export_types = list(/obj/item/clothing/mask/breath) -/datum/export/gear/mask/gas - cost = 10 - unit_name = "gas mask" - export_types = list(/obj/item/clothing/mask/gas) - include_subtypes = FALSE +//Hardsuits //If you steal/fine more they are worth selling +//Blanket +/datum/export/gear/hardsuit + cost = 250 //Its just metal/plastic after all + unit_name = "unknown hardsuit" + export_types = list(/obj/item/clothing/suit/space/hardsuit) + include_subtypes = TRUE -/datum/export/gear/space/helmet - cost = 75 +/datum/export/gear/engi_hardsuit + cost = 500 + unit_name = "engine hardsuit" + export_types = list(/obj/item/clothing/suit/space/hardsuit/engine) + +/datum/export/gear/atmos_hardsuit + cost = 600 + unit_name = "atmos hardsuit" + export_types = list(/obj/item/clothing/suit/space/hardsuit/engine/atmos) + +/datum/export/gear/engi_hardsuit + cost = 1000 + unit_name = "elite engine hardsuit" + export_types = list(/obj/item/clothing/suit/space/hardsuit/engine/elite) + +/datum/export/gear/mining_hardsuit + cost = 350 //common + unit_name = "mining hardsuit" + export_types = list(/obj/item/clothing/suit/space/hardsuit/mining) + +/datum/export/gear/sec_hardsuit + cost = 750 + unit_name = "sec hardsuit" + export_types = list(/obj/item/clothing/head/helmet/space/hardsuit/mining, /obj/item/clothing/head/helmet/space/hardsuit/syndi/owl) + +/datum/export/gear/syndi_hardsuit + cost = 1250 + unit_name = "syndi hardsuit" + export_types = list(/obj/item/clothing/suit/space/hardsuit/syndi) + +/datum/export/gear/syndi_hardsuit + cost = 2750 + unit_name = "elite syndi hardsuit" + export_types = list(/obj/item/clothing/suit/space/hardsuit/syndi/elite) + +/datum/export/gear/medical_hardsuit + cost = 350 //Not all that good + unit_name = "meidcal hardsuit" + export_types = list(/obj/item/clothing/suit/space/hardsuit/medical) + +/datum/export/gear/rd_hardsuit + cost = 850 //rare + unit_name = "prototype hardsuit" + export_types = list(/obj/item/clothing/suit/space/hardsuit/rd) + +/datum/export/gear/sec_hardsuit + cost = 750 + unit_name = "sec hardsuit" + export_types = list(/obj/item/clothing/suit/space/hardsuit/security) + +/datum/export/gear/command_hardsuit + cost = 1300 + unit_name = "command hardsuit" + export_types = list(/obj/item/clothing/suit/space/hardsuit/security/hos, /obj/item/clothing/suit/space/hardsuit/captain) + +/datum/export/gear/magic_hardsuit + cost = 3000 + unit_name = "magic hardsuit" + export_types = list(/obj/item/clothing/suit/space/hardsuit/wizard, /obj/item/clothing/suit/space/hardsuit/shielded/wizard, /obj/item/clothing/suit/space/hardsuit/cult) + include_subtypes = TRUE + +/datum/export/gear/shield_hardsuit + cost = 2000 + unit_name = "shielded hardsuit" + export_types = list(/obj/item/clothing/suit/space/hardsuit/shielded) + include_subtypes = TRUE + +/datum/export/gear/rigs + cost = 2750 + unit_name = "RIG" + export_types = list(/obj/item/clothing/suit/space/hardsuit/ancient, /obj/item/clothing/suit/space/hardsuit/ancient/mason) + +//Soft Suits + +//Blanket +datum/export/gear/space/helmet + cost = 55 unit_name = "space helmet" - export_types = list(/obj/item/clothing/head/helmet/space, /obj/item/clothing/head/helmet/space/eva, /obj/item/clothing/head/helmet/space/nasavoid) - include_subtypes = FALSE + export_types = list(/obj/item/clothing/head/helmet/space) + include_subtypes = TRUE /datum/export/gear/space/suit - cost = 150 + cost = 60 unit_name = "space suit" - export_types = list(/obj/item/clothing/suit/space, /obj/item/clothing/suit/space/eva, /obj/item/clothing/suit/space/nasavoid) - include_subtypes = FALSE + export_types = list(/obj/item/clothing/suit/space) + include_subtypes = TRUE +datum/export/gear/space/helmet/plasma + cost = 100 + unit_name = "plasmaman space helmet" + export_types = list(/obj/item/clothing/suit/space/eva/plasmaman) -/datum/export/gear/space/syndiehelmet - cost = 150 - unit_name = "Syndicate space helmet" +/datum/export/gear/space/suit/plasma + cost = 100 + unit_name = "plasmaman space suit" + export_types = list(/obj/item/clothing/suit/space/eva/plasmaman) + +datum/export/gear/space/helmet/synda + cost = 150 //Flash proof + unit_name = "syndicate space helmet" export_types = list(/obj/item/clothing/head/helmet/space/syndicate) + include_subtypes = TRUE -/datum/export/gear/space/syndiesuit - cost = 300 - unit_name = "Syndicate space suit" - export_types = list(/obj/item/clothing/suit/space/syndicate) +/datum/export/gear/space/suit/synda + cost = 150 + unit_name = "syndicate space suit" + export_types = list(/obj/item/clothing/head/helmet/space/syndicate) + include_subtypes = TRUE +//Glasses + +//Blanket +datum/export/gear/glasses //glasses are not worth selling + cost = 3 + unit_name = "glasses" + export_types = list(/obj/item/clothing/glasses) + include_subtypes = TRUE + +/datum/export/gear/mesons + cost = 6 + unit_name = "mesons" + export_types = list(/obj/item/clothing/glasses/meson, /obj/item/clothing/glasses/material/mining) + include_subtypes = TRUE + +/datum/export/gear/scigoggles + cost = 8 + unit_name = "chem giggles" + export_types = list(/obj/item/clothing/glasses/science) + include_subtypes = TRUE + +/datum/export/gear/nvgoggles + cost = 20 + unit_name = "night vison giggles" + export_types = list(/obj/item/clothing/glasses/night) + include_subtypes = TRUE + +/datum/export/gear/sunglasses + cost = 12 + unit_name = "sunglasses" + export_types = list(/obj/item/clothing/glasses/sunglasses) + include_subtypes = TRUE + +/datum/export/gear/huds + cost = 10 + unit_name = "huds" + export_types = list(/obj/item/clothing/glasses/hud) + include_subtypes = TRUE + +/datum/export/gear/huds/glasses + cost = 22 + export_types = list(/obj/item/clothing/glasses/hud/health/sunglasses, /obj/item/clothing/glasses/hud/security/sunglasses) + +/datum/export/gear/weldinggoggles + cost = 20 + unit_name = "welding goggles" + export_types = list(/obj/item/clothing/glasses/welding) + include_subtypes = TRUE + +/datum/export/gear/thermals + cost = 30 + unit_name = "heat seeing goggles" + export_types = list(/obj/item/clothing/glasses/thermal, /obj/item/clothing/glasses/hud/toggle/thermal) + include_subtypes = TRUE + +/datum/export/gear/magic_glasses + cost = 140 + unit_name = "magic goggles" + export_types = list(/obj/item/clothing/glasses/godeye, /obj/item/clothing/glasses/hud/health/night/cultblind, /obj/item/clothing/glasses/wraith_spectacles, /obj/item/clothing/glasses/judicial_visor) + include_subtypes = TRUE + +////////// +//UNDER/// +////////// + +/datum/export/gear/jumpsuit + cost = 3 + unit_name = "jumpsuit" + k_elasticity = 1/100 //you can craft white jumpsuits, if someone does that 300 times, they deserve the 800 credits + export_types = list(/obj/item/clothing/under) + include_subtypes = TRUE + +/datum/export/gear/fancy_jumpsuit + cost = 10 + unit_name = "fancy clothing" + k_elasticity = 1/90 //These will be what sells + export_types = list(/obj/item/clothing/under/scratch, /obj/item/clothing/under/sl_suit, /obj/item/clothing/under/rank/vice, /obj/item/clothing/under/suit_jacket, \ + /obj/item/clothing/under/burial, /obj/item/clothing/under/skirt/black, /obj/item/clothing/under/captainparade, /obj/item/clothing/under/hosparademale, \ + /obj/item/clothing/under/hosparadefem, /obj/item/clothing/under/assistantformal, /obj/item/clothing/under/stripeddress, /obj/item/clothing/under/redeveninggown, \ + /obj/item/clothing/under/plaid_skirt, /obj/item/clothing/under/geisha, /obj/item/clothing/under/trek, /obj/item/clothing/under/wedding, /obj/item/clothing/under/aviatoruniform,\ + /obj/item/clothing/under/mega, /obj/item/clothing/under/cia, /obj/item/clothing/under/casualwear, /obj/item/clothing/under/rank) + include_subtypes = TRUE + +/datum/export/gear/armored_jumpsuit + cost = 15 + unit_name = "armored_jumpsuit" + k_elasticity = 1/90 //These will be what sells + export_types = list(/obj/item/clothing/under/durathread, /obj/item/clothing/under/rank/security, /obj/item/clothing/under/plasmaman, /obj/item/clothing/under/syndicate, \ + /obj/item/clothing/under/rank/det, /obj/item/clothing/under/rank/head_of_security, /obj/item/clothing/under/rank/security/spacepol) + exclude_types = list(/obj/item/clothing/under/syndicate/tacticool, /obj/item/clothing/under/syndicate/tacticool/skirt) + include_subtypes = TRUE + +/datum/export/gear/jumpsuit_addon + cost = 12 //Few and rare as well as quick drop off of vaule + unit_name = "jumpsuit add on" + k_elasticity = 1/10 + export_types = list(/obj/item/clothing/accessory) + include_subtypes = TRUE + +/datum/export/gear/robes_magic + cost = 120 + unit_name = "magic robes" + export_types = list(/obj/item/clothing/suit/wizrobe, /obj/item/clothing/suit/cultrobes, /obj/item/clothing/suit/magusred, /obj/item/clothing/suit/hooded/cultrobes) + exclude_types = list(/obj/item/clothing/suit/wizrobe/fake) + include_subtypes = TRUE + +//Amror +/datum/export/gear/armor + cost = 80 + unit_name = "misc armor" + export_types = list(/obj/item/clothing/suit/armor) + include_subtypes = TRUE + +/datum/export/gear/sec_armor + cost = 180 + unit_name = "sec armor" + export_types = list(/obj/item/clothing/suit/armor/vest/leather, /obj/item/clothing/suit/armor/bulletproof, /obj/item/clothing/suit/armor/vest/det_suit) + include_subtypes = TRUE + +/datum/export/gear/hosarmor + cost = 380 + unit_name = "hos armor" + export_types = list(/obj/item/clothing/suit/armor/hos) + include_subtypes = TRUE + +/datum/export/gear/wardenarmor + cost = 280 + unit_name = "warden armor" + export_types = list(/obj/item/clothing/suit/armor/vest/warden) + include_subtypes = TRUE + +/datum/export/gear/reflector + cost = 500 + unit_name = "reflector armor" + export_types = list(/obj/item/clothing/suit/armor/laserproof) + include_subtypes = TRUE + +/datum/export/gear/heavy_armor + cost = 600 //REALY hard to fine/make takes lots of slimes + unit_name = "heavy armor" + export_types = list(/obj/item/clothing/suit/armor/heavy) + include_subtypes = TRUE + +/datum/export/gear/plate_armor + cost = 200 + unit_name = "plate armor" + export_types = list(/obj/item/clothing/suit/armor/riot/knight) + include_subtypes = TRUE + +/datum/export/gear/riot_armor + cost = 250 + unit_name = "riot armor" + export_types = list(/obj/item/clothing/suit/armor/riot) + include_subtypes = TRUE + +/datum/export/gear/bone_armor + cost = 50 + unit_name = "bone armor" + export_types = list(/obj/item/clothing/suit/armor/bone) + include_subtypes = TRUE + +/datum/export/gear/swat_armor + cost = 350 + unit_name = "swat mki armor" + export_types = list(/obj/item/clothing/suit/space/swat) + include_subtypes = TRUE + +/datum/export/gear/dragon_armor + cost = 750 + unit_name = "drake bone armor" + export_types = list(/obj/item/clothing/suit/hooded/cloak/drake) + include_subtypes = TRUE + +/datum/export/gear/commandamor + cost = 480 + unit_name = "command armor" + export_types = list(/obj/item/clothing/suit/armor/vest/capcarapace, /obj/item/clothing/suit/armor/centcom) + include_subtypes = TRUE + +/datum/export/gear/reactive_base + cost = 600 + k_elasticity = 1/2 //Lets not go over board + unit_name = "hollow reactive armor" + export_types = list(/obj/item/reactive_armour_shell, /obj/item/clothing/suit/armor/reactive) + +/datum/export/gear/reactive_active + cost = 1200 + k_elasticity = 1/3 //Lets not go over board + unit_name = "working reactive armor" + export_types = list(/obj/item/clothing/suit/armor/reactive/repulse, /obj/item/clothing/suit/armor/reactive/tesla, /obj/item/clothing/suit/armor/reactive/teleport) + +/////////////////////////// +//Bomb/Rad/Bio Suits/Fire// +/////////////////////////// /datum/export/gear/radhelmet - cost = 50 + cost = 20 unit_name = "radsuit hood" export_types = list(/obj/item/clothing/head/radiation) /datum/export/gear/radsuit - cost = 100 + cost = 40 unit_name = "radsuit" export_types = list(/obj/item/clothing/suit/radiation) +/datum/export/gear/firehelmet + cost = 10 + unit_name = "firesuit helmet" + export_types = list(/obj/item/clothing/head/hardhat/red) + +/datum/export/gear/fireatmos + cost = 120 + unit_name = "atmos firesuit" + export_types = list(/obj/item/clothing/suit/fire/atmos) + +/datum/export/gear/firesuit + cost = 20 + unit_name = "firesuit" + export_types = list(/obj/item/clothing/suit/fire, /obj/item/clothing/suit/fire/firefighter, /obj/item/clothing/suit/fire/heavy) + /datum/export/gear/biohood - cost = 50 + cost = 40 unit_name = "biosuit hood" export_types = list(/obj/item/clothing/head/bio_hood) + include_subtypes = TRUE /datum/export/gear/biosuit - cost = 100 + cost = 60 unit_name = "biosuit" export_types = list(/obj/item/clothing/suit/bio_suit) + include_subtypes = TRUE /datum/export/gear/bombhelmet - cost = 50 + cost = 40 unit_name = "bomb suit hood" export_types = list(/obj/item/clothing/head/bomb_hood) + include_subtypes = TRUE /datum/export/gear/bombsuit - cost = 100 + cost = 60 unit_name = "bomb suit" export_types = list(/obj/item/clothing/suit/bomb_suit) + include_subtypes = TRUE + +//////////////////// +//Cloaks and Coats// +//////////////////// + +/datum/export/gear/cloaks + cost = 30 + unit_name = "cloak" + export_types = list(/obj/item/clothing/neck/cloak) + include_subtypes = TRUE + +/datum/export/gear/cloaksmining + cost = 90 + unit_name = "lava land cloak" + export_types = list(/obj/item/clothing/suit/hooded/cloak/goliath) + include_subtypes = TRUE + +/datum/export/gear/labcoats + cost = 15 + unit_name = "labcoats" + export_types = list(/obj/item/clothing/suit/toggle/labcoat) + include_subtypes = TRUE + +/datum/export/gear/wintercoats + cost = 25 + unit_name = "wintercoats" + export_types = list(/obj/item/clothing/suit/hooded/wintercoat) + include_subtypes = TRUE + +////////// +//SUITS/// +////////// + +/datum/export/gear/suits + cost = 40 + unit_name = "suit" + export_types = list(/obj/item/clothing/suit) + include_subtypes = TRUE + +////////////////////// +//Chameleon Gear////// +////////////////////// +/datum/export/gear/chameleon //Selling a full kit is easy money for 2 tc + cost = 280 + unit_name = "chameleon item" + export_types = list(/obj/item/clothing/head/chameleon, /obj/item/clothing/mask/chameleon, /obj/item/clothing/under/chameleon, /obj/item/clothing/suit/chameleon, /obj/item/clothing/glasses/chameleon,\ + /obj/item/clothing/gloves/chameleon, /obj/item/clothing/head/chameleon, /obj/item/clothing/shoes/chameleon, /obj/item/storage/backpack/chameleon, \ + /obj/item/storage/belt/chameleon, /obj/item/radio/headset/chameleon, /obj/item/pda/chameleon, /obj/item/stamp/chameleon, /obj/item/clothing/neck/cloak/chameleon) + include_subtypes = TRUE \ No newline at end of file diff --git a/code/modules/cargo/exports/large_objects.dm b/code/modules/cargo/exports/large_objects.dm index bf77d836fb..88ff5f4729 100644 --- a/code/modules/cargo/exports/large_objects.dm +++ b/code/modules/cargo/exports/large_objects.dm @@ -1,3 +1,6 @@ +/datum/export/large + k_elasticity = 0 + /datum/export/large/crate cost = 500 k_elasticity = 0 @@ -21,13 +24,13 @@ export_types = list(/obj/structure/ore_box) /datum/export/large/crate/wood - cost = 240 + cost = 140 unit_name = "wooden crate" export_types = list(/obj/structure/closet/crate/wooden) exclude_types = list() /datum/export/large/crate/coffin - cost = 250//50 wooden crates cost 2000 points, and you can make 10 coffins in seconds with those planks. Each coffin selling for 250 means you can make a net gain of 500 points for wasting your time making coffins. + cost = 150 unit_name = "coffin" export_types = list(/obj/structure/closet/crate/coffin) @@ -131,16 +134,48 @@ unit_name = "security barrier" export_types = list(/obj/item/grenade/barrier, /obj/structure/barricade/security) +/datum/export/large/frame + cost = 20 + unit_name = "structure frame" + export_types = list(/obj/structure/frame, /obj/structure/table_frame) + include_subtypes = TRUE + +/datum/export/large/pacman + cost = 125 + unit_name = "pacman" + export_types = list(/obj/machinery/power/port_gen/pacman) + +/datum/export/large/pacman + cost = 150 + unit_name = "super pacman" + export_types = list(/obj/machinery/power/port_gen/pacman/super) + +/datum/export/large/pacman + cost = 175 + unit_name = "mrs super pacman" + export_types = list(/obj/machinery/power/port_gen/pacman/mrs) + +/datum/export/large/hydroponics + cost = 120 + unit_name = "hydroponics tray" + export_types = list(/obj/machinery/hydroponics) + +/datum/export/large/nice_chair + cost = 12 + unit_name = "Padded Chair" + export_types = list(/obj/structure/chair/comfy) + /datum/export/large/gas_canister cost = 10 //Base cost of canister. You get more for nice gases inside. unit_name = "Gas Canister" export_types = list(/obj/machinery/portable_atmospherics/canister) + /datum/export/large/gas_canister/get_cost(obj/O) var/obj/machinery/portable_atmospherics/canister/C = O var/worth = 10 var/gases = C.air_contents.gases - worth += gases[/datum/gas/bz]*4 + worth += gases[/datum/gas/bz]*4 worth += gases[/datum/gas/stimulum]*25 worth += gases[/datum/gas/hypernoblium]*1000 worth += gases[/datum/gas/miasma]*15 @@ -149,86 +184,169 @@ worth += gases[/datum/gas/nitryl]*30 return worth -/datum/export/large/odysseus + +////////////// +//Matstatues// +////////////// + +/datum/export/large/nukestatue + cost = 175 + unit_name = "Nuke statue" + export_types = list(/obj/structure/statue/uranium/nuke) + +/datum/export/large/engstatue + cost = 175 + unit_name = "Engine statue" + export_types = list(/obj/structure/statue/uranium/eng) + +/datum/export/large/plasmastatue + cost = 720 + unit_name = "Scientist statue" + export_types = list(/obj/structure/statue/plasma/scientist) + +/datum/export/large/hosstatue + cost = 225 + unit_name = "HoS statue" + export_types = list(/obj/structure/statue/gold/hos) + +/datum/export/large/rdstatue + cost = 225 + unit_name = "RD statue" + export_types = list(/obj/structure/statue/gold/rd) + +/datum/export/large/hopstatue + cost = 225 + unit_name = "HoP statue" + export_types = list(/obj/structure/statue/gold/hop) + +/datum/export/large/cmostatue + cost = 225 + unit_name = "CMO statue" + export_types = list(/obj/structure/statue/gold/cmo) + +/datum/export/large/cestatue + cost = 225 + unit_name = "CE statue" + export_types = list(/obj/structure/statue/gold/ce) + +/datum/export/large/mdstatue + cost = 200 + unit_name = "MD statue" + export_types = list(/obj/structure/statue/silver/md) + +/datum/export/large/janitorstatue + cost = 200 + unit_name = "Janitor statue" + export_types = list(/obj/structure/statue/silver/janitor) + +/datum/export/large/secstatue + cost = 200 + unit_name = "Sec statue" + export_types = list(/obj/structure/statue/silver/sec) + +/datum/export/large/medborgstatue + cost = 200 + unit_name = "Medborg statue" + export_types = list(/obj/structure/statue/silver/medborg) + +/datum/export/large/secborgstatue + cost = 200 + unit_name = "Secborg statue" + export_types = list(/obj/structure/statue/silver/secborg) + +/datum/export/large/capstatue + cost = 1200 + unit_name = "Captain statue" + export_types = list(/obj/structure/statue/diamond/captain) + +/datum/export/large/aistatue + cost = 1200 + unit_name = "AI statue" + export_types = list(/obj/structure/statue/diamond/ai1, /obj/structure/statue/diamond/ai2) + +/datum/export/large/clownstatue + cost = 2750 + unit_name = "Clown statue" + export_types = list(/obj/structure/statue/bananium/clown) + +/datum/export/large/sandstatue + cost = 90 //Big cash + unit_name = "sandstone statue" + export_types = list(/obj/structure/statue/sandstone/assistant) + +//////////// +//MECHS///// +//////////// + +/datum/export/large/mech + include_subtypes = FALSE + +/datum/export/large/mech/odysseus cost = 5500 unit_name = "working odysseus" export_types = list(/obj/mecha/medical/odysseus) - include_subtypes = FALSE -/datum/export/large/ripley +/datum/export/large/mech/ripley cost = 6500 unit_name = "working ripley" export_types = list(/obj/mecha/working/ripley) - include_subtypes = FALSE -/datum/export/large/firefighter +/datum/export/large/mech/firefighter cost = 9000 unit_name = "working firefighter" export_types = list(/obj/mecha/working/ripley/firefighter) - include_subtypes = FALSE -/datum/export/large/gygax +/datum/export/large/mech/gygax cost = 19000 unit_name = "working gygax" export_types = list(/obj/mecha/combat/gygax) - include_subtypes = FALSE -/datum/export/large/durand +/datum/export/large/mech/durand cost = 10000 unit_name = "working durand" export_types = list(/obj/mecha/combat/durand) - include_subtypes = FALSE -/datum/export/large/phazon +/datum/export/large/mech/phazon cost = 25000 //Little over half do to needing a core unit_name = "working phazon" export_types = list(/obj/mecha/combat/phazon) - include_subtypes = FALSE -/datum/export/large/marauder +/datum/export/large/mech/marauder cost = 15000 //Still a Combat class mech - CC tech as well! 150% "normal" boundy price. unit_name = "working marauder" export_types = list(/obj/mecha/combat/marauder) - include_subtypes = FALSE -/datum/export/large/deathripley +/datum/export/large/mech/deathripley cost = 8500 //Still a "Combat class" mech - Illegal tech as well! 165% "normal" boundy price. unit_name = "working illegally modified" export_types = list(/obj/mecha/working/ripley/deathripley) - include_subtypes = FALSE -/datum/export/large/gygaxdark +/datum/export/large/mech/gygaxdark cost = 28500 //Still a Combat class mech - Illegal tech as well! 150% "normal" boundy price. unit_name = "working illegally modified gygax" export_types = list(/obj/mecha/combat/gygax/dark) - include_subtypes = FALSE -/datum/export/large/oldripley +/datum/export/large/mech/oldripley cost = 6250 //old mech - Scrap metal ! 50% "normal" boundy price. unit_name = "working miner ripley" export_types = list(/obj/mecha/working/ripley/mining) - include_subtypes = FALSE -/datum/export/large/honk +/datum/export/large/mech/honk cost = 12000 //Still a "Combat class" mech - Comats bordem honk! unit_name = "working honker" export_types = list(/obj/mecha/combat/honker) - include_subtypes = FALSE -/datum/export/large/reticence +/datum/export/large/mech/reticence cost = 12000 //Still a "Combat class" mech - Has cloking and lethal weaponds. unit_name = "working reticence" export_types = list(/obj/mecha/combat/reticence) - include_subtypes = FALSE -/datum/export/large/seraph +/datum/export/large/mech/seraph cost = 25500 //Still a Combat class mech - CC tech as well! 150% "normal" boundy price. unit_name = "working seraph" export_types = list(/obj/mecha/combat/marauder/seraph) - include_subtypes = FALSE -/datum/export/large/mauler +/datum/export/large/mech/mauler cost = 12000 //Still a Combat class mech - CC lethal weaponds. unit_name = "working legally modified marauder" export_types = list(/obj/mecha/combat/marauder/mauler) - include_subtypes = FALSE diff --git a/code/modules/cargo/exports/manifest.dm b/code/modules/cargo/exports/manifest.dm index 02b060e0bf..d03f5a46ce 100644 --- a/code/modules/cargo/exports/manifest.dm +++ b/code/modules/cargo/exports/manifest.dm @@ -81,6 +81,7 @@ /datum/export/paperwork_correct cost = 150 + k_elasticity = 0 unit_name = "correct paperwork" export_types = list(/obj/item/folder/paperwork_correct) @@ -88,5 +89,6 @@ /datum/export/paperwork_incorrect cost = -500 // Failed to meet NT standers + k_elasticity = 0 unit_name = "returned incorrect paperwork" export_types = list(/obj/item/folder/paperwork) diff --git a/code/modules/cargo/exports/materials.dm b/code/modules/cargo/exports/materials.dm index 04dc76fd52..cd11660ed8 100644 --- a/code/modules/cargo/exports/materials.dm +++ b/code/modules/cargo/exports/materials.dm @@ -1,4 +1,5 @@ /datum/export/material + k_elasticity = 0 cost = 5 // Cost per MINERAL_MATERIAL_AMOUNT, which is 2000cm3 as of April 2016. message = "cm3 of developer's tears. Please, report this on github" var/material_id = null @@ -27,51 +28,56 @@ return round(amount/MINERAL_MATERIAL_AMOUNT) -// Materials. Nothing but plasma is really worth selling. Better leave it all to RnD and sell some plasma instead. +// Materials. Selling raw can lead to a big payout but takes a lot of work for miners to get a lot. Best to craft art/rnd gear /datum/export/material/bananium - cost = 1000 + cost = 500 material_id = MAT_BANANIUM message = "cm3 of bananium" /datum/export/material/diamond - cost = 500 + cost = 250 material_id = MAT_DIAMOND message = "cm3 of diamonds" /datum/export/material/plasma - cost = 200 + cost = 100 k_elasticity = 0 material_id = MAT_PLASMA message = "cm3 of plasma" /datum/export/material/uranium - cost = 100 + cost = 50 material_id = MAT_URANIUM message = "cm3 of uranium" /datum/export/material/gold - cost = 125 + cost = 60 material_id = MAT_GOLD message = "cm3 of gold" /datum/export/material/silver - cost = 50 + cost = 25 material_id = MAT_SILVER message = "cm3 of silver" /datum/export/material/titanium - cost = 125 + cost = 60 material_id = MAT_TITANIUM message = "cm3 of titanium" /datum/export/material/plastitanium - cost = 325 // plasma + titanium costs + cost = 165 // plasma + titanium costs material_id = MAT_TITANIUM // code can only check for one material_id; plastitanium is half plasma, half titanium message = "cm3 of plastitanium" -/datum/export/material/metal +/datum/export/material/plastic cost = 5 + material_id = MAT_PLASTIC + message = "cm3 of plastic" + +/datum/export/material/metal + cost = 3 message = "cm3 of metal" material_id = MAT_METAL export_types = list( @@ -79,7 +85,7 @@ /obj/item/stack/rods, /obj/item/stack/ore, /obj/item/coin) /datum/export/material/glass - cost = 5 + cost = 3 message = "cm3 of glass" material_id = MAT_GLASS export_types = list(/obj/item/stack/sheet/glass, /obj/item/stack/ore, diff --git a/code/modules/cargo/exports/orgains_robotics.dm b/code/modules/cargo/exports/orgains_robotics.dm new file mode 100644 index 0000000000..924d27c1d2 --- /dev/null +++ b/code/modules/cargo/exports/orgains_robotics.dm @@ -0,0 +1,141 @@ +// Orgains and Robotics exports. Hearts, new lims, implants, etc. + +/datum/export/robotics + include_subtypes = FALSE + k_elasticity = 0 //ALWAYS worth selling upgrades + +/datum/export/implant + include_subtypes = FALSE + k_elasticity = 0 //ALWAYS worth selling upgrades + +/datum/export/orgains + include_subtypes = TRUE + k_elasticity = 0 //ALWAYS worth selling orgains + +/datum/export/implant/autodoc + cost = 150 + unit_name = "autsurgeon" + export_types = list(/obj/item/autosurgeon) + include_subtypes = TRUE + +/datum/export/implant/implant + cost = 50 + unit_name = "implant" + export_types = list(/obj/item/implant) + include_subtypes = TRUE + +/datum/export/implant/cnsreboot + cost = 350 + unit_name = "anti drop implant" + export_types = list(/obj/item/organ/cyberimp/brain/anti_drop) + +/datum/export/implant/antistun + cost = 450 + unit_name = "rebooter implant" + export_types = list(/obj/item/organ/cyberimp/brain/anti_stun) + +/datum/export/implant/breathtube + cost = 150 + unit_name = "breath implant" + export_types = list(/obj/item/organ/cyberimp/mouth/breathing_tube) + +/datum/export/implant/hungerbgone + cost = 200 + unit_name = "nutriment implant" + export_types = list(/obj/item/organ/cyberimp/chest/nutriment) + +/datum/export/implant/hungerbgoneplus + cost = 300 + unit_name = "upgraded nutriment implant" + export_types = list(/obj/item/organ/cyberimp/chest/nutriment/plus) + +/datum/export/implant/reviver + cost = 350 + unit_name = "reviver implant" + export_types = list(/obj/item/organ/cyberimp/chest/reviver) + +/datum/export/implant/thrusters + cost = 150 + unit_name = "thrusters set implant" + export_types = list(/obj/item/organ/cyberimp/chest/thrusters) + +/datum/export/implant/thrusters + cost = 150 + unit_name = "thrusters set implant" + export_types = list(/obj/item/organ/cyberimp/chest/thrusters) + +/datum/export/implant/arm + cost = 200 + unit_name = "arm set implant" + export_types = list(/obj/item/organ/cyberimp/arm/toolset, /obj/item/organ/cyberimp/arm/surgery) + include_subtypes = TRUE + +/datum/export/implant/combatarm + cost = 800 + unit_name = "combat arm set implant" + export_types = list(/obj/item/organ/cyberimp/arm/gun/laser, /obj/item/organ/cyberimp/arm/gun/taser, /obj/item/organ/cyberimp/arm/esword, /obj/item/organ/cyberimp/arm/medibeam, /obj/item/organ/cyberimp/arm/combat, /obj/item/organ/cyberimp/arm/flash, /obj/item/organ/cyberimp/arm/baton) + include_subtypes = TRUE + +/datum/export/orgains/heart + cost = 250 + unit_name = "heart" + export_types = list(/obj/item/organ/heart) + exclude_types = list(/obj/item/organ/heart/cursed, /obj/item/organ/heart/cybernetic) + +/datum/export/orgains/tongue + cost = 75 + unit_name = "tongue" + export_types = list(/obj/item/organ/tongue) + +/datum/export/orgains/eyes + cost = 50 //So many things take your eyes out anyways + unit_name = "eyes" + export_types = list(/obj/item/organ/eyes) + exclude_types = list(/obj/item/organ/eyes/robotic) + +/datum/export/orgains/stomach + cost = 50 //can be replaced + unit_name = "stomach" + export_types = list(/obj/item/organ/stomach) + +/datum/export/orgains/lungs + cost = 150 + unit_name = "lungs" + export_types = list(/obj/item/organ/lungs) + exclude_types = list(/obj/item/organ/lungs/cybernetic, /obj/item/organ/lungs/cybernetic/upgraded) + +/datum/export/orgains/liver + cost = 175 + unit_name = "liver" + export_types = list(/obj/item/organ/liver) + exclude_types = list(/obj/item/organ/liver/cybernetic, /obj/item/organ/liver/cybernetic/upgraded) + +/datum/export/orgains/tail //Shhh + cost = 500 + unit_name = "error shipment failer" + export_types = list(/obj/item/organ/tail) + +/datum/export/orgains/vocal_cords + cost = 500 + unit_name = "vocal cords" + export_types = list(/obj/item/organ/vocal_cords) //These are gotten via different races + +/datum/export/robotics/lims + cost = 30 + unit_name = "robotic lim replacement" + export_types = list(/obj/item/bodypart/l_arm/robot, /obj/item/bodypart/r_arm/robot, /obj/item/bodypart/l_leg/robot, /obj/item/bodypart/r_leg/robot, /obj/item/bodypart/chest/robot, /obj/item/bodypart/head/robot) + +/datum/export/robotics/surpluse + cost = 40 + unit_name = "robotic lim replacement" + export_types = list(/obj/item/bodypart/l_arm/robot/surplus, /obj/item/bodypart/r_arm/robot/surplus, /obj/item/bodypart/l_leg/robot/surplus, /obj/item/bodypart/r_leg/robot/surplus) + +/datum/export/robotics/surplus_upgraded + cost = 50 + unit_name = "upgraded robotic lim replacement" + export_types = list(/obj/item/bodypart/l_arm/robot/surplus_upgraded, /obj/item/bodypart/r_arm/robot/surplus_upgraded, /obj/item/bodypart/l_leg/robot/surplus_upgraded, /obj/item/bodypart/r_leg/robot/surplus_upgraded) + +/datum/export/robotics/surgery_gear_basic + cost = 5 + unit_name = "surgery tool" + export_types = list(/obj/item/retractor, /obj/item/hemostat, /obj/item/cautery, /obj/item/surgicaldrill, /obj/item/scalpel, /obj/item/circular_saw, /obj/item/surgical_drapes) diff --git a/code/modules/cargo/exports/parts.dm b/code/modules/cargo/exports/parts.dm index e6fda5f6b1..b505bb5da4 100644 --- a/code/modules/cargo/exports/parts.dm +++ b/code/modules/cargo/exports/parts.dm @@ -6,16 +6,96 @@ export_types = list(/obj/item/solar_assembly) /datum/export/solar/tracker_board - cost = 100 + cost = 30 unit_name = "solar tracker board" export_types = list(/obj/item/electronics/tracker) /datum/export/solar/control_board - cost = 150 + cost = 75 unit_name = "solar panel control board" export_types = list(/obj/item/circuitboard/computer/solar_control) /datum/export/swarmer - cost = 2000 + cost = 500 unit_name = "deactivated alien deconstruction drone" export_types = list(/obj/item/deactivated_swarmer) + +//Board + +/datum/export/board + cost = 5 + unit_name = "circuit board" + export_types = list(/obj/item/circuitboard) + include_subtypes = TRUE + +/datum/export/board/SMES + cost = 20 + k_elasticity = 1/2 //Only a few + unit_name = "smes board" + export_types = list(/obj/item/circuitboard/machine/smes) + +//Stock Parts + +/datum/export/subspace + cost = 3 + unit_name = "subspace part" + export_types = list(/obj/item/stock_parts/subspace) + include_subtypes = TRUE + +/datum/export/t1 + cost = 1 + unit_name = "basic stock part" + export_types = list(/obj/item/stock_parts/capacitor, /obj/item/stock_parts/scanning_module, /obj/item/stock_parts/manipulator, /obj/item/stock_parts/micro_laser, /obj/item/stock_parts/matter_bin) + +/datum/export/t2 + cost = 2 + unit_name = "upgraded stock part" + export_types = list(/obj/item/stock_parts/capacitor/adv, /obj/item/stock_parts/scanning_module/adv, /obj/item/stock_parts/manipulator/nano, /obj/item/stock_parts/micro_laser/high, /obj/item/stock_parts/matter_bin/adv) + +/datum/export/t3 + cost = 3 + unit_name = "advanced stock part" + export_types = list(/obj/item/stock_parts/capacitor/super, /obj/item/stock_parts/scanning_module/phasic, /obj/item/stock_parts/manipulator/pico, /obj/item/stock_parts/micro_laser/ultra, /obj/item/stock_parts/matter_bin/super) + +/datum/export/t4 + cost = 4 + unit_name = "blue space stock part" + export_types = list(/obj/item/stock_parts/capacitor/quadratic, /obj/item/stock_parts/scanning_module/triphasic, /obj/item/stock_parts/manipulator/femto, /obj/item/stock_parts/micro_laser/quadultra, /obj/item/stock_parts/matter_bin/bluespace) + +//Cells + +/datum/export/cell + cost = 5 + unit_name = "power cell" + export_types = list(/obj/item/stock_parts/cell) + include_subtypes = TRUE + +/datum/export/cell + cost = 10 + unit_name = "upgraded power cell" + export_types = list(/obj/item/stock_parts/cell/upgraded, /obj/item/stock_parts/cell/upgraded/plus) + +/datum/export/cellhigh + cost = 15 + unit_name = "high power cell" + export_types = list(/obj/item/stock_parts/cell/high, /obj/item/stock_parts/cell/high/plus) + +/datum/export/cellhyper + cost = 20 + unit_name = "super-capacity power cell" + export_types = list(/obj/item/stock_parts/cell/super, /obj/item/stock_parts/cell/hyper) + +/datum/export/cellbs + cost = 25 + unit_name = "bluespace power cell" + export_types = list(/obj/item/stock_parts/cell/bluespace) + +/datum/export/cellyellow + cost = 40 + unit_name = "slime power cell" + export_types = list(/obj/item/stock_parts/cell/high/slime) + +/datum/export/cellyellowhyper + cost = 120 //Takes a lot to make and is really good + unit_name = "hyper slime power cell" + export_types = list(/obj/item/stock_parts/cell/high/slime/hypercharged) \ No newline at end of file diff --git a/code/modules/cargo/exports/sheets.dm b/code/modules/cargo/exports/sheets.dm index 708eb34133..8397a7dc1f 100644 --- a/code/modules/cargo/exports/sheets.dm +++ b/code/modules/cargo/exports/sheets.dm @@ -1,5 +1,6 @@ /datum/export/stack unit_name = "sheet" + k_elasticity = 0 /datum/export/stack/get_amount(obj/O) var/obj/item/stack/S = O @@ -9,47 +10,52 @@ // Hides +/datum/export/stack/leather + cost = 30 + unit_name = "leather" + export_types = list(/obj/item/stack/sheet/leather) + /datum/export/stack/skin/monkey - cost = 50 + cost = 30 unit_name = "monkey hide" export_types = list(/obj/item/stack/sheet/animalhide/monkey) /datum/export/stack/skin/human - cost = 100 + cost = 70 export_category = EXPORT_CONTRABAND unit_name = "piece" message = "of human skin" export_types = list(/obj/item/stack/sheet/animalhide/human) /datum/export/stack/skin/goliath_hide - cost = 200 + cost = 160 unit_name = "goliath hide" export_types = list(/obj/item/stack/sheet/animalhide/goliath_hide) /datum/export/stack/skin/cat - cost = 150 + cost = 120 export_category = EXPORT_CONTRABAND unit_name = "cat hide" export_types = list(/obj/item/stack/sheet/animalhide/cat) /datum/export/stack/skin/corgi - cost = 200 + cost = 140 export_category = EXPORT_CONTRABAND unit_name = "corgi hide" export_types = list(/obj/item/stack/sheet/animalhide/corgi) /datum/export/stack/skin/lizard - cost = 150 + cost = 50 unit_name = "lizard hide" export_types = list(/obj/item/stack/sheet/animalhide/lizard) /datum/export/stack/skin/gondola - cost = 5000 + cost = 1000 unit_name = "gondola hide" export_types = list(/obj/item/stack/sheet/animalhide/gondola) /datum/export/stack/skin/xeno - cost = 500 + cost = 300 unit_name = "alien hide" export_types = list(/obj/item/stack/sheet/animalhide/xeno) @@ -57,23 +63,23 @@ // For base materials, see materials.dm /datum/export/stack/plasteel - cost = 155 // 2000u of plasma + 2000u of metal. + cost = 105 // 2000u of plasma + 2000u of metal. message = "of plasteel" export_types = list(/obj/item/stack/sheet/plasteel) // 1 glass + 0.5 metal, cost is rounded up. /datum/export/stack/rglass - cost = 8 + cost = 6 message = "of reinforced glass" export_types = list(/obj/item/stack/sheet/rglass) /datum/export/stack/bscrystal - cost = 300 + cost = 150 message = "of bluespace crystals" export_types = list(/obj/item/stack/sheet/bluespace_crystal) /datum/export/stack/wood - cost = 30 + cost = 15 unit_name = "wood plank" export_types = list(/obj/item/stack/sheet/mineral/wood) @@ -93,16 +99,50 @@ unit_name = "cable piece" export_types = list(/obj/item/stack/cable_coil) +/datum/export/stack/cloth + cost = 10 + unit_name = "sheets" + message = "of cloth" + export_types = list(/obj/item/stack/sheet/cloth) + +/datum/export/stack/duracloth + cost = 40 + unit_name = "sheets" + message = "of duracloth" + export_types = list(/obj/item/stack/sheet/durathread) + // Weird Stuff /datum/export/stack/abductor - cost = 1000 + cost = 400 message = "of alien alloy" export_types = list(/obj/item/stack/sheet/mineral/abductor) /datum/export/stack/adamantine unit_name = "bar" - cost = 500 + cost = 250 message = "of adamantine" export_types = list(/obj/item/stack/sheet/mineral/adamantine) +/datum/export/stack/bone + cost = 20 + message = "of bones" + export_types = list(/obj/item/stack/sheet/bone) + +/datum/export/stack/bronze + unit_name = "tiles" + cost = 5 + message = "of brozne" + export_types = list(/obj/item/stack/tile/bronze) + +/datum/export/stack/brass + unit_name = "tiles" + cost = 50 + message = "of brass" + export_types = list(/obj/item/stack/tile/brass) + +/datum/export/stack/paper + unit_name = "sheets" + cost = 30 + message = "of paperframes" + export_types = list(/obj/item/stack/sheet/paperframes) \ No newline at end of file diff --git a/code/modules/cargo/exports/tools.dm b/code/modules/cargo/exports/tools.dm index 9e58e4ba95..4984bfe9b9 100644 --- a/code/modules/cargo/exports/tools.dm +++ b/code/modules/cargo/exports/tools.dm @@ -1,5 +1,5 @@ /datum/export/toolbox - cost = 4 + cost = 6 unit_name = "toolbox" export_types = list(/obj/item/storage/toolbox) @@ -8,7 +8,80 @@ // electrical toolbox: 36cr // robust: priceless +// Adv tools + +/datum/export/gear/powerdrill + cost = 25 + k_elasticity = 1/40 //Market can only take so much + unit_name = "power tool" + export_types = list(/obj/item/crowbar/power, /obj/item/screwdriver/power, \ + /obj/item/weldingtool/experimental, /obj/item/wirecutters/power, /obj/item/wrench/power) + include_subtypes = TRUE + +/datum/export/gear/advtool + cost = 175 + k_elasticity = 0 //Only known to be made by 2 station, market is hungery for it + unit_name = "adv tool" + export_types = list(/obj/item/crowbar/advanced, /obj/item/crowbar/abductor, /obj/item/screwdriver/abductor, /obj/item/screwdriver/advanced, \ + /obj/item/weldingtool/abductor, /obj/item/weldingtool/advanced, /obj/item/wirecutters/abductor, /obj/item/wirecutters/advanced, \ + /obj/item/wrench/abductor, /obj/item/wrench/advanced) + include_subtypes = TRUE + +// Lights/Eletronic + +/datum/export/lights + cost = 10 + unit_name = "light fixer" + export_types = list(/obj/item/wallframe/light_fixture) + include_subtypes = TRUE + +/datum/export/apc_board + cost = 5 + unit_name = "apc electronics" + export_types = list(/obj/item/electronics/apc) + include_subtypes = TRUE + +/datum/export/apc_frame + cost = 3 + unit_name = "apc frame" + export_types = list(/obj/item/wallframe/apc) + include_subtypes = TRUE + +/datum/export/floodlights + cost = 15 + unit_name = "floodlight fixer" + export_types = list(/obj/structure/floodlight_frame) + include_subtypes = TRUE + +/datum/export/bolbstubes + cost = 1 //Time + unit_name = "light replacement" + export_types = list(/obj/item/light/tube, /obj/item/light/bulb) + +/datum/export/lightreplacer + cost = 20 + unit_name = "lightreplacer" + export_types = list(/obj/item/lightreplacer) + // Basic tools +/datum/export/basicmining + cost = 20 + unit_name = "basic mining tool" + export_types = list(/obj/item/pickaxe, /obj/item/pickaxe/mini, /obj/item/shovel, /obj/item/resonator) + include_subtypes = FALSE + +/datum/export/upgradedmining + cost = 50 + unit_name = "mining tool" + export_types = list(/obj/item/pickaxe/silver, /obj/item/pickaxe/drill, /obj/item/gun/energy/plasmacutter, /obj/item/resonator/upgraded) + include_subtypes = FALSE + +/datum/export/advdmining + cost = 150 + unit_name = "advanced mining tool" + export_types = list(/obj/item/pickaxe/diamond, /obj/item/pickaxe/drill/diamonddrill, /obj/item/pickaxe/drill/jackhammer, /obj/item/gun/energy/plasmacutter/adv) + include_subtypes = FALSE + /datum/export/screwdriver cost = 2 unit_name = "screwdriver" @@ -31,7 +104,6 @@ message = "of wirecutters" export_types = list(/obj/item/wirecutters) - /datum/export/weldingtool cost = 5 unit_name = "welding tool" @@ -48,9 +120,8 @@ unit_name = "industrial welding tool" export_types = list(/obj/item/weldingtool/largetank, /obj/item/weldingtool/hugetank) - /datum/export/extinguisher - cost = 15 + cost = 10 unit_name = "fire extinguisher" export_types = list(/obj/item/extinguisher) include_subtypes = FALSE @@ -60,9 +131,8 @@ unit_name = "pocket fire extinguisher" export_types = list(/obj/item/extinguisher/mini) - /datum/export/flashlight - cost = 5 + cost = 3 unit_name = "flashlight" export_types = list(/obj/item/flashlight) include_subtypes = FALSE @@ -73,11 +143,10 @@ export_types = list(/obj/item/flashlight/flare) /datum/export/flashlight/seclite - cost = 10 + cost = 5 unit_name = "seclite" export_types = list(/obj/item/flashlight/seclite) - /datum/export/analyzer cost = 5 unit_name = "analyzer" @@ -88,14 +157,12 @@ unit_name = "t-ray scanner" export_types = list(/obj/item/t_scanner) - /datum/export/radio cost = 5 unit_name = "radio" export_types = list(/obj/item/radio) exclude_types = list(/obj/item/radio/mech) - /datum/export/rcd cost = 100 unit_name = "rapid construction device" @@ -111,6 +178,21 @@ unit_name = "rapid piping device" export_types = list(/obj/item/pipe_dispenser) +/datum/export/rld + cost = 150 + unit_name = "rapid light device" + export_types = list(/obj/item/construction/rld) + +/datum/export/rped + cost = 100 + unit_name = "rapid part exchange device" + export_types = list(/obj/item/storage/part_replacer) + +/datum/export/bsrped + cost = 200 + unit_name = "blue space part exchange device" + export_types = list(/obj/item/storage/part_replacer/bluespace) + /datum/export/singulo //failsafe in case someone decides to ship a live singularity to CentCom without the corresponding bounty cost = 1 unit_name = "singularity" diff --git a/code/modules/cargo/exports/weapons.dm b/code/modules/cargo/exports/weapons.dm index bad221c3ac..97dd9c10aa 100644 --- a/code/modules/cargo/exports/weapons.dm +++ b/code/modules/cargo/exports/weapons.dm @@ -3,6 +3,26 @@ /datum/export/weapon include_subtypes = FALSE +/datum/export/weapon/makeshift_shield + cost = 30 + unit_name = "unknown shield" + export_types = list(/obj/item/shield/riot, /obj/item/shield/riot/roman, /obj/item/shield/riot/buckler, /obj/item/shield/makeshift) + +/datum/export/weapon/riot_shield + cost = 50 + unit_name = "riot shield" + export_types = list(/obj/item/shield/riot, /obj/item/shield/riot/tower) + +/datum/export/weapon/riot_shield + cost = 70 + unit_name = "flash shield" + export_types = list(/obj/item/assembly/flash/shield) + +/datum/export/weapon/tele_shield + cost = 100 + unit_name = "tele shield" + export_types = list(/obj/item/shield/riot/tele, /obj/item/shield/energy) + /datum/export/weapon/baton cost = 100 unit_name = "stun baton" @@ -15,7 +35,6 @@ unit_name = "combat knife" export_types = list(/obj/item/kitchen/knife/combat) - /datum/export/weapon/taser cost = 200 unit_name = "advanced taser" @@ -27,26 +46,25 @@ export_types = list(/obj/item/gun/energy/laser) /datum/export/weapon/disabler - cost = 100 + cost = 50 unit_name = "disabler" export_types = list(/obj/item/gun/energy/disabler) /datum/export/weapon/energy_gun - cost = 300 + cost = 200 unit_name = "energy gun" export_types = list(/obj/item/gun/energy/e_gun) /datum/export/weapon/wt550 - cost = 300 + cost = 130 unit_name = "WT-550 automatic rifle" export_types = list(/obj/item/gun/ballistic/automatic/wt550) /datum/export/weapon/shotgun - cost = 300 + cost = 200 unit_name = "combat shotgun" export_types = list(/obj/item/gun/ballistic/shotgun/automatic/combat) - /datum/export/weapon/flashbang cost = 5 unit_name = "flashbang grenade" @@ -57,7 +75,6 @@ unit_name = "tear gas grenade" export_types = list(/obj/item/grenade/chem_grenade/teargas) - /datum/export/weapon/flash cost = 5 unit_name = "handheld flash" @@ -69,3 +86,271 @@ unit_name = "pair" message = "of handcuffs" export_types = list(/obj/item/restraints/handcuffs) + +////////////// +//RND Guns//// +////////////// + +/datum/export/weapon/lasercarbine + cost = 120 + unit_name = "laser carbine" + export_types = list(/obj/item/gun/energy/laser/carbine) + include_subtypes = TRUE + +/datum/export/weapon/teslagun + cost = 130 + unit_name = "tesla revolver" + export_types = list(/obj/item/gun/energy/tesla_revolver) + +/datum/export/weapon/aeg + cost = 200 //Endless power + unit_name = "advance engery gun" + export_types = list(/obj/item/gun/energy/e_gun/nuclear) + +/datum/export/weapon/deconer + cost = 600 + unit_name = "deconer" + export_types = list(/obj/item/gun/energy/decloner) + +/datum/export/weapon/ntsniper + cost = 500 + unit_name = "beam rifle" + export_types = list(/obj/item/gun/energy/beam_rifle) + +/datum/export/weapon/needle_gun + cost = 50 + unit_name = "syringe revolver" + export_types = list(/obj/item/gun/syringe/rapidsyringe) + +/datum/export/weapon/temp_gun + cost = 175 //Its just smaller + unit_name = "small temperature gun" + k_elasticity = 1/5 //Its just a smaller temperature gun, easy to mass make + export_types = list(/obj/item/gun/energy/temperature) + +/datum/export/weapon/flowergun + cost = 100 + unit_name = "floral somatoray" + export_types = list(/obj/item/gun/energy/floragun) + +/datum/export/weapon/xraygun + cost = 300 //Wall hacks + unit_name = "x ray gun" + export_types = list(/obj/item/gun/energy/xray) + +/datum/export/weapon/ioncarbine + cost = 200 + k_elasticity = 1/5 //Its just a smaller temperature gun, easy to mass make + unit_name = "ion carbine" + export_types = list(/obj/item/gun/energy/ionrifle/carbine) + +/datum/export/weapon/largeebow + cost = 500 + unit_name = "crossbow" + export_types = list(/obj/item/gun/energy/kinetic_accelerator/crossbow/large) + +/datum/export/weapon/largebomb + cost = 20 + unit_name = "large grenade" + export_types = list(/obj/item/grenade/chem_grenade/large) + +/datum/export/weapon/gravworm + cost = 150 + unit_name = "bluespace weapon" + export_types = list(/obj/item/gun/energy/wormhole_projector, /obj/item/gun/energy/gravity_gun) + +/datum/export/weapon/cryopryo + cost = 70 + unit_name = "heat based grenade" + export_types = list(/obj/item/grenade/chem_grenade/pyro, /obj/item/grenade/chem_grenade/cryo) + +/datum/export/weapon/advgrenade + cost = 80 + unit_name = "advanced grenade" + export_types = list(/obj/item/grenade/chem_grenade/adv_release) + +///////////////// +//Ammo and Pins// +///////////////// + +/datum/export/weapon/wtammo + cost = 10 + unit_name = "WT-550 automatic rifle ammo" + export_types = list(/obj/item/ammo_box/magazine/wt550m9, /obj/item/ammo_box/magazine/wt550m9/wtrubber) + +/datum/export/weapon/wtammo/advanced + cost = 30 + unit_name = "advanced WT-550 automatic rifle ammo" + export_types = list( /obj/item/ammo_box/magazine/wt550m9/wtap, /obj/item/ammo_box/magazine/wt550m9/wttx, /obj/item/ammo_box/magazine/wt550m9/wtic) + +/datum/export/weapon/mindshield + cost = 80 + unit_name = "mindshield locked pin" + export_types = list(/obj/item/firing_pin/implant/mindshield) + +/datum/export/weapon/testrange + cost = 20 + unit_name = "test range pin" + export_types = list(/obj/item/firing_pin/test_range) + +/datum/export/weapon/techslug + cost = 15 + k_elasticity = 0 + unit_name = "advanced shotgun shell" + export_types = list(/obj/item/ammo_casing/shotgun/dragonsbreath, /obj/item/ammo_casing/shotgun/meteorslug, /obj/item/ammo_casing/shotgun/pulseslug, /obj/item/ammo_casing/shotgun/frag12, /obj/item/ammo_casing/shotgun/ion, /obj/item/ammo_casing/shotgun/laserslug) + +///////////////////////// +//The Traitor Sell Outs// +///////////////////////// + +/datum/export/weapon/pistol + cost = 120 + unit_name = "illegal firearm" + export_types = list(/obj/item/gun/ballistic/automatic/pistol) + +/datum/export/weapon/revolver + cost = 200 + unit_name = "large handgun" + export_types = list(/obj/item/gun/ballistic/revolver/syndie) + +/datum/export/weapon/rocketlauncher + cost = 1000 + unit_name = "rocketlauncher" + export_types = list(/obj/item/gun/ballistic/rocketlauncher) + +/datum/export/weapon/antitank + cost = 300 + unit_name = "hand cannon" + export_types = list(/obj/item/gun/ballistic/automatic/pistol/antitank/syndicate) + +/datum/export/weapon/clownstuff + cost = 500 + unit_name = "clown war tech" + export_types = list(/obj/item/pneumatic_cannon/pie/selfcharge, /obj/item/shield/energy/bananium, /obj/item/melee/transforming/energy/sword/bananium, ) + +/datum/export/weapon/bulldog + cost = 400 + unit_name = "drum loaded shotgun" + export_types = list(/obj/item/gun/ballistic/automatic/shotgun/bulldog) + +/datum/export/weapon/smg + cost = 350 + unit_name = "automatic c-20r" + export_types = list(/obj/item/gun/ballistic/automatic/c20r) + +/datum/export/weapon/duelsaber + cost = 360 //Get it? + unit_name = "energy saber" + export_types = list(/obj/item/twohanded/dualsaber) + +/datum/export/weapon/esword + cost = 130 + unit_name = "energy sword" + export_types = list(/obj/item/melee/transforming/energy/sword/cx/traitor, /obj/item/melee/transforming/energy/sword/saber) + +/datum/export/weapon/rapier + cost = 150 + unit_name = "rapier" + export_types = list(/obj/item/storage/belt/sabre/rapier) + +/datum/export/weapon/flamer + cost = 20 //welder + some rods cheap + unit_name = "flamethrower" + export_types = list(/obj/item/flamethrower) + +/datum/export/weapon/gloves + cost = 90 + unit_name = "star struck gloves" + export_types = list(/obj/item/clothing/gloves/rapid) + +/datum/export/weapon/l6 + cost = 500 + unit_name = "law 6 saw" + export_types = list(/obj/item/gun/ballistic/automatic/l6_saw) + +/datum/export/weapon/m90 + cost = 400 + unit_name = "assault class weapon" + export_types = list(/obj/item/gun/ballistic/automatic/m90) + +/datum/export/weapon/powerglove + cost = 100 + unit_name = "hydraulic glove" + export_types = list(/obj/item/melee/powerfist) + +/datum/export/weapon/sniper + cost = 750 + unit_name = ".50 sniper" + export_types = list(/obj/item/gun/ballistic/automatic/sniper_rifle/syndicate) + +/datum/export/weapon/ebow + cost = 600 + unit_name = "mini crossbow" + export_types = list(/obj/item/gun/energy/kinetic_accelerator/crossbow) + +/datum/export/weapon/m10mm + cost = 10 + unit_name = "10mm magazine" + export_types = list(/obj/item/ammo_box/magazine/m10mm) + include_subtypes = TRUE + +/datum/export/weapon/dj_a_bomb + cost = 100 + unit_name = "40mm shell" + export_types = list(/obj/item/ammo_casing/a40mm) + +/datum/export/weapon/point50mags + cost = 50 + unit_name = ".50 magazine" + export_types = list(/obj/item/ammo_box/magazine/sniper_rounds) + include_subtypes = TRUE + +/datum/export/weapon/smg_mag + cost = 45 + unit_name = "smg magazine" + export_types = list(/obj/item/ammo_box/magazine/smgm45, /obj/item/ammo_box/magazine/m556) + +/datum/export/weapon/l6sawammo + cost = 60 + unit_name = "law 6 saw ammo box" + export_types = list(/obj/item/ammo_box/magazine/mm195x129) + include_subtypes = TRUE + +/datum/export/weapon/rocket + cost = 120 + unit_name = "rocket" + export_types = list(/obj/item/ammo_casing/caseless/rocket) + include_subtypes = TRUE + +/datum/export/weapon/ninemmammo + cost = 20 + unit_name = "9mm ammo magazine" + export_types = list(/obj/item/ammo_box/magazine/pistolm9mm) + +/datum/export/weapon/fletcher_ammo + cost = 60 + unit_name = "illegal ammo magazines" + export_types = list(/obj/item/ammo_box/magazine/flechette) + include_subtypes = TRUE + +/datum/export/weapon/dj_a_pizzabomb + cost = -6000 + unit_name = "Repair Costs" + export_types = list(/obj/item/pizzabox/bomb, /obj/item/sbeacondrop/bomb) + +/datum/export/weapon/real_toolbox + cost = 600 + unit_name = "golden toolbox" + export_types = list(/obj/item/storage/toolbox/gold_real) + +/datum/export/weapon/melee + cost = 30 + unit_name = "unlisted weapon" + export_types = list(/obj/item/melee) + include_subtypes = TRUE + +/datum/export/weapon/gun + cost = 30 + unit_name = "unlisted weapon" + export_types = list(/obj/item/gun) + include_subtypes = TRUE \ No newline at end of file diff --git a/code/modules/cargo/expressconsole.dm b/code/modules/cargo/expressconsole.dm index 5288c27ff6..0097346a34 100644 --- a/code/modules/cargo/expressconsole.dm +++ b/code/modules/cargo/expressconsole.dm @@ -54,6 +54,7 @@ ..() /obj/machinery/computer/cargo/express/emag_act(mob/living/user) + . = SEND_SIGNAL(src, COMSIG_ATOM_EMAG_ACT) if(obj_flags & EMAGGED) return user.visible_message("[user] swipes a suspicious card through [src]!", @@ -63,6 +64,8 @@ var/obj/item/circuitboard/computer/cargo/board = circuit board.obj_flags |= EMAGGED packin_up() + req_access = list() + return TRUE /obj/machinery/computer/cargo/express/proc/packin_up() // oh shit, I'm sorry meme_pack_data = list() // sorry for what? diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm index 53a8ab42c3..c9e9c37f6c 100644 --- a/code/modules/cargo/packs.dm +++ b/code/modules/cargo/packs.dm @@ -35,2792 +35,4 @@ A.flags_1 |= ADMIN_SPAWNED_1 else for(var/item in contains) - new item(C) - -// If you add something to this list, please group it by type and sort it alphabetically instead of just jamming it in like an animal - -////////////////////////////////////////////////////////////////////////////// -//////////////////////////// Emergency /////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -/datum/supply_pack/emergency - group = "Emergency" - -/datum/supply_pack/emergency/vehicle - name = "Biker Gang Kit" //TUNNEL SNAKES OWN THIS TOWN - desc = "TUNNEL SNAKES OWN THIS TOWN. Contains an unbranded All Terrain Vehicle, and a complete gang outfit -- consists of black gloves, a menacing skull bandanna, and a SWEET leather overcoat!" - cost = 2000 - contraband = TRUE - contains = list(/obj/vehicle/ridden/atv, - /obj/item/key, - /obj/item/clothing/suit/jacket/leather/overcoat, - /obj/item/clothing/gloves/color/black, - /obj/item/clothing/head/soft, - /obj/item/clothing/mask/bandana/skull)//so you can properly #cargoniabikergang - crate_name = "Biker Kit" - crate_type = /obj/structure/closet/crate/large - -/datum/supply_pack/emergency/equipment - name = "Emergency Bot/Internals Crate" - desc = "Explosions got you down? These supplies are guaranteed to patch up holes, in stations and people alike! Comes with two floorbots, two medbots, five oxygen masks and five small oxygen tanks." - cost = 3500 - contains = list(/mob/living/simple_animal/bot/floorbot, - /mob/living/simple_animal/bot/floorbot, - /mob/living/simple_animal/bot/medbot, - /mob/living/simple_animal/bot/medbot, - /obj/item/tank/internals/air, - /obj/item/tank/internals/air, - /obj/item/tank/internals/air, - /obj/item/tank/internals/air, - /obj/item/tank/internals/air, - /obj/item/clothing/mask/gas, - /obj/item/clothing/mask/gas, - /obj/item/clothing/mask/gas, - /obj/item/clothing/mask/gas, - /obj/item/clothing/mask/gas) - crate_name = "emergency crate" - crate_type = /obj/structure/closet/crate/internals - -/datum/supply_pack/emergency/radiatione_emergency - name = "Emergenc Radiation Protection Crate" - desc = "Survive the Nuclear Apocalypse and Supermatter Engine alike with two sets of Radiation suits. Each set contains a helmet, suit, and Geiger counter. We'll even throw in a few pill bottles that are able to handles radiation and the affects of the poisoning." - cost = 2500 - contains = list(/obj/item/clothing/head/radiation, - /obj/item/clothing/head/radiation, - /obj/item/clothing/suit/radiation, - /obj/item/clothing/suit/radiation, - /obj/item/geiger_counter, - /obj/item/geiger_counter, - /obj/item/storage/pill_bottle/mutarad, - /obj/item/storage/firstaid/radbgone) - crate_name = "radiation protection crate" - crate_type = /obj/structure/closet/crate/radiation - -/datum/supply_pack/emergency/rcds - name = "Emergency RCDs" - desc = "Bombs going off on station? SME blown and now you need to fix the hole it left behind? Well this crate has a pare of Rcds to be able to easily fix up any problem you may have!" - cost = 1500 - contains = list(/obj/item/construction/rcd, - /obj/item/construction/rcd) - crate_name = "emergency rcds" - crate_type = /obj/structure/closet/crate/internals - -/datum/supply_pack/emergency/soft_suit - name = "Emergency Space Suit " - desc = "Is there bombs going off left and right? Is there meteors shooting around the station? Well we have two fragile space suit for emergencys as well as air and masks." - cost = 1000 - contains = list(/obj/item/tank/internals/air, - /obj/item/tank/internals/air, - /obj/item/clothing/mask/gas, - /obj/item/clothing/mask/gas, - /obj/item/clothing/suit/space/fragile, - /obj/item/clothing/suit/space/fragile, - /obj/item/clothing/head/helmet/space/fragile, - /obj/item/clothing/head/helmet/space/fragile) - crate_name = "emergency crate" - crate_type = /obj/structure/closet/crate/internals - -/datum/supply_pack/emergency/firefighting - name = "Firefighting Crate" - desc = "Only you can prevent station fires. Partner up with two firefighter suits, gas masks, flashlights, large oxygen tanks, extinguishers, and hardhats!" - cost = 1000 - contains = list(/obj/item/clothing/suit/fire/firefighter, - /obj/item/clothing/suit/fire/firefighter, - /obj/item/clothing/mask/gas, - /obj/item/clothing/mask/gas, - /obj/item/flashlight, - /obj/item/flashlight, - /obj/item/tank/internals/oxygen/red, - /obj/item/tank/internals/oxygen/red, - /obj/item/extinguisher/advanced, - /obj/item/extinguisher/advanced, - /obj/item/clothing/head/hardhat/red, - /obj/item/clothing/head/hardhat/red) - crate_name = "firefighting crate" - -/datum/supply_pack/emergency/atmostank - name = "Firefighting Tank Backpack" - desc = "Mow down fires with this high-capacity fire fighting tank backpack. Requires Atmospherics access to open." - cost = 1000 - access = ACCESS_ATMOSPHERICS - contains = list(/obj/item/watertank/atmos) - crate_name = "firefighting backpack crate" - crate_type = /obj/structure/closet/crate/secure - -/datum/supply_pack/emergency/internals - name = "Internals Crate" - desc = "Master your life energy and control your breathing with three breath masks, three emergency oxygen tanks and three large air tanks."//IS THAT A - cost = 1000 - contains = list(/obj/item/clothing/mask/gas, - /obj/item/clothing/mask/gas, - /obj/item/clothing/mask/gas, - /obj/item/clothing/mask/breath, - /obj/item/clothing/mask/breath, - /obj/item/clothing/mask/breath, - /obj/item/tank/internals/emergency_oxygen, - /obj/item/tank/internals/emergency_oxygen, - /obj/item/tank/internals/emergency_oxygen, - /obj/item/tank/internals/air, - /obj/item/tank/internals/air, - /obj/item/tank/internals/air) - crate_name = "internals crate" - crate_type = /obj/structure/closet/crate/internals - -/datum/supply_pack/emergency/metalfoam - name = "Metal Foam Grenade Crate" - desc = "Seal up those pesky hull breaches with 14 Metal Foam Grenades." - cost = 2000 - contains = list(/obj/item/storage/box/metalfoam, - /obj/item/storage/box/metalfoam) - crate_name = "metal foam grenade crate" - -/datum/supply_pack/emergency/syndicate - name = "NULL_ENTRY" - desc = "(#@&^$THIS PACKAGE CONTAINS 30TC WORTH OF SOME RANDOM SYNDICATE GEAR WE HAD LYING AROUND THE WAREHOUSE. GIVE EM HELL, OPERATIVE@&!*() " - hidden = TRUE - cost = 20000 - contains = list() - crate_name = "emergency crate" - crate_type = /obj/structure/closet/crate/internals - dangerous = TRUE - -/datum/supply_pack/emergency/syndicate/fill(obj/structure/closet/crate/C) - var/crate_value = 30 - var/list/uplink_items = get_uplink_items(SSticker.mode) - while(crate_value) - var/category = pick(uplink_items) - var/item = pick(uplink_items[category]) - var/datum/uplink_item/I = uplink_items[category][item] - if(!I.surplus_nullcrates || prob(100 - I.surplus_nullcrates)) - continue - if(crate_value < I.cost) - continue - crate_value -= I.cost - new I.item(C) - -/datum/supply_pack/emergency/plasma_spacesuit - name = "Plasmaman Space Envirosuits" - desc = "Contains two space-worthy envirosuits for Plasmamen. Order now and we'll throw in two free helmets! Requires EVA access to open." - cost = 4000 - access = ACCESS_EVA - contains = list(/obj/item/clothing/suit/space/eva/plasmaman, - /obj/item/clothing/suit/space/eva/plasmaman, - /obj/item/clothing/head/helmet/space/plasmaman, - /obj/item/clothing/head/helmet/space/plasmaman) - crate_name = "plasmaman EVA crate" - crate_type = /obj/structure/closet/crate/secure - -/datum/supply_pack/emergency/plasmaman - name = "Plasmaman Supply Kit" - desc = "Keep those Plasmamen alive with two sets of Plasmaman outfits. Each set contains a plasmaman jumpsuit, internals tank, and helmet." - cost = 2000 - contains = list(/obj/item/clothing/under/plasmaman, - /obj/item/clothing/under/plasmaman, - /obj/item/tank/internals/plasmaman/belt/full, - /obj/item/tank/internals/plasmaman/belt/full, - /obj/item/clothing/head/helmet/space/plasmaman, - /obj/item/clothing/head/helmet/space/plasmaman) - crate_name = "plasmaman supply kit" - -/datum/supply_pack/emergency/radiation - name = "Radiation Protection Crate" - desc = "Survive the Nuclear Apocalypse and Supermatter Engine alike with two sets of Radiation suits. Each set contains a helmet, suit, and Geiger counter. We'll even throw in a bottle of vodka and some glasses too, considering the life-expectancy of people who order this." - cost = 1000 - contains = list(/obj/item/clothing/head/radiation, - /obj/item/clothing/head/radiation, - /obj/item/clothing/suit/radiation, - /obj/item/clothing/suit/radiation, - /obj/item/geiger_counter, - /obj/item/geiger_counter, - /obj/item/reagent_containers/food/drinks/bottle/vodka, - /obj/item/reagent_containers/food/drinks/drinkingglass/shotglass, - /obj/item/reagent_containers/food/drinks/drinkingglass/shotglass) - crate_name = "radiation protection crate" - crate_type = /obj/structure/closet/crate/radiation - -/datum/supply_pack/emergency/spacesuit - name = "Space Suit Crate" - desc = "Contains two aging suits from Space-Goodwill. Requires EVA access to open." - cost = 3000 - access = ACCESS_EVA - contains = list(/obj/item/clothing/suit/space, - /obj/item/clothing/suit/space, - /obj/item/clothing/head/helmet/space, - /obj/item/clothing/head/helmet/space, - /obj/item/clothing/mask/breath, - /obj/item/clothing/mask/breath) - crate_name = "space suit crate" - crate_type = /obj/structure/closet/crate/secure - -/datum/supply_pack/emergency/spacejets - name = "Spare EVA Jetpacks" - desc = "Contains three EVA grade jectpaks. Requires EVA access to open." - cost = 2000 - access = ACCESS_EVA - contains = list(/obj/item/tank/jetpack/carbondioxide/eva, - /obj/item/tank/jetpack/carbondioxide/eva, - /obj/item/tank/jetpack/carbondioxide/eva) - crate_name = "eva jetpacks crate" - crate_type = /obj/structure/closet/crate/secure - -/datum/supply_pack/emergency/specialops - name = "Special Ops Supplies" - desc = "(*!&@#TOO CHEAP FOR THAT NULL_ENTRY, HUH OPERATIVE? WELL, THIS LITTLE ORDER CAN STILL HELP YOU OUT IN A PINCH. CONTAINS A BOX OF FIVE EMP GRENADES, THREE SMOKEBOMBS, AN INCENDIARY GRENADE, AND A \"SLEEPY PEN\" FULL OF NICE TOXINS!#@*$" - hidden = TRUE - cost = 2000 - contains = list(/obj/item/storage/box/emps, - /obj/item/grenade/smokebomb, - /obj/item/grenade/smokebomb, - /obj/item/grenade/smokebomb, - /obj/item/pen/sleepy, - /obj/item/grenade/chem_grenade/incendiary) - crate_name = "emergency crate" - crate_type = /obj/structure/closet/crate/internals - -/datum/supply_pack/emergency/weedcontrol - name = "Weed Control Crate" - desc = "Keep those invasive species OUT. Contains a scythe, gasmask, two sprays of Plant-B-Gone, and two anti-weed chemical grenades. Warranty void if used on ambrosia. Requires Hydroponics access to open." - cost = 1500 - access = ACCESS_HYDROPONICS - contains = list(/obj/item/scythe, - /obj/item/clothing/mask/gas, - /obj/item/grenade/chem_grenade/antiweed, - /obj/item/grenade/chem_grenade/antiweed, - /obj/item/reagent_containers/spray/plantbgone, - /obj/item/reagent_containers/spray/plantbgone) - crate_name = "weed control crate" - crate_type = /obj/structure/closet/crate/secure/hydroponics - -/datum/supply_pack/medical/anitvirus - name = "Virus Containment Crate" - desc = "Viro let out a death plague Mk II again? Someone didnt wash there hands? Old plagues born anew? Well this crate is for you! Hope you cure it before it brakes out of the station... This crate needs medical access to open and has two bio suits, a box of needles and beakers, five spaceacillin needles, and a medibot." - cost = 3000 - access = ACCESS_MEDICAL - contains = list(/mob/living/simple_animal/bot/medbot, - /obj/item/clothing/head/bio_hood, - /obj/item/clothing/head/bio_hood, - /obj/item/clothing/suit/bio_suit, - /obj/item/clothing/suit/bio_suit, - /obj/item/reagent_containers/syringe/antiviral, - /obj/item/reagent_containers/syringe/antiviral, - /obj/item/reagent_containers/syringe/antiviral, - /obj/item/reagent_containers/syringe/antiviral, - /obj/item/reagent_containers/syringe/antiviral, - /obj/item/storage/box/syringes, - /obj/item/storage/box/beakers) - crate_name = "virus containment unit crate" - crate_type = /obj/structure/closet/crate/secure/plasma - -////////////////////////////////////////////////////////////////////////////// -//////////////////////////// Security //////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -/datum/supply_pack/security - group = "Security" - access = ACCESS_SECURITY - crate_type = /obj/structure/closet/crate/secure/gear - -/datum/supply_pack/security/armor - name = "Armor Crate" - desc = "Three vests of well-rounded, decently-protective armor. Requires Security access to open." - cost = 1000 - contains = list(/obj/item/clothing/suit/armor/vest, - /obj/item/clothing/suit/armor/vest, - /obj/item/clothing/suit/armor/vest) - crate_name = "armor crate" - -/datum/supply_pack/security/disabler - name = "Disabler Crate" - desc = "Three stamina-draining disabler weapons. Requires Security access to open." - cost = 1500 - contains = list(/obj/item/gun/energy/disabler, - /obj/item/gun/energy/disabler, - /obj/item/gun/energy/disabler) - crate_name = "disabler crate" - -/datum/supply_pack/security/forensics - name = "Forensics Crate" - desc = "Stay hot on the criminal's heels with Nanotrasen's Detective Essentials(tm). Contains a forensics scanner, six evidence bags, camera, tape recorder, white crayon, and of course, a fedora. Requires Security access to open." - cost = 2000 - contains = list(/obj/item/detective_scanner, - /obj/item/storage/box/evidence, - /obj/item/camera, - /obj/item/taperecorder, - /obj/item/toy/crayon/white, - /obj/item/clothing/head/fedora/det_hat) - crate_name = "forensics crate" - -/datum/supply_pack/security/helmets - name = "Helmets Crate" - desc = "Contains three standard-issue brain buckets. Requires Security access to open." - cost = 1000 - contains = list(/obj/item/clothing/head/helmet/sec, - /obj/item/clothing/head/helmet/sec, - /obj/item/clothing/head/helmet/sec) - crate_name = "helmet crate" - -/datum/supply_pack/security/laser - name = "Lasers Crate" - desc = "Contains three lethal, high-energy laser guns. Requires Security access to open." - cost = 2000 - contains = list(/obj/item/gun/energy/laser, - /obj/item/gun/energy/laser, - /obj/item/gun/energy/laser) - crate_name = "laser crate" - -/datum/supply_pack/security/russianclothing - name = "Russian Surplus Clothing" - desc = "An old russian crate full of surplus armor that they used to use! Has two sets of bulletproff armor, a few union suits and some warm hats!" - contraband = TRUE - cost = 5000 // Its basicly sec suits, good boots/gloves - contains = list(/obj/item/clothing/suit/security/officer/russian, - /obj/item/clothing/suit/security/officer/russian, - /obj/item/clothing/shoes/combat, - /obj/item/clothing/shoes/combat, - /obj/item/clothing/head/ushanka, - /obj/item/clothing/head/ushanka, - /obj/item/clothing/suit/armor/bulletproof, - /obj/item/clothing/suit/armor/bulletproof, - /obj/item/clothing/head/helmet/alt, - /obj/item/clothing/head/helmet/alt, - /obj/item/clothing/gloves/combat, - /obj/item/clothing/gloves/combat, - /obj/item/clothing/mask/gas, - /obj/item/clothing/mask/gas) - crate_name = "surplus russian clothing" - crate_type = /obj/structure/closet/crate/internals - -/datum/supply_pack/security/russianmosin - name = "Russian Minutemen Gear" - desc = "An old russian Minutemen crate, comes with a full russian outfit, a mosin and a stripper clip." - contraband = TRUE - access = FALSE - cost = 5000 // - contains = list(/obj/item/clothing/suit/security/officer/russian, - /obj/item/clothing/shoes/combat, - /obj/item/clothing/head/ushanka, - /obj/item/clothing/suit/armor/bulletproof, - /obj/item/clothing/head/helmet/alt, - /obj/item/clothing/gloves/combat, - /obj/item/clothing/mask/gas, - /obj/item/gun/ballistic/shotgun/boltaction, - /obj/item/ammo_box/a762) - crate_name = "surplus russian gear" - crate_type = /obj/structure/closet/crate/internals - -/datum/supply_pack/security/sechardsuit - name = "Sec Hardsuit" - desc = "One Sec Hardsuit with a small air tank and mask." - cost = 3000 // half of SWAT gear for have the armor and half the gear - contains = list(/obj/item/clothing/suit/space/hardsuit/security, - /obj/item/tank/internals/air, - /obj/item/clothing/mask/gas) - crate_name = "sec hardsuit crate" - -/datum/supply_pack/security/securitybarriers - name = "Security Barrier Grenades" - desc = "Stem the tide with four Security Barrier grenades. Requires Security access to open." - contains = list(/obj/item/grenade/barrier, - /obj/item/grenade/barrier, - /obj/item/grenade/barrier, - /obj/item/grenade/barrier) - cost = 2000 - crate_name = "security barriers crate" - -/datum/supply_pack/security/securityclothes - name = "Security Clothing Crate" - desc = "Contains appropriate outfits for the station's private security force. Contains outfits for the Warden, Head of Security, and two Security Officers. Each outfit comes with a rank-appropriate jumpsuit, suit, and beret. Requires Security access to open." - cost = 3000 - contains = list(/obj/item/clothing/under/rank/security/navyblue, - /obj/item/clothing/under/rank/security/navyblue, - /obj/item/clothing/suit/security/officer, - /obj/item/clothing/suit/security/officer, - /obj/item/clothing/head/beret/sec/navyofficer, - /obj/item/clothing/head/beret/sec/navyofficer, - /obj/item/clothing/under/rank/warden/navyblue, - /obj/item/clothing/suit/security/warden, - /obj/item/clothing/head/beret/sec/navywarden, - /obj/item/clothing/under/rank/head_of_security/navyblue, - /obj/item/clothing/suit/security/hos, - /obj/item/clothing/head/beret/sec/navyhos) - crate_name = "security clothing crate" - -/datum/supply_pack/security/supplies - name = "Security Supplies Crate" - desc = "Contains seven flashbangs, seven teargas grenades, six flashes, and seven handcuffs. Requires Security access to open." - cost = 1000 - contains = list(/obj/item/storage/box/flashbangs, - /obj/item/storage/box/teargas, - /obj/item/storage/box/flashes, - /obj/item/storage/box/handcuffs) - crate_name = "security supply crate" - -/datum/supply_pack/security/firingpins - name = "Standard Firing Pins Crate" - desc = "Upgrade your arsenal with 10 standard firing pins. Requires Security access to open." - cost = 2000 - contains = list(/obj/item/storage/box/firingpins, - /obj/item/storage/box/firingpins) - crate_name = "firing pins crate" - -/datum/supply_pack/security/justiceinbound - name = "Standard Justice Enforcer Crate" - desc = "This is it. The Bee's Knees. The Creme of the Crop. The Pick of the Litter. The best of the best of the best. The Crown Jewel of Nanotrasen. The Alpha and the Omega of security headwear. Guaranteed to strike fear into the hearts of each and every criminal aboard the station. Also comes with a security gasmask. Requires Security access to open." - cost = 6000 //justice comes at a price. An expensive, noisy price. - contraband = TRUE - contains = list(/obj/item/clothing/head/helmet/justice, - /obj/item/clothing/mask/gas/sechailer) - crate_name = "security clothing crate" - -/datum/supply_pack/security/baton - name = "Stun Batons Crate" - desc = "Arm the Civil Protection Forces with three stun batons. Batteries included. Requires Security access to open." - cost = 1000 - contains = list(/obj/item/melee/baton/loaded, - /obj/item/melee/baton/loaded, - /obj/item/melee/baton/loaded) - crate_name = "stun baton crate" - -/datum/supply_pack/security/taser - name = "Taser Crate" - desc = "From the depths of stunbased combat, this order rises above, supreme. Contains three hybrid tasers, capable of firing both electrodes and disabling shots. Requires Security access to open." - cost = 3000 - contains = list(/obj/item/gun/energy/e_gun/advtaser, - /obj/item/gun/energy/e_gun/advtaser, - /obj/item/gun/energy/e_gun/advtaser) - crate_name = "taser crate" - -/datum/supply_pack/security/wall_flash - name = "Wall-Mounted Flash Crate" - desc = "Contains four wall-mounted flashes. Requires Security access to open." - cost = 1000 - contains = list(/obj/item/storage/box/wall_flash, - /obj/item/storage/box/wall_flash, - /obj/item/storage/box/wall_flash, - /obj/item/storage/box/wall_flash) - crate_name = "wall-mounted flash crate" - -////////////////////////////////////////////////////////////////////////////// -//////////////////////////// Armory ////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -/datum/supply_pack/security/armory - group = "Armory" - access = ACCESS_ARMORY - crate_type = /obj/structure/closet/crate/secure/weapon - -/datum/supply_pack/security/armory/bulletarmor - name = "Bulletproof Armor Crate" - desc = "Contains three sets of bulletproof armor. Guaranteed to reduce a bullet's stopping power by over half. Requires Armory access to open." - cost = 1500 - contains = list(/obj/item/clothing/suit/armor/bulletproof, - /obj/item/clothing/suit/armor/bulletproof, - /obj/item/clothing/suit/armor/bulletproof) - crate_name = "bulletproof armor crate" - -/datum/supply_pack/security/armory/bullethelmets - name = "Bulletproof Helmet Crate" - desc = "Contains three sets of bulletproof helmets. Guaranteed to reduce a bullet's stopping power by over half. Requires Armory access to open." - cost = 1500 - contains = list(/obj/item/clothing/head/helmet/alt, - /obj/item/clothing/head/helmet/alt, - /obj/item/clothing/head/helmet/alt) - crate_name = "bulletproof helmet crate" - -/datum/supply_pack/security/armory/chemimp - name = "Chemical Implants Crate" - desc = "Contains five Remote Chemical implants. Requires Armory access to open." - cost = 2000 - contains = list(/obj/item/storage/box/chemimp) - crate_name = "chemical implant crate" - -/datum/supply_pack/security/armory/combatknives - name = "Combat Knives Crate" - desc = "Contains three sharpened combat knives. Each knife guaranteed to fit snugly inside any Nanotrasen-standard boot. Requires Armory access to open." - cost = 3000 - contains = list(/obj/item/kitchen/knife/combat, - /obj/item/kitchen/knife/combat, - /obj/item/kitchen/knife/combat) - crate_name = "combat knife crate" - -/datum/supply_pack/security/armory/ballistic - name = "Combat Shotguns Crate" - desc = "For when the enemy absolutely needs to be replaced with lead. Contains three Aussec-designed Combat Shotguns, with three Shotgun Bandoliers, as well as seven buchshot and 12g shotgun slugs. Requires Armory access to open." - cost = 8000 - contains = list(/obj/item/gun/ballistic/shotgun/automatic/combat, - /obj/item/gun/ballistic/shotgun/automatic/combat, - /obj/item/gun/ballistic/shotgun/automatic/combat, - /obj/item/storage/belt/bandolier, - /obj/item/storage/belt/bandolier, - /obj/item/storage/belt/bandolier, - /obj/item/storage/box/lethalshot, - /obj/item/storage/box/lethalslugs) - crate_name = "combat shotguns crate" - -/datum/supply_pack/security/armory/dragnetgun - name = "DRAGnet gun Crate" - desc = "Contains two DRAGnet gun. A Dynamic Rapid-Apprehension of the Guilty net the revolution in law enforcement technology that YOU Want! Requires Armory access to open." - cost = 3500 - contains = list(/obj/item/gun/energy/e_gun/dragnet, - /obj/item/gun/energy/e_gun/dragnet) - crate_name = "anti riot net guns crate" - -/datum/supply_pack/security/armory/energy - name = "Energy Guns Crate" - desc = "Contains three Energy Guns, capable of firing both nonlethal and lethal blasts of light. Requires Armory access to open." - cost = 3500 - contains = list(/obj/item/gun/energy/e_gun, - /obj/item/gun/energy/e_gun, - /obj/item/gun/energy/e_gun) - crate_name = "energy gun crate" - crate_type = /obj/structure/closet/crate/secure/plasma - -/datum/supply_pack/security/armory/exileimp // Theres boxes in 2 lockers as well as gateway never realy being used sad - name = "Exile Implants Crate" - desc = "Contains five Exile implants. Requires Armory access to open." - cost = 1000 - contains = list(/obj/item/storage/box/exileimp) - crate_name = "exile implant crate" - -/datum/supply_pack/security/armory/mindshield - name = "Mindshield Implants Crate" - desc = "Prevent against radical thoughts with three Mindshield implants. Requires Armory access to open." - cost = 4000 - contains = list(/obj/item/storage/lockbox/loyalty) - crate_name = "mindshield implant crate" - -/datum/supply_pack/security/armory/trackingimp - name = "Tracking Implants Crate" - desc = "Contains four tracking implants. Requires Armory access to open." - cost = 1000 - contains = list(/obj/item/storage/box/trackimp) - crate_name = "tracking implant crate" - -/datum/supply_pack/security/armory/fire - name = "Incendiary Weapons Crate" - desc = "Burn, baby burn. Contains three incendiary grenades, seven incendiary slugs, three plasma canisters, and a flamethrower. Requires Brige access to open." - cost = 1500 - access = ACCESS_HEADS - contains = list(/obj/item/flamethrower/full, - /obj/item/tank/internals/plasma, - /obj/item/tank/internals/plasma, - /obj/item/tank/internals/plasma, - /obj/item/grenade/chem_grenade/incendiary, - /obj/item/grenade/chem_grenade/incendiary, - /obj/item/grenade/chem_grenade/incendiary, - /obj/item/storage/box/fireshot) - crate_name = "incendiary weapons crate" - crate_type = /obj/structure/closet/crate/secure/plasma - dangerous = TRUE - -/datum/supply_pack/security/armory/miniguns - name = "Personal Miniature Energy Guns" - desc = "Contains three miniature energy guns. Each gun has a disabler and a lethal option. Requires Armory access to open." - cost = 5000 - contains = list(/obj/item/gun/energy/e_gun/mini, - /obj/item/gun/energy/e_gun/mini, - /obj/item/gun/energy/e_gun/mini) - crate_name = "personal energy guns crate" - crate_type = /obj/structure/closet/crate/secure/plasma - -/datum/supply_pack/security/armory/laserarmor - name = "Reflector Vest Crate" - desc = "Contains two vests of highly reflective material. Each armor piece diffuses a laser's energy by over half, as well as offering a good chance to reflect the laser entirely. Requires Armory access to open." - cost = 2000 - contains = list(/obj/item/clothing/suit/armor/laserproof, - /obj/item/clothing/suit/armor/laserproof) - crate_name = "reflector vest crate" - crate_type = /obj/structure/closet/crate/secure/plasma - -/datum/supply_pack/security/armory/riotarmor - name = "Riot Armor Crate" - desc = "Contains three sets of heavy body armor. Advanced padding protects against close-ranged weaponry, making melee attacks feel only half as potent to the user. Requires Armory access to open." - cost = 1500 - contains = list(/obj/item/clothing/suit/armor/riot, - /obj/item/clothing/suit/armor/riot, - /obj/item/clothing/suit/armor/riot) - crate_name = "riot armor crate" - -/datum/supply_pack/security/armory/riothelmets - name = "Riot Helmets Crate" - desc = "Contains three riot helmets. Requires Armory access to open." - cost = 1500 - contains = list(/obj/item/clothing/head/helmet/riot, - /obj/item/clothing/head/helmet/riot, - /obj/item/clothing/head/helmet/riot) - crate_name = "riot helmets crate" - -/datum/supply_pack/security/armory/riotshields - name = "Riot Shields Crate" - desc = "For when the greytide gets really uppity. Contains three riot shields. Requires Armory access to open." - cost = 2000 - contains = list(/obj/item/shield/riot, - /obj/item/shield/riot, - /obj/item/shield/riot) - crate_name = "riot shields crate" - -/datum/supply_pack/security/armory/riotshotguns - name = "Riot Shotgun Crate" - desc = "For when the greytide gets really uppity. Contains three riot shotguns, seven rubber shot and beanbag shells. Requires Armory access to open." - cost = 6000 - contains = list(/obj/item/gun/ballistic/shotgun/riot, - /obj/item/gun/ballistic/shotgun/riot, - /obj/item/gun/ballistic/shotgun/riot, - /obj/item/storage/box/rubbershot, - /obj/item/storage/box/beanbag) - crate_name = "riot shotgun crate" - -/datum/supply_pack/security/armory/swat - name = "SWAT Crate" - desc = "Contains two fullbody sets of tough, fireproof, pressurized suits designed in a joint effort by IS-ERI and Nanotrasen. Each set contains a suit, helmet, mask, combat belt, and combat gloves. Requires Armory access to open." - cost = 6000 - contains = list(/obj/item/clothing/head/helmet/swat/nanotrasen, - /obj/item/clothing/head/helmet/swat/nanotrasen, - /obj/item/clothing/suit/space/swat, - /obj/item/clothing/suit/space/swat, - /obj/item/clothing/mask/gas/sechailer/swat, - /obj/item/clothing/mask/gas/sechailer/swat, - /obj/item/storage/belt/military/assault, - /obj/item/storage/belt/military/assault, - /obj/item/clothing/gloves/combat, - /obj/item/clothing/gloves/combat) - crate_name = "swat crate" - -/datum/supply_pack/security/armory/swattasers //Lesser AEG tbh - name = "SWAT tatical tasers Crate" - desc = "Contains two tactical energy gun, these guns are able to tase, disable and lethal as well as hold a seclight. Requires Armory access to open." - cost = 8000 - contains = list(/obj/item/gun/energy/e_gun/stun, - /obj/item/gun/energy/e_gun/stun) - crate_name = "swat taser crate" - -/datum/supply_pack/security/armory/woodstock - name = "Classic WoodStock Shotguns Crate" - desc = "Contains three rustic, pumpaction shotguns. Requires Armory access to open." - cost = 3500 - contains = list(/obj/item/gun/ballistic/shotgun, - /obj/item/gun/ballistic/shotgun, - /obj/item/gun/ballistic/shotgun) - crate_name = "woodstock shotguns crate" - -/datum/supply_pack/security/armory/wt550 - name = "WT-550 Semi-Auto Rifle Crate" - desc = "Contains two high-powered, semiautomatic rifles chambered in 4.6x30mm. Requires Armory access to open." - cost = 3500 - contains = list(/obj/item/gun/ballistic/automatic/wt550, - /obj/item/gun/ballistic/automatic/wt550) - crate_name = "auto rifle crate" - -/datum/supply_pack/security/armory/wt550ammo - name = "WT-550 Semi-Auto SMG Ammo Crate" - desc = "Contains four 20-round magazines for the WT-550 Semi-Auto SMG. Each magazine is designed to facilitate rapid tactical reloads. Requires Armory access to open." - cost = 2500 - contains = list(/obj/item/ammo_box/magazine/wt550m9, - /obj/item/ammo_box/magazine/wt550m9, - /obj/item/ammo_box/magazine/wt550m9, - /obj/item/ammo_box/magazine/wt550m9) - crate_name = "auto rifle ammo crate" - -/datum/supply_pack/security/armory/wt550ammo_nonlethal // Takes around 12 shots to stun crit someone - name = "WT-550 Semi-Auto SMG Non-Lethal Ammo Crate" - desc = "Contains four 20-round magazines for the WT-550 Semi-Auto SMG. Each magazine is designed to facilitate rapid tactical reloads. Requires Armory access to open." - cost = 1500 - contains = list(/obj/item/ammo_box/magazine/wt550m9/wtrubber, - /obj/item/ammo_box/magazine/wt550m9/wtrubber, - /obj/item/ammo_box/magazine/wt550m9/wtrubber, - /obj/item/ammo_box/magazine/wt550m9/wtrubber) - crate_name = "auto rifle ammo crate" - -/datum/supply_pack/security/armory/wt550ammo_special - name = "WT-550 Semi-Auto SMG Special Ammo Crate" - desc = "Contains 2 20-round Armour Piercing and Incendiary magazines for the WT-550 Semi-Auto SMG. Each magazine is designed to facilitate rapid tactical reloads. Requires Armory access to open." - cost = 4500 - contains = list(/obj/item/ammo_box/magazine/wt550m9/wtap, - /obj/item/ammo_box/magazine/wt550m9/wtap, - /obj/item/ammo_box/magazine/wt550m9/wtic, - /obj/item/ammo_box/magazine/wt550m9/wtic) - crate_name = "auto rifle ammo crate" - -////////////////////////////////////////////////////////////////////////////// -//////////////////////////// Engineering ///////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -/datum/supply_pack/engineering - group = "Engineering" - crate_type = /obj/structure/closet/crate/engineering - -/datum/supply_pack/engineering/shieldgen - name = "Anti-breach Shield Projector Crate" - desc = "Hull breaches again? Say no more with the Nanotrasen Anti-Breach Shield Projector! Uses forcefield technology to keep the air in, and the space out. Contains two shield projectors." - cost = 2500 - contains = list(/obj/machinery/shieldgen, - /obj/machinery/shieldgen) - crate_name = "anti-breach shield projector crate" - -/datum/supply_pack/engineering/conveyor - name = "Conveyor Assembly Crate" - desc = "Keep production moving along with six conveyor belts. Conveyor switch included. If you have any questions, check out the enclosed instruction book." - cost = 750 - contains = list(/obj/item/conveyor_construct, - /obj/item/conveyor_construct, - /obj/item/conveyor_construct, - /obj/item/conveyor_construct, - /obj/item/conveyor_construct, - /obj/item/conveyor_construct, - /obj/item/conveyor_switch_construct, - /obj/item/paper/guides/conveyor) - crate_name = "conveyor assembly crate" - -/datum/supply_pack/engineering/engiequipment - name = "Engineering Gear Crate" - desc = "Gear up with three toolbelts, high-visibility vests, welding helmets, hardhats, and two pairs of meson goggles!" - cost = 1300 - contains = list(/obj/item/storage/belt/utility, - /obj/item/storage/belt/utility, - /obj/item/storage/belt/utility, - /obj/item/clothing/suit/hazardvest, - /obj/item/clothing/suit/hazardvest, - /obj/item/clothing/suit/hazardvest, - /obj/item/clothing/head/welding, - /obj/item/clothing/head/welding, - /obj/item/clothing/head/welding, - /obj/item/clothing/head/hardhat, - /obj/item/clothing/head/hardhat, - /obj/item/clothing/head/hardhat, - /obj/item/clothing/glasses/meson/engine, - /obj/item/clothing/glasses/meson/engine) - crate_name = "engineering gear crate" - -/datum/supply_pack/engineering/engihardsuit - name = "Engineering Hardsuit" - desc = "Poly 'Who stole all the hardsuits!' Well now you can get more hardsuits if needed! NOTE ONE HARDSUIT IS IN THIS CRATE, as well as one air tank and mask!" - cost = 2500 - contains = list(/obj/item/tank/internals/air, - /obj/item/clothing/mask/gas, - /obj/item/clothing/suit/space/hardsuit/engine) - crate_name = "engineering hardsuit" - -/datum/supply_pack/engineering/atmoshardsuit - name = "Atmospherics Hardsuit" - desc = "Too many techs and not enough hardsuits? Time to buy some more! Comes with gas mask and air tank. Ask the CE to open." - cost = 5000 - access = ACCESS_CE - contains = list(/obj/item/tank/internals/air, - /obj/item/clothing/mask/gas, - /obj/item/clothing/suit/space/hardsuit/engine/atmos) - crate_name = "atmospherics hardsuit" - crate_type = /obj/structure/closet/crate/secure/engineering - -/datum/supply_pack/engineering/industrialrcd - name = "Industrial RCD" - desc = "A industrial RCD in case the station has gone through more then one meteor storm and the CE needs to bring out the somthing a bit more reliable. Dose not contain spare ammo for the industrial RCD or any other RCD modles." - cost = 4500 - access = ACCESS_CE - contains = list(/obj/item/construction/rcd/industrial) - crate_name = "industrial rcd" - crate_type = /obj/structure/closet/crate/secure/engineering - -/datum/supply_pack/engineering/powergamermitts - name = "Insulated Gloves Crate" - desc = "The backbone of modern society. Barely ever ordered for actual engineering. Contains three insulated gloves." - cost = 2000 //Made of pure-grade bullshittinium - contains = list(/obj/item/clothing/gloves/color/yellow, - /obj/item/clothing/gloves/color/yellow, - /obj/item/clothing/gloves/color/yellow) - crate_name = "insulated gloves crate" - crate_type = /obj/structure/closet/crate/engineering/electrical - -/obj/item/stock_parts/cell/inducer_supply - maxcharge = 5000 - charge = 5000 - -/datum/supply_pack/engineering/inducers - name = "NT-75 Electromagnetic Power Inducers Crate" - desc = "No rechargers? No problem, with the NT-75 EPI, you can recharge any standard cell-based equipment anytime, anywhere. Contains two Inducers." - cost = 2000 - contains = list(/obj/item/inducer/sci {cell_type = /obj/item/stock_parts/cell/inducer_supply; opened = 0}, /obj/item/inducer/sci {cell_type = /obj/item/stock_parts/cell/inducer_supply; opened = 0}) //FALSE doesn't work in modified type paths apparently. - crate_name = "inducer crate" - crate_type = /obj/structure/closet/crate/engineering/electrical - -/datum/supply_pack/engineering/pacman - name = "P.A.C.M.A.N Generator Crate" - desc = "Engineers can't set up the engine? Not an issue for you, once you get your hands on this P.A.C.M.A.N. Generator! Takes in plasma and spits out sweet sweet energy." - cost = 2500 - contains = list(/obj/machinery/power/port_gen/pacman) - crate_name = "PACMAN generator crate" - crate_type = /obj/structure/closet/crate/engineering/electrical - -/datum/supply_pack/engineering/power - name = "Power Cell Crate" - desc = "Looking for power overwhelming? Look no further. Contains three high-voltage power cells." - cost = 1000 - contains = list(/obj/item/stock_parts/cell/high, - /obj/item/stock_parts/cell/high, - /obj/item/stock_parts/cell/high) - crate_name = "power cell crate" - crate_type = /obj/structure/closet/crate/engineering/electrical - -/datum/supply_pack/engineering/shuttle_engine - name = "Shuttle Engine Crate" - desc = "Through advanced bluespace-shenanigans, our engineers have managed to fit an entire shuttle engine into one tiny little crate. Requires CE access to open." - cost = 5000 - access = ACCESS_CE - contains = list(/obj/structure/shuttle/engine/propulsion/burst/cargo) - crate_name = "shuttle engine crate" - crate_type = /obj/structure/closet/crate/secure/engineering - special = TRUE - -/datum/supply_pack/engineering/tools - name = "Toolbox Crate" - desc = "Any robust spaceman is never far from their trusty toolbox. Contains three electrical toolboxes and three mechanical toolboxes." - contains = list(/obj/item/storage/toolbox/electrical, - /obj/item/storage/toolbox/electrical, - /obj/item/storage/toolbox/electrical, - /obj/item/storage/toolbox/mechanical, - /obj/item/storage/toolbox/mechanical, - /obj/item/storage/toolbox/mechanical) - cost = 1000 - crate_name = "toolbox crate" - -/datum/supply_pack/engineering/bsa - name = "Bluespace Artillery Parts" - desc = "The pride of Nanotrasen Naval Command. The legendary Bluespace Artillery Cannon is a devastating feat of human engineering and testament to wartime determination. Highly advanced research is required for proper construction. " - cost = 15000 - special = TRUE - contains = list(/obj/item/circuitboard/machine/bsa/front, - /obj/item/circuitboard/machine/bsa/middle, - /obj/item/circuitboard/machine/bsa/back, - /obj/item/circuitboard/computer/bsa_control - ) - crate_name= "bluespace artillery parts crate" - -/datum/supply_pack/engineering/dna_vault - name = "DNA Vault Parts" - desc = "Secure the longevity of the current state of humanity within this massive library of scientific knowledge, capable of granting superhuman powers and abilities. Highly advanced research is required for proper construction. Also contains five DNA probes." - cost = 12000 - special = TRUE - contains = list( - /obj/item/circuitboard/machine/dna_vault, - /obj/item/dna_probe, - /obj/item/dna_probe, - /obj/item/dna_probe, - /obj/item/dna_probe, - /obj/item/dna_probe - ) - crate_name= "dna vault parts crate" - -/datum/supply_pack/engineering/dna_probes - name = "DNA Vault Samplers" - desc = "Contains five DNA probes for use in the DNA vault." - cost = 3000 - special = TRUE - contains = list(/obj/item/dna_probe, - /obj/item/dna_probe, - /obj/item/dna_probe, - /obj/item/dna_probe, - /obj/item/dna_probe - ) - crate_name= "dna samplers crate" - - -/datum/supply_pack/engineering/shield_sat - name = "Shield Generator Satellite" - desc = "Protect the very existence of this station with these Anti-Meteor defenses. Contains three Shield Generator Satellites." - cost = 4000 - contains = list( - /obj/machinery/satellite/meteor_shield, - /obj/machinery/satellite/meteor_shield, - /obj/machinery/satellite/meteor_shield - ) - crate_name= "shield sat crate" - -/datum/supply_pack/engineering/shield_sat_control - name = "Shield System Control Board" - desc = "A control system for the Shield Generator Satellite system." - cost = 4000 - contains = list(/obj/item/circuitboard/computer/sat_control) - crate_name= "shield control board crate" - -////////////////////////////////////////////////////////////////////////////// -//////////////////////// Engine Construction ///////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -/datum/supply_pack/engine - group = "Engine Construction" - crate_type = /obj/structure/closet/crate/engineering - -/datum/supply_pack/engine/am_jar - name = "Antimatter Containment Jar Crate" - desc = "Two Antimatter containment jars stuffed into a single crate." - cost = 2000 - contains = list(/obj/item/am_containment, - /obj/item/am_containment) - crate_name = "antimatter jar crate" - -/datum/supply_pack/engine/am_core - name = "Antimatter Control Crate" - desc = "The brains of the Antimatter engine, this device is sure to teach the station's powergrid the true meaning of real power." - cost = 5000 - contains = list(/obj/machinery/power/am_control_unit) - crate_name = "antimatter control crate" - -/datum/supply_pack/engine/am_shielding - name = "Antimatter Shielding Crate" - desc = "Contains ten Antimatter shields, somehow crammed into a crate." - cost = 2000 - contains = list(/obj/item/am_shielding_container, - /obj/item/am_shielding_container, - /obj/item/am_shielding_container, - /obj/item/am_shielding_container, - /obj/item/am_shielding_container, - /obj/item/am_shielding_container, - /obj/item/am_shielding_container, - /obj/item/am_shielding_container, - /obj/item/am_shielding_container, - /obj/item/am_shielding_container) //10 shields: 3x3 containment and a core - crate_name = "antimatter shielding crate" - -/datum/supply_pack/engine/emitter - name = "Emitter Crate" - desc = "Useful for powering forcefield generators while destroying locked crates and intruders alike. Contains two high-powered energy emitters. Requires CE access to open." - cost = 1500 - access = ACCESS_CE - contains = list(/obj/machinery/power/emitter, - /obj/machinery/power/emitter) - crate_name = "emitter crate" - crate_type = /obj/structure/closet/crate/secure/engineering - dangerous = TRUE - -/datum/supply_pack/engine/field_gen - name = "Field Generator Crate" - desc = "Typically the only thing standing between the station and a messy death. Powered by emitters. Contains two field generators." - cost = 1500 - contains = list(/obj/machinery/field/generator, - /obj/machinery/field/generator) - crate_name = "field generator crate" - -/datum/supply_pack/engine/grounding_rods - name = "Grounding Rod Crate" - desc = "Four grounding rods guaranteed to keep any uppity tesla's lightning under control." - cost = 1700 - contains = list(/obj/machinery/power/grounding_rod, - /obj/machinery/power/grounding_rod, - /obj/machinery/power/grounding_rod, - /obj/machinery/power/grounding_rod) - crate_name = "grounding rod crate" - crate_type = /obj/structure/closet/crate/engineering/electrical - -/datum/supply_pack/engine/mason - name = "M.A.S.O.N RIG Crate" - desc = "The rare M.A.S.O.N RIG. Requires CE access to open." - cost = 15000 - access = ACCESS_CE - contains = list(/obj/item/clothing/suit/space/hardsuit/ancient/mason) - crate_name = "M.A.S.O.N Rig" - crate_type = /obj/structure/closet/crate/secure/engineering - -/datum/supply_pack/engine/PA - name = "Particle Accelerator Crate" - desc = "A supermassive black hole or hyper-powered teslaball are the perfect way to spice up any party! This \"My First Apocalypse\" kit contains everything you need to build your own Particle Accelerator! Ages 10 and up." - cost = 3000 - contains = list(/obj/structure/particle_accelerator/fuel_chamber, - /obj/machinery/particle_accelerator/control_box, - /obj/structure/particle_accelerator/particle_emitter/center, - /obj/structure/particle_accelerator/particle_emitter/left, - /obj/structure/particle_accelerator/particle_emitter/right, - /obj/structure/particle_accelerator/power_box, - /obj/structure/particle_accelerator/end_cap) - crate_name = "particle accelerator crate" - -/datum/supply_pack/engine/collector - name = "Radiation Collector Crate" - desc = "Contains three radiation collectors. Useful for collecting energy off nearby Supermatter Crystals, Singularities or Teslas!" - cost = 2500 - contains = list(/obj/machinery/power/rad_collector, - /obj/machinery/power/rad_collector, - /obj/machinery/power/rad_collector) - crate_name = "collector crate" - -/datum/supply_pack/engine/sing_gen - name = "Singularity Generator Crate" - desc = "The key to unlocking the power of Lord Singuloth. Particle Accelerator not included." - cost = 5000 - contains = list(/obj/machinery/the_singularitygen) - crate_name = "singularity generator crate" - -/datum/supply_pack/engine/solar - name = "Solar Panel Crate" - desc = "Go green with this DIY advanced solar array. Contains twenty one solar assemblies, a solar-control circuit board, and tracker. If you have any questions, please check out the enclosed instruction book." - cost = 2000 - contains = list(/obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/circuitboard/computer/solar_control, - /obj/item/electronics/tracker, - /obj/item/paper/guides/jobs/engi/solars) - crate_name = "solar panel crate" - crate_type = /obj/structure/closet/crate/engineering/electrical - -/datum/supply_pack/engine/supermatter_shard - name = "Supermatter Shard Crate" - desc = "The power of the heavens condensed into a single crystal. Requires CE access to open." - cost = 10000 - access = ACCESS_CE - contains = list(/obj/machinery/power/supermatter_crystal/shard) - crate_name = "supermatter shard crate" - crate_type = /obj/structure/closet/crate/secure/engineering - dangerous = TRUE - -/datum/supply_pack/engine/tesla_coils - name = "Tesla Coil Crate" - desc = "Whether it's high-voltage executions, creating research points, or just plain old power generation: This pack of four Tesla coils can do it all!" - cost = 2500 - contains = list(/obj/machinery/power/tesla_coil, - /obj/machinery/power/tesla_coil, - /obj/machinery/power/tesla_coil, - /obj/machinery/power/tesla_coil) - crate_name = "tesla coil crate" - crate_type = /obj/structure/closet/crate/engineering/electrical - -/datum/supply_pack/engine/tesla_gen - name = "Tesla Generator Crate" - desc = "The key to unlocking the power of the Tesla energy ball. Particle Accelerator not included." - cost = 5000 - contains = list(/obj/machinery/the_singularitygen/tesla) - crate_name = "tesla generator crate" - -////////////////////////////////////////////////////////////////////////////// -/////////////////////// Canisters & Materials //////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -/datum/supply_pack/materials - group = "Canisters & Materials" - -/datum/supply_pack/materials/cardboard50 - name = "50 Cardboard Sheets" - desc = "Create a bunch of boxes." - cost = 1000 - contains = list(/obj/item/stack/sheet/cardboard/fifty) - crate_name = "cardboard sheets crate" - -/datum/supply_pack/materials/glass50 - name = "50 Glass Sheets" - desc = "Let some nice light in with fifty glass sheets!" - cost = 1000 - contains = list(/obj/item/stack/sheet/glass/fifty) - crate_name = "glass sheets crate" - -/datum/supply_pack/materials/metal50 - name = "50 Metal Sheets" - desc = "Any construction project begins with a good stack of fifty metal sheets!" - cost = 1000 - contains = list(/obj/item/stack/sheet/metal/fifty) - crate_name = "metal sheets crate" - -/datum/supply_pack/materials/plasteel20 - name = "20 Plasteel Sheets" - desc = "Reinforce the station's integrity with twenty plasteel sheets!" - cost = 7500 - contains = list(/obj/item/stack/sheet/plasteel/twenty) - crate_name = "plasteel sheets crate" - -/datum/supply_pack/materials/plasteel50 - name = "50 Plasteel Sheets" - desc = "For when you REALLY have to reinforce something." - cost = 16500 - contains = list(/obj/item/stack/sheet/plasteel/fifty) - crate_name = "plasteel sheets crate" - -/datum/supply_pack/materials/plastic50 - name = "50 Plastic Sheets" - desc = "Build a limitless amount of toys with fifty plastic sheets!" - cost = 1000 - contains = list(/obj/item/stack/sheet/plastic/fifty) - crate_name = "plastic sheets crate" - -/datum/supply_pack/materials/sandstone30 - name = "30 Sandstone Blocks" - desc = "Neither sandy nor stoney, these thirty blocks will still get the job done." - cost = 1000 - contains = list(/obj/item/stack/sheet/mineral/sandstone/thirty) - crate_name = "sandstone blocks crate" - -/datum/supply_pack/materials/wood50 - name = "50 Wood Planks" - desc = "Turn cargo's boring metal groundwork into beautiful panelled flooring and much more with fifty wooden planks!" - cost = 2000 - contains = list(/obj/item/stack/sheet/mineral/wood/fifty) - crate_name = "wood planks crate" - -/datum/supply_pack/materials/rcdammo - name = "Spare RDC ammo" - desc = "This crate contains sixteen RCD ammo packs, to help with any holes or projects people mite be working on." - cost = 3750 - contains = list(/obj/item/rcd_ammo, - /obj/item/rcd_ammo, - /obj/item/rcd_ammo, - /obj/item/rcd_ammo, - /obj/item/rcd_ammo, - /obj/item/rcd_ammo, - /obj/item/rcd_ammo, - /obj/item/rcd_ammo, - /obj/item/rcd_ammo, - /obj/item/rcd_ammo, - /obj/item/rcd_ammo, - /obj/item/rcd_ammo, - /obj/item/rcd_ammo, - /obj/item/rcd_ammo, - /obj/item/rcd_ammo, - /obj/item/rcd_ammo) - crate_name = "rcd ammo" - -/datum/supply_pack/materials/bz - name = "BZ Canister Crate" - desc = "Contains a canister of BZ. Requires Toxins access to open." - cost = 7500 // Costs 3 credits more than what you can get for selling it. - access = ACCESS_TOX_STORAGE - contains = list(/obj/machinery/portable_atmospherics/canister/bz) - crate_name = "BZ canister crate" - crate_type = /obj/structure/closet/crate/secure/science - -/datum/supply_pack/materials/carbon_dio - name = "Carbon Dioxide Canister" - desc = "Contains a canister of Carbon Dioxide." - cost = 3000 - contains = list(/obj/machinery/portable_atmospherics/canister/carbon_dioxide) - crate_name = "carbon dioxide canister crate" - crate_type = /obj/structure/closet/crate/large - -/datum/supply_pack/materials/nitrogen - name = "Nitrogen Canister" - desc = "Contains a canister of Nitrogen." - cost = 2000 - contains = list(/obj/machinery/portable_atmospherics/canister/nitrogen) - crate_name = "nitrogen canister crate" - crate_type = /obj/structure/closet/crate/large - -/datum/supply_pack/materials/nitrous_oxide_canister - name = "Nitrous Oxide Canister" - desc = "Contains a canister of Nitrous Oxide. Requires Atmospherics access to open." - cost = 3000 - access = ACCESS_ATMOSPHERICS - contains = list(/obj/machinery/portable_atmospherics/canister/nitrous_oxide) - crate_name = "nitrous oxide canister crate" - crate_type = /obj/structure/closet/crate/secure - -/datum/supply_pack/materials/oxygen - name = "Oxygen Canister" - desc = "Contains a canister of Oxygen. Canned in Druidia." - cost = 1500 - contains = list(/obj/machinery/portable_atmospherics/canister/oxygen) - crate_name = "oxygen canister crate" - crate_type = /obj/structure/closet/crate/large - -/datum/supply_pack/materials/water_vapor - name = "Water Vapor Canister" - desc = "Contains a canister of Water Vapor. I swear to god if you open this in the halls..." - cost = 2500 - contains = list(/obj/machinery/portable_atmospherics/canister/water_vapor) - crate_name = "water vapor canister crate" - crate_type = /obj/structure/closet/crate/large - -/datum/supply_pack/materials/fueltank - name = "Fuel Tank Crate" - desc = "Contains a welding fuel tank. Caution, highly flammable." - cost = 800 - contains = list(/obj/structure/reagent_dispensers/fueltank) - crate_name = "fuel tank crate" - crate_type = /obj/structure/closet/crate/large - -/datum/supply_pack/materials/watertank - name = "Water Tank Crate" - desc = "Contains a tank of dihydrogen monoxide... sounds dangerous." - cost = 600 - contains = list(/obj/structure/reagent_dispensers/watertank) - crate_name = "water tank crate" - crate_type = /obj/structure/closet/crate/large - -/datum/supply_pack/materials/foamtank - name = "Firefighting Foam Tank Crate" - desc = "Contains a tank of firefighting foam. Also known as \"plasmaman's bane\"." - cost = 1500 - contains = list(/obj/structure/reagent_dispensers/foamtank) - crate_name = "foam tank crate" - crate_type = /obj/structure/closet/crate/large - -/datum/supply_pack/materials/hightank - name = "Large Water Tank Crate" - desc = "Contains a high-capacity water tank. Useful for botany or other service jobs." - cost = 1200 - contains = list(/obj/structure/reagent_dispensers/watertank/high) - crate_name = "high-capacity water tank crate" - crate_type = /obj/structure/closet/crate/large - -////////////////////////////////////////////////////////////////////////////// -//////////////////////////// Medical ///////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -/datum/supply_pack/medical - group = "Medical" - crate_type = /obj/structure/closet/crate/medical - -/datum/supply_pack/medical/firstaidbruises - name = "Bruise Treatment Kit Crate" - desc = "Contains three first aid kits focused on healing bruises and broken bones." - cost = 1000 - contains = list(/obj/item/storage/firstaid/brute, - /obj/item/storage/firstaid/brute, - /obj/item/storage/firstaid/brute) - crate_name = "brute treatment kit crate" - -/datum/supply_pack/medical/firstaidburns - name = "Burn Treatment Kit Crate" - desc = "Contains three first aid kits focused on healing severe burns." - cost = 1000 - contains = list(/obj/item/storage/firstaid/fire, - /obj/item/storage/firstaid/fire, - /obj/item/storage/firstaid/fire) - crate_name = "burn treatment kit crate" - -/datum/supply_pack/medical/bloodpacks - name = "Blood Pack Variety Crate" - desc = "Contains eight different blood packs for reintroducing blood to patients." - cost = 3000 - contains = list(/obj/item/reagent_containers/blood, - /obj/item/reagent_containers/blood, - /obj/item/reagent_containers/blood/APlus, - /obj/item/reagent_containers/blood/AMinus, - /obj/item/reagent_containers/blood/BPlus, - /obj/item/reagent_containers/blood/BMinus, - /obj/item/reagent_containers/blood/OPlus, - /obj/item/reagent_containers/blood/OMinus, - /obj/item/reagent_containers/blood/lizard) - crate_name = "blood freezer" - crate_type = /obj/structure/closet/crate/freezer - -/datum/supply_pack/medical/defibs - name = "Defibrillator Crate" - desc = "Contains two defibrillators for bringing the recently deceased back to life." - cost = 2500 - contains = list(/obj/item/defibrillator/loaded, - /obj/item/defibrillator/loaded) - crate_name = "defibrillator crate" - -/datum/supply_pack/medical/firstaid - name = "First Aid Kit Crate" - desc = "Contains four first aid kits for healing most types of wounds." - cost = 1000 - contains = list(/obj/item/storage/firstaid/regular, - /obj/item/storage/firstaid/regular, - /obj/item/storage/firstaid/regular, - /obj/item/storage/firstaid/regular) - crate_name = "first aid kit crate" - -/datum/supply_pack/medical/iv_drip - name = "IV Drip Crate" - desc = "Contains a single IV drip stand for intravenous delivery." - cost = 700 - contains = list(/obj/machinery/iv_drip) - crate_name = "iv drip crate" - -/datum/supply_pack/science/adv_surgery_tools - name = "Med-Co Advanced surgery tools" - desc = "A full set of Med-Co advanced surgery tools, this crate also comes with a spay of synth flesh as well as a can of . Requires Surgery access to open." - cost = 5000 - access = ACCESS_SURGERY - contains = list(/obj/item/storage/belt/medical/surgery_belt_adv, - /obj/item/reagent_containers/medspray/synthflesh, - /obj/item/reagent_containers/medspray/sterilizine) - crate_name = "medco newest surgery tools" - crate_type = /obj/structure/closet/crate/medical - -/datum/supply_pack/medical/medicalhardsuit - name = "Medical Hardsuit" - desc = "Got people being spaced left and right? Hole in the same room as the dead body of Hos or cap? Fear not, now you can buy one medical hardsuit with a mask and air tank to save your fellow crewmembers." - cost = 2500 - contains = list(/obj/item/tank/internals/air, - /obj/item/clothing/mask/gas, - /obj/item/clothing/suit/space/hardsuit/medical) - crate_name = "medical hardsuit" - -/datum/supply_pack/medical/supplies - name = "Medical Supplies Crate" - desc = "Contains seven beakers, syringes, and bodybags. Three morphine bottles, four insulin pills. Two charcoal bottles, epinephrine bottles, antitoxin bottles, and large beakers. Finally, a single roll of medical gauze, as well as a bottle of stimulant pills for long, hard work days. German doctor not included." - cost = 2500 - contains = list(/obj/item/reagent_containers/glass/bottle/charcoal, - /obj/item/reagent_containers/glass/bottle/charcoal, - /obj/item/reagent_containers/glass/bottle/epinephrine, - /obj/item/reagent_containers/glass/bottle/epinephrine, - /obj/item/reagent_containers/glass/bottle/morphine, - /obj/item/reagent_containers/glass/bottle/morphine, - /obj/item/reagent_containers/glass/bottle/morphine, - /obj/item/reagent_containers/glass/bottle/toxin, - /obj/item/reagent_containers/glass/bottle/toxin, - /obj/item/reagent_containers/glass/beaker/large, - /obj/item/reagent_containers/glass/beaker/large, - /obj/item/reagent_containers/pill/insulin, - /obj/item/reagent_containers/pill/insulin, - /obj/item/reagent_containers/pill/insulin, - /obj/item/reagent_containers/pill/insulin, - /obj/item/stack/medical/gauze, - /obj/item/storage/box/beakers, - /obj/item/storage/box/medsprays, - /obj/item/storage/box/syringes, - /obj/item/storage/box/bodybags, - /obj/item/storage/pill_bottle/stimulant) - crate_name = "medical supplies crate" - -/datum/supply_pack/medical/vending - name = "Medical Vending Crate" - desc = "Contains refills for medical vending machines." - cost = 2000 - contains = list(/obj/item/vending_refill/medical, - /obj/item/vending_refill/wallmed) - crate_name = "medical vending crate" - -/datum/supply_pack/medical/sprays - name = "Medical Sprays" - desc = "Contains two cans of Styptic Spray, Silver Sulfadiazine Spray, Synthflesh Spray and Sterilizer Compound Spray." - cost = 2500 - contains = list(/obj/item/reagent_containers/medspray/styptic, - /obj/item/reagent_containers/medspray/styptic, - /obj/item/reagent_containers/medspray/silver_sulf, - /obj/item/reagent_containers/medspray/silver_sulf, - /obj/item/reagent_containers/medspray/synthflesh, - /obj/item/reagent_containers/medspray/synthflesh, - /obj/item/reagent_containers/medspray/sterilizine, - /obj/item/reagent_containers/medspray/sterilizine) - crate_name = "medical supplies crate" - -/datum/supply_pack/medical/firstaidmixed - name = "Mixed Medical Kits" - desc = "Contains one of each medical kits for dealing with a variety of injured crewmembers." - cost = 1500 - contains = list(/obj/item/storage/firstaid/toxin, - /obj/item/storage/firstaid/o2, - /obj/item/storage/firstaid/brute, - /obj/item/storage/firstaid/fire, - /obj/item/storage/firstaid/regular) - crate_name = "medical supplies crate" - -/datum/supply_pack/medical/firstaidoxygen - name = "Oxygen Deprivation Kit Crate" - desc = "Contains three first aid kits focused on helping oxygen deprivation victims." - cost = 1000 - contains = list(/obj/item/storage/firstaid/o2, - /obj/item/storage/firstaid/o2, - /obj/item/storage/firstaid/o2) - crate_name = "oxygen deprivation kit crate" - -/datum/supply_pack/medical/advrad - name = "Radiation Treatment Crate Deluxe" - desc = "A crate for when radiation is out of hand... Contains two rad-b-gone kits, one bottle of anti radiation deluxe pill bottle, as well as a radiation treatment deluxe pill bottle!" - cost = 3500 - contains = list(/obj/item/storage/pill_bottle/antirad_plus, - /obj/item/storage/pill_bottle/mutarad, - /obj/item/storage/firstaid/radbgone, - /obj/item/storage/firstaid/radbgone, - /obj/item/geiger_counter, - /obj/item/geiger_counter) - crate_name = "radiation protection crate" - crate_type = /obj/structure/closet/crate/radiation - -/datum/supply_pack/medical/surgery - name = "Surgical Supplies Crate" - desc = "Do you want to perform surgery, but don't have one of those fancy shmancy degrees? Just get started with this crate containing a medical duffelbag, Sterilizine spray and collapsible roller bed." - cost = 1000 - contains = list(/obj/item/storage/backpack/duffelbag/med/surgery, - /obj/item/reagent_containers/medspray/sterilizine, - /obj/item/roller) - crate_name = "surgical supplies crate" - -/datum/supply_pack/medical/firstaidtoxins - name = "Toxin Treatment Kit Crate" - desc = "Contains three first aid kits focused on healing damage dealt by heavy toxins." - cost = 1000 - contains = list(/obj/item/storage/firstaid/toxin, - /obj/item/storage/firstaid/toxin, - /obj/item/storage/firstaid/toxin) - crate_name = "toxin treatment kit crate" - -/datum/supply_pack/medical/virus - name = "Virus Crate" - desc = "Contains twelve different bottles, containing several viral samples for virology research. Also includes seven beakers and syringes. Balled-up jeans not included. Requires CMO access to open." - cost = 2500 - access = ACCESS_CMO - contains = list(/obj/item/reagent_containers/glass/bottle/flu_virion, - /obj/item/reagent_containers/glass/bottle/cold, - /obj/item/reagent_containers/glass/bottle/random_virus, - /obj/item/reagent_containers/glass/bottle/random_virus, - /obj/item/reagent_containers/glass/bottle/random_virus, - /obj/item/reagent_containers/glass/bottle/random_virus, - /obj/item/reagent_containers/glass/bottle/fake_gbs, - /obj/item/reagent_containers/glass/bottle/magnitis, - /obj/item/reagent_containers/glass/bottle/pierrot_throat, - /obj/item/reagent_containers/glass/bottle/brainrot, - /obj/item/reagent_containers/glass/bottle/anxiety, - /obj/item/reagent_containers/glass/bottle/beesease, - /obj/item/storage/box/syringes, - /obj/item/storage/box/beakers, - /obj/item/reagent_containers/glass/bottle/mutagen) - crate_name = "virus crate" - crate_type = /obj/structure/closet/crate/secure/plasma - dangerous = TRUE - - -////////////////////////////////////////////////////////////////////////////// -//////////////////////////// Science ///////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -/datum/supply_pack/science - group = "Science" - crate_type = /obj/structure/closet/crate/science - -/datum/supply_pack/science/robotics/mecha_odysseus - name = "Circuit Crate (Odysseus)" - desc = "Ever wanted to build your own giant medical robot? Well, now you can! Contains the Odysseus main control board and Odysseus peripherals board. Requires Robotics access to open." - cost = 2500 - access = ACCESS_ROBOTICS - contains = list(/obj/item/circuitboard/mecha/odysseus/peripherals, - /obj/item/circuitboard/mecha/odysseus/main) - crate_name = "\improper Odysseus circuit crate" - crate_type = /obj/structure/closet/crate/secure/science - -/datum/supply_pack/science/robotics/mecha_ripley - name = "Circuit Crate (Ripley APLU)" - desc = "Rip apart rocks and xenomorphs alike with the Ripley APLU. Contains the Main Ripley control board, as well as the Ripley Peripherals board. Requires Robotics access to open." - cost = 3000 - access = ACCESS_ROBOTICS - contains = list(/obj/item/book/manual/ripley_build_and_repair, - /obj/item/circuitboard/mecha/ripley/main, - /obj/item/circuitboard/mecha/ripley/peripherals) - crate_name = "\improper APLU Ripley circuit crate" - crate_type = /obj/structure/closet/crate/secure/science - -/datum/supply_pack/science/circuitry - name = "Circuitry Starter Pack Crate" - desc = "Journey into the mysterious world of Circuitry with this starter pack. Contains a circuit printer, analyzer, debugger and wirer. Power cells not included." - cost = 1000 - contains = list(/obj/item/integrated_electronics/analyzer, - /obj/item/integrated_circuit_printer, - /obj/item/integrated_electronics/debugger, - /obj/item/integrated_electronics/wirer) - crate_name = "circuitry starter pack crate" - -/datum/supply_pack/science/plasma - name = "Plasma Assembly Crate" - desc = "Everything you need to burn something to the ground, this contains three plasma assembly sets. Each set contains a plasma tank, igniter, proximity sensor, and timer! Warranty void if exposed to high temperatures. Requires Toxins access to open." - cost = 1000 - access = ACCESS_TOX_STORAGE - contains = list(/obj/item/tank/internals/plasma, - /obj/item/tank/internals/plasma, - /obj/item/tank/internals/plasma, - /obj/item/assembly/igniter, - /obj/item/assembly/igniter, - /obj/item/assembly/igniter, - /obj/item/assembly/prox_sensor, - /obj/item/assembly/prox_sensor, - /obj/item/assembly/prox_sensor, - /obj/item/assembly/timer, - /obj/item/assembly/timer, - /obj/item/assembly/timer) - crate_name = "plasma assembly crate" - crate_type = /obj/structure/closet/crate/secure/plasma - -/datum/supply_pack/science/robotics - name = "Robotics Assembly Crate" - desc = "The tools you need to replace those finicky humans with a loyal robot army! Contains three proximity sensors, two high-powered cells, six flashes, and an electrical toolbox. Requires Robotics access to open." - cost = 1000 - access = ACCESS_ROBOTICS - contains = list(/obj/item/assembly/prox_sensor, - /obj/item/assembly/prox_sensor, - /obj/item/assembly/prox_sensor, - /obj/item/storage/toolbox/electrical, - /obj/item/storage/box/flashes, - /obj/item/stock_parts/cell/high, - /obj/item/stock_parts/cell/high) - crate_name = "robotics assembly crate" - crate_type = /obj/structure/closet/crate/secure/science - -/datum/supply_pack/science/shieldwalls - name = "Shield Generator Crate" - desc = "These high powered Shield Wall Generators are guaranteed to keep any unwanted lifeforms on the outside, where they belong! Contains four shield wall generators. Requires Teleporter access to open." - cost = 2000 - access = ACCESS_TELEPORTER - contains = list(/obj/machinery/shieldwallgen, - /obj/machinery/shieldwallgen, - /obj/machinery/shieldwallgen, - /obj/machinery/shieldwallgen) - crate_name = "shield generators crate" - crate_type = /obj/structure/closet/crate/secure/science - -/datum/supply_pack/science/tablets - name = "Tablet Crate" - desc = "What's a computer? Contains five cargo tablets." - cost = 5000 - contains = list(/obj/item/modular_computer/tablet/preset/cargo, - /obj/item/modular_computer/tablet/preset/cargo, - /obj/item/modular_computer/tablet/preset/cargo, - /obj/item/modular_computer/tablet/preset/cargo, - /obj/item/modular_computer/tablet/preset/cargo) - crate_name = "tablet crate" - -/datum/supply_pack/science/transfer_valves - name = "Tank Transfer Valves Crate" - desc = "The key ingredient for making a lot of people very angry very fast. Contains two tank transfer valves. Requires RD access to open." - cost = 6000 - access = ACCESS_RD - contains = list(/obj/item/transfer_valve, - /obj/item/transfer_valve) - crate_name = "tank transfer valves crate" - crate_type = /obj/structure/closet/crate/secure/science - dangerous = TRUE - -/datum/supply_pack/science/tech_slugs - name = "Tech Slug Ammo Shells" - desc = "A new type of shell that is able to be made into a few different dangerous types. Contains two boxes of tech slugs, 14 shells in all." - cost = 1000 - contains = list(/obj/item/storage/box/techsslug, - /obj/item/storage/box/techsslug) - crate_name = "tech slug crate" - - -////////////////////////////////////////////////////////////////////////////// -/////////////////////////////// Service ////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -/datum/supply_pack/service - group = "Service" - -/datum/supply_pack/service/advlighting - name = "Advanced Lighting crate" - desc = "Thanks to advanced lighting tech we here at the Lamp Factory have be able to produce more lamps and lamp items! This crate has three lamps, a box of lights and a state of the art rapid-light-device!" - cost = 2500 //Fair - contains = list(/obj/item/construction/rld, - /obj/item/flashlight/lamp, - /obj/item/flashlight/lamp, - /obj/item/flashlight/lamp/green, - /obj/item/storage/box/lights/mixed) - crate_name = "advanced lighting crate" - crate_type = /obj/structure/closet/crate/secure - -/datum/supply_pack/service/cargo_supples - name = "Cargo Supplies Crate" - desc = "Sold everything that wasn't bolted down? You can get right back to work with this crate containing stamps, an export scanner, destination tagger, hand labeler and some package wrapping." - cost = 1000 - contains = list(/obj/item/stamp, - /obj/item/stamp/denied, - /obj/item/export_scanner, - /obj/item/destTagger, - /obj/item/hand_labeler, - /obj/item/stack/packageWrap) - crate_name = "cargo supplies crate" - -/datum/supply_pack/service/food_cart - name = "Food Cart Crate" - desc = "Want to sell food on the go? Cook lost their cart? Well we just so happen to have a few carts to spare!" - cost = 1000 - contains = list(/obj/machinery/food_cart) - crate_name = "food cart crate" - crate_type = /obj/structure/closet/crate - -/datum/supply_pack/service/noslipfloor - name = "High-traction Floor Tiles" - desc = "Make slipping a thing of the past with sixty industrial-grade anti-slip floortiles!" - cost = 2000 - contains = list(/obj/item/stack/tile/noslip/thirty, - /obj/item/stack/tile/noslip/thirty) - crate_name = "high-traction floor tiles crate" - -/datum/supply_pack/service/icecream_cart - name = "Ice Cream Cart Crate" - desc = "Plasma fire a to hot for you, want a nice treat after a hard days work? Well now we have the cart for you! This Ice Cream Vat has everthing you need to make you and your friends so ice cream treats! This cart comes stocked with some ingredients for each type of scoopable icecream." - cost = 2750 //Comes prestocked with basic ingredients - contains = list(/obj/machinery/icecream_vat) - crate_name = "ice cream vat crate" - crate_type = /obj/structure/closet/crate - -/datum/supply_pack/service/janitor - name = "Janitorial Supplies Crate" - desc = "Fight back against dirt and grime with Nanotrasen's Janitorial Essentials(tm)! Contains three buckets, caution signs, and cleaner grenades. Also has a single mop, spray cleaner, rag, NT soap and a trash bag." - cost = 1000 - contains = list(/obj/item/reagent_containers/glass/bucket, - /obj/item/reagent_containers/glass/bucket, - /obj/item/reagent_containers/glass/bucket, - /obj/item/mop, - /obj/item/caution, - /obj/item/caution, - /obj/item/caution, - /obj/item/storage/bag/trash, - /obj/item/reagent_containers/spray/cleaner, - /obj/item/reagent_containers/rag, - /obj/item/grenade/chem_grenade/cleaner, - /obj/item/grenade/chem_grenade/cleaner, - /obj/item/grenade/chem_grenade/cleaner, - /obj/item/soap/nanotrasen) - crate_name = "janitorial supplies crate" - -/datum/supply_pack/service/janitor/janicart - name = "Janitorial Cart and Galoshes Crate" - desc = "The keystone to any successful janitor. As long as you have feet, this pair of galoshes will keep them firmly planted on the ground. Also contains a janitorial cart." - cost = 2000 - contains = list(/obj/structure/janitorialcart, - /obj/item/clothing/shoes/galoshes) - crate_name = "janitorial cart crate" - crate_type = /obj/structure/closet/crate/large - -/datum/supply_pack/service/janitor/janitank - name = "Janitor Backpack Crate" - desc = "Call forth divine judgement upon dirt and grime with this high capacity janitor backpack. Contains 500 units of station-cleansing cleaner. Requires janitor access to open." - cost = 1000 - access = ACCESS_JANITOR - contains = list(/obj/item/watertank/janitor) - crate_name = "janitor backpack crate" - crate_type = /obj/structure/closet/crate/secure - -/datum/supply_pack/service/janitor/janpremium - name = "Janitor Premium Supplies" - desc = "Do to the union for better supplies, we have desided to make a deal for you, In this crate you can get a brand new chem, Drying Angent this stuff is the work of slimes or magic! This crate also contains a rag to test out the Drying Angent magic, three wet floor signs, and some spare bottles of ammonia." - cost = 3000 - access = ACCESS_JANITOR - contains = list(/obj/item/caution, - /obj/item/caution, - /obj/item/caution, - /obj/item/reagent_containers/rag, - /obj/item/reagent_containers/glass/bottle/ammonia, - /obj/item/reagent_containers/glass/bottle/ammonia, - /obj/item/reagent_containers/spray/drying_agent) - crate_name = "janitor backpack crate" - -/datum/supply_pack/service/mule - name = "MULEbot Crate" - desc = "Pink-haired Quartermaster not doing her job? Replace her with this tireless worker, today!" - cost = 2000 - contains = list(/mob/living/simple_animal/bot/mulebot) - crate_name = "\improper MULEbot Crate" - crate_type = /obj/structure/closet/crate/large - -/datum/supply_pack/service/party - name = "Party Equipment" - desc = "Celebrate both life and death on the station with Nanotrasen's Party Essentials(tm)! Contains seven colored glowsticks, four beers, two ales, and a bottle of patron, goldschlager, and shaker!" - cost = 2000 - contains = list(/obj/item/storage/box/drinkingglasses, - /obj/item/reagent_containers/food/drinks/shaker, - /obj/item/reagent_containers/food/drinks/bottle/patron, - /obj/item/reagent_containers/food/drinks/bottle/goldschlager, - /obj/item/reagent_containers/food/drinks/ale, - /obj/item/reagent_containers/food/drinks/ale, - /obj/item/reagent_containers/food/drinks/beer, - /obj/item/reagent_containers/food/drinks/beer, - /obj/item/reagent_containers/food/drinks/beer, - /obj/item/reagent_containers/food/drinks/beer, - /obj/item/flashlight/glowstick, - /obj/item/flashlight/glowstick/red, - /obj/item/flashlight/glowstick/blue, - /obj/item/flashlight/glowstick/cyan, - /obj/item/flashlight/glowstick/orange, - /obj/item/flashlight/glowstick/yellow, - /obj/item/flashlight/glowstick/pink) - crate_name = "party equipment crate" - -/datum/supply_pack/service/carpet - name = "Premium Carpet Crate" - desc = "Plasteel floor tiles getting on your nerves? These stacks of extra soft carpet will tie any room together. Contains the classics." - cost = 1000 - contains = list(/obj/item/stack/tile/carpet/fifty, - /obj/item/stack/tile/carpet/fifty, - /obj/item/stack/tile/carpet/black/fifty, - /obj/item/stack/tile/carpet/black/fifty) - crate_name = "premium carpet crate" - -/datum/supply_pack/service/carpet2 - name = "Premium Carpet Crate #2" - desc = "Plasteel floor tiles getting on your nerves? These stacks of extra soft carpet will tie any room together. Contains red, and monochrome" - cost = 1000 - contains = list(/obj/item/stack/tile/carpet/blackred/fifty, - /obj/item/stack/tile/carpet/blackred/fifty, - /obj/item/stack/tile/carpet/monochrome/fifty, - /obj/item/stack/tile/carpet/monochrome/fifty) - crate_name = "premium carpet crate #2" - -/datum/supply_pack/service/lightbulbs - name = "Replacement Lights" - desc = "May the light of Aether shine upon this station! Or at least, the light of forty two light tubes and twenty one light bulbs as well as a light replacer." - cost = 1200 - contains = list(/obj/item/storage/box/lights/mixed, - /obj/item/storage/box/lights/mixed, - /obj/item/storage/box/lights/mixed, - /obj/item/lightreplacer) - crate_name = "replacement lights" - -/datum/supply_pack/service/minerkit - name = "Shaft Miner Starter Kit" - desc = "All the miners died too fast? Assistant wants to get a taste of life off-station? Either way, this kit is the best way to turn a regular crewman into an ore-producing, monster-slaying machine. Contains meson goggles, a pickaxe, advanced mining scanner, cargo headset, ore bag, gasmask, and explorer suit. Requires QM access to open." - cost = 2500 - access = ACCESS_QM - contains = list(/obj/item/pickaxe/mini, - /obj/item/clothing/glasses/meson, - /obj/item/t_scanner/adv_mining_scanner/lesser, - /obj/item/radio/headset/headset_cargo/mining, - /obj/item/storage/bag/ore, - /obj/item/clothing/suit/hooded/explorer/standard, - /obj/item/clothing/mask/gas/explorer) - crate_name = "shaft miner starter kit" - crate_type = /obj/structure/closet/crate/secure - -////////////////////////////////////////////////////////////////////////////// -/////////////////////////// Vending Restocks ///////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -/datum/supply_pack/service/vending/bartending - name = "Bartending Supply Crate" - desc = "Bring on the booze with vending machine refills, as well as a free book containing the well-kept secrets to the bartending trade!" - cost = 2000 - contains = list(/obj/item/vending_refill/boozeomat, - /obj/item/vending_refill/coffee, - /obj/item/book/granter/action/drink_fling) - crate_name = "bartending supply crate" - -/datum/supply_pack/service/vending/cigarette - name = "Cigarette Supply Crate" - desc = "Don't believe the reports - smoke today! Contains a cigarette vending machine refill." - cost = 1500 - contains = list(/obj/item/vending_refill/cigarette) - crate_name = "cigarette supply crate" - crate_type = /obj/structure/closet/crate - -/datum/supply_pack/service/vending/games - name = "Games Supply Crate" - desc = "Get your game on with this game vending machine refill." - cost = 1000 - contains = list(/obj/item/vending_refill/games) - crate_name = "games supply crate" - crate_type = /obj/structure/closet/crate - -/datum/supply_pack/service/vending/snack - name = "Snack Supply Crate" - desc = "One vending machine refill of cavity-bringin' goodness! The number one dentist recommended order!" - cost = 1500 - contains = list(/obj/item/vending_refill/snack) - crate_name = "snacks supply crate" - -/datum/supply_pack/service/vending/cola - name = "Softdrinks Supply Crate" - desc = "Got whacked by a toolbox, but you still have those pesky teeth? Get rid of those pearly whites with this soda machine refill, today!" - cost = 1500 - contains = list(/obj/item/vending_refill/cola) - crate_name = "soft drinks supply crate" - -////////////////////////////////////////////////////////////////////////////// -//////////////////////////// Organic ///////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -/datum/supply_pack/organic - group = "Food & Hydroponics" - crate_type = /obj/structure/closet/crate/freezer - -/datum/supply_pack/organic/hydroponics/beekeeping_suits - name = "Beekeeper Suit Crate" - desc = "Bee business booming? Better be benevolent and boost botany by bestowing bi-Beekeeper-suits! Contains two beekeeper suits and matching headwear." - cost = 1000 - contains = list(/obj/item/clothing/head/beekeeper_head, - /obj/item/clothing/suit/beekeeper_suit, - /obj/item/clothing/head/beekeeper_head, - /obj/item/clothing/suit/beekeeper_suit) - crate_name = "beekeeper suits" - crate_type = /obj/structure/closet/crate/hydroponics - -/datum/supply_pack/organic/hydroponics/beekeeping_fullkit - name = "Beekeeping Starter Crate" - desc = "BEES BEES BEES. Contains three honey frames, a beekeeper suit and helmet, flyswatter, bee house, and, of course, a pure-bred Nanotrasen-Standardized Queen Bee!" - cost = 1500 - contains = list(/obj/structure/beebox/unwrenched, - /obj/item/honey_frame, - /obj/item/honey_frame, - /obj/item/honey_frame, - /obj/item/queen_bee/bought, - /obj/item/clothing/head/beekeeper_head, - /obj/item/clothing/suit/beekeeper_suit, - /obj/item/melee/flyswatter) - crate_name = "beekeeping starter crate" - crate_type = /obj/structure/closet/crate/hydroponics - -/datum/supply_pack/organic/candy - name = "Candy Crate" - desc = "For people that have a insatiable sweet tooth! Has ten candies to be eaten up.." - cost = 2500 - var/num_contained = 10 //number of items picked to be contained in a randomised crate - contains = list(/obj/item/reagent_containers/food/snacks/candy, - /obj/item/reagent_containers/food/snacks/lollipop, - /obj/item/reagent_containers/food/snacks/gumball, - /obj/item/reagent_containers/food/snacks/chocolateegg, - /obj/item/reagent_containers/food/snacks/donut, - /obj/item/reagent_containers/food/snacks/cookie, - /obj/item/reagent_containers/food/snacks/sugarcookie, - /obj/item/reagent_containers/food/snacks/chococornet, - /obj/item/reagent_containers/food/snacks/mint, - /obj/item/reagent_containers/food/snacks/spiderlollipop, - /obj/item/reagent_containers/food/snacks/chococoin, - /obj/item/reagent_containers/food/snacks/fudgedice, - /obj/item/reagent_containers/food/snacks/chocoorange, - /obj/item/reagent_containers/food/snacks/honeybar, - /obj/item/reagent_containers/food/snacks/tinychocolate, - /obj/item/reagent_containers/food/snacks/spacetwinkie, - /obj/item/reagent_containers/food/snacks/syndicake, - /obj/item/reagent_containers/food/snacks/cheesiehonkers, - /obj/item/reagent_containers/food/snacks/sugarcookie/spookyskull, - /obj/item/reagent_containers/food/snacks/sugarcookie/spookycoffin, - /obj/item/reagent_containers/food/snacks/candy_corn, - /obj/item/reagent_containers/food/snacks/candiedapple, - /obj/item/reagent_containers/food/snacks/chocolatebar, - /obj/item/reagent_containers/food/snacks/candyheart, - /obj/item/storage/fancy/heart_box, - /obj/item/storage/fancy/donut_box) - crate_name = "candy crate" - -/datum/supply_pack/organic/cutlery - name = "Kitchen Cutlery Deluxe Set" - desc = "Need to slice and dice away those ''Tomatos'' well we got what you need! From a nice set of knifes, forks, plates, glasses, and a whetstone for when you got some grizzle that is a bit harder to slice then normal." - cost = 10000 - contraband = TRUE - contains = list(/obj/item/sharpener, - /obj/item/kitchen/fork, - /obj/item/kitchen/fork, - /obj/item/kitchen/knife, - /obj/item/kitchen/knife, - /obj/item/kitchen/knife, - /obj/item/kitchen/knife, - /obj/item/kitchen/knife/butcher, - /obj/item/kitchen/knife/butcher, - /obj/item/kitchen/rollingpin, //Deluxe for a reason - /obj/item/trash/plate, - /obj/item/trash/plate, - /obj/item/trash/plate, - /obj/item/trash/plate, - /obj/item/reagent_containers/food/drinks/drinkingglass, - /obj/item/reagent_containers/food/drinks/drinkingglass, - /obj/item/reagent_containers/food/drinks/drinkingglass, - /obj/item/reagent_containers/food/drinks/drinkingglass/shotglass, - /obj/item/reagent_containers/food/drinks/drinkingglass/shotglass) - crate_name = "kitchen cutlery deluxe set" - -/datum/supply_pack/organic/food - name = "Food Crate" - desc = "Get things cooking with this crate full of useful ingredients! Contains a two dozen eggs, three bananas, and two bags of flour and rice, two cartons of milk, soymilk, as well as salt and pepper shakers, a enzyme and sugar bottle, and three slabs of monkeymeat." - cost = 1000 - contains = list(/obj/item/reagent_containers/food/condiment/flour, - /obj/item/reagent_containers/food/condiment/flour, - /obj/item/reagent_containers/food/condiment/rice, - /obj/item/reagent_containers/food/condiment/rice, - /obj/item/reagent_containers/food/condiment/milk, - /obj/item/reagent_containers/food/condiment/milk, - /obj/item/reagent_containers/food/condiment/soymilk, - /obj/item/reagent_containers/food/condiment/saltshaker, - /obj/item/reagent_containers/food/condiment/peppermill, - /obj/item/storage/fancy/egg_box, - /obj/item/storage/fancy/egg_box, - /obj/item/reagent_containers/food/condiment/enzyme, - /obj/item/reagent_containers/food/condiment/sugar, - /obj/item/reagent_containers/food/snacks/meat/slab/monkey, - /obj/item/reagent_containers/food/snacks/meat/slab/monkey, - /obj/item/reagent_containers/food/snacks/meat/slab/monkey, - /obj/item/reagent_containers/food/snacks/grown/banana, - /obj/item/reagent_containers/food/snacks/grown/banana, - /obj/item/reagent_containers/food/snacks/grown/banana) - crate_name = "food crate" - -/datum/supply_pack/organic/cream_piee - name = "High-yield Clown-grade Cream Pie Crate" - desc = "Designed by Aussec's Advanced Warfare Research Division, these high-yield, Clown-grade cream pies are powered by a synergy of performance and efficiency. Guaranteed to provide maximum results." - cost = 6000 - contains = list(/obj/item/storage/backpack/duffelbag/clown/cream_pie) - crate_name = "party equipment crate" - contraband = TRUE - access = ACCESS_THEATRE - crate_type = /obj/structure/closet/crate/secure - -/datum/supply_pack/organic/hunting - name = "Huntting gear" - desc = "Even in space, we can fine prey to hunt, this crate contains everthing a fine hunter needs to have a sporting time. This crate needs armory access to open. A true huntter only needs a fine bottle of cognac, a nice coat, some good o' cigars, and of cource a huntting shotgun. " - cost = 3500 - contraband = TRUE - contains = list(/obj/item/clothing/head/flatcap, - /obj/item/clothing/suit/hooded/wintercoat/captain, - /obj/item/reagent_containers/food/drinks/bottle/cognac, - /obj/item/storage/fancy/cigarettes/cigars/havana, - /obj/item/clothing/gloves/color/white, - /obj/item/clothing/under/rank/curator, - /obj/item/gun/ballistic/shotgun/lethal) - access = ACCESS_ARMORY - crate_name = "sporting crate" - crate_type = /obj/structure/closet/crate/secure // Would have liked a wooden crate but access >:( - -/datum/supply_pack/organic/hydroponics - name = "Hydroponics Crate" - desc = "Supplies for growing a great garden! Contains two bottles of ammonia, two Plant-B-Gone spray bottles, a hatchet, cultivator, plant analyzer, as well as a pair of leather gloves and a botanist's apron." - cost = 1500 - contains = list(/obj/item/reagent_containers/spray/plantbgone, - /obj/item/reagent_containers/spray/plantbgone, - /obj/item/reagent_containers/glass/bottle/ammonia, - /obj/item/reagent_containers/glass/bottle/ammonia, - /obj/item/hatchet, - /obj/item/cultivator, - /obj/item/plant_analyzer, - /obj/item/clothing/gloves/botanic_leather, - /obj/item/clothing/suit/apron) - crate_name = "hydroponics crate" - crate_type = /obj/structure/closet/crate/hydroponics - -/datum/supply_pack/organic/hydroponics/hydrotank - name = "Hydroponics Backpack Crate" - desc = "Bring on the flood with this high-capacity backpack crate. Contains 500 units of life-giving H2O. Requires hydroponics access to open." - cost = 1000 - access = ACCESS_HYDROPONICS - contains = list(/obj/item/watertank) - crate_name = "hydroponics backpack crate" - crate_type = /obj/structure/closet/crate/secure - -/datum/supply_pack/organic/mre - name = "MRE supply kit (emergency rations)" - desc = "The lights are out. Oxygen's running low. You've run out of food except space weevils. Don't let this be you! Order our NT branded MRE kits today! This pack contains 5 MRE packs with a randomized menu and an oxygen tank." - cost = 2000 - contains = list(/obj/item/storage/box/mre/menu1/safe, - /obj/item/storage/box/mre/menu1/safe, - /obj/item/storage/box/mre/menu2/safe, - /obj/item/storage/box/mre/menu2/safe, - /obj/item/storage/box/mre/menu3) - crate_name = "MRE crate (emergency rations)" - -/datum/supply_pack/organic/pizza - name = "Pizza Crate" - desc = "Best prices on this side of the galaxy. All deliveries are guaranteed to be 99% anomaly-free!" - cost = 6000 // Best prices this side of the galaxy. - contains = list(/obj/item/pizzabox/margherita, - /obj/item/pizzabox/mushroom, - /obj/item/pizzabox/meat, - /obj/item/pizzabox/vegetable, - /obj/item/pizzabox/pineapple) - crate_name = "pizza crate" - var/static/anomalous_box_provided = FALSE - -/datum/supply_pack/organic/pizza/fill(obj/structure/closet/crate/C) - . = ..() - if(!anomalous_box_provided) - for(var/obj/item/pizzabox/P in C) - if(prob(1)) //1% chance for each box, so 4% total chance per order - var/obj/item/pizzabox/infinite/fourfiveeight = new(C) - fourfiveeight.boxtag = P.boxtag - qdel(P) - anomalous_box_provided = TRUE - log_game("An anomalous pizza box was provided in a pizza crate at during cargo delivery") - if(prob(50)) - addtimer(CALLBACK(src, .proc/anomalous_pizza_report), rand(300, 1800)) - else - message_admins("An anomalous pizza box was silently created with no command report in a pizza crate delivery.") - break - -/datum/supply_pack/organic/pizza/proc/anomalous_pizza_report() - print_command_report("[station_name()], our anomalous materials divison has reported a missing object that is highly likely to have been sent to your station during a routine cargo \ - delivery. Please search all crates and manifests provided with the delivery and return the object if is located. The object resembles a standard \[DATA EXPUNGED\] and is to be \ - considered \[REDACTED\] and returned at your leisure. Note that objects the anomaly produces are specifically attuned exactly to the individual opening the anomaly; regardless \ - of species, the individual will find the object edible and it will taste great according to their personal definitions, which vary significantly based on person and species.") - -/datum/supply_pack/organic/potted_plants - name = "Potted Plants Crate" - desc = "Spruce up the station with these lovely plants! Contains a random assortment of five potted plants from Nanotrasen's potted plant research division. Warranty void if thrown." - cost = 700 - contains = list(/obj/item/twohanded/required/kirbyplants/random, - /obj/item/twohanded/required/kirbyplants/random, - /obj/item/twohanded/required/kirbyplants/random, - /obj/item/twohanded/required/kirbyplants/random, - /obj/item/twohanded/required/kirbyplants/random) - crate_name = "potted plants crate" - crate_type = /obj/structure/closet/crate/hydroponics - -/datum/supply_pack/organic/seeds - name = "Seeds Crate" - desc = "Big things have small beginnings. Contains thirteen different seeds." - cost = 1000 - contains = list(/obj/item/seeds/chili, - /obj/item/seeds/berry, - /obj/item/seeds/corn, - /obj/item/seeds/eggplant, - /obj/item/seeds/tomato, - /obj/item/seeds/soya, - /obj/item/seeds/wheat, - /obj/item/seeds/wheat/rice, - /obj/item/seeds/carrot, - /obj/item/seeds/sunflower, - /obj/item/seeds/chanter, - /obj/item/seeds/potato, - /obj/item/seeds/sugarcane) - crate_name = "seeds crate" - crate_type = /obj/structure/closet/crate/hydroponics - -/datum/supply_pack/organic/vday - name = "Surplus Valentine Crate" - desc = "Turns out we got warehouses of this love-y dove-y crap. Were sending out small barged buddle of Valentine gear. This crate has two boxes of chocolate, three poppy flowers, five candy hearts, and three cards." - cost = 3000 - contraband = TRUE - contains = list(/obj/item/storage/fancy/heart_box, - /obj/item/storage/fancy/heart_box, - /obj/item/reagent_containers/food/snacks/grown/poppy, - /obj/item/reagent_containers/food/snacks/grown/poppy, - /obj/item/reagent_containers/food/snacks/grown/poppy, - /obj/item/reagent_containers/food/snacks/candyheart, - /obj/item/reagent_containers/food/snacks/candyheart, - /obj/item/reagent_containers/food/snacks/candyheart, - /obj/item/reagent_containers/food/snacks/candyheart, - /obj/item/reagent_containers/food/snacks/candyheart, - /obj/item/valentine, - /obj/item/valentine, - /obj/item/valentine) - crate_name = "valentine crate" - crate_type = /obj/structure/closet/crate/secure - -/datum/supply_pack/organic/exoticseeds - name = "Exotic Seeds Crate" - desc = "Any entrepreneuring botanist's dream. Contains twelve different seeds, including three replica-pod seeds and two mystery seeds!" - cost = 1500 - contains = list(/obj/item/seeds/nettle, - /obj/item/seeds/replicapod, - /obj/item/seeds/replicapod, - /obj/item/seeds/replicapod, - /obj/item/seeds/plump, - /obj/item/seeds/liberty, - /obj/item/seeds/amanita, - /obj/item/seeds/reishi, - /obj/item/seeds/banana, - /obj/item/seeds/eggplant/eggy, - /obj/item/seeds/random, - /obj/item/seeds/random) - crate_name = "exotic seeds crate" - crate_type = /obj/structure/closet/crate/hydroponics - -////////////////////////////////////////////////////////////////////////////// -////////////////////////////// Livestock ///////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -/datum/supply_pack/critter - group = "Livestock" - crate_type = /obj/structure/closet/crate/critter - -/datum/supply_pack/critter/butterfly - name = "Butterflies Crate" - desc = "Not a very dangerous insect, but they do give off a better image than, say, flies or cockroaches."//is that a motherfucking worm reference - contraband = TRUE - cost = 5000 - contains = list(/mob/living/simple_animal/butterfly) - crate_name = "entomology samples crate" - -/datum/supply_pack/critter/butterfly/generate() - . = ..() - for(var/i in 1 to 49) - new /mob/living/simple_animal/butterfly(.) - -/datum/supply_pack/critter/cat - name = "Cat Crate" - desc = "The cat goes meow! Comes with a collar and a nice cat toy! Cheeseburger not included."//i can't believe im making this reference - cost = 5000 //Cats are worth as much as corgis. - contains = list(/mob/living/simple_animal/pet/cat, - /obj/item/clothing/neck/petcollar, - /obj/item/toy/cattoy) - crate_name = "cat crate" - -/datum/supply_pack/critter/cat/generate() - . = ..() - if(prob(50)) - var/mob/living/simple_animal/pet/cat/C = locate() in . - qdel(C) - new /mob/living/simple_animal/pet/cat/Proc(.) - -/datum/supply_pack/critter/chick - name = "Chicken Crate" - desc = "The chicken goes bwaak!" - cost = 2000 - contains = list( /mob/living/simple_animal/chick) - crate_name = "chicken crate" - -/datum/supply_pack/critter/crab - name = "Crab Rocket" - desc = "CRAAAAAAB ROCKET. CRAB ROCKET. CRAB ROCKET. CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB ROCKET. CRAFT. ROCKET. BUY. CRAFT ROCKET. CRAB ROOOCKET. CRAB ROOOOCKET. CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB ROOOOOOOOOOOOOOOOOOOOOOCK EEEEEEEEEEEEEEEEEEEEEEEEE EEEETTTTTTTTTTTTAAAAAAAAA AAAHHHHHHHHHHHHH. CRAB ROCKET. CRAAAB ROCKEEEEEEEEEGGGGHHHHTT CRAB CRAB CRAABROCKET CRAB ROCKEEEET."//fun fact: i actually spent like 10 minutes and transcribed the entire video. - cost = 5000 - contains = list(/mob/living/simple_animal/crab) - crate_name = "look sir free crabs" - DropPodOnly = TRUE - -/datum/supply_pack/critter/crab/generate() - . = ..() - for(var/i in 1 to 49) - new /mob/living/simple_animal/crab(.) - -/datum/supply_pack/critter/corgi - name = "Corgi Crate" - desc = "Considered the optimal dog breed by thousands of research scientists, this Corgi is but one dog from the millions of Ian's noble bloodline. Comes with a cute collar!" - cost = 5000 - contains = list(/mob/living/simple_animal/pet/dog/corgi, - /obj/item/clothing/neck/petcollar) - crate_name = "corgi crate" - -/datum/supply_pack/critter/corgi/generate() - . = ..() - if(prob(50)) - var/mob/living/simple_animal/pet/dog/corgi/D = locate() in . - if(D.gender == FEMALE) - qdel(D) - new /mob/living/simple_animal/pet/dog/corgi/Lisa(.) - -/datum/supply_pack/critter/corgis/exotic - name = "Exotic Corgi Crate" - desc = "Corgis fit for a king, these corgis come in a unique color to signify their superiority. Comes with a cute collar!" - cost = 5500 - contains = list(/mob/living/simple_animal/pet/dog/corgi/exoticcorgi, - /obj/item/clothing/neck/petcollar) - crate_name = "exotic corgi crate" - -/datum/supply_pack/critter/cow - name = "Cow Crate" - desc = "The cow goes moo!" - cost = 3000 - contains = list(/mob/living/simple_animal/cow) - crate_name = "cow crate" - -/datum/supply_pack/critter/fox - name = "Fox Crate" - desc = "The fox goes...? Comes with a collar!"//what does the fox say - cost = 5000 - contains = list(/mob/living/simple_animal/pet/fox, - /obj/item/clothing/neck/petcollar) - crate_name = "fox crate" - -/datum/supply_pack/critter/goat - name = "Goat Crate" - desc = "The goat goes baa! Warranty void if used as a replacement for Pete." - cost = 2500 - contains = list(/mob/living/simple_animal/hostile/retaliate/goat) - crate_name = "goat crate" - -/datum/supply_pack/critter/monkey - name = "Monkey Cube Crate" - desc = "Stop monkeying around! Contains seven monkey cubes. Just add water!" - cost = 2000 - contains = list (/obj/item/storage/box/monkeycubes) - crate_name = "monkey cube crate" - -/datum/supply_pack/critter/pug - name = "Pug Crate" - desc = "Like a normal dog, but... squished. Comes with a nice collar!" - cost = 5000 - contains = list(/mob/living/simple_animal/pet/dog/pug, - /obj/item/clothing/neck/petcollar) - crate_name = "pug crate" - -/datum/supply_pack/critter/snake - name = "Snake Crate" - desc = "Tired of these MOTHER FUCKING snakes on this MOTHER FUCKING space station? Then this isn't the crate for you. Contains three poisonous snakes." - cost = 3000 - contains = list(/mob/living/simple_animal/hostile/retaliate/poison/snake, - /mob/living/simple_animal/hostile/retaliate/poison/snake, - /mob/living/simple_animal/hostile/retaliate/poison/snake) - crate_name = "snake crate" - -/datum/supply_pack/critter/secbat - name = "Security Bat Crate" - desc = "Contains five security bats, perfect to Bat-up any security officer." - cost = 2500 - contains = list(/mob/living/simple_animal/hostile/retaliate/bat/secbat, - /mob/living/simple_animal/hostile/retaliate/bat/secbat, - /mob/living/simple_animal/hostile/retaliate/bat/secbat, - /mob/living/simple_animal/hostile/retaliate/bat/secbat, - /mob/living/simple_animal/hostile/retaliate/bat/secbat) - crate_name = "security bat crate" - -////////////////////////////////////////////////////////////////////////////// -//////////////////////////// Costumes & Toys ///////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -/datum/supply_pack/costumes_toys - group = "Costumes & Toys" - -/datum/supply_pack/costumes_toys/randomised - name = "Collectable Hats Crate" - desc = "Flaunt your status with three unique, highly-collectable hats!" - cost = 20000 - var/num_contained = 3 //number of items picked to be contained in a randomised crate - contains = list(/obj/item/clothing/head/collectable/chef, - /obj/item/clothing/head/collectable/paper, - /obj/item/clothing/head/collectable/tophat, - /obj/item/clothing/head/collectable/captain, - /obj/item/clothing/head/collectable/beret, - /obj/item/clothing/head/collectable/welding, - /obj/item/clothing/head/collectable/flatcap, - /obj/item/clothing/head/collectable/pirate, - /obj/item/clothing/head/collectable/kitty, - /obj/item/clothing/head/collectable/rabbitears, - /obj/item/clothing/head/collectable/wizard, - /obj/item/clothing/head/collectable/hardhat, - /obj/item/clothing/head/collectable/HoS, - /obj/item/clothing/head/collectable/HoP, - /obj/item/clothing/head/collectable/thunderdome, - /obj/item/clothing/head/collectable/swat, - /obj/item/clothing/head/collectable/slime, - /obj/item/clothing/head/collectable/police, - /obj/item/clothing/head/collectable/slime, - /obj/item/clothing/head/collectable/xenom, - /obj/item/clothing/head/collectable/petehat) - crate_name = "collectable hats crate" - crate_type = /obj/structure/closet/crate/wooden - -/datum/supply_pack/costumes_toys/randomised/contraband - name = "Contraband Crate" - desc = "Psst.. bud... want some contraband? I can get you a poster, some nice cigs, dank, even some sponsored items...you know, the good stuff. Just keep it away from the cops, kay?" - contraband = TRUE - cost = 3000 - num_contained = 5 //SOME - contains = list(/obj/item/poster/random_contraband, - /obj/item/poster/random_contraband, - /obj/item/reagent_containers/food/snacks/grown/cannabis, - /obj/item/reagent_containers/food/snacks/grown/cannabis/rainbow, - /obj/item/reagent_containers/food/snacks/grown/cannabis/white, - /obj/item/storage/pill_bottle/zoom, - /obj/item/storage/pill_bottle/happy, - /obj/item/storage/pill_bottle/lsd, - /obj/item/storage/pill_bottle/aranesp, - /obj/item/storage/pill_bottle/stimulant, - /obj/item/toy/cards/deck/syndicate, - /obj/item/reagent_containers/food/drinks/bottle/absinthe, - /obj/item/clothing/under/syndicate/tacticool, - /obj/item/storage/fancy/cigarettes/cigpack_syndicate, - /obj/item/storage/fancy/cigarettes/cigpack_shadyjims, - /obj/item/clothing/mask/gas/syndicate, - /obj/item/clothing/neck/necklace/dope, - /obj/item/vending_refill/donksoft, - /obj/item/circuitboard/computer/arcade/amputation) - crate_name = "crate" - -/datum/supply_pack/costumes_toys/foamforce - name = "Foam Force Crate" - desc = "Break out the big guns with eight Foam Force shotguns!" - cost = 1000 - contains = list(/obj/item/gun/ballistic/shotgun/toy, - /obj/item/gun/ballistic/shotgun/toy, - /obj/item/gun/ballistic/shotgun/toy, - /obj/item/gun/ballistic/shotgun/toy, - /obj/item/gun/ballistic/shotgun/toy, - /obj/item/gun/ballistic/shotgun/toy, - /obj/item/gun/ballistic/shotgun/toy, - /obj/item/gun/ballistic/shotgun/toy) - crate_name = "foam force crate" - -/datum/supply_pack/costumes_toys/foamforce/bonus - name = "Foam Force Pistols Crate" - desc = "Psst.. hey bud... remember those old foam force pistols that got discontinued for being too cool? Well I got two of those right here with your name on em. I'll even throw in a spare mag for each, waddya say?" - contraband = TRUE - cost = 4000 - contains = list(/obj/item/gun/ballistic/automatic/toy/pistol, - /obj/item/gun/ballistic/automatic/toy/pistol, - /obj/item/ammo_box/magazine/toy/pistol, - /obj/item/ammo_box/magazine/toy/pistol) - crate_name = "foam force crate" - -/datum/supply_pack/costumes_toys/formalwear - name = "Formalwear Crate" - desc = "You're gonna like the way you look, I guaranteed it. Contains an asston of fancy clothing." - cost = 3000 //Lots of very expensive items. You gotta pay up to look good! - contains = list(/obj/item/clothing/under/blacktango, - /obj/item/clothing/under/assistantformal, - /obj/item/clothing/under/assistantformal, - /obj/item/clothing/under/lawyer/bluesuit, - /obj/item/clothing/suit/toggle/lawyer, - /obj/item/clothing/under/lawyer/purpsuit, - /obj/item/clothing/suit/toggle/lawyer/purple, - /obj/item/clothing/under/lawyer/blacksuit, - /obj/item/clothing/suit/toggle/lawyer/black, - /obj/item/clothing/accessory/waistcoat, - /obj/item/clothing/neck/tie/blue, - /obj/item/clothing/neck/tie/red, - /obj/item/clothing/neck/tie/black, - /obj/item/clothing/head/bowler, - /obj/item/clothing/head/fedora, - /obj/item/clothing/head/flatcap, - /obj/item/clothing/head/beret, - /obj/item/clothing/head/that, - /obj/item/clothing/shoes/laceup, - /obj/item/clothing/shoes/laceup, - /obj/item/clothing/shoes/laceup, - /obj/item/clothing/under/suit_jacket/charcoal, - /obj/item/clothing/under/suit_jacket/navy, - /obj/item/clothing/under/suit_jacket/burgundy, - /obj/item/clothing/under/suit_jacket/checkered, - /obj/item/clothing/under/suit_jacket/tan, - /obj/item/lipstick/random) - crate_name = "formalwear crate" - crate_type = /obj/structure/closet/crate/wooden - -/datum/supply_pack/costumes_toys/clownpin - name = "Hilarious Firing Pin Crate" - desc = "I uh... I'm not really sure what this does. Wanna buy it?" - cost = 5000 - contraband = TRUE - contains = list(/obj/item/firing_pin/clown) - crate_name = "toy crate" // It's /technically/ a toy. For the clown, at least. - crate_type = /obj/structure/closet/crate/wooden - -/datum/supply_pack/costumes_toys/lasertag - name = "Laser Tag Crate" - desc = "Foam Force is for boys. Laser Tag is for men. Contains three sets of red suits, blue suits, matching helmets, and matching laser tag guns." - cost = 1500 - contains = list(/obj/item/gun/energy/laser/redtag, - /obj/item/gun/energy/laser/redtag, - /obj/item/gun/energy/laser/redtag, - /obj/item/gun/energy/laser/bluetag, - /obj/item/gun/energy/laser/bluetag, - /obj/item/gun/energy/laser/bluetag, - /obj/item/clothing/suit/redtag, - /obj/item/clothing/suit/redtag, - /obj/item/clothing/suit/redtag, - /obj/item/clothing/suit/bluetag, - /obj/item/clothing/suit/bluetag, - /obj/item/clothing/suit/bluetag, - /obj/item/clothing/head/helmet/redtaghelm, - /obj/item/clothing/head/helmet/redtaghelm, - /obj/item/clothing/head/helmet/redtaghelm, - /obj/item/clothing/head/helmet/bluetaghelm, - /obj/item/clothing/head/helmet/bluetaghelm, - /obj/item/clothing/head/helmet/bluetaghelm) - crate_name = "laser tag crate" - -/datum/supply_pack/costumes_toys/lasertag/pins - name = "Laser Tag Firing Pins Crate" - desc = "Three laser tag firing pins used in laser-tag units to ensure users are wearing their vests." - cost = 3000 - contraband = TRUE - contains = list(/obj/item/storage/box/lasertagpins) - crate_name = "laser tag crate" - -/datum/supply_pack/costumes_toys/costume_original - name = "Original Costume Crate" - desc = "Reenact Shakespearean plays with this assortment of outfits. Contains eight different costumes!" - cost = 1000 - contains = list(/obj/item/clothing/head/snowman, - /obj/item/clothing/suit/snowman, - /obj/item/clothing/head/chicken, - /obj/item/clothing/suit/chickensuit, - /obj/item/clothing/mask/gas/monkeymask, - /obj/item/clothing/suit/monkeysuit, - /obj/item/clothing/head/cardborg, - /obj/item/clothing/suit/cardborg, - /obj/item/clothing/head/xenos, - /obj/item/clothing/suit/xenos, - /obj/item/clothing/suit/hooded/ian_costume, - /obj/item/clothing/suit/hooded/carp_costume, - /obj/item/clothing/suit/hooded/bee_costume) - crate_name = "original costume crate" - crate_type = /obj/structure/closet/crate/wooden - -/datum/supply_pack/costumes_toys/costume - name = "Standard Costume Crate" - desc = "Supply the station's entertainers with the equipment of their trade with these Nanotrasen-approved costumes! Contains a full clown and mime outfit, along with a bike horn and a bottle of nothing." - cost = 1000 - access = ACCESS_THEATRE - contains = list(/obj/item/storage/backpack/clown, - /obj/item/clothing/shoes/clown_shoes, - /obj/item/clothing/mask/gas/clown_hat, - /obj/item/clothing/under/rank/clown, - /obj/item/bikehorn, - /obj/item/clothing/under/rank/mime, - /obj/item/clothing/shoes/sneakers/black, - /obj/item/clothing/gloves/color/white, - /obj/item/clothing/mask/gas/mime, - /obj/item/clothing/head/beret, - /obj/item/clothing/suit/suspenders, - /obj/item/reagent_containers/food/drinks/bottle/bottleofnothing, - /obj/item/storage/backpack/mime) - crate_name = "standard costume crate" - crate_type = /obj/structure/closet/crate/wooden - -/datum/supply_pack/costumes_toys/randomised/toys - name = "Toy Crate" - desc = "Who cares about pride and accomplishment? Skip the gaming and get straight to the sweet rewards with this product! Contains five random toys. Warranty void if used to prank research directors." - cost = 1500 // or play the arcade machines ya lazy bum - num_contained = 5 - contains = list(/obj/item/storage/box/snappops, - /obj/item/toy/talking/AI, - /obj/item/toy/talking/codex_gigas, - /obj/item/clothing/under/syndicate/tacticool, - /obj/item/toy/sword , - /obj/item/toy/gun, - /obj/item/gun/ballistic/shotgun/toy/crossbow, - /obj/item/storage/box/fakesyndiesuit, - /obj/item/storage/crayons, - /obj/item/toy/spinningtoy, - /obj/item/toy/prize/ripley, - /obj/item/toy/prize/fireripley, - /obj/item/toy/prize/deathripley, - /obj/item/toy/prize/gygax, - /obj/item/toy/prize/durand, - /obj/item/toy/prize/honk, - /obj/item/toy/prize/marauder, - /obj/item/toy/prize/seraph, - /obj/item/toy/prize/mauler, - /obj/item/toy/prize/odysseus, - /obj/item/toy/prize/phazon, - /obj/item/toy/prize/reticence, - /obj/item/toy/cards/deck, - /obj/item/toy/nuke, - /obj/item/toy/minimeteor, - /obj/item/toy/redbutton, - /obj/item/toy/talking/owl, - /obj/item/toy/talking/griffin, - /obj/item/coin/antagtoken, - /obj/item/stack/tile/fakespace/loaded, - /obj/item/stack/tile/fakepit/loaded, - /obj/item/toy/toy_xeno, - /obj/item/storage/box/actionfigure, - /obj/item/restraints/handcuffs/fake, - /obj/item/grenade/chem_grenade/glitter/pink, - /obj/item/grenade/chem_grenade/glitter/blue, - /obj/item/grenade/chem_grenade/glitter/white, - /obj/item/toy/eightball, - /obj/item/toy/windupToolbox, - /obj/item/toy/clockwork_watch, - /obj/item/toy/toy_dagger, - /obj/item/extendohand/acme, - /obj/item/hot_potato/harmless/toy, - /obj/item/card/emagfake, - /obj/item/clothing/shoes/wheelys, - /obj/item/clothing/shoes/kindleKicks, - /obj/item/storage/belt/military/snack, - /obj/item/toy/eightball, - /obj/item/vending_refill/donksoft) - crate_name = "toy crate" - crate_type = /obj/structure/closet/crate/wooden - -/datum/supply_pack/costumes_toys/randomised/plush - name = "Plush Crate" - desc = "Plush tide station wide. Contains 5 random plushies for you to love. Warranty void if your love violates the terms of use." - cost = 1500 // or play the arcade machines ya lazy bum - num_contained = 5 - contains = list(/obj/item/toy/plush/random, - /obj/item/toy/plush/random, - /obj/item/toy/plush/random, - /obj/item/toy/plush/random, - /obj/item/toy/plush/random) //I'm lazy - crate_name = "plushie crate" - crate_type = /obj/structure/closet/crate/wooden - -/datum/supply_pack/costumes_toys/wizard - name = "Wizard Costume Crate" - desc = "Pretend to join the Wizard Federation with this full wizard outfit! Nanotrasen would like to remind its employees that actually joining the Wizard Federation is subject to termination of job and life." - cost = 2000 - contains = list(/obj/item/staff, - /obj/item/clothing/suit/wizrobe/fake, - /obj/item/clothing/shoes/sandal, - /obj/item/clothing/head/wizard/fake) - crate_name = "wizard costume crate" - crate_type = /obj/structure/closet/crate/wooden - -/datum/supply_pack/costumes_toys/randomised/fill(obj/structure/closet/crate/C) - var/list/L = contains.Copy() - for(var/i in 1 to num_contained) - var/item = pick_n_take(L) - new item(C) - -/datum/supply_pack/costumes_toys/wardrobes/autodrobe - name = "Autodrobe Supply Crate" - desc = "Autodrobe missing your favorite dress? Solve that issue today with this autodrobe refill." - cost = 1500 - contains = list(/obj/item/vending_refill/autodrobe) - crate_name = "autodrobe supply crate" - -/datum/supply_pack/costumes_toys/wardrobes/cargo - name = "Cargo Wardrobe Supply Crate" - desc = "This crate contains a refill for the CargoDrobe." - cost = 750 - contains = list(/obj/item/vending_refill/wardrobe/cargo_wardrobe) - crate_name = "cargo department supply crate" - -/datum/supply_pack/costumes_toys/wardrobes/engineering - name = "Engineering Wardrobe Supply Crate" - desc = "This crate contains refills for the EngiDrobe and AtmosDrobe." - cost = 1500 - contains = list(/obj/item/vending_refill/wardrobe/engi_wardrobe, - /obj/item/vending_refill/wardrobe/atmos_wardrobe) - crate_name = "engineering department wardrobe supply crate" - -/datum/supply_pack/costumes_toys/wardrobes/general - name = "General Wardrobes Supply Crate" - desc = "This crate contains refills for the CuraDrobe, BarDrobe, ChefDrobe, JaniDrobe, ChapDrobe." - cost = 3750 - contains = list(/obj/item/vending_refill/wardrobe/curator_wardrobe, - /obj/item/vending_refill/wardrobe/bar_wardrobe, - /obj/item/vending_refill/wardrobe/chef_wardrobe, - /obj/item/vending_refill/wardrobe/jani_wardrobe, - /obj/item/vending_refill/wardrobe/chap_wardrobe) - crate_name = "general wardrobes vendor refills" - -/datum/supply_pack/costumes_toys/wardrobes/hydroponics - name = "Hydrobe Supply Crate" - desc = "This crate contains a refill for the Hydrobe." - cost = 750 - contains = list(/obj/item/vending_refill/wardrobe/hydro_wardrobe) - crate_name = "hydrobe supply crate" - -/datum/supply_pack/costumes_toys/wardrobes/medical - name = "Medical Wardrobe Supply Crate" - desc = "This crate contains refills for the MediDrobe, ChemDrobe, GeneDrobe, and ViroDrobe." - cost = 3000 - contains = list(/obj/item/vending_refill/wardrobe/medi_wardrobe, - /obj/item/vending_refill/wardrobe/chem_wardrobe, - /obj/item/vending_refill/wardrobe/gene_wardrobe, - /obj/item/vending_refill/wardrobe/viro_wardrobe) - crate_name = "medical department wardrobe supply crate" - -/datum/supply_pack/costumes_toys/wardrobes/science - name = "Science Wardrobe Supply Crate" - desc = "This crate contains refills for the SciDrobe and RoboDrobe." - cost = 1500 - contains = list(/obj/item/vending_refill/wardrobe/robo_wardrobe, - /obj/item/vending_refill/wardrobe/science_wardrobe) - crate_name = "science department wardrobe supply crate" - -/datum/supply_pack/costumes_toys/wardrobes/security - name = "Security Wardrobe Supply Crate" - desc = "This crate contains refills for the SecDrobe and LawDrobe." - cost = 1500 - contains = list(/obj/item/vending_refill/wardrobe/sec_wardrobe, - /obj/item/vending_refill/wardrobe/law_wardrobe) - crate_name = "security department supply crate" - -////////////////////////////////////////////////////////////////////////////// -//////////////////////////// Miscellaneous /////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -/datum/supply_pack/misc - group = "Miscellaneous Supplies" - -/datum/supply_pack/misc/artsupply - name = "Art Supplies" - desc = "Make some happy little accidents with six canvasses, two easels, two boxes of crayons, and a rainbow crayon!" - cost = 800 - contains = list(/obj/structure/easel, - /obj/structure/easel, - /obj/item/canvas/nineteenXnineteen, - /obj/item/canvas/nineteenXnineteen, - /obj/item/canvas/twentythreeXnineteen, - /obj/item/canvas/twentythreeXnineteen, - /obj/item/canvas/twentythreeXtwentythree, - /obj/item/canvas/twentythreeXtwentythree, - /obj/item/storage/crayons, - /obj/item/storage/crayons, - /obj/item/toy/crayon/rainbow, - /obj/item/toy/crayon/white, - /obj/item/toy/crayon/white) - crate_name = "art supply crate" - crate_type = /obj/structure/closet/crate/wooden - -/datum/supply_pack/misc/captain_pen - name = "Captain Pen" - desc = "A spare Captain fountain pen." - access = ACCESS_CAPTAIN - cost = 10000 - contains = list(/obj/item/pen/fountain/captain) - crate_name = "captain pen" - crate_type = /obj/structure/closet/crate/secure/weapon //It is a combat pen - -/datum/supply_pack/misc/bicycle - name = "Bicycle" - desc = "Nanotrasen reminds all employees to never toy with powers outside their control." - cost = 1000000 - contains = list(/obj/vehicle/ridden/bicycle) - crate_name = "Bicycle Crate" - crate_type = /obj/structure/closet/crate/large - -/datum/supply_pack/misc/bigband - name = "Big Band Instrument Collection" - desc = "Get your sad station movin' and groovin' with this fine collection! Contains nine different instruments!" - cost = 5000 - crate_name = "Big band musical instruments collection" - contains = list(/obj/item/instrument/violin, - /obj/item/instrument/guitar, - /obj/item/instrument/glockenspiel, - /obj/item/instrument/accordion, - /obj/item/instrument/saxophone, - /obj/item/instrument/trombone, - /obj/item/instrument/recorder, - /obj/item/instrument/harmonica, - /obj/structure/piano/unanchored) - crate_type = /obj/structure/closet/crate/wooden - -/datum/supply_pack/misc/book_crate - name = "Book Crate" - desc = "Surplus from the Nanotrasen Archives, these five books are sure to be good reads." - cost = 1500 - contains = list(/obj/item/book/codex_gigas, - /obj/item/book/manual/random/, - /obj/item/book/manual/random/, - /obj/item/book/manual/random/, - /obj/item/book/random/triple) - crate_type = /obj/structure/closet/crate/wooden - -/datum/supply_pack/misc/paper - name = "Bureaucracy Crate" - desc = "High stacks of papers on your desk Are a big problem - make it Pea-sized with these bureaucratic supplies! Contains five pens, some camera film, hand labeler supplies, a paper bin, three folders, two clipboards and two stamps as well as a briefcase."//that was too forced - cost = 1500 - contains = list(/obj/structure/filingcabinet/chestdrawer/wheeled, - /obj/item/camera_film, - /obj/item/hand_labeler, - /obj/item/hand_labeler_refill, - /obj/item/hand_labeler_refill, - /obj/item/paper_bin, - /obj/item/pen/fourcolor, - /obj/item/pen/fourcolor, - /obj/item/pen, - /obj/item/pen/blue, - /obj/item/pen/red, - /obj/item/folder/blue, - /obj/item/folder/red, - /obj/item/folder/yellow, - /obj/item/clipboard, - /obj/item/clipboard, - /obj/item/stamp, - /obj/item/stamp/denied, - /obj/item/storage/briefcase) - crate_name = "bureaucracy crate" - -/datum/supply_pack/misc/fountainpens - name = "Calligraphy Crate" - desc = "Sign death warrants in style with these seven executive fountain pens." - cost = 700 - contains = list(/obj/item/storage/box/fountainpens, - /obj/item/paper_bin) - crate_type = /obj/structure/closet/crate/wooden - crate_name = "calligraphy crate" - -/datum/supply_pack/misc/wrapping_paper - name = "Festive Wrapping Paper Crate" - desc = "Want to mail your loved ones gift-wrapped chocolates, stuffed animals, the Clown's severed head? You can do all that, with this crate full of wrapping paper." - cost = 1000 - contains = list(/obj/item/stack/wrapping_paper) - crate_type = /obj/structure/closet/crate/wooden - crate_name = "festive wrapping paper crate" - - -/datum/supply_pack/misc/funeral - name = "Funeral Supply crate" - desc = "At the end of the day, someone's gonna want someone dead. Give them a proper send-off with these funeral supplies! Contains a coffin with burial garmets and flowers." - cost = 600 - contains = list(/obj/item/clothing/under/burial, - /obj/item/reagent_containers/food/snacks/grown/harebell, - /obj/item/reagent_containers/food/snacks/grown/poppy/geranium - ) - crate_name = "coffin" - crate_type = /obj/structure/closet/crate/coffin - -/datum/supply_pack/misc/religious_supplies - name = "Religious Supplies Crate" - desc = "Keep your local chaplain happy and well-supplied, lest they call down judgement upon your cargo bay. Contains two bottles of holywater, bibles, chaplain robes, and burial garmets." - cost = 4000 // it costs so much because the Space Church is ran by Space Jews - contains = list(/obj/item/reagent_containers/food/drinks/bottle/holywater, - /obj/item/reagent_containers/food/drinks/bottle/holywater, - /obj/item/storage/book/bible/booze, - /obj/item/storage/book/bible/booze, - /obj/item/clothing/suit/hooded/chaplain_hoodie, - /obj/item/clothing/suit/hooded/chaplain_hoodie - ) - crate_name = "religious supplies crate" - -/datum/supply_pack/misc/lewd - name = "Lewd Crate" // OwO - desc = "Psss want to have a good time with your sluts? Well I got what you want maid clothing, dildos, collars and more!" - cost = 5000 - contraband = TRUE - contains = list(/obj/item/dildo/custom, - /obj/item/dildo/custom, - /obj/item/vending_refill/kink, - /obj/item/vending_refill/kink, - /obj/item/clothing/under/maid, - /obj/item/clothing/under/maid, - /obj/item/electropack/shockcollar, - /obj/item/electropack/shockcollar, - /obj/item/restraints/handcuffs/fake/kinky, - /obj/item/restraints/handcuffs/fake/kinky, - /obj/item/clothing/head/kitty/genuine, // Why its illegal - /obj/item/clothing/head/kitty/genuine, - /obj/item/storage/pill_bottle/penis_enlargement, - /obj/structure/reagent_dispensers/keg/aphro) - crate_name = "lewd kit" - crate_type = /obj/structure/closet/crate - -/datum/supply_pack/misc/lewdkeg - name = "Lewd Deluxe Keg" - desc = "That other stuff not getting you ready? Well I have a Chemslut making tons of the good stuff." - cost = 7000 //It can be a weapon - contraband = TRUE - contains = list(/obj/structure/reagent_dispensers/keg/aphro/strong) - crate_name = "deluxe keg" - crate_type = /obj/structure/closet/crate - -/datum/supply_pack/misc/paper_work - name = "Freelance Paper work" - desc = "The Nanotrasen Primary Bureaucratic Database Intelligence (PDBI) reports that the station has not completed its funding and grant paperwork this solar cycle. In order to gain further funding, your station is required to fill out (10) ten of these forms or no additional capital will be disbursed. We have sent you ten copies of the following form and we expect every one to be up to Nanotrasen Standards." // Disbursement. It's not a typo, look it up. - cost = 400 // Net of 0 credits - contains = list(/obj/item/folder/paperwork, - /obj/item/folder/paperwork, - /obj/item/folder/paperwork, - /obj/item/folder/paperwork, - /obj/item/folder/paperwork, - /obj/item/folder/paperwork, - /obj/item/folder/paperwork, - /obj/item/folder/paperwork, - /obj/item/folder/paperwork, - /obj/item/folder/paperwork, - /obj/item/pen/fountain, - /obj/item/pen/fountain, - /obj/item/pen/fountain, - /obj/item/pen/fountain, - /obj/item/pen/fountain) - crate_name = "Paperwork" - -/datum/supply_pack/misc/randomised/promiscuous - name = "Promiscuous Organs" - desc = "Do YOU want to have more genital? Well we have just the thing for you~. This crate has two autosurgeon, that will let you have a new sex, organ to impress that hot stud and or chick." - cost = 4000 //Only get 2! - contraband = TRUE - var/num_contained = 2 - contains = list(/obj/item/autosurgeon/penis, - /obj/item/autosurgeon/testicles, - /obj/item/autosurgeon/vagina, - /obj/item/autosurgeon/breasts, - /obj/item/autosurgeon/womb) - crate_name = "promiscuous organs" - -/datum/supply_pack/misc/toner - name = "Toner Crate" - desc = "Spent too much ink printing butt pictures? Fret not, with these six toner refills, you'll be printing butts 'till the cows come home!'" - cost = 1000 - contains = list(/obj/item/toner, - /obj/item/toner, - /obj/item/toner, - /obj/item/toner, - /obj/item/toner, - /obj/item/toner) - crate_name = "toner crate" + new item(C) \ No newline at end of file diff --git a/code/modules/cargo/packs/armory.dm b/code/modules/cargo/packs/armory.dm new file mode 100644 index 0000000000..4713d94106 --- /dev/null +++ b/code/modules/cargo/packs/armory.dm @@ -0,0 +1,244 @@ + +//Reminders- +// If you add something to this list, please group it by type and sort it alphabetically instead of just jamming it in like an animal +// cost = 700- Minimum cost, or infinite points are possible. +////////////////////////////////////////////////////////////////////////////// +//////////////////////////// Armory ////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +/datum/supply_pack/security/armory + group = "Armory" + access = ACCESS_ARMORY + crate_type = /obj/structure/closet/crate/secure/weapon + +/datum/supply_pack/security/armory/bulletarmor + name = "Bulletproof Armor Crate" + desc = "Contains three sets of bulletproof armor. Guaranteed to reduce a bullet's stopping power by over half. Requires Armory access to open." + cost = 1250 + contains = list(/obj/item/clothing/suit/armor/bulletproof, + /obj/item/clothing/suit/armor/bulletproof, + /obj/item/clothing/suit/armor/bulletproof) + crate_name = "bulletproof armor crate" + +/datum/supply_pack/security/armory/bullethelmets + name = "Bulletproof Helmet Crate" + desc = "Contains three sets of bulletproof helmets. Guaranteed to reduce a bullet's stopping power by over half. Requires Armory access to open." + cost = 1250 + contains = list(/obj/item/clothing/head/helmet/alt, + /obj/item/clothing/head/helmet/alt, + /obj/item/clothing/head/helmet/alt) + crate_name = "bulletproof helmet crate" + +/datum/supply_pack/security/armory/chemimp + name = "Chemical Implants Crate" + desc = "Contains five Remote Chemical implants. Requires Armory access to open." + cost = 1700 + contains = list(/obj/item/storage/box/chemimp) + crate_name = "chemical implant crate" + +/datum/supply_pack/security/armory/combatknives + name = "Combat Knives Crate" + desc = "Contains three sharpened combat knives. Each knife guaranteed to fit snugly inside any Nanotrasen-standard boot. Requires Armory access to open." + cost = 3200 + contains = list(/obj/item/kitchen/knife/combat, + /obj/item/kitchen/knife/combat, + /obj/item/kitchen/knife/combat) + crate_name = "combat knife crate" + +/datum/supply_pack/security/armory/ballistic + name = "Combat Shotguns Crate" + desc = "For when the enemy absolutely needs to be replaced with lead. Contains three Aussec-designed Combat Shotguns, with three Shotgun Bandoliers, as well as seven buchshot and 12g shotgun slugs. Requires Armory access to open." + cost = 8000 + contains = list(/obj/item/gun/ballistic/shotgun/automatic/combat, + /obj/item/gun/ballistic/shotgun/automatic/combat, + /obj/item/gun/ballistic/shotgun/automatic/combat, + /obj/item/storage/belt/bandolier, + /obj/item/storage/belt/bandolier, + /obj/item/storage/belt/bandolier, + /obj/item/storage/box/lethalshot, + /obj/item/storage/box/lethalslugs) + crate_name = "combat shotguns crate" + +/datum/supply_pack/security/armory/dragnetgun + name = "DRAGnet gun Crate" + desc = "Contains two DRAGnet gun. A Dynamic Rapid-Apprehension of the Guilty net the revolution in law enforcement technology that YOU Want! Requires Armory access to open." + cost = 3250 + contains = list(/obj/item/gun/energy/e_gun/dragnet, + /obj/item/gun/energy/e_gun/dragnet) + crate_name = "anti riot net guns crate" + +/datum/supply_pack/security/armory/energy + name = "Energy Guns Crate" + desc = "Contains three Energy Guns, capable of firing both nonlethal and lethal blasts of light. Requires Armory access to open." + cost = 3250 + contains = list(/obj/item/gun/energy/e_gun, + /obj/item/gun/energy/e_gun, + /obj/item/gun/energy/e_gun) + crate_name = "energy gun crate" + crate_type = /obj/structure/closet/crate/secure/plasma + +/datum/supply_pack/security/armory/exileimp // Theres boxes in 2 lockers as well as gateway never realy being used sad + name = "Exile Implants Crate" + desc = "Contains five Exile implants. Requires Armory access to open." + cost = 1050 //stops endless points + contains = list(/obj/item/storage/box/exileimp) + crate_name = "exile implant crate" + +/datum/supply_pack/security/armory/mindshield + name = "Mindshield Implants Crate" + desc = "Prevent against radical thoughts with three Mindshield implants. Requires Armory access to open." + cost = 4000 + contains = list(/obj/item/storage/lockbox/loyalty) + crate_name = "mindshield implant crate" + +/datum/supply_pack/security/armory/trackingimp + name = "Tracking Implants Crate" + desc = "Contains four tracking implants. Requires Armory access to open." + cost = 1050 + contains = list(/obj/item/storage/box/trackimp) + crate_name = "tracking implant crate" + +/datum/supply_pack/security/armory/fire + name = "Incendiary Weapons Crate" + desc = "Burn, baby burn. Contains three incendiary grenades, seven incendiary slugs, three plasma canisters, and a flamethrower. Requires Brige access to open." + cost = 1750 + access = ACCESS_HEADS + contains = list(/obj/item/flamethrower/full, + /obj/item/tank/internals/plasma, + /obj/item/tank/internals/plasma, + /obj/item/tank/internals/plasma, + /obj/item/grenade/chem_grenade/incendiary, + /obj/item/grenade/chem_grenade/incendiary, + /obj/item/grenade/chem_grenade/incendiary, + /obj/item/storage/box/fireshot) + crate_name = "incendiary weapons crate" + crate_type = /obj/structure/closet/crate/secure/plasma + dangerous = TRUE + +/datum/supply_pack/security/armory/miniguns + name = "Personal Miniature Energy Guns" + desc = "Contains three miniature energy guns. Each gun has a disabler and a lethal option. Requires Armory access to open." + cost = 3000 + contains = list(/obj/item/gun/energy/e_gun/mini, + /obj/item/gun/energy/e_gun/mini, + /obj/item/gun/energy/e_gun/mini) + crate_name = "personal energy guns crate" + crate_type = /obj/structure/closet/crate/secure/plasma + +/datum/supply_pack/security/armory/laserarmor + name = "Reflector Vest Crate" + desc = "Contains two vests of highly reflective material. Each armor piece diffuses a laser's energy by over half, as well as offering a good chance to reflect the laser entirely. Requires Armory access to open." + cost = 2000 + contains = list(/obj/item/clothing/suit/armor/laserproof, + /obj/item/clothing/suit/armor/laserproof) + crate_name = "reflector vest crate" + crate_type = /obj/structure/closet/crate/secure/plasma + +/datum/supply_pack/security/armory/riotarmor + name = "Riot Armor Crate" + desc = "Contains three sets of heavy body armor. Advanced padding protects against close-ranged weaponry, making melee attacks feel only half as potent to the user. Requires Armory access to open." + cost = 1750 + contains = list(/obj/item/clothing/suit/armor/riot, + /obj/item/clothing/suit/armor/riot, + /obj/item/clothing/suit/armor/riot) + crate_name = "riot armor crate" + +/datum/supply_pack/security/armory/riothelmets + name = "Riot Helmets Crate" + desc = "Contains three riot helmets. Requires Armory access to open." + cost = 1750 + contains = list(/obj/item/clothing/head/helmet/riot, + /obj/item/clothing/head/helmet/riot, + /obj/item/clothing/head/helmet/riot) + crate_name = "riot helmets crate" + +/datum/supply_pack/security/armory/riotshields + name = "Riot Shields Crate" + desc = "For when the greytide gets really uppity. Contains three riot shields. Requires Armory access to open." + cost = 2200 + contains = list(/obj/item/shield/riot, + /obj/item/shield/riot, + /obj/item/shield/riot) + crate_name = "riot shields crate" + +/datum/supply_pack/security/armory/riotshotguns + name = "Riot Shotgun Crate" + desc = "For when the greytide gets really uppity. Contains three riot shotguns, seven rubber shot and beanbag shells. Requires Armory access to open." + cost = 6500 + contains = list(/obj/item/gun/ballistic/shotgun/riot, + /obj/item/gun/ballistic/shotgun/riot, + /obj/item/gun/ballistic/shotgun/riot, + /obj/item/storage/box/rubbershot, + /obj/item/storage/box/beanbag) + crate_name = "riot shotgun crate" + +/datum/supply_pack/security/armory/swat + name = "SWAT Crate" + desc = "Contains two fullbody sets of tough, fireproof, pressurized suits designed in a joint effort by IS-ERI and Nanotrasen. Each set contains a suit, helmet, mask, combat belt, and combat gloves. Requires Armory access to open." + cost = 6750 + contains = list(/obj/item/clothing/head/helmet/swat/nanotrasen, + /obj/item/clothing/head/helmet/swat/nanotrasen, + /obj/item/clothing/suit/space/swat, + /obj/item/clothing/suit/space/swat, + /obj/item/clothing/mask/gas/sechailer/swat, + /obj/item/clothing/mask/gas/sechailer/swat, + /obj/item/storage/belt/military/assault, + /obj/item/storage/belt/military/assault, + /obj/item/clothing/gloves/combat, + /obj/item/clothing/gloves/combat) + crate_name = "swat crate" + +/datum/supply_pack/security/armory/swattasers //Lesser AEG tbh + name = "SWAT tatical tasers Crate" + desc = "Contains two tactical energy gun, these guns are able to tase, disable and lethal as well as hold a seclight. Requires Armory access to open." + cost = 7000 + contains = list(/obj/item/gun/energy/e_gun/stun, + /obj/item/gun/energy/e_gun/stun) + crate_name = "swat taser crate" + +/datum/supply_pack/security/armory/woodstock + name = "Classic WoodStock Shotguns Crate" + desc = "Contains three rustic, pumpaction shotguns. Requires Armory access to open." + cost = 3500 + contains = list(/obj/item/gun/ballistic/shotgun, + /obj/item/gun/ballistic/shotgun, + /obj/item/gun/ballistic/shotgun) + crate_name = "woodstock shotguns crate" + +/datum/supply_pack/security/armory/wt550 + name = "WT-550 Semi-Auto Rifle Crate" + desc = "Contains two high-powered, semiautomatic rifles chambered in 4.6x30mm. Requires Armory access to open." + cost = 3250 + contains = list(/obj/item/gun/ballistic/automatic/wt550, + /obj/item/gun/ballistic/automatic/wt550) + crate_name = "auto rifle crate" + +/datum/supply_pack/security/armory/wt550ammo + name = "WT-550 Semi-Auto SMG Ammo Crate" + desc = "Contains four 20-round magazines for the WT-550 Semi-Auto SMG. Each magazine is designed to facilitate rapid tactical reloads. Requires Armory access to open." + cost = 2750 + contains = list(/obj/item/ammo_box/magazine/wt550m9, + /obj/item/ammo_box/magazine/wt550m9, + /obj/item/ammo_box/magazine/wt550m9, + /obj/item/ammo_box/magazine/wt550m9) + crate_name = "auto rifle ammo crate" + +/datum/supply_pack/security/armory/wt550ammo_nonlethal // Takes around 12 shots to stun crit someone + name = "WT-550 Semi-Auto SMG Non-Lethal Ammo Crate" + desc = "Contains four 20-round magazines for the WT-550 Semi-Auto SMG. Each magazine is designed to facilitate rapid tactical reloads. Requires Armory access to open." + cost = 1200 + contains = list(/obj/item/ammo_box/magazine/wt550m9/wtrubber, + /obj/item/ammo_box/magazine/wt550m9/wtrubber, + /obj/item/ammo_box/magazine/wt550m9/wtrubber, + /obj/item/ammo_box/magazine/wt550m9/wtrubber) + crate_name = "auto rifle ammo crate" + +/datum/supply_pack/security/armory/wt550ammo_special + name = "WT-550 Semi-Auto SMG Special Ammo Crate" + desc = "Contains 2 20-round Armour Piercing and Incendiary magazines for the WT-550 Semi-Auto SMG. Each magazine is designed to facilitate rapid tactical reloads. Requires Armory access to open." + cost = 3500 + contains = list(/obj/item/ammo_box/magazine/wt550m9/wtap, + /obj/item/ammo_box/magazine/wt550m9/wtap, + /obj/item/ammo_box/magazine/wt550m9/wtic, + /obj/item/ammo_box/magazine/wt550m9/wtic) + crate_name = "auto rifle ammo crate" diff --git a/code/modules/cargo/packs/costumes_toys.dm b/code/modules/cargo/packs/costumes_toys.dm new file mode 100644 index 0000000000..40d21e4505 --- /dev/null +++ b/code/modules/cargo/packs/costumes_toys.dm @@ -0,0 +1,369 @@ + +//Reminders- +// If you add something to this list, please group it by type and sort it alphabetically instead of just jamming it in like an animal +// cost = 700- Minimum cost, or infinite points are possible. +////////////////////////////////////////////////////////////////////////////// +//////////////////////////// Costumes & Toys ///////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +/datum/supply_pack/costumes_toys + group = "Costumes & Toys" + +/datum/supply_pack/costumes_toys/randomised + name = "Collectable Hats Crate" + desc = "Flaunt your status with three unique, highly-collectable hats!" + cost = 20000 + var/num_contained = 3 //number of items picked to be contained in a randomised crate + contains = list(/obj/item/clothing/head/collectable/chef, + /obj/item/clothing/head/collectable/paper, + /obj/item/clothing/head/collectable/tophat, + /obj/item/clothing/head/collectable/captain, + /obj/item/clothing/head/collectable/beret, + /obj/item/clothing/head/collectable/welding, + /obj/item/clothing/head/collectable/flatcap, + /obj/item/clothing/head/collectable/pirate, + /obj/item/clothing/head/collectable/kitty, + /obj/item/clothing/head/collectable/rabbitears, + /obj/item/clothing/head/collectable/wizard, + /obj/item/clothing/head/collectable/hardhat, + /obj/item/clothing/head/collectable/HoS, + /obj/item/clothing/head/collectable/HoP, + /obj/item/clothing/head/collectable/thunderdome, + /obj/item/clothing/head/collectable/swat, + /obj/item/clothing/head/collectable/slime, + /obj/item/clothing/head/collectable/police, + /obj/item/clothing/head/collectable/slime, + /obj/item/clothing/head/collectable/xenom, + /obj/item/clothing/head/collectable/petehat) + crate_name = "collectable hats crate" + crate_type = /obj/structure/closet/crate/wooden + +/datum/supply_pack/costumes_toys/randomised/contraband + name = "Contraband Crate" + desc = "Psst.. bud... want some contraband? I can get you a poster, some nice cigs, dank, even some sponsored items...you know, the good stuff. Just keep it away from the cops, kay?" + contraband = TRUE + cost = 3000 + num_contained = 5 //SOME + contains = list(/obj/item/poster/random_contraband, + /obj/item/poster/random_contraband, + /obj/item/reagent_containers/food/snacks/grown/cannabis, + /obj/item/reagent_containers/food/snacks/grown/cannabis/rainbow, + /obj/item/reagent_containers/food/snacks/grown/cannabis/white, + /obj/item/storage/pill_bottle/zoom, + /obj/item/storage/pill_bottle/happy, + /obj/item/storage/pill_bottle/lsd, + /obj/item/storage/pill_bottle/aranesp, + /obj/item/storage/pill_bottle/stimulant, + /obj/item/toy/cards/deck/syndicate, + /obj/item/reagent_containers/food/drinks/bottle/absinthe, + /obj/item/clothing/under/syndicate/tacticool, + /obj/item/clothing/under/syndicate, + /obj/item/suppressor, + /obj/item/storage/fancy/cigarettes/cigpack_syndicate, + /obj/item/storage/fancy/cigarettes/cigpack_shadyjims, + /obj/item/clothing/mask/gas/syndicate, + /obj/item/clothing/neck/necklace/dope, + /obj/item/vending_refill/donksoft, + /obj/item/circuitboard/computer/arcade/amputation) + crate_name = "crate" + +/datum/supply_pack/costumes_toys/foamforce + name = "Foam Force Crate" + desc = "Break out the big guns with eight Foam Force shotguns!" + cost = 1000 + contains = list(/obj/item/gun/ballistic/shotgun/toy, + /obj/item/gun/ballistic/shotgun/toy, + /obj/item/gun/ballistic/shotgun/toy, + /obj/item/gun/ballistic/shotgun/toy, + /obj/item/gun/ballistic/shotgun/toy, + /obj/item/gun/ballistic/shotgun/toy, + /obj/item/gun/ballistic/shotgun/toy, + /obj/item/gun/ballistic/shotgun/toy) + crate_name = "foam force crate" + +/datum/supply_pack/costumes_toys/foamforce/bonus + name = "Foam Force Pistols Crate" + desc = "Psst.. hey bud... remember those old foam force pistols that got discontinued for being too cool? Well I got two of those right here with your name on em. I'll even throw in a spare mag for each, waddya say?" + contraband = TRUE + cost = 4000 + contains = list(/obj/item/gun/ballistic/automatic/toy/pistol, + /obj/item/gun/ballistic/automatic/toy/pistol, + /obj/item/ammo_box/magazine/toy/pistol, + /obj/item/ammo_box/magazine/toy/pistol) + crate_name = "foam force crate" + +/datum/supply_pack/costumes_toys/formalwear + name = "Formalwear Crate" + desc = "You're gonna like the way you look, I guaranteed it. Contains an asston of fancy clothing." + cost = 4750 //Lots of fancy clothing that can be sold back! + contains = list(/obj/item/clothing/under/blacktango, + /obj/item/clothing/under/assistantformal, + /obj/item/clothing/under/assistantformal, + /obj/item/clothing/under/lawyer/bluesuit, + /obj/item/clothing/suit/toggle/lawyer, + /obj/item/clothing/under/lawyer/purpsuit, + /obj/item/clothing/suit/toggle/lawyer/purple, + /obj/item/clothing/under/lawyer/blacksuit, + /obj/item/clothing/suit/toggle/lawyer/black, + /obj/item/clothing/accessory/waistcoat, + /obj/item/clothing/neck/tie/blue, + /obj/item/clothing/neck/tie/red, + /obj/item/clothing/neck/tie/black, + /obj/item/clothing/head/bowler, + /obj/item/clothing/head/fedora, + /obj/item/clothing/head/flatcap, + /obj/item/clothing/head/beret, + /obj/item/clothing/head/that, + /obj/item/clothing/shoes/laceup, + /obj/item/clothing/shoes/laceup, + /obj/item/clothing/shoes/laceup, + /obj/item/clothing/under/suit_jacket/charcoal, + /obj/item/clothing/under/suit_jacket/navy, + /obj/item/clothing/under/suit_jacket/burgundy, + /obj/item/clothing/under/suit_jacket/checkered, + /obj/item/clothing/under/suit_jacket/tan, + /obj/item/lipstick/random) + crate_name = "formalwear crate" + crate_type = /obj/structure/closet/crate/wooden + +/datum/supply_pack/costumes_toys/clownpin + name = "Hilarious Firing Pin Crate" + desc = "I uh... I'm not really sure what this does. Wanna buy it?" + cost = 5000 + contraband = TRUE + contains = list(/obj/item/firing_pin/clown) + crate_name = "toy crate" // It's /technically/ a toy. For the clown, at least. + crate_type = /obj/structure/closet/crate/wooden + +/datum/supply_pack/costumes_toys/lasertag + name = "Laser Tag Crate" + desc = "Foam Force is for boys. Laser Tag is for men. Contains three sets of red suits, blue suits, matching helmets, and matching laser tag guns." + cost = 3500 + contains = list(/obj/item/gun/energy/laser/redtag, + /obj/item/gun/energy/laser/redtag, + /obj/item/gun/energy/laser/redtag, + /obj/item/gun/energy/laser/bluetag, + /obj/item/gun/energy/laser/bluetag, + /obj/item/gun/energy/laser/bluetag, + /obj/item/clothing/suit/redtag, + /obj/item/clothing/suit/redtag, + /obj/item/clothing/suit/redtag, + /obj/item/clothing/suit/bluetag, + /obj/item/clothing/suit/bluetag, + /obj/item/clothing/suit/bluetag, + /obj/item/clothing/head/helmet/redtaghelm, + /obj/item/clothing/head/helmet/redtaghelm, + /obj/item/clothing/head/helmet/redtaghelm, + /obj/item/clothing/head/helmet/bluetaghelm, + /obj/item/clothing/head/helmet/bluetaghelm, + /obj/item/clothing/head/helmet/bluetaghelm) + crate_name = "laser tag crate" + +/datum/supply_pack/costumes_toys/lasertag/pins + name = "Laser Tag Firing Pins Crate" + desc = "Three laser tag firing pins used in laser-tag units to ensure users are wearing their vests." + cost = 3000 + contraband = TRUE + contains = list(/obj/item/storage/box/lasertagpins) + crate_name = "laser tag crate" + +/datum/supply_pack/costumes_toys/costume_original + name = "Original Costume Crate" + desc = "Reenact Shakespearean plays with this assortment of outfits. Contains eight different costumes!" + cost = 1750 + contains = list(/obj/item/clothing/head/snowman, + /obj/item/clothing/suit/snowman, + /obj/item/clothing/head/chicken, + /obj/item/clothing/suit/chickensuit, + /obj/item/clothing/mask/gas/monkeymask, + /obj/item/clothing/suit/monkeysuit, + /obj/item/clothing/head/cardborg, + /obj/item/clothing/suit/cardborg, + /obj/item/clothing/head/xenos, + /obj/item/clothing/suit/xenos, + /obj/item/clothing/suit/hooded/ian_costume, + /obj/item/clothing/suit/hooded/carp_costume, + /obj/item/clothing/suit/hooded/bee_costume) + crate_name = "original costume crate" + crate_type = /obj/structure/closet/crate/wooden + +/datum/supply_pack/costumes_toys/costume + name = "Standard Costume Crate" + desc = "Supply the station's entertainers with the equipment of their trade with these Nanotrasen-approved costumes! Contains a full clown and mime outfit, along with a bike horn and a bottle of nothing." + cost = 1300 + access = ACCESS_THEATRE + contains = list(/obj/item/storage/backpack/clown, + /obj/item/clothing/shoes/clown_shoes, + /obj/item/clothing/mask/gas/clown_hat, + /obj/item/clothing/under/rank/clown, + /obj/item/bikehorn, + /obj/item/clothing/under/rank/mime, + /obj/item/clothing/shoes/sneakers/black, + /obj/item/clothing/gloves/color/white, + /obj/item/clothing/mask/gas/mime, + /obj/item/clothing/head/beret, + /obj/item/clothing/suit/suspenders, + /obj/item/reagent_containers/food/drinks/bottle/bottleofnothing, + /obj/item/storage/backpack/mime) + crate_name = "standard costume crate" + crate_type = /obj/structure/closet/crate/wooden + +/datum/supply_pack/costumes_toys/randomised/toys + name = "Toy Crate" + desc = "Who cares about pride and accomplishment? Skip the gaming and get straight to the sweet rewards with this product! Contains five random toys. Warranty void if used to prank research directors." + cost = 1500 // or play the arcade machines ya lazy bum + num_contained = 5 + contains = list(/obj/item/storage/box/snappops, + /obj/item/toy/talking/AI, + /obj/item/toy/talking/codex_gigas, + /obj/item/clothing/under/syndicate/tacticool, + /obj/item/toy/sword , + /obj/item/toy/gun, + /obj/item/gun/ballistic/shotgun/toy/crossbow, + /obj/item/storage/box/fakesyndiesuit, + /obj/item/storage/crayons, + /obj/item/toy/spinningtoy, + /obj/item/toy/prize/ripley, + /obj/item/toy/prize/fireripley, + /obj/item/toy/prize/deathripley, + /obj/item/toy/prize/gygax, + /obj/item/toy/prize/durand, + /obj/item/toy/prize/honk, + /obj/item/toy/prize/marauder, + /obj/item/toy/prize/seraph, + /obj/item/toy/prize/mauler, + /obj/item/toy/prize/odysseus, + /obj/item/toy/prize/phazon, + /obj/item/toy/prize/reticence, + /obj/item/toy/cards/deck, + /obj/item/toy/nuke, + /obj/item/toy/minimeteor, + /obj/item/toy/redbutton, + /obj/item/toy/talking/owl, + /obj/item/toy/talking/griffin, + /obj/item/coin/antagtoken, + /obj/item/stack/tile/fakespace/loaded, + /obj/item/stack/tile/fakepit/loaded, + /obj/item/toy/toy_xeno, + /obj/item/storage/box/actionfigure, + /obj/item/restraints/handcuffs/fake, + /obj/item/grenade/chem_grenade/glitter/pink, + /obj/item/grenade/chem_grenade/glitter/blue, + /obj/item/grenade/chem_grenade/glitter/white, + /obj/item/toy/eightball, + /obj/item/toy/windupToolbox, + /obj/item/toy/clockwork_watch, + /obj/item/toy/toy_dagger, + /obj/item/extendohand/acme, + /obj/item/hot_potato/harmless/toy, + /obj/item/card/emagfake, + /obj/item/clothing/shoes/wheelys, + /obj/item/clothing/shoes/kindleKicks, + /obj/item/storage/belt/military/snack, + /obj/item/toy/eightball, + /obj/item/vending_refill/donksoft) + crate_name = "toy crate" + crate_type = /obj/structure/closet/crate/wooden + +/datum/supply_pack/costumes_toys/randomised/plush + name = "Plush Crate" + desc = "Plush tide station wide. Contains 5 random plushies for you to love. Warranty void if your love violates the terms of use." + cost = 1500 // or play the arcade machines ya lazy bum + num_contained = 5 + contains = list(/obj/item/toy/plush/random, + /obj/item/toy/plush/random, + /obj/item/toy/plush/random, + /obj/item/toy/plush/random, + /obj/item/toy/plush/random) //I'm lazy + crate_name = "plushie crate" + crate_type = /obj/structure/closet/crate/wooden + +/datum/supply_pack/costumes_toys/wizard + name = "Wizard Costume Crate" + desc = "Pretend to join the Wizard Federation with this full wizard outfit! Nanotrasen would like to remind its employees that actually joining the Wizard Federation is subject to termination of job and life." + cost = 2000 + contains = list(/obj/item/staff, + /obj/item/clothing/suit/wizrobe/fake, + /obj/item/clothing/shoes/sandal, + /obj/item/clothing/head/wizard/fake) + crate_name = "wizard costume crate" + crate_type = /obj/structure/closet/crate/wooden + +/datum/supply_pack/costumes_toys/randomised/fill(obj/structure/closet/crate/C) + var/list/L = contains.Copy() + for(var/i in 1 to num_contained) + var/item = pick_n_take(L) + new item(C) + +/datum/supply_pack/costumes_toys/wardrobes/autodrobe + name = "Autodrobe Supply Crate" + desc = "Autodrobe missing your favorite dress? Solve that issue today with this autodrobe refill." + cost = 1500 + contains = list(/obj/item/vending_refill/autodrobe) + crate_name = "autodrobe supply crate" + +/datum/supply_pack/costumes_toys/wardrobes/cargo + name = "Cargo Wardrobe Supply Crate" + desc = "This crate contains a refill for the CargoDrobe." + cost = 750 + contains = list(/obj/item/vending_refill/wardrobe/cargo_wardrobe) + crate_name = "cargo department supply crate" + +/datum/supply_pack/costumes_toys/wardrobes/engineering + name = "Engineering Wardrobe Supply Crate" + desc = "This crate contains refills for the EngiDrobe and AtmosDrobe." + cost = 1500 + contains = list(/obj/item/vending_refill/wardrobe/engi_wardrobe, + /obj/item/vending_refill/wardrobe/atmos_wardrobe) + crate_name = "engineering department wardrobe supply crate" + +/datum/supply_pack/costumes_toys/wardrobes/general + name = "General Wardrobes Supply Crate" + desc = "This crate contains refills for the CuraDrobe, BarDrobe, ChefDrobe, JaniDrobe, ChapDrobe." + cost = 3750 + contains = list(/obj/item/vending_refill/wardrobe/curator_wardrobe, + /obj/item/vending_refill/wardrobe/bar_wardrobe, + /obj/item/vending_refill/wardrobe/chef_wardrobe, + /obj/item/vending_refill/wardrobe/jani_wardrobe, + /obj/item/vending_refill/wardrobe/chap_wardrobe) + crate_name = "general wardrobes vendor refills" + +/datum/supply_pack/costumes_toys/wardrobes/hydroponics + name = "Hydrobe Supply Crate" + desc = "This crate contains a refill for the Hydrobe." + cost = 750 + contains = list(/obj/item/vending_refill/wardrobe/hydro_wardrobe) + crate_name = "hydrobe supply crate" + +/datum/supply_pack/costumes_toys/wardrobes/medical + name = "Medical Wardrobe Supply Crate" + desc = "This crate contains refills for the MediDrobe, ChemDrobe, GeneDrobe, and ViroDrobe." + cost = 3000 + contains = list(/obj/item/vending_refill/wardrobe/medi_wardrobe, + /obj/item/vending_refill/wardrobe/chem_wardrobe, + /obj/item/vending_refill/wardrobe/gene_wardrobe, + /obj/item/vending_refill/wardrobe/viro_wardrobe) + crate_name = "medical department wardrobe supply crate" + +/datum/supply_pack/costumes_toys/wardrobes/science + name = "Science Wardrobe Supply Crate" + desc = "This crate contains refills for the SciDrobe and RoboDrobe." + cost = 1500 + contains = list(/obj/item/vending_refill/wardrobe/robo_wardrobe, + /obj/item/vending_refill/wardrobe/science_wardrobe) + crate_name = "science department wardrobe supply crate" + +/datum/supply_pack/costumes_toys/wardrobes/security + name = "Security Wardrobe Supply Crate" + desc = "This crate contains refills for the SecDrobe and LawDrobe." + cost = 1500 + contains = list(/obj/item/vending_refill/wardrobe/sec_wardrobe, + /obj/item/vending_refill/wardrobe/law_wardrobe) + crate_name = "security department supply crate" + +/datum/supply_pack/costumes_toys/kinkmate + name = "Kinkmate construction kit" + cost = 2000 + contraband = TRUE + contains = list(/obj/item/vending_refill/kink, /obj/item/circuitboard/machine/kinkmate) + crate_name = "Kinkmate construction kit" diff --git a/code/modules/cargo/packs/emergency.dm b/code/modules/cargo/packs/emergency.dm new file mode 100644 index 0000000000..be99199f30 --- /dev/null +++ b/code/modules/cargo/packs/emergency.dm @@ -0,0 +1,275 @@ + +//Reminders- +// If you add something to this list, please group it by type and sort it alphabetically instead of just jamming it in like an animal +// cost = 700- Minimum cost, or infinite points are possible. +////////////////////////////////////////////////////////////////////////////// +//////////////////////////// Emergency /////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +/datum/supply_pack/emergency + group = "Emergency" + +/datum/supply_pack/emergency/vehicle + name = "Biker Gang Kit" //TUNNEL SNAKES OWN THIS TOWN + desc = "TUNNEL SNAKES OWN THIS TOWN. Contains an unbranded All Terrain Vehicle, and a complete gang outfit -- consists of black gloves, a menacing skull bandanna, and a SWEET leather overcoat!" + cost = 2800 + contraband = TRUE + contains = list(/obj/vehicle/ridden/atv, + /obj/item/key, + /obj/item/clothing/suit/jacket/leather/overcoat, + /obj/item/clothing/gloves/color/black, + /obj/item/clothing/head/soft, + /obj/item/clothing/mask/bandana/skull)//so you can properly #cargoniabikergang + crate_name = "Biker Kit" + crate_type = /obj/structure/closet/crate/large + +/datum/supply_pack/emergency/equipment + name = "Emergency Bot/Internals Crate" + desc = "Explosions got you down? These supplies are guaranteed to patch up holes, in stations and people alike! Comes with two floorbots, two medbots, five oxygen masks and five small oxygen tanks." + cost = 3750 + contains = list(/mob/living/simple_animal/bot/floorbot, + /mob/living/simple_animal/bot/floorbot, + /mob/living/simple_animal/bot/medbot, + /mob/living/simple_animal/bot/medbot, + /obj/item/tank/internals/air, + /obj/item/tank/internals/air, + /obj/item/tank/internals/air, + /obj/item/tank/internals/air, + /obj/item/tank/internals/air, + /obj/item/clothing/mask/gas, + /obj/item/clothing/mask/gas, + /obj/item/clothing/mask/gas, + /obj/item/clothing/mask/gas, + /obj/item/clothing/mask/gas) + crate_name = "emergency crate" + crate_type = /obj/structure/closet/crate/internals + +/datum/supply_pack/emergency/radiatione_emergency + name = "Emergenc Radiation Protection Crate" + desc = "Survive the Nuclear Apocalypse and Supermatter Engine alike with two sets of Radiation suits. Each set contains a helmet, suit, and Geiger counter. We'll even throw in a few pill bottles that are able to handles radiation and the affects of the poisoning." + cost = 2500 + contains = list(/obj/item/clothing/head/radiation, + /obj/item/clothing/head/radiation, + /obj/item/clothing/suit/radiation, + /obj/item/clothing/suit/radiation, + /obj/item/geiger_counter, + /obj/item/geiger_counter, + /obj/item/storage/pill_bottle/mutarad, + /obj/item/storage/firstaid/radbgone) + crate_name = "radiation protection crate" + crate_type = /obj/structure/closet/crate/radiation + +/datum/supply_pack/emergency/rcds + name = "Emergency RCDs" + desc = "Bombs going off on station? SME blown and now you need to fix the hole it left behind? Well this crate has a pare of Rcds to be able to easily fix up any problem you may have!" + cost = 1500 + contains = list(/obj/item/construction/rcd, + /obj/item/construction/rcd) + crate_name = "emergency rcds" + crate_type = /obj/structure/closet/crate/internals + +/datum/supply_pack/emergency/soft_suit + name = "Emergency Space Suit " + desc = "Is there bombs going off left and right? Is there meteors shooting around the station? Well we have two fragile space suit for emergencys as well as air and masks." + cost = 1200 + contains = list(/obj/item/tank/internals/air, + /obj/item/tank/internals/air, + /obj/item/clothing/mask/gas, + /obj/item/clothing/mask/gas, + /obj/item/clothing/suit/space/fragile, + /obj/item/clothing/suit/space/fragile, + /obj/item/clothing/head/helmet/space/fragile, + /obj/item/clothing/head/helmet/space/fragile) + crate_name = "emergency crate" + crate_type = /obj/structure/closet/crate/internals + +/datum/supply_pack/emergency/firefighting + name = "Firefighting Crate" + desc = "Only you can prevent station fires. Partner up with two firefighter suits, gas masks, flashlights, large oxygen tanks, extinguishers, and hardhats!" + cost = 1200 + contains = list(/obj/item/clothing/suit/fire/firefighter, + /obj/item/clothing/suit/fire/firefighter, + /obj/item/clothing/mask/gas, + /obj/item/clothing/mask/gas, + /obj/item/flashlight, + /obj/item/flashlight, + /obj/item/tank/internals/oxygen/red, + /obj/item/tank/internals/oxygen/red, + /obj/item/extinguisher/advanced, + /obj/item/extinguisher/advanced, + /obj/item/clothing/head/hardhat/red, + /obj/item/clothing/head/hardhat/red) + crate_name = "firefighting crate" + +/datum/supply_pack/emergency/atmostank + name = "Firefighting Tank Backpack" + desc = "Mow down fires with this high-capacity fire fighting tank backpack. Requires Atmospherics access to open." + cost = 1000 + access = ACCESS_ATMOSPHERICS + contains = list(/obj/item/watertank/atmos) + crate_name = "firefighting backpack crate" + crate_type = /obj/structure/closet/crate/secure + +/datum/supply_pack/emergency/internals + name = "Internals Crate" + desc = "Master your life energy and control your breathing with three breath masks, three emergency oxygen tanks and three large air tanks."//IS THAT A + cost = 1000 + contains = list(/obj/item/clothing/mask/gas, + /obj/item/clothing/mask/gas, + /obj/item/clothing/mask/gas, + /obj/item/clothing/mask/breath, + /obj/item/clothing/mask/breath, + /obj/item/clothing/mask/breath, + /obj/item/tank/internals/emergency_oxygen, + /obj/item/tank/internals/emergency_oxygen, + /obj/item/tank/internals/emergency_oxygen, + /obj/item/tank/internals/air, + /obj/item/tank/internals/air, + /obj/item/tank/internals/air) + crate_name = "internals crate" + crate_type = /obj/structure/closet/crate/internals + +/datum/supply_pack/emergency/metalfoam + name = "Metal Foam Grenade Crate" + desc = "Seal up those pesky hull breaches with 14 Metal Foam Grenades." + cost = 2000 + contains = list(/obj/item/storage/box/metalfoam, + /obj/item/storage/box/metalfoam) + crate_name = "metal foam grenade crate" + +/datum/supply_pack/emergency/syndicate + name = "NULL_ENTRY" + desc = "(#@&^$THIS PACKAGE CONTAINS 30TC WORTH OF SOME RANDOM SYNDICATE GEAR WE HAD LYING AROUND THE WAREHOUSE. GIVE EM HELL, OPERATIVE@&!*() " + hidden = TRUE + cost = 20000 + contains = list() + crate_name = "emergency crate" + crate_type = /obj/structure/closet/crate/internals + dangerous = TRUE + +/datum/supply_pack/emergency/syndicate/fill(obj/structure/closet/crate/C) + var/crate_value = 30 + var/list/uplink_items = get_uplink_items(SSticker.mode) + while(crate_value) + var/category = pick(uplink_items) + var/item = pick(uplink_items[category]) + var/datum/uplink_item/I = uplink_items[category][item] + if(!I.surplus_nullcrates || prob(100 - I.surplus_nullcrates)) + continue + if(crate_value < I.cost) + continue + crate_value -= I.cost + new I.item(C) + +/datum/supply_pack/emergency/plasma_spacesuit + name = "Plasmaman Space Envirosuits" + desc = "Contains two space-worthy envirosuits for Plasmamen. Order now and we'll throw in two free helmets! Requires EVA access to open." + cost = 4000 + access = ACCESS_EVA + contains = list(/obj/item/clothing/suit/space/eva/plasmaman, + /obj/item/clothing/suit/space/eva/plasmaman, + /obj/item/clothing/head/helmet/space/plasmaman, + /obj/item/clothing/head/helmet/space/plasmaman) + crate_name = "plasmaman EVA crate" + crate_type = /obj/structure/closet/crate/secure + +/datum/supply_pack/emergency/plasmaman + name = "Plasmaman Supply Kit" + desc = "Keep those Plasmamen alive with two sets of Plasmaman outfits. Each set contains a plasmaman jumpsuit, internals tank, and helmet." + cost = 2000 + contains = list(/obj/item/clothing/under/plasmaman, + /obj/item/clothing/under/plasmaman, + /obj/item/tank/internals/plasmaman/belt/full, + /obj/item/tank/internals/plasmaman/belt/full, + /obj/item/clothing/head/helmet/space/plasmaman, + /obj/item/clothing/head/helmet/space/plasmaman) + crate_name = "plasmaman supply kit" + +/datum/supply_pack/emergency/radiation + name = "Radiation Protection Crate" + desc = "Survive the Nuclear Apocalypse and Supermatter Engine alike with two sets of Radiation suits. Each set contains a helmet, suit, and Geiger counter. We'll even throw in a bottle of vodka and some glasses too, considering the life-expectancy of people who order this." + cost = 1300 + contains = list(/obj/item/clothing/head/radiation, + /obj/item/clothing/head/radiation, + /obj/item/clothing/suit/radiation, + /obj/item/clothing/suit/radiation, + /obj/item/geiger_counter, + /obj/item/geiger_counter, + /obj/item/reagent_containers/food/drinks/bottle/vodka, + /obj/item/reagent_containers/food/drinks/drinkingglass/shotglass, + /obj/item/reagent_containers/food/drinks/drinkingglass/shotglass) + crate_name = "radiation protection crate" + crate_type = /obj/structure/closet/crate/radiation + +/datum/supply_pack/emergency/spacesuit + name = "Space Suit Crate" + desc = "Contains two aging suits from Space-Goodwill. Requires EVA access to open." + cost = 3000 + access = ACCESS_EVA + contains = list(/obj/item/clothing/suit/space, + /obj/item/clothing/suit/space, + /obj/item/clothing/head/helmet/space, + /obj/item/clothing/head/helmet/space, + /obj/item/clothing/mask/breath, + /obj/item/clothing/mask/breath) + crate_name = "space suit crate" + crate_type = /obj/structure/closet/crate/secure + +/datum/supply_pack/emergency/spacejets + name = "Spare EVA Jetpacks" + desc = "Contains three EVA grade jectpaks. Requires EVA access to open." + cost = 2000 + access = ACCESS_EVA + contains = list(/obj/item/tank/jetpack/carbondioxide/eva, + /obj/item/tank/jetpack/carbondioxide/eva, + /obj/item/tank/jetpack/carbondioxide/eva) + crate_name = "eva jetpacks crate" + crate_type = /obj/structure/closet/crate/secure + +/datum/supply_pack/emergency/specialops + name = "Special Ops Supplies" + desc = "(*!&@#TOO CHEAP FOR THAT NULL_ENTRY, HUH OPERATIVE? WELL, THIS LITTLE ORDER CAN STILL HELP YOU OUT IN A PINCH. CONTAINS A BOX OF FIVE EMP GRENADES, THREE SMOKEBOMBS, AN INCENDIARY GRENADE, AND A \"SLEEPY PEN\" FULL OF NICE TOXINS!#@*$" + hidden = TRUE + cost = 2200 + contains = list(/obj/item/storage/box/emps, + /obj/item/grenade/smokebomb, + /obj/item/grenade/smokebomb, + /obj/item/grenade/smokebomb, + /obj/item/pen/sleepy, + /obj/item/grenade/chem_grenade/incendiary) + crate_name = "emergency crate" + crate_type = /obj/structure/closet/crate/internals + +/datum/supply_pack/emergency/weedcontrol + name = "Weed Control Crate" + desc = "Keep those invasive species OUT. Contains a scythe, gasmask, two sprays of Plant-B-Gone, and two anti-weed chemical grenades. Warranty void if used on ambrosia. Requires Hydroponics access to open." + cost = 1800 + access = ACCESS_HYDROPONICS + contains = list(/obj/item/scythe, + /obj/item/clothing/mask/gas, + /obj/item/grenade/chem_grenade/antiweed, + /obj/item/grenade/chem_grenade/antiweed, + /obj/item/reagent_containers/spray/plantbgone, + /obj/item/reagent_containers/spray/plantbgone) + crate_name = "weed control crate" + crate_type = /obj/structure/closet/crate/secure/hydroponics + +/datum/supply_pack/medical/anitvirus + name = "Virus Containment Crate" + desc = "Viro let out a death plague Mk II again? Someone didnt wash there hands? Old plagues born anew? Well this crate is for you! Hope you cure it before it brakes out of the station... This crate needs medical access to open and has two bio suits, a box of needles and beakers, five spaceacillin needles, and a medibot." + cost = 3000 + access = ACCESS_MEDICAL + contains = list(/mob/living/simple_animal/bot/medbot, + /obj/item/clothing/head/bio_hood, + /obj/item/clothing/head/bio_hood, + /obj/item/clothing/suit/bio_suit, + /obj/item/clothing/suit/bio_suit, + /obj/item/reagent_containers/syringe/antiviral, + /obj/item/reagent_containers/syringe/antiviral, + /obj/item/reagent_containers/syringe/antiviral, + /obj/item/reagent_containers/syringe/antiviral, + /obj/item/reagent_containers/syringe/antiviral, + /obj/item/storage/box/syringes, + /obj/item/storage/box/beakers) + crate_name = "virus containment unit crate" + crate_type = /obj/structure/closet/crate/secure/plasma diff --git a/code/modules/cargo/packs/engine.dm b/code/modules/cargo/packs/engine.dm new file mode 100644 index 0000000000..a4438c7ef8 --- /dev/null +++ b/code/modules/cargo/packs/engine.dm @@ -0,0 +1,169 @@ + +//Reminders- +// If you add something to this list, please group it by type and sort it alphabetically instead of just jamming it in like an animal +// cost = 700- Minimum cost, or infinite points are possible. +////////////////////////////////////////////////////////////////////////////// +//////////////////////// Engine Construction ///////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +/datum/supply_pack/engine + group = "Engine Construction" + crate_type = /obj/structure/closet/crate/engineering + +/datum/supply_pack/engine/am_jar + name = "Antimatter Containment Jar Crate" + desc = "Two Antimatter containment jars stuffed into a single crate." + cost = 2300 + contains = list(/obj/item/am_containment, + /obj/item/am_containment) + crate_name = "antimatter jar crate" + +/datum/supply_pack/engine/am_core + name = "Antimatter Control Crate" + desc = "The brains of the Antimatter engine, this device is sure to teach the station's powergrid the true meaning of real power." + cost = 5200 + contains = list(/obj/machinery/power/am_control_unit) + crate_name = "antimatter control crate" + +/datum/supply_pack/engine/am_shielding + name = "Antimatter Shielding Crate" + desc = "Contains ten Antimatter shields, somehow crammed into a crate." + cost = 2500 + contains = list(/obj/item/am_shielding_container, + /obj/item/am_shielding_container, + /obj/item/am_shielding_container, + /obj/item/am_shielding_container, + /obj/item/am_shielding_container, + /obj/item/am_shielding_container, + /obj/item/am_shielding_container, + /obj/item/am_shielding_container, + /obj/item/am_shielding_container, + /obj/item/am_shielding_container) //10 shields: 3x3 containment and a core + crate_name = "antimatter shielding crate" + +/datum/supply_pack/engine/emitter + name = "Emitter Crate" + desc = "Useful for powering forcefield generators while destroying locked crates and intruders alike. Contains two high-powered energy emitters. Requires CE access to open." + cost = 1750 + access = ACCESS_CE + contains = list(/obj/machinery/power/emitter, + /obj/machinery/power/emitter) + crate_name = "emitter crate" + crate_type = /obj/structure/closet/crate/secure/engineering + dangerous = TRUE + +/datum/supply_pack/engine/field_gen + name = "Field Generator Crate" + desc = "Typically the only thing standing between the station and a messy death. Powered by emitters. Contains two field generators." + cost = 1750 + contains = list(/obj/machinery/field/generator, + /obj/machinery/field/generator) + crate_name = "field generator crate" + +/datum/supply_pack/engine/grounding_rods + name = "Grounding Rod Crate" + desc = "Four grounding rods guaranteed to keep any uppity tesla's lightning under control." + cost = 2200 + contains = list(/obj/machinery/power/grounding_rod, + /obj/machinery/power/grounding_rod, + /obj/machinery/power/grounding_rod, + /obj/machinery/power/grounding_rod) + crate_name = "grounding rod crate" + crate_type = /obj/structure/closet/crate/engineering/electrical + +/datum/supply_pack/engine/mason + name = "M.A.S.O.N RIG Crate" + desc = "The rare M.A.S.O.N RIG. Requires CE access to open." + cost = 15000 + access = ACCESS_CE + contains = list(/obj/item/clothing/suit/space/hardsuit/ancient/mason) + crate_name = "M.A.S.O.N Rig" + crate_type = /obj/structure/closet/crate/secure/engineering + +/datum/supply_pack/engine/PA + name = "Particle Accelerator Crate" + desc = "A supermassive black hole or hyper-powered teslaball are the perfect way to spice up any party! This \"My First Apocalypse\" kit contains everything you need to build your own Particle Accelerator! Ages 10 and up." + cost = 3750 + contains = list(/obj/structure/particle_accelerator/fuel_chamber, + /obj/machinery/particle_accelerator/control_box, + /obj/structure/particle_accelerator/particle_emitter/center, + /obj/structure/particle_accelerator/particle_emitter/left, + /obj/structure/particle_accelerator/particle_emitter/right, + /obj/structure/particle_accelerator/power_box, + /obj/structure/particle_accelerator/end_cap) + crate_name = "particle accelerator crate" + +/datum/supply_pack/engine/collector + name = "Radiation Collector Crate" + desc = "Contains three radiation collectors. Useful for collecting energy off nearby Supermatter Crystals, Singularities or Teslas!" + cost = 2750 + contains = list(/obj/machinery/power/rad_collector, + /obj/machinery/power/rad_collector, + /obj/machinery/power/rad_collector) + crate_name = "collector crate" + +/datum/supply_pack/engine/sing_gen + name = "Singularity Generator Crate" + desc = "The key to unlocking the power of Lord Singuloth. Particle Accelerator not included." + cost = 6000 + contains = list(/obj/machinery/the_singularitygen) + crate_name = "singularity generator crate" + +/datum/supply_pack/engine/solar + name = "Solar Panel Crate" + desc = "Go green with this DIY advanced solar array. Contains twenty one solar assemblies, a solar-control circuit board, and tracker. If you have any questions, please check out the enclosed instruction book." + cost = 2850 + contains = list(/obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/solar_assembly, + /obj/item/circuitboard/computer/solar_control, + /obj/item/electronics/tracker, + /obj/item/paper/guides/jobs/engi/solars) + crate_name = "solar panel crate" + crate_type = /obj/structure/closet/crate/engineering/electrical + +/datum/supply_pack/engine/supermatter_shard + name = "Supermatter Shard Crate" + desc = "The power of the heavens condensed into a single crystal. Requires CE access to open." + cost = 10000 + access = ACCESS_CE + contains = list(/obj/machinery/power/supermatter_crystal/shard) + crate_name = "supermatter shard crate" + crate_type = /obj/structure/closet/crate/secure/engineering + dangerous = TRUE + +/datum/supply_pack/engine/tesla_coils + name = "Tesla Coil Crate" + desc = "Whether it's high-voltage executions, creating research points, or just plain old power generation: This pack of four Tesla coils can do it all!" + cost = 3500 + contains = list(/obj/machinery/power/tesla_coil, + /obj/machinery/power/tesla_coil, + /obj/machinery/power/tesla_coil, + /obj/machinery/power/tesla_coil) + crate_name = "tesla coil crate" + crate_type = /obj/structure/closet/crate/engineering/electrical + +/datum/supply_pack/engine/tesla_gen + name = "Tesla Generator Crate" + desc = "The key to unlocking the power of the Tesla energy ball. Particle Accelerator not included." + cost = 7000 + contains = list(/obj/machinery/the_singularitygen/tesla) + crate_name = "tesla generator crate" diff --git a/code/modules/cargo/packs/engineering.dm b/code/modules/cargo/packs/engineering.dm new file mode 100644 index 0000000000..3d46b776c4 --- /dev/null +++ b/code/modules/cargo/packs/engineering.dm @@ -0,0 +1,203 @@ + +//Reminders- +// If you add something to this list, please group it by type and sort it alphabetically instead of just jamming it in like an animal +// cost = 700- Minimum cost, or infinite points are possible. +////////////////////////////////////////////////////////////////////////////// +//////////////////////////// Engineering ///////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +/datum/supply_pack/engineering + group = "Engineering" + crate_type = /obj/structure/closet/crate/engineering + +/datum/supply_pack/engineering/shieldgen + name = "Anti-breach Shield Projector Crate" + desc = "Hull breaches again? Say no more with the Nanotrasen Anti-Breach Shield Projector! Uses forcefield technology to keep the air in, and the space out. Contains two shield projectors." + cost = 2500 + contains = list(/obj/machinery/shieldgen, + /obj/machinery/shieldgen) + crate_name = "anti-breach shield projector crate" + +/datum/supply_pack/engineering/conveyor + name = "Conveyor Assembly Crate" + desc = "Keep production moving along with six conveyor belts. Conveyor switch included. If you have any questions, check out the enclosed instruction book." + cost = 750 + contains = list(/obj/item/conveyor_construct, + /obj/item/conveyor_construct, + /obj/item/conveyor_construct, + /obj/item/conveyor_construct, + /obj/item/conveyor_construct, + /obj/item/conveyor_construct, + /obj/item/conveyor_switch_construct, + /obj/item/paper/guides/conveyor) + crate_name = "conveyor assembly crate" + +/datum/supply_pack/engineering/engiequipment + name = "Engineering Gear Crate" + desc = "Gear up with three toolbelts, high-visibility vests, welding helmets, hardhats, and two pairs of meson goggles!" + cost = 1500 + contains = list(/obj/item/storage/belt/utility, + /obj/item/storage/belt/utility, + /obj/item/storage/belt/utility, + /obj/item/clothing/suit/hazardvest, + /obj/item/clothing/suit/hazardvest, + /obj/item/clothing/suit/hazardvest, + /obj/item/clothing/head/welding, + /obj/item/clothing/head/welding, + /obj/item/clothing/head/welding, + /obj/item/clothing/head/hardhat, + /obj/item/clothing/head/hardhat, + /obj/item/clothing/head/hardhat, + /obj/item/clothing/glasses/meson/engine, + /obj/item/clothing/glasses/meson/engine) + crate_name = "engineering gear crate" + +/datum/supply_pack/engineering/engihardsuit + name = "Engineering Hardsuit" + desc = "Poly 'Who stole all the hardsuits!' Well now you can get more hardsuits if needed! NOTE ONE HARDSUIT IS IN THIS CRATE, as well as one air tank and mask!" + cost = 2750 + contains = list(/obj/item/tank/internals/air, + /obj/item/clothing/mask/gas, + /obj/item/clothing/suit/space/hardsuit/engine) + crate_name = "engineering hardsuit" + +/datum/supply_pack/engineering/atmoshardsuit + name = "Atmospherics Hardsuit" + desc = "Too many techs and not enough hardsuits? Time to buy some more! Comes with gas mask and air tank. Ask the CE to open." + cost = 5000 + access = ACCESS_CE + contains = list(/obj/item/tank/internals/air, + /obj/item/clothing/mask/gas, + /obj/item/clothing/suit/space/hardsuit/engine/atmos) + crate_name = "atmospherics hardsuit" + crate_type = /obj/structure/closet/crate/secure/engineering + +/datum/supply_pack/engineering/industrialrcd + name = "Industrial RCD" + desc = "A industrial RCD in case the station has gone through more then one meteor storm and the CE needs to bring out the somthing a bit more reliable. Dose not contain spare ammo for the industrial RCD or any other RCD modles." + cost = 4500 + access = ACCESS_CE + contains = list(/obj/item/construction/rcd/industrial) + crate_name = "industrial rcd" + crate_type = /obj/structure/closet/crate/secure/engineering + +/datum/supply_pack/engineering/powergamermitts + name = "Insulated Gloves Crate" + desc = "The backbone of modern society. Barely ever ordered for actual engineering. Contains three insulated gloves." + cost = 2750 //Made of pure-grade bullshittinium + contains = list(/obj/item/clothing/gloves/color/yellow, + /obj/item/clothing/gloves/color/yellow, + /obj/item/clothing/gloves/color/yellow) + crate_name = "insulated gloves crate" + crate_type = /obj/structure/closet/crate/engineering/electrical + +/obj/item/stock_parts/cell/inducer_supply + maxcharge = 5000 + charge = 5000 + +/datum/supply_pack/engineering/inducers + name = "NT-75 Electromagnetic Power Inducers Crate" + desc = "No rechargers? No problem, with the NT-75 EPI, you can recharge any standard cell-based equipment anytime, anywhere. Contains two Inducers." + cost = 2300 + contains = list(/obj/item/inducer/sci {cell_type = /obj/item/stock_parts/cell/inducer_supply; opened = 0}, /obj/item/inducer/sci {cell_type = /obj/item/stock_parts/cell/inducer_supply; opened = 0}) //FALSE doesn't work in modified type paths apparently. + crate_name = "inducer crate" + crate_type = /obj/structure/closet/crate/engineering/electrical + +/datum/supply_pack/engineering/pacman + name = "P.A.C.M.A.N Generator Crate" + desc = "Engineers can't set up the engine? Not an issue for you, once you get your hands on this P.A.C.M.A.N. Generator! Takes in plasma and spits out sweet sweet energy." + cost = 2250 + contains = list(/obj/machinery/power/port_gen/pacman) + crate_name = "PACMAN generator crate" + crate_type = /obj/structure/closet/crate/engineering/electrical + +/datum/supply_pack/engineering/power + name = "Power Cell Crate" + desc = "Looking for power overwhelming? Look no further. Contains three high-voltage power cells." + cost = 1000 + contains = list(/obj/item/stock_parts/cell/high, + /obj/item/stock_parts/cell/high, + /obj/item/stock_parts/cell/high) + crate_name = "power cell crate" + crate_type = /obj/structure/closet/crate/engineering/electrical + +/datum/supply_pack/engineering/shuttle_engine + name = "Shuttle Engine Crate" + desc = "Through advanced bluespace-shenanigans, our engineers have managed to fit an entire shuttle engine into one tiny little crate. Requires CE access to open." + cost = 5000 + access = ACCESS_CE + contains = list(/obj/structure/shuttle/engine/propulsion/burst/cargo) + crate_name = "shuttle engine crate" + crate_type = /obj/structure/closet/crate/secure/engineering + special = TRUE + +/datum/supply_pack/engineering/tools + name = "Toolbox Crate" + desc = "Any robust spaceman is never far from their trusty toolbox. Contains three electrical toolboxes and three mechanical toolboxes." + contains = list(/obj/item/storage/toolbox/electrical, + /obj/item/storage/toolbox/electrical, + /obj/item/storage/toolbox/electrical, + /obj/item/storage/toolbox/mechanical, + /obj/item/storage/toolbox/mechanical, + /obj/item/storage/toolbox/mechanical) + cost = 1200 + crate_name = "toolbox crate" + +/datum/supply_pack/engineering/bsa + name = "Bluespace Artillery Parts" + desc = "The pride of Nanotrasen Naval Command. The legendary Bluespace Artillery Cannon is a devastating feat of human engineering and testament to wartime determination. Highly advanced research is required for proper construction. " + cost = 15000 + special = TRUE + contains = list(/obj/item/circuitboard/machine/bsa/front, + /obj/item/circuitboard/machine/bsa/middle, + /obj/item/circuitboard/machine/bsa/back, + /obj/item/circuitboard/computer/bsa_control + ) + crate_name= "bluespace artillery parts crate" + +/datum/supply_pack/engineering/dna_vault + name = "DNA Vault Parts" + desc = "Secure the longevity of the current state of humanity within this massive library of scientific knowledge, capable of granting superhuman powers and abilities. Highly advanced research is required for proper construction. Also contains five DNA probes." + cost = 12000 + special = TRUE + contains = list( + /obj/item/circuitboard/machine/dna_vault, + /obj/item/dna_probe, + /obj/item/dna_probe, + /obj/item/dna_probe, + /obj/item/dna_probe, + /obj/item/dna_probe + ) + crate_name= "dna vault parts crate" + +/datum/supply_pack/engineering/dna_probes + name = "DNA Vault Samplers" + desc = "Contains five DNA probes for use in the DNA vault." + cost = 3000 + special = TRUE + contains = list(/obj/item/dna_probe, + /obj/item/dna_probe, + /obj/item/dna_probe, + /obj/item/dna_probe, + /obj/item/dna_probe + ) + crate_name= "dna samplers crate" + + +/datum/supply_pack/engineering/shield_sat + name = "Shield Generator Satellite" + desc = "Protect the very existence of this station with these Anti-Meteor defenses. Contains three Shield Generator Satellites." + cost = 4000 + contains = list( + /obj/machinery/satellite/meteor_shield, + /obj/machinery/satellite/meteor_shield, + /obj/machinery/satellite/meteor_shield + ) + crate_name= "shield sat crate" + +/datum/supply_pack/engineering/shield_sat_control + name = "Shield System Control Board" + desc = "A control system for the Shield Generator Satellite system." + cost = 4000 + contains = list(/obj/item/circuitboard/computer/sat_control) + crate_name= "shield control board crate" diff --git a/code/modules/cargo/packs/livestock.dm b/code/modules/cargo/packs/livestock.dm new file mode 100644 index 0000000000..6479869ee0 --- /dev/null +++ b/code/modules/cargo/packs/livestock.dm @@ -0,0 +1,154 @@ + +//Reminders- +// If you add something to this list, please group it by type and sort it alphabetically instead of just jamming it in like an animal +// cost = 700- Minimum cost, or infinite points are possible. +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// Livestock ///////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +/datum/supply_pack/critter + group = "Livestock" + crate_type = /obj/structure/closet/crate/critter + +/datum/supply_pack/critter/butterfly + name = "Butterflies Crate" + desc = "Not a very dangerous insect, but they do give off a better image than, say, flies or cockroaches."//is that a motherfucking worm reference + contraband = TRUE + cost = 5000 + contains = list(/mob/living/simple_animal/butterfly) + crate_name = "entomology samples crate" + +/datum/supply_pack/critter/butterfly/generate() + . = ..() + for(var/i in 1 to 49) + new /mob/living/simple_animal/butterfly(.) + +/datum/supply_pack/critter/cat + name = "Cat Crate" + desc = "The cat goes meow! Comes with a collar and a nice cat toy! Cheeseburger not included."//i can't believe im making this reference + cost = 5000 //Cats are worth as much as corgis. + contains = list(/mob/living/simple_animal/pet/cat, + /obj/item/clothing/neck/petcollar, + /obj/item/toy/cattoy) + crate_name = "cat crate" + +/datum/supply_pack/critter/cat/generate() + . = ..() + if(prob(50)) + var/mob/living/simple_animal/pet/cat/C = locate() in . + qdel(C) + new /mob/living/simple_animal/pet/cat/Proc(.) + +/datum/supply_pack/critter/chick + name = "Chicken Crate" + desc = "The chicken goes bwaak!" + cost = 2000 + contains = list( /mob/living/simple_animal/chick) + crate_name = "chicken crate" + +/datum/supply_pack/critter/crab + name = "Crab Rocket" + desc = "CRAAAAAAB ROCKET. CRAB ROCKET. CRAB ROCKET. CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB ROCKET. CRAFT. ROCKET. BUY. CRAFT ROCKET. CRAB ROOOCKET. CRAB ROOOOCKET. CRAB CRAB CRAB CRAB CRAB CRAB CRAB CRAB ROOOOOOOOOOOOOOOOOOOOOOCK EEEEEEEEEEEEEEEEEEEEEEEEE EEEETTTTTTTTTTTTAAAAAAAAA AAAHHHHHHHHHHHHH. CRAB ROCKET. CRAAAB ROCKEEEEEEEEEGGGGHHHHTT CRAB CRAB CRAABROCKET CRAB ROCKEEEET."//fun fact: i actually spent like 10 minutes and transcribed the entire video. + cost = 5000 + contains = list(/mob/living/simple_animal/crab) + crate_name = "look sir free crabs" + DropPodOnly = TRUE + +/datum/supply_pack/critter/crab/generate() + . = ..() + for(var/i in 1 to 49) + new /mob/living/simple_animal/crab(.) + +/datum/supply_pack/critter/corgi + name = "Corgi Crate" + desc = "Considered the optimal dog breed by thousands of research scientists, this Corgi is but one dog from the millions of Ian's noble bloodline. Comes with a cute collar!" + cost = 5000 + contains = list(/mob/living/simple_animal/pet/dog/corgi, + /obj/item/clothing/neck/petcollar) + crate_name = "corgi crate" + +/datum/supply_pack/critter/corgi/generate() + . = ..() + if(prob(50)) + var/mob/living/simple_animal/pet/dog/corgi/D = locate() in . + if(D.gender == FEMALE) + qdel(D) + new /mob/living/simple_animal/pet/dog/corgi/Lisa(.) + +/datum/supply_pack/critter/corgis/exotic + name = "Exotic Corgi Crate" + desc = "Corgis fit for a king, these corgis come in a unique color to signify their superiority. Comes with a cute collar!" + cost = 5500 + contains = list(/mob/living/simple_animal/pet/dog/corgi/exoticcorgi, + /obj/item/clothing/neck/petcollar) + crate_name = "exotic corgi crate" + +/datum/supply_pack/critter/cow + name = "Cow Crate" + desc = "The cow goes moo!" + cost = 3000 + contains = list(/mob/living/simple_animal/cow) + crate_name = "cow crate" + +/datum/supply_pack/critter/fox + name = "Fox Crate" + desc = "The fox goes...? Comes with a collar!"//what does the fox say + cost = 5000 + contains = list(/mob/living/simple_animal/pet/fox, + /obj/item/clothing/neck/petcollar) + crate_name = "fox crate" + +/datum/supply_pack/critter/goat + name = "Goat Crate" + desc = "The goat goes baa! Warranty void if used as a replacement for Pete." + cost = 2500 + contains = list(/mob/living/simple_animal/hostile/retaliate/goat) + crate_name = "goat crate" + +/datum/supply_pack/critter/goose + name = "Goose Crate" + desc = "Angry and violent birds. Evil, evil creatures." + cost = 2500 + contains = list(/mob/living/simple_animal/hostile/retaliate/goose) + crate_name = "goose crate" + +/datum/supply_pack/critter/monkey + name = "Monkey Cube Crate" + desc = "Stop monkeying around! Contains seven monkey cubes. Just add water!" + cost = 2000 + contains = list (/obj/item/storage/box/monkeycubes) + crate_name = "monkey cube crate" + +/datum/supply_pack/critter/pug + name = "Pug Crate" + desc = "Like a normal dog, but... squished. Comes with a nice collar!" + cost = 5000 + contains = list(/mob/living/simple_animal/pet/dog/pug, + /obj/item/clothing/neck/petcollar) + crate_name = "pug crate" + +/datum/supply_pack/organic/critter/kiwi + name = "Space kiwi Crate" + cost = 2000 + contains = list( /mob/living/simple_animal/kiwi) + crate_name = "space kiwi crate" + +/datum/supply_pack/critter/snake + name = "Snake Crate" + desc = "Tired of these MOTHER FUCKING snakes on this MOTHER FUCKING space station? Then this isn't the crate for you. Contains three poisonous snakes." + cost = 3000 + contains = list(/mob/living/simple_animal/hostile/retaliate/poison/snake, + /mob/living/simple_animal/hostile/retaliate/poison/snake, + /mob/living/simple_animal/hostile/retaliate/poison/snake) + crate_name = "snake crate" + +/datum/supply_pack/critter/secbat + name = "Security Bat Crate" + desc = "Contains five security bats, perfect to Bat-up any security officer." + cost = 2500 + contains = list(/mob/living/simple_animal/hostile/retaliate/bat/secbat, + /mob/living/simple_animal/hostile/retaliate/bat/secbat, + /mob/living/simple_animal/hostile/retaliate/bat/secbat, + /mob/living/simple_animal/hostile/retaliate/bat/secbat, + /mob/living/simple_animal/hostile/retaliate/bat/secbat) + crate_name = "security bat crate" diff --git a/code/modules/cargo/packs/materials.dm b/code/modules/cargo/packs/materials.dm new file mode 100644 index 0000000000..0f8ad2462a --- /dev/null +++ b/code/modules/cargo/packs/materials.dm @@ -0,0 +1,170 @@ + +//Reminders- +// If you add something to this list, please group it by type and sort it alphabetically instead of just jamming it in like an animal +// cost = 700- Minimum cost, or infinite points are possible. +////////////////////////////////////////////////////////////////////////////// +/////////////////////// Canisters & Materials //////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +/datum/supply_pack/materials + group = "Canisters & Materials" + +/datum/supply_pack/materials/cardboard50 + name = "50 Cardboard Sheets" + desc = "Create a bunch of boxes." + cost = 1000 + contains = list(/obj/item/stack/sheet/cardboard/fifty) + crate_name = "cardboard sheets crate" + +/datum/supply_pack/materials/glass50 + name = "50 Glass Sheets" + desc = "Let some nice light in with fifty glass sheets!" + cost = 850 + contains = list(/obj/item/stack/sheet/glass/fifty) + crate_name = "glass sheets crate" + +/datum/supply_pack/materials/metal50 + name = "50 Metal Sheets" + desc = "Any construction project begins with a good stack of fifty metal sheets!" + cost = 850 + contains = list(/obj/item/stack/sheet/metal/fifty) + crate_name = "metal sheets crate" + +/datum/supply_pack/materials/plasteel20 + name = "20 Plasteel Sheets" + desc = "Reinforce the station's integrity with twenty plasteel sheets!" + cost = 4700 + contains = list(/obj/item/stack/sheet/plasteel/twenty) + crate_name = "plasteel sheets crate" + +/datum/supply_pack/materials/plasteel50 + name = "50 Plasteel Sheets" + desc = "For when you REALLY have to reinforce something." + cost = 9050 + contains = list(/obj/item/stack/sheet/plasteel/fifty) + crate_name = "plasteel sheets crate" + +/datum/supply_pack/materials/plastic50 + name = "50 Plastic Sheets" + desc = "Build a limitless amount of toys with fifty plastic sheets!" + cost = 950 + contains = list(/obj/item/stack/sheet/plastic/fifty) + crate_name = "plastic sheets crate" + +/datum/supply_pack/materials/sandstone30 + name = "30 Sandstone Blocks" + desc = "Neither sandy nor stoney, these thirty blocks will still get the job done." + cost = 800 + contains = list(/obj/item/stack/sheet/mineral/sandstone/thirty) + crate_name = "sandstone blocks crate" + +/datum/supply_pack/materials/wood50 + name = "50 Wood Planks" + desc = "Turn cargo's boring metal groundwork into beautiful panelled flooring and much more with fifty wooden planks!" + cost = 1450 + contains = list(/obj/item/stack/sheet/mineral/wood/fifty) + crate_name = "wood planks crate" + +/datum/supply_pack/materials/rcdammo + name = "Spare RDC ammo" + desc = "This crate contains sixteen RCD ammo packs, to help with any holes or projects people mite be working on." + cost = 3750 + contains = list(/obj/item/rcd_ammo, + /obj/item/rcd_ammo, + /obj/item/rcd_ammo, + /obj/item/rcd_ammo, + /obj/item/rcd_ammo, + /obj/item/rcd_ammo, + /obj/item/rcd_ammo, + /obj/item/rcd_ammo, + /obj/item/rcd_ammo, + /obj/item/rcd_ammo, + /obj/item/rcd_ammo, + /obj/item/rcd_ammo, + /obj/item/rcd_ammo, + /obj/item/rcd_ammo, + /obj/item/rcd_ammo, + /obj/item/rcd_ammo) + crate_name = "rcd ammo" + +/datum/supply_pack/materials/bz + name = "BZ Canister Crate" + desc = "Contains a canister of BZ. Requires Toxins access to open." + cost = 7500 // Costs 3 credits more than what you can get for selling it. + access = ACCESS_TOX_STORAGE + contains = list(/obj/machinery/portable_atmospherics/canister/bz) + crate_name = "BZ canister crate" + crate_type = /obj/structure/closet/crate/secure/science + +/datum/supply_pack/materials/carbon_dio + name = "Carbon Dioxide Canister" + desc = "Contains a canister of Carbon Dioxide." + cost = 3000 + contains = list(/obj/machinery/portable_atmospherics/canister/carbon_dioxide) + crate_name = "carbon dioxide canister crate" + crate_type = /obj/structure/closet/crate/large + +/datum/supply_pack/materials/nitrogen + name = "Nitrogen Canister" + desc = "Contains a canister of Nitrogen." + cost = 2000 + contains = list(/obj/machinery/portable_atmospherics/canister/nitrogen) + crate_name = "nitrogen canister crate" + crate_type = /obj/structure/closet/crate/large + +/datum/supply_pack/materials/nitrous_oxide_canister + name = "Nitrous Oxide Canister" + desc = "Contains a canister of Nitrous Oxide. Requires Atmospherics access to open." + cost = 3000 + access = ACCESS_ATMOSPHERICS + contains = list(/obj/machinery/portable_atmospherics/canister/nitrous_oxide) + crate_name = "nitrous oxide canister crate" + crate_type = /obj/structure/closet/crate/secure + +/datum/supply_pack/materials/oxygen + name = "Oxygen Canister" + desc = "Contains a canister of Oxygen. Canned in Druidia." + cost = 1500 + contains = list(/obj/machinery/portable_atmospherics/canister/oxygen) + crate_name = "oxygen canister crate" + crate_type = /obj/structure/closet/crate/large + +/datum/supply_pack/materials/water_vapor + name = "Water Vapor Canister" + desc = "Contains a canister of Water Vapor. I swear to god if you open this in the halls..." + cost = 2500 + contains = list(/obj/machinery/portable_atmospherics/canister/water_vapor) + crate_name = "water vapor canister crate" + crate_type = /obj/structure/closet/crate/large + +/datum/supply_pack/materials/fueltank + name = "Fuel Tank Crate" + desc = "Contains a welding fuel tank. Caution, highly flammable." + cost = 800 + contains = list(/obj/structure/reagent_dispensers/fueltank) + crate_name = "fuel tank crate" + crate_type = /obj/structure/closet/crate/large + +/datum/supply_pack/materials/watertank + name = "Water Tank Crate" + desc = "Contains a tank of dihydrogen monoxide... sounds dangerous." + cost = 600 + contains = list(/obj/structure/reagent_dispensers/watertank) + crate_name = "water tank crate" + crate_type = /obj/structure/closet/crate/large + +/datum/supply_pack/materials/foamtank + name = "Firefighting Foam Tank Crate" + desc = "Contains a tank of firefighting foam. Also known as \"plasmaman's bane\"." + cost = 1500 + contains = list(/obj/structure/reagent_dispensers/foamtank) + crate_name = "foam tank crate" + crate_type = /obj/structure/closet/crate/large + +/datum/supply_pack/materials/hightank + name = "Large Water Tank Crate" + desc = "Contains a high-capacity water tank. Useful for botany or other service jobs." + cost = 1200 + contains = list(/obj/structure/reagent_dispensers/watertank/high) + crate_name = "high-capacity water tank crate" + crate_type = /obj/structure/closet/crate/large diff --git a/code/modules/cargo/packs/medical.dm b/code/modules/cargo/packs/medical.dm new file mode 100644 index 0000000000..e1d27c5022 --- /dev/null +++ b/code/modules/cargo/packs/medical.dm @@ -0,0 +1,214 @@ + +//Reminders- +// If you add something to this list, please group it by type and sort it alphabetically instead of just jamming it in like an animal +// cost = 700- Minimum cost, or infinite points are possible. +////////////////////////////////////////////////////////////////////////////// +//////////////////////////// Medical ///////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +/datum/supply_pack/medical + group = "Medical" + crate_type = /obj/structure/closet/crate/medical + +/datum/supply_pack/medical/firstaidbruises + name = "Bruise Treatment Kit Crate" + desc = "Contains three first aid kits focused on healing bruises and broken bones." + cost = 1000 + contains = list(/obj/item/storage/firstaid/brute, + /obj/item/storage/firstaid/brute, + /obj/item/storage/firstaid/brute) + crate_name = "brute treatment kit crate" + +/datum/supply_pack/medical/firstaidburns + name = "Burn Treatment Kit Crate" + desc = "Contains three first aid kits focused on healing severe burns." + cost = 1000 + contains = list(/obj/item/storage/firstaid/fire, + /obj/item/storage/firstaid/fire, + /obj/item/storage/firstaid/fire) + crate_name = "burn treatment kit crate" + +/datum/supply_pack/medical/bloodpacks + name = "Blood Pack Variety Crate" + desc = "Contains eight different blood packs for reintroducing blood to patients." + cost = 3000 + contains = list(/obj/item/reagent_containers/blood, + /obj/item/reagent_containers/blood, + /obj/item/reagent_containers/blood/APlus, + /obj/item/reagent_containers/blood/AMinus, + /obj/item/reagent_containers/blood/BPlus, + /obj/item/reagent_containers/blood/BMinus, + /obj/item/reagent_containers/blood/OPlus, + /obj/item/reagent_containers/blood/OMinus, + /obj/item/reagent_containers/blood/lizard) + crate_name = "blood freezer" + crate_type = /obj/structure/closet/crate/freezer + +/datum/supply_pack/medical/defibs + name = "Defibrillator Crate" + desc = "Contains two defibrillators for bringing the recently deceased back to life." + cost = 2500 + contains = list(/obj/item/defibrillator/loaded, + /obj/item/defibrillator/loaded) + crate_name = "defibrillator crate" + +/datum/supply_pack/medical/firstaid + name = "First Aid Kit Crate" + desc = "Contains four first aid kits for healing most types of wounds." + cost = 1000 + contains = list(/obj/item/storage/firstaid/regular, + /obj/item/storage/firstaid/regular, + /obj/item/storage/firstaid/regular, + /obj/item/storage/firstaid/regular) + crate_name = "first aid kit crate" + +/datum/supply_pack/medical/iv_drip + name = "IV Drip Crate" + desc = "Contains a single IV drip stand for intravenous delivery." + cost = 800 + contains = list(/obj/machinery/iv_drip) + crate_name = "iv drip crate" + +/datum/supply_pack/science/adv_surgery_tools + name = "Med-Co Advanced surgery tools" + desc = "A full set of Med-Co advanced surgery tools, this crate also comes with a spay of synth flesh as well as a can of . Requires Surgery access to open." + cost = 5500 + access = ACCESS_SURGERY + contains = list(/obj/item/storage/belt/medical/surgery_belt_adv, + /obj/item/reagent_containers/medspray/synthflesh, + /obj/item/reagent_containers/medspray/sterilizine) + crate_name = "medco newest surgery tools" + crate_type = /obj/structure/closet/crate/medical + +/datum/supply_pack/medical/medicalhardsuit + name = "Medical Hardsuit" + desc = "Got people being spaced left and right? Hole in the same room as the dead body of Hos or cap? Fear not, now you can buy one medical hardsuit with a mask and air tank to save your fellow crewmembers." + cost = 2750 + contains = list(/obj/item/tank/internals/air, + /obj/item/clothing/mask/gas, + /obj/item/clothing/suit/space/hardsuit/medical) + crate_name = "medical hardsuit" + +/datum/supply_pack/medical/supplies + name = "Medical Supplies Crate" + desc = "Contains seven beakers, syringes, and bodybags. Three morphine bottles, four insulin pills. Two charcoal bottles, epinephrine bottles, antitoxin bottles, and large beakers. Finally, a single roll of medical gauze, as well as a bottle of stimulant pills for long, hard work days. German doctor not included." + cost = 2500 + contains = list(/obj/item/reagent_containers/glass/bottle/charcoal, + /obj/item/reagent_containers/glass/bottle/charcoal, + /obj/item/reagent_containers/glass/bottle/epinephrine, + /obj/item/reagent_containers/glass/bottle/epinephrine, + /obj/item/reagent_containers/glass/bottle/morphine, + /obj/item/reagent_containers/glass/bottle/morphine, + /obj/item/reagent_containers/glass/bottle/morphine, + /obj/item/reagent_containers/glass/bottle/toxin, + /obj/item/reagent_containers/glass/bottle/toxin, + /obj/item/reagent_containers/glass/beaker/large, + /obj/item/reagent_containers/glass/beaker/large, + /obj/item/reagent_containers/pill/insulin, + /obj/item/reagent_containers/pill/insulin, + /obj/item/reagent_containers/pill/insulin, + /obj/item/reagent_containers/pill/insulin, + /obj/item/stack/medical/gauze, + /obj/item/storage/box/beakers, + /obj/item/storage/box/medsprays, + /obj/item/storage/box/syringes, + /obj/item/storage/box/bodybags, + /obj/item/storage/pill_bottle/stimulant) + crate_name = "medical supplies crate" + +/datum/supply_pack/medical/vending + name = "Medical Vending Crate" + desc = "Contains refills for medical vending machines." + cost = 2000 + contains = list(/obj/item/vending_refill/medical, + /obj/item/vending_refill/wallmed) + crate_name = "medical vending crate" + +/datum/supply_pack/medical/sprays + name = "Medical Sprays" + desc = "Contains two cans of Styptic Spray, Silver Sulfadiazine Spray, Synthflesh Spray and Sterilizer Compound Spray." + cost = 2250 + contains = list(/obj/item/reagent_containers/medspray/styptic, + /obj/item/reagent_containers/medspray/styptic, + /obj/item/reagent_containers/medspray/silver_sulf, + /obj/item/reagent_containers/medspray/silver_sulf, + /obj/item/reagent_containers/medspray/synthflesh, + /obj/item/reagent_containers/medspray/synthflesh, + /obj/item/reagent_containers/medspray/sterilizine, + /obj/item/reagent_containers/medspray/sterilizine) + crate_name = "medical supplies crate" + +/datum/supply_pack/medical/firstaidmixed + name = "Mixed Medical Kits" + desc = "Contains one of each medical kits for dealing with a variety of injured crewmembers." + cost = 1250 + contains = list(/obj/item/storage/firstaid/toxin, + /obj/item/storage/firstaid/o2, + /obj/item/storage/firstaid/brute, + /obj/item/storage/firstaid/fire, + /obj/item/storage/firstaid/regular) + crate_name = "medical supplies crate" + +/datum/supply_pack/medical/firstaidoxygen + name = "Oxygen Deprivation Kit Crate" + desc = "Contains three first aid kits focused on helping oxygen deprivation victims." + cost = 1000 + contains = list(/obj/item/storage/firstaid/o2, + /obj/item/storage/firstaid/o2, + /obj/item/storage/firstaid/o2) + crate_name = "oxygen deprivation kit crate" + +/datum/supply_pack/medical/advrad + name = "Radiation Treatment Crate Deluxe" + desc = "A crate for when radiation is out of hand... Contains two rad-b-gone kits, one bottle of anti radiation deluxe pill bottle, as well as a radiation treatment deluxe pill bottle!" + cost = 3500 + contains = list(/obj/item/storage/pill_bottle/antirad_plus, + /obj/item/storage/pill_bottle/mutarad, + /obj/item/storage/firstaid/radbgone, + /obj/item/storage/firstaid/radbgone, + /obj/item/geiger_counter, + /obj/item/geiger_counter) + crate_name = "radiation protection crate" + crate_type = /obj/structure/closet/crate/radiation + +/datum/supply_pack/medical/surgery + name = "Surgical Supplies Crate" + desc = "Do you want to perform surgery, but don't have one of those fancy shmancy degrees? Just get started with this crate containing a medical duffelbag, Sterilizine spray and collapsible roller bed." + cost = 1300 + contains = list(/obj/item/storage/backpack/duffelbag/med/surgery, + /obj/item/reagent_containers/medspray/sterilizine, + /obj/item/roller) + crate_name = "surgical supplies crate" + +/datum/supply_pack/medical/firstaidtoxins + name = "Toxin Treatment Kit Crate" + desc = "Contains three first aid kits focused on healing damage dealt by heavy toxins." + cost = 1000 + contains = list(/obj/item/storage/firstaid/toxin, + /obj/item/storage/firstaid/toxin, + /obj/item/storage/firstaid/toxin) + crate_name = "toxin treatment kit crate" + +/datum/supply_pack/medical/virus + name = "Virus Crate" + desc = "Contains twelve different bottles, containing several viral samples for virology research. Also includes seven beakers and syringes. Balled-up jeans not included. Requires CMO access to open." + cost = 2500 + access = ACCESS_CMO + contains = list(/obj/item/reagent_containers/glass/bottle/flu_virion, + /obj/item/reagent_containers/glass/bottle/cold, + /obj/item/reagent_containers/glass/bottle/random_virus, + /obj/item/reagent_containers/glass/bottle/random_virus, + /obj/item/reagent_containers/glass/bottle/random_virus, + /obj/item/reagent_containers/glass/bottle/random_virus, + /obj/item/reagent_containers/glass/bottle/fake_gbs, + /obj/item/reagent_containers/glass/bottle/magnitis, + /obj/item/reagent_containers/glass/bottle/pierrot_throat, + /obj/item/reagent_containers/glass/bottle/brainrot, + /obj/item/reagent_containers/glass/bottle/anxiety, + /obj/item/reagent_containers/glass/bottle/beesease, + /obj/item/storage/box/syringes, + /obj/item/storage/box/beakers, + /obj/item/reagent_containers/glass/bottle/mutagen) + crate_name = "virus crate" + crate_type = /obj/structure/closet/crate/secure/plasma + dangerous = TRUE diff --git a/code/modules/cargo/packs/misc.dm b/code/modules/cargo/packs/misc.dm new file mode 100644 index 0000000000..56ddd92a76 --- /dev/null +++ b/code/modules/cargo/packs/misc.dm @@ -0,0 +1,223 @@ + +//Reminders- +// If you add something to this list, please group it by type and sort it alphabetically instead of just jamming it in like an animal +// cost = 700- Minimum cost, or infinite points are possible. +////////////////////////////////////////////////////////////////////////////// +//////////////////////////// Miscellaneous /////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +/datum/supply_pack/misc + group = "Miscellaneous Supplies" + +/datum/supply_pack/misc/artsupply + name = "Art Supplies" + desc = "Make some happy little accidents with six canvasses, two easels, two boxes of crayons, and a rainbow crayon!" + cost = 800 + contains = list(/obj/structure/easel, + /obj/structure/easel, + /obj/item/canvas/nineteenXnineteen, + /obj/item/canvas/nineteenXnineteen, + /obj/item/canvas/twentythreeXnineteen, + /obj/item/canvas/twentythreeXnineteen, + /obj/item/canvas/twentythreeXtwentythree, + /obj/item/canvas/twentythreeXtwentythree, + /obj/item/storage/crayons, + /obj/item/storage/crayons, + /obj/item/toy/crayon/rainbow, + /obj/item/toy/crayon/white, + /obj/item/toy/crayon/white) + crate_name = "art supply crate" + crate_type = /obj/structure/closet/crate/wooden + +/datum/supply_pack/misc/captain_pen + name = "Captain Pen" + desc = "A spare Captain fountain pen." + access = ACCESS_CAPTAIN + cost = 10000 + contains = list(/obj/item/pen/fountain/captain) + crate_name = "captain pen" + crate_type = /obj/structure/closet/crate/secure/weapon //It is a combat pen + +/datum/supply_pack/misc/bicycle + name = "Bicycle" + desc = "Nanotrasen reminds all employees to never toy with powers outside their control." + cost = 1000000 + contains = list(/obj/vehicle/ridden/bicycle) + crate_name = "Bicycle Crate" + crate_type = /obj/structure/closet/crate/large + +/datum/supply_pack/misc/bigband + name = "Big Band Instrument Collection" + desc = "Get your sad station movin' and groovin' with this fine collection! Contains nine different instruments!" + cost = 5000 + crate_name = "Big band musical instruments collection" + contains = list(/obj/item/instrument/violin, + /obj/item/instrument/guitar, + /obj/item/instrument/glockenspiel, + /obj/item/instrument/accordion, + /obj/item/instrument/saxophone, + /obj/item/instrument/trombone, + /obj/item/instrument/recorder, + /obj/item/instrument/harmonica, + /obj/structure/piano/unanchored) + crate_type = /obj/structure/closet/crate/wooden + +/datum/supply_pack/misc/book_crate + name = "Book Crate" + desc = "Surplus from the Nanotrasen Archives, these five books are sure to be good reads." + cost = 1500 + contains = list(/obj/item/book/codex_gigas, + /obj/item/book/manual/random/, + /obj/item/book/manual/random/, + /obj/item/book/manual/random/, + /obj/item/book/random/triple) + crate_type = /obj/structure/closet/crate/wooden + +/datum/supply_pack/misc/paper + name = "Bureaucracy Crate" + desc = "High stacks of papers on your desk Are a big problem - make it Pea-sized with these bureaucratic supplies! Contains five pens, some camera film, hand labeler supplies, a paper bin, three folders, two clipboards and two stamps as well as a briefcase."//that was too forced + cost = 1500 + contains = list(/obj/structure/filingcabinet/chestdrawer/wheeled, + /obj/item/camera_film, + /obj/item/hand_labeler, + /obj/item/hand_labeler_refill, + /obj/item/hand_labeler_refill, + /obj/item/paper_bin, + /obj/item/pen/fourcolor, + /obj/item/pen/fourcolor, + /obj/item/pen, + /obj/item/pen/blue, + /obj/item/pen/red, + /obj/item/folder/blue, + /obj/item/folder/red, + /obj/item/folder/yellow, + /obj/item/clipboard, + /obj/item/clipboard, + /obj/item/stamp, + /obj/item/stamp/denied, + /obj/item/storage/briefcase) + crate_name = "bureaucracy crate" + +/datum/supply_pack/misc/fountainpens + name = "Calligraphy Crate" + desc = "Sign death warrants in style with these seven executive fountain pens." + cost = 730 + contains = list(/obj/item/storage/box/fountainpens, + /obj/item/paper_bin) + crate_type = /obj/structure/closet/crate/wooden + crate_name = "calligraphy crate" + +/datum/supply_pack/misc/wrapping_paper + name = "Festive Wrapping Paper Crate" + desc = "Want to mail your loved ones gift-wrapped chocolates, stuffed animals, the Clown's severed head? You can do all that, with this crate full of wrapping paper." + cost = 1000 + contains = list(/obj/item/stack/wrapping_paper) + crate_type = /obj/structure/closet/crate/wooden + crate_name = "festive wrapping paper crate" + +/datum/supply_pack/misc/paper_work + name = "Freelance Paper work" + desc = "The Nanotrasen Primary Bureaucratic Database Intelligence (PDBI) reports that the station has not completed its funding and grant paperwork this solar cycle. In order to gain further funding, your station is required to fill out (10) ten of these forms or no additional capital will be disbursed. We have sent you ten copies of the following form and we expect every one to be up to Nanotrasen Standards." // Disbursement. It's not a typo, look it up. + cost = 700 // Net of 0 credits + contains = list(/obj/item/folder/paperwork, + /obj/item/folder/paperwork, + /obj/item/folder/paperwork, + /obj/item/folder/paperwork, + /obj/item/folder/paperwork, + /obj/item/folder/paperwork, + /obj/item/folder/paperwork, + /obj/item/folder/paperwork, + /obj/item/folder/paperwork, + /obj/item/folder/paperwork, + /obj/item/pen/fountain, + /obj/item/pen/fountain, + /obj/item/pen/fountain, + /obj/item/pen/fountain, + /obj/item/pen/fountain) + crate_name = "Paperwork" + +/datum/supply_pack/misc/funeral + name = "Funeral Supply crate" + desc = "At the end of the day, someone's gonna want someone dead. Give them a proper send-off with these funeral supplies! Contains a coffin with burial garmets and flowers." + cost = 800 + contains = list(/obj/item/clothing/under/burial, + /obj/item/reagent_containers/food/snacks/grown/harebell, + /obj/item/reagent_containers/food/snacks/grown/poppy/geranium + ) + crate_name = "coffin" + crate_type = /obj/structure/closet/crate/coffin + +/datum/supply_pack/misc/jukebox + name = "Jukebox" + cost = 15000 + contains = list(/obj/machinery/jukebox) + crate_name = "Jukebox" + +/datum/supply_pack/misc/lewd + name = "Lewd Crate" // OwO + desc = "Psss want to have a good time with your sluts? Well I got what you want maid clothing, dildos, collars and more!" + cost = 5250 + contraband = TRUE + contains = list(/obj/item/dildo/custom, + /obj/item/dildo/custom, + /obj/item/vending_refill/kink, + /obj/item/vending_refill/kink, + /obj/item/clothing/under/maid, + /obj/item/clothing/under/maid, + /obj/item/electropack/shockcollar, + /obj/item/electropack/shockcollar, + /obj/item/restraints/handcuffs/fake/kinky, + /obj/item/restraints/handcuffs/fake/kinky, + /obj/item/clothing/head/kitty/genuine, // Why its illegal + /obj/item/clothing/head/kitty/genuine, + /obj/item/storage/pill_bottle/penis_enlargement, + /obj/structure/reagent_dispensers/keg/aphro) + crate_name = "lewd kit" + crate_type = /obj/structure/closet/crate + +/datum/supply_pack/misc/lewdkeg + name = "Lewd Deluxe Keg" + desc = "That other stuff not getting you ready? Well I have a Chemslut making tons of the good stuff." + cost = 7500 //It can be a weapon + contraband = TRUE + contains = list(/obj/structure/reagent_dispensers/keg/aphro/strong) + crate_name = "deluxe keg" + crate_type = /obj/structure/closet/crate + +/datum/supply_pack/misc/religious_supplies + name = "Religious Supplies Crate" + desc = "Keep your local chaplain happy and well-supplied, lest they call down judgement upon your cargo bay. Contains two bottles of holywater, bibles, chaplain robes, and burial garmets." + cost = 4000 // it costs so much because the Space Church is ran by Space Jews + contains = list(/obj/item/reagent_containers/food/drinks/bottle/holywater, + /obj/item/reagent_containers/food/drinks/bottle/holywater, + /obj/item/storage/book/bible/booze, + /obj/item/storage/book/bible/booze, + /obj/item/clothing/suit/hooded/chaplain_hoodie, + /obj/item/clothing/suit/hooded/chaplain_hoodie + ) + crate_name = "religious supplies crate" + +/datum/supply_pack/misc/randomised/promiscuous + name = "Promiscuous Organs" + desc = "Do YOU want to have more genital? Well we have just the thing for you~. This crate has two autosurgeon, that will let you have a new sex, organ to impress that hot stud and or chick." + cost = 4000 //Only get 2! + contraband = TRUE + var/num_contained = 2 + contains = list(/obj/item/autosurgeon/penis, + /obj/item/autosurgeon/testicles, + /obj/item/autosurgeon/vagina, + /obj/item/autosurgeon/breasts, + /obj/item/autosurgeon/womb) + crate_name = "promiscuous organs" + +/datum/supply_pack/misc/toner + name = "Toner Crate" + desc = "Spent too much ink printing butt pictures? Fret not, with these six toner refills, you'll be printing butts 'till the cows come home!'" + cost = 1000 + contains = list(/obj/item/toner, + /obj/item/toner, + /obj/item/toner, + /obj/item/toner, + /obj/item/toner, + /obj/item/toner) + crate_name = "toner crate" diff --git a/code/modules/cargo/packs/organic.dm b/code/modules/cargo/packs/organic.dm new file mode 100644 index 0000000000..2b5df207c3 --- /dev/null +++ b/code/modules/cargo/packs/organic.dm @@ -0,0 +1,290 @@ + +//Reminders- +// If you add something to this list, please group it by type and sort it alphabetically instead of just jamming it in like an animal +// cost = 700- Minimum cost, or infinite points are possible. +////////////////////////////////////////////////////////////////////////////// +//////////////////////////// Organic ///////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +/datum/supply_pack/organic + group = "Food & Hydroponics" + crate_type = /obj/structure/closet/crate/freezer + +/datum/supply_pack/organic/hydroponics/beekeeping_suits + name = "Beekeeper Suit Crate" + desc = "Bee business booming? Better be benevolent and boost botany by bestowing bi-Beekeeper-suits! Contains two beekeeper suits and matching headwear." + cost = 1300 + contains = list(/obj/item/clothing/head/beekeeper_head, + /obj/item/clothing/suit/beekeeper_suit, + /obj/item/clothing/head/beekeeper_head, + /obj/item/clothing/suit/beekeeper_suit) + crate_name = "beekeeper suits" + crate_type = /obj/structure/closet/crate/hydroponics + +/datum/supply_pack/organic/hydroponics/beekeeping_fullkit + name = "Beekeeping Starter Crate" + desc = "BEES BEES BEES. Contains three honey frames, a beekeeper suit and helmet, flyswatter, bee house, and, of course, a pure-bred Nanotrasen-Standardized Queen Bee!" + cost = 1800 + contains = list(/obj/structure/beebox/unwrenched, + /obj/item/honey_frame, + /obj/item/honey_frame, + /obj/item/honey_frame, + /obj/item/queen_bee/bought, + /obj/item/clothing/head/beekeeper_head, + /obj/item/clothing/suit/beekeeper_suit, + /obj/item/melee/flyswatter) + crate_name = "beekeeping starter crate" + crate_type = /obj/structure/closet/crate/hydroponics + +/datum/supply_pack/organic/candy/randomised + name = "Candy Crate" + desc = "For people that have a insatiable sweet tooth! Has ten candies to be eaten up.." + cost = 2500 + var/num_contained = 10 //number of items picked to be contained in a randomised crate + contains = list(/obj/item/reagent_containers/food/snacks/candy, + /obj/item/reagent_containers/food/snacks/lollipop, + /obj/item/reagent_containers/food/snacks/gumball, + /obj/item/reagent_containers/food/snacks/chocolateegg, + /obj/item/reagent_containers/food/snacks/donut, + /obj/item/reagent_containers/food/snacks/cookie, + /obj/item/reagent_containers/food/snacks/sugarcookie, + /obj/item/reagent_containers/food/snacks/chococornet, + /obj/item/reagent_containers/food/snacks/mint, + /obj/item/reagent_containers/food/snacks/spiderlollipop, + /obj/item/reagent_containers/food/snacks/chococoin, + /obj/item/reagent_containers/food/snacks/fudgedice, + /obj/item/reagent_containers/food/snacks/chocoorange, + /obj/item/reagent_containers/food/snacks/honeybar, + /obj/item/reagent_containers/food/snacks/tinychocolate, + /obj/item/reagent_containers/food/snacks/spacetwinkie, + /obj/item/reagent_containers/food/snacks/syndicake, + /obj/item/reagent_containers/food/snacks/cheesiehonkers, + /obj/item/reagent_containers/food/snacks/sugarcookie/spookyskull, + /obj/item/reagent_containers/food/snacks/sugarcookie/spookycoffin, + /obj/item/reagent_containers/food/snacks/candy_corn, + /obj/item/reagent_containers/food/snacks/candiedapple, + /obj/item/reagent_containers/food/snacks/chocolatebar, + /obj/item/reagent_containers/food/snacks/candyheart, + /obj/item/storage/fancy/heart_box, + /obj/item/storage/fancy/donut_box) + crate_name = "candy crate" + +/datum/supply_pack/organic/cutlery + name = "Kitchen Cutlery Deluxe Set" + desc = "Need to slice and dice away those ''Tomatos'' well we got what you need! From a nice set of knifes, forks, plates, glasses, and a whetstone for when you got some grizzle that is a bit harder to slice then normal." + cost = 10000 + contraband = TRUE + contains = list(/obj/item/sharpener, + /obj/item/kitchen/fork, + /obj/item/kitchen/fork, + /obj/item/kitchen/knife, + /obj/item/kitchen/knife, + /obj/item/kitchen/knife, + /obj/item/kitchen/knife, + /obj/item/kitchen/knife/butcher, + /obj/item/kitchen/knife/butcher, + /obj/item/kitchen/rollingpin, //Deluxe for a reason + /obj/item/trash/plate, + /obj/item/trash/plate, + /obj/item/trash/plate, + /obj/item/trash/plate, + /obj/item/reagent_containers/food/drinks/drinkingglass, + /obj/item/reagent_containers/food/drinks/drinkingglass, + /obj/item/reagent_containers/food/drinks/drinkingglass, + /obj/item/reagent_containers/food/drinks/drinkingglass/shotglass, + /obj/item/reagent_containers/food/drinks/drinkingglass/shotglass) + crate_name = "kitchen cutlery deluxe set" + +/datum/supply_pack/organic/food + name = "Food Crate" + desc = "Get things cooking with this crate full of useful ingredients! Contains a two dozen eggs, three bananas, and two bags of flour and rice, two cartons of milk, soymilk, as well as salt and pepper shakers, a enzyme and sugar bottle, and three slabs of monkeymeat." + cost = 1000 + contains = list(/obj/item/reagent_containers/food/condiment/flour, + /obj/item/reagent_containers/food/condiment/flour, + /obj/item/reagent_containers/food/condiment/rice, + /obj/item/reagent_containers/food/condiment/rice, + /obj/item/reagent_containers/food/condiment/milk, + /obj/item/reagent_containers/food/condiment/milk, + /obj/item/reagent_containers/food/condiment/soymilk, + /obj/item/reagent_containers/food/condiment/saltshaker, + /obj/item/reagent_containers/food/condiment/peppermill, + /obj/item/storage/fancy/egg_box, + /obj/item/storage/fancy/egg_box, + /obj/item/reagent_containers/food/condiment/enzyme, + /obj/item/reagent_containers/food/condiment/sugar, + /obj/item/reagent_containers/food/snacks/meat/slab/monkey, + /obj/item/reagent_containers/food/snacks/meat/slab/monkey, + /obj/item/reagent_containers/food/snacks/meat/slab/monkey, + /obj/item/reagent_containers/food/snacks/grown/banana, + /obj/item/reagent_containers/food/snacks/grown/banana, + /obj/item/reagent_containers/food/snacks/grown/banana) + crate_name = "food crate" + +/datum/supply_pack/organic/cream_piee + name = "High-yield Clown-grade Cream Pie Crate" + desc = "Designed by Aussec's Advanced Warfare Research Division, these high-yield, Clown-grade cream pies are powered by a synergy of performance and efficiency. Guaranteed to provide maximum results." + cost = 6000 + contains = list(/obj/item/storage/backpack/duffelbag/clown/cream_pie) + crate_name = "party equipment crate" + contraband = TRUE + access = ACCESS_THEATRE + crate_type = /obj/structure/closet/crate/secure + +/datum/supply_pack/organic/hunting + name = "Huntting gear" + desc = "Even in space, we can fine prey to hunt, this crate contains everthing a fine hunter needs to have a sporting time. This crate needs armory access to open. A true huntter only needs a fine bottle of cognac, a nice coat, some good o' cigars, and of cource a huntting shotgun. " + cost = 3500 + contraband = TRUE + contains = list(/obj/item/clothing/head/flatcap, + /obj/item/clothing/suit/hooded/wintercoat/captain, + /obj/item/reagent_containers/food/drinks/bottle/cognac, + /obj/item/storage/fancy/cigarettes/cigars/havana, + /obj/item/clothing/gloves/color/white, + /obj/item/clothing/under/rank/curator, + /obj/item/gun/ballistic/shotgun/lethal) + access = ACCESS_ARMORY + crate_name = "sporting crate" + crate_type = /obj/structure/closet/crate/secure // Would have liked a wooden crate but access >:( + +/datum/supply_pack/organic/hydroponics + name = "Hydroponics Crate" + desc = "Supplies for growing a great garden! Contains two bottles of ammonia, two Plant-B-Gone spray bottles, a hatchet, cultivator, plant analyzer, as well as a pair of leather gloves and a botanist's apron." + cost = 1750 + contains = list(/obj/item/reagent_containers/spray/plantbgone, + /obj/item/reagent_containers/spray/plantbgone, + /obj/item/reagent_containers/glass/bottle/ammonia, + /obj/item/reagent_containers/glass/bottle/ammonia, + /obj/item/hatchet, + /obj/item/cultivator, + /obj/item/plant_analyzer, + /obj/item/clothing/gloves/botanic_leather, + /obj/item/clothing/suit/apron) + crate_name = "hydroponics crate" + crate_type = /obj/structure/closet/crate/hydroponics + +/datum/supply_pack/organic/hydroponics/hydrotank + name = "Hydroponics Backpack Crate" + desc = "Bring on the flood with this high-capacity backpack crate. Contains 500 units of life-giving H2O. Requires hydroponics access to open." + cost = 1200 + access = ACCESS_HYDROPONICS + contains = list(/obj/item/watertank) + crate_name = "hydroponics backpack crate" + crate_type = /obj/structure/closet/crate/secure + +/datum/supply_pack/organic/mre + name = "MRE supply kit (emergency rations)" + desc = "The lights are out. Oxygen's running low. You've run out of food except space weevils. Don't let this be you! Order our NT branded MRE kits today! This pack contains 5 MRE packs with a randomized menu and an oxygen tank." + cost = 2000 + contains = list(/obj/item/storage/box/mre/menu1/safe, + /obj/item/storage/box/mre/menu1/safe, + /obj/item/storage/box/mre/menu2/safe, + /obj/item/storage/box/mre/menu2/safe, + /obj/item/storage/box/mre/menu3, + /obj/item/storage/box/mre/menu4/safe) + crate_name = "MRE crate (emergency rations)" + +/datum/supply_pack/organic/pizza + name = "Pizza Crate" + desc = "Best prices on this side of the galaxy. All deliveries are guaranteed to be 99% anomaly-free!" + cost = 6000 // Best prices this side of the galaxy. + contains = list(/obj/item/pizzabox/margherita, + /obj/item/pizzabox/mushroom, + /obj/item/pizzabox/meat, + /obj/item/pizzabox/vegetable, + /obj/item/pizzabox/pineapple) + crate_name = "pizza crate" + var/static/anomalous_box_provided = FALSE + +/datum/supply_pack/organic/pizza/fill(obj/structure/closet/crate/C) + . = ..() + if(!anomalous_box_provided) + for(var/obj/item/pizzabox/P in C) + if(prob(1)) //1% chance for each box, so 4% total chance per order + var/obj/item/pizzabox/infinite/fourfiveeight = new(C) + fourfiveeight.boxtag = P.boxtag + qdel(P) + anomalous_box_provided = TRUE + log_game("An anomalous pizza box was provided in a pizza crate at during cargo delivery") + if(prob(50)) + addtimer(CALLBACK(src, .proc/anomalous_pizza_report), rand(300, 1800)) + else + message_admins("An anomalous pizza box was silently created with no command report in a pizza crate delivery.") + break + +/datum/supply_pack/organic/pizza/proc/anomalous_pizza_report() + print_command_report("[station_name()], our anomalous materials divison has reported a missing object that is highly likely to have been sent to your station during a routine cargo \ + delivery. Please search all crates and manifests provided with the delivery and return the object if is located. The object resembles a standard \[DATA EXPUNGED\] and is to be \ + considered \[REDACTED\] and returned at your leisure. Note that objects the anomaly produces are specifically attuned exactly to the individual opening the anomaly; regardless \ + of species, the individual will find the object edible and it will taste great according to their personal definitions, which vary significantly based on person and species.") + +/datum/supply_pack/organic/potted_plants + name = "Potted Plants Crate" + desc = "Spruce up the station with these lovely plants! Contains a random assortment of five potted plants from Nanotrasen's potted plant research division. Warranty void if thrown." + cost = 730 + contains = list(/obj/item/twohanded/required/kirbyplants/random, + /obj/item/twohanded/required/kirbyplants/random, + /obj/item/twohanded/required/kirbyplants/random, + /obj/item/twohanded/required/kirbyplants/random, + /obj/item/twohanded/required/kirbyplants/random) + crate_name = "potted plants crate" + crate_type = /obj/structure/closet/crate/hydroponics + +/datum/supply_pack/organic/seeds + name = "Seeds Crate" + desc = "Big things have small beginnings. Contains thirteen different seeds." + cost = 1250 + contains = list(/obj/item/seeds/chili, + /obj/item/seeds/berry, + /obj/item/seeds/corn, + /obj/item/seeds/eggplant, + /obj/item/seeds/tomato, + /obj/item/seeds/soya, + /obj/item/seeds/wheat, + /obj/item/seeds/wheat/rice, + /obj/item/seeds/carrot, + /obj/item/seeds/sunflower, + /obj/item/seeds/chanter, + /obj/item/seeds/potato, + /obj/item/seeds/sugarcane) + crate_name = "seeds crate" + crate_type = /obj/structure/closet/crate/hydroponics + +/datum/supply_pack/organic/vday + name = "Surplus Valentine Crate" + desc = "Turns out we got warehouses of this love-y dove-y crap. Were sending out small barged buddle of Valentine gear. This crate has two boxes of chocolate, three poppy flowers, five candy hearts, and three cards." + cost = 3000 + contraband = TRUE + contains = list(/obj/item/storage/fancy/heart_box, + /obj/item/storage/fancy/heart_box, + /obj/item/reagent_containers/food/snacks/grown/poppy, + /obj/item/reagent_containers/food/snacks/grown/poppy, + /obj/item/reagent_containers/food/snacks/grown/poppy, + /obj/item/reagent_containers/food/snacks/candyheart, + /obj/item/reagent_containers/food/snacks/candyheart, + /obj/item/reagent_containers/food/snacks/candyheart, + /obj/item/reagent_containers/food/snacks/candyheart, + /obj/item/reagent_containers/food/snacks/candyheart, + /obj/item/valentine, + /obj/item/valentine, + /obj/item/valentine) + crate_name = "valentine crate" + crate_type = /obj/structure/closet/crate/secure + +/datum/supply_pack/organic/exoticseeds + name = "Exotic Seeds Crate" + desc = "Any entrepreneuring botanist's dream. Contains twelve different seeds, including three replica-pod seeds and two mystery seeds!" + cost = 1500 + contains = list(/obj/item/seeds/nettle, + /obj/item/seeds/replicapod, + /obj/item/seeds/replicapod, + /obj/item/seeds/replicapod, + /obj/item/seeds/plump, + /obj/item/seeds/liberty, + /obj/item/seeds/amanita, + /obj/item/seeds/reishi, + /obj/item/seeds/banana, + /obj/item/seeds/eggplant/eggy, + /obj/item/seeds/random, + /obj/item/seeds/random) + crate_name = "exotic seeds crate" + crate_type = /obj/structure/closet/crate/hydroponics diff --git a/code/modules/cargo/packs/science.dm b/code/modules/cargo/packs/science.dm new file mode 100644 index 0000000000..c4fbc0bfe5 --- /dev/null +++ b/code/modules/cargo/packs/science.dm @@ -0,0 +1,119 @@ + +//Reminders- +// If you add something to this list, please group it by type and sort it alphabetically instead of just jamming it in like an animal +// cost = 700- Minimum cost, or infinite points are possible. +////////////////////////////////////////////////////////////////////////////// +//////////////////////////// Science ///////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +/datum/supply_pack/science + group = "Science" + crate_type = /obj/structure/closet/crate/science + +/datum/supply_pack/science/robotics/mecha_odysseus + name = "Circuit Crate (Odysseus)" + desc = "Ever wanted to build your own giant medical robot? Well, now you can! Contains the Odysseus main control board and Odysseus peripherals board. Requires Robotics access to open." + cost = 2500 + access = ACCESS_ROBOTICS + contains = list(/obj/item/circuitboard/mecha/odysseus/peripherals, + /obj/item/circuitboard/mecha/odysseus/main) + crate_name = "\improper Odysseus circuit crate" + crate_type = /obj/structure/closet/crate/secure/science + +/datum/supply_pack/science/robotics/mecha_ripley + name = "Circuit Crate (Ripley APLU)" + desc = "Rip apart rocks and xenomorphs alike with the Ripley APLU. Contains the Main Ripley control board, as well as the Ripley Peripherals board. Requires Robotics access to open." + cost = 3000 + access = ACCESS_ROBOTICS + contains = list(/obj/item/book/manual/ripley_build_and_repair, + /obj/item/circuitboard/mecha/ripley/main, + /obj/item/circuitboard/mecha/ripley/peripherals) + crate_name = "\improper APLU Ripley circuit crate" + crate_type = /obj/structure/closet/crate/secure/science + +/datum/supply_pack/science/circuitry + name = "Circuitry Starter Pack Crate" + desc = "Journey into the mysterious world of Circuitry with this starter pack. Contains a circuit printer, analyzer, debugger and wirer. Power cells not included." + cost = 1000 + contains = list(/obj/item/integrated_electronics/analyzer, + /obj/item/integrated_circuit_printer, + /obj/item/integrated_electronics/debugger, + /obj/item/integrated_electronics/wirer) + crate_name = "circuitry starter pack crate" + +/datum/supply_pack/science/plasma + name = "Plasma Assembly Crate" + desc = "Everything you need to burn something to the ground, this contains three plasma assembly sets. Each set contains a plasma tank, igniter, proximity sensor, and timer! Warranty void if exposed to high temperatures. Requires Toxins access to open." + cost = 1800 + access = ACCESS_TOX_STORAGE + contains = list(/obj/item/tank/internals/plasma, + /obj/item/tank/internals/plasma, + /obj/item/tank/internals/plasma, + /obj/item/assembly/igniter, + /obj/item/assembly/igniter, + /obj/item/assembly/igniter, + /obj/item/assembly/prox_sensor, + /obj/item/assembly/prox_sensor, + /obj/item/assembly/prox_sensor, + /obj/item/assembly/timer, + /obj/item/assembly/timer, + /obj/item/assembly/timer) + crate_name = "plasma assembly crate" + crate_type = /obj/structure/closet/crate/secure/plasma + +/datum/supply_pack/science/robotics + name = "Robotics Assembly Crate" + desc = "The tools you need to replace those finicky humans with a loyal robot army! Contains three proximity sensors, two high-powered cells, six flashes, and an electrical toolbox. Requires Robotics access to open." + cost = 1500 + access = ACCESS_ROBOTICS + contains = list(/obj/item/assembly/prox_sensor, + /obj/item/assembly/prox_sensor, + /obj/item/assembly/prox_sensor, + /obj/item/storage/toolbox/electrical, + /obj/item/storage/box/flashes, + /obj/item/stock_parts/cell/high, + /obj/item/stock_parts/cell/high) + crate_name = "robotics assembly crate" + crate_type = /obj/structure/closet/crate/secure/science + +/datum/supply_pack/science/shieldwalls + name = "Shield Generator Crate" + desc = "These high powered Shield Wall Generators are guaranteed to keep any unwanted lifeforms on the outside, where they belong! Contains four shield wall generators. Requires Teleporter access to open." + cost = 2000 + access = ACCESS_TELEPORTER + contains = list(/obj/machinery/shieldwallgen, + /obj/machinery/shieldwallgen, + /obj/machinery/shieldwallgen, + /obj/machinery/shieldwallgen) + crate_name = "shield generators crate" + crate_type = /obj/structure/closet/crate/secure/science + +/datum/supply_pack/science/tablets + name = "Tablet Crate" + desc = "What's a computer? Contains five cargo tablets." + cost = 5000 + contains = list(/obj/item/modular_computer/tablet/preset/cargo, + /obj/item/modular_computer/tablet/preset/cargo, + /obj/item/modular_computer/tablet/preset/cargo, + /obj/item/modular_computer/tablet/preset/cargo, + /obj/item/modular_computer/tablet/preset/cargo) + crate_name = "tablet crate" + +/datum/supply_pack/science/transfer_valves + name = "Tank Transfer Valves Crate" + desc = "The key ingredient for making a lot of people very angry very fast. Contains two tank transfer valves. Requires RD access to open." + cost = 6000 + access = ACCESS_RD + contains = list(/obj/item/transfer_valve, + /obj/item/transfer_valve) + crate_name = "tank transfer valves crate" + crate_type = /obj/structure/closet/crate/secure/science + dangerous = TRUE + +/datum/supply_pack/science/tech_slugs + name = "Tech Slug Ammo Shells" + desc = "A new type of shell that is able to be made into a few different dangerous types. Contains two boxes of tech slugs, 14 shells in all." + cost = 1700 + contains = list(/obj/item/storage/box/techsslug, + /obj/item/storage/box/techsslug) + crate_name = "tech slug crate" diff --git a/code/modules/cargo/packs/security.dm b/code/modules/cargo/packs/security.dm new file mode 100644 index 0000000000..3c68fe7f6d --- /dev/null +++ b/code/modules/cargo/packs/security.dm @@ -0,0 +1,192 @@ + +//Reminders- +// If you add something to this list, please group it by type and sort it alphabetically instead of just jamming it in like an animal +// cost = 700- Minimum cost, or infinite points are possible. +////////////////////////////////////////////////////////////////////////////// +//////////////////////////// Security //////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +/datum/supply_pack/security + group = "Security" + access = ACCESS_SECURITY + crate_type = /obj/structure/closet/crate/secure/gear + +/datum/supply_pack/security/armor + name = "Armor Crate" + desc = "Three vests of well-rounded, decently-protective armor. Requires Security access to open." + cost = 1200 + contains = list(/obj/item/clothing/suit/armor/vest, + /obj/item/clothing/suit/armor/vest, + /obj/item/clothing/suit/armor/vest) + crate_name = "armor crate" + +/datum/supply_pack/security/disabler + name = "Disabler Crate" + desc = "Three stamina-draining disabler weapons. Requires Security access to open." + cost = 1300 + contains = list(/obj/item/gun/energy/disabler, + /obj/item/gun/energy/disabler, + /obj/item/gun/energy/disabler) + crate_name = "disabler crate" + +/datum/supply_pack/security/forensics + name = "Forensics Crate" + desc = "Stay hot on the criminal's heels with Nanotrasen's Detective Essentials(tm). Contains a forensics scanner, six evidence bags, camera, tape recorder, white crayon, and of course, a fedora. Requires Security access to open." + cost = 1800 + contains = list(/obj/item/detective_scanner, + /obj/item/storage/box/evidence, + /obj/item/camera, + /obj/item/taperecorder, + /obj/item/toy/crayon/white, + /obj/item/clothing/head/fedora/det_hat) + crate_name = "forensics crate" + +/datum/supply_pack/security/helmets + name = "Helmets Crate" + desc = "Contains three standard-issue brain buckets. Requires Security access to open." + cost = 1200 + contains = list(/obj/item/clothing/head/helmet/sec, + /obj/item/clothing/head/helmet/sec, + /obj/item/clothing/head/helmet/sec) + crate_name = "helmet crate" + +/datum/supply_pack/security/laser + name = "Lasers Crate" + desc = "Contains three lethal, high-energy laser guns. Requires Security access to open." + cost = 1750 + contains = list(/obj/item/gun/energy/laser, + /obj/item/gun/energy/laser, + /obj/item/gun/energy/laser) + crate_name = "laser crate" + +/datum/supply_pack/security/russianclothing + name = "Russian Surplus Clothing" + desc = "An old russian crate full of surplus armor that they used to use! Has two sets of bulletproff armor, a few union suits and some warm hats!" + contraband = TRUE + cost = 5750 // Its basicly sec suits, good boots/gloves + contains = list(/obj/item/clothing/suit/security/officer/russian, + /obj/item/clothing/suit/security/officer/russian, + /obj/item/clothing/shoes/combat, + /obj/item/clothing/shoes/combat, + /obj/item/clothing/head/ushanka, + /obj/item/clothing/head/ushanka, + /obj/item/clothing/suit/armor/bulletproof, + /obj/item/clothing/suit/armor/bulletproof, + /obj/item/clothing/head/helmet/alt, + /obj/item/clothing/head/helmet/alt, + /obj/item/clothing/gloves/combat, + /obj/item/clothing/gloves/combat, + /obj/item/clothing/mask/gas, + /obj/item/clothing/mask/gas) + crate_name = "surplus russian clothing" + crate_type = /obj/structure/closet/crate/internals + +/datum/supply_pack/security/russianmosin + name = "Russian Minutemen Gear" + desc = "An old russian Minutemen crate, comes with a full russian outfit, a mosin and a stripper clip." + contraband = TRUE + access = FALSE + cost = 5500 // + contains = list(/obj/item/clothing/suit/security/officer/russian, + /obj/item/clothing/shoes/combat, + /obj/item/clothing/head/ushanka, + /obj/item/clothing/suit/armor/bulletproof, + /obj/item/clothing/head/helmet/alt, + /obj/item/clothing/gloves/combat, + /obj/item/clothing/mask/gas, + /obj/item/gun/ballistic/shotgun/boltaction, + /obj/item/ammo_box/a762) + crate_name = "surplus russian gear" + crate_type = /obj/structure/closet/crate/internals + +/datum/supply_pack/security/sechardsuit + name = "Sec Hardsuit" + desc = "One Sec Hardsuit with a small air tank and mask." + cost = 3000 // half of SWAT gear for have the armor and half the gear + contains = list(/obj/item/clothing/suit/space/hardsuit/security, + /obj/item/tank/internals/air, + /obj/item/clothing/mask/gas) + crate_name = "sec hardsuit crate" + +/datum/supply_pack/security/securitybarriers + name = "Security Barrier Grenades" + desc = "Stem the tide with four Security Barrier grenades. Requires Security access to open." + contains = list(/obj/item/grenade/barrier, + /obj/item/grenade/barrier, + /obj/item/grenade/barrier, + /obj/item/grenade/barrier) + cost = 2000 + crate_name = "security barriers crate" + +/datum/supply_pack/security/securityclothes + name = "Security Clothing Crate" + desc = "Contains appropriate outfits for the station's private security force. Contains outfits for the Warden, Head of Security, and two Security Officers. Each outfit comes with a rank-appropriate jumpsuit, suit, and beret. Requires Security access to open." + cost = 3250 + contains = list(/obj/item/clothing/under/rank/security/navyblue, + /obj/item/clothing/under/rank/security/navyblue, + /obj/item/clothing/suit/security/officer, + /obj/item/clothing/suit/security/officer, + /obj/item/clothing/head/beret/sec/navyofficer, + /obj/item/clothing/head/beret/sec/navyofficer, + /obj/item/clothing/under/rank/warden/navyblue, + /obj/item/clothing/suit/security/warden, + /obj/item/clothing/head/beret/sec/navywarden, + /obj/item/clothing/under/rank/head_of_security/navyblue, + /obj/item/clothing/suit/security/hos, + /obj/item/clothing/head/beret/sec/navyhos) + crate_name = "security clothing crate" + +/datum/supply_pack/security/supplies + name = "Security Supplies Crate" + desc = "Contains seven flashbangs, seven teargas grenades, six flashes, and seven handcuffs. Requires Security access to open." + cost = 1200 + contains = list(/obj/item/storage/box/flashbangs, + /obj/item/storage/box/teargas, + /obj/item/storage/box/flashes, + /obj/item/storage/box/handcuffs) + crate_name = "security supply crate" + +/datum/supply_pack/security/firingpins + name = "Standard Firing Pins Crate" + desc = "Upgrade your arsenal with 10 standard firing pins. Requires Security access to open." + cost = 2000 + contains = list(/obj/item/storage/box/firingpins, + /obj/item/storage/box/firingpins) + crate_name = "firing pins crate" + +/datum/supply_pack/security/justiceinbound + name = "Standard Justice Enforcer Crate" + desc = "This is it. The Bee's Knees. The Creme of the Crop. The Pick of the Litter. The best of the best of the best. The Crown Jewel of Nanotrasen. The Alpha and the Omega of security headwear. Guaranteed to strike fear into the hearts of each and every criminal aboard the station. Also comes with a security gasmask. Requires Security access to open." + cost = 6000 //justice comes at a price. An expensive, noisy price. + contraband = TRUE + contains = list(/obj/item/clothing/head/helmet/justice, + /obj/item/clothing/mask/gas/sechailer) + crate_name = "security clothing crate" + +/datum/supply_pack/security/baton + name = "Stun Batons Crate" + desc = "Arm the Civil Protection Forces with three stun batons. Batteries included. Requires Security access to open." + cost = 1200 + contains = list(/obj/item/melee/baton/loaded, + /obj/item/melee/baton/loaded, + /obj/item/melee/baton/loaded) + crate_name = "stun baton crate" + +/datum/supply_pack/security/taser + name = "Taser Crate" + desc = "From the depths of stunbased combat, this order rises above, supreme. Contains three hybrid tasers, capable of firing both electrodes and disabling shots. Requires Security access to open." + cost = 3500 + contains = list(/obj/item/gun/energy/e_gun/advtaser, + /obj/item/gun/energy/e_gun/advtaser, + /obj/item/gun/energy/e_gun/advtaser) + crate_name = "taser crate" + +/datum/supply_pack/security/wall_flash + name = "Wall-Mounted Flash Crate" + desc = "Contains four wall-mounted flashes. Requires Security access to open." + cost = 1000 + contains = list(/obj/item/storage/box/wall_flash, + /obj/item/storage/box/wall_flash, + /obj/item/storage/box/wall_flash, + /obj/item/storage/box/wall_flash) + crate_name = "wall-mounted flash crate" diff --git a/code/modules/cargo/packs/service.dm b/code/modules/cargo/packs/service.dm new file mode 100644 index 0000000000..c7f98cac0b --- /dev/null +++ b/code/modules/cargo/packs/service.dm @@ -0,0 +1,266 @@ + +//Reminders- +// If you add something to this list, please group it by type and sort it alphabetically instead of just jamming it in like an animal +// cost = 700- Minimum cost, or infinite points are possible. +////////////////////////////////////////////////////////////////////////////// +/////////////////////////////// Service ////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +/datum/supply_pack/service + group = "Service" + +/datum/supply_pack/service/advlighting + name = "Advanced Lighting crate" + desc = "Thanks to advanced lighting tech we here at the Lamp Factory have be able to produce more lamps and lamp items! This crate has three lamps, a box of lights and a state of the art rapid-light-device!" + cost = 2750 + contains = list(/obj/item/construction/rld, + /obj/item/flashlight/lamp, + /obj/item/flashlight/lamp, + /obj/item/flashlight/lamp/green, + /obj/item/storage/box/lights/mixed) + crate_name = "advanced lighting crate" + crate_type = /obj/structure/closet/crate/secure + +/datum/supply_pack/service/cargo_supples + name = "Cargo Supplies Crate" + desc = "Sold everything that wasn't bolted down? You can get right back to work with this crate containing stamps, an export scanner, destination tagger, hand labeler and some package wrapping." + cost = 1000 + contains = list(/obj/item/stamp, + /obj/item/stamp/denied, + /obj/item/export_scanner, + /obj/item/destTagger, + /obj/item/hand_labeler, + /obj/item/stack/packageWrap) + crate_name = "cargo supplies crate" + +/datum/supply_pack/service/carpet_exotic + name = "Exotic Carpet Crate" + desc = "Exotic carpets straight from Space Russia, for all your decorating needs. Contains 100 tiles each of 10 different flooring patterns." + cost = 10000 + contains = list(/obj/item/stack/tile/carpet/blue/fifty, + /obj/item/stack/tile/carpet/blue/fifty, + /obj/item/stack/tile/carpet/cyan/fifty, + /obj/item/stack/tile/carpet/cyan/fifty, + /obj/item/stack/tile/carpet/green/fifty, + /obj/item/stack/tile/carpet/green/fifty, + /obj/item/stack/tile/carpet/orange/fifty, + /obj/item/stack/tile/carpet/orange/fifty, + /obj/item/stack/tile/carpet/purple/fifty, + /obj/item/stack/tile/carpet/purple/fifty, + /obj/item/stack/tile/carpet/red/fifty, + /obj/item/stack/tile/carpet/red/fifty, + /obj/item/stack/tile/carpet/royalblue/fifty, + /obj/item/stack/tile/carpet/royalblue/fifty, + /obj/item/stack/tile/carpet/royalblack/fifty, + /obj/item/stack/tile/carpet/royalblack/fifty, + /obj/item/stack/tile/carpet/blackred/fifty, + /obj/item/stack/tile/carpet/blackred/fifty, + /obj/item/stack/tile/carpet/monochrome/fifty, + /obj/item/stack/tile/carpet/monochrome/fifty) + crate_name = "exotic carpet crate" + +/datum/supply_pack/service/food_cart + name = "Food Cart Crate" + desc = "Want to sell food on the go? Cook lost their cart? Well we just so happen to have a few carts to spare!" + cost = 1000 + contains = list(/obj/machinery/food_cart) + crate_name = "food cart crate" + crate_type = /obj/structure/closet/crate + +/datum/supply_pack/service/noslipfloor + name = "High-traction Floor Tiles" + desc = "Make slipping a thing of the past with sixty industrial-grade anti-slip floortiles!" + cost = 2000 + contains = list(/obj/item/stack/tile/noslip/thirty, + /obj/item/stack/tile/noslip/thirty) + crate_name = "high-traction floor tiles crate" + +/datum/supply_pack/service/icecream_cart + name = "Ice Cream Cart Crate" + desc = "Plasma fire a to hot for you, want a nice treat after a hard days work? Well now we have the cart for you! This Ice Cream Vat has everthing you need to make you and your friends so ice cream treats! This cart comes stocked with some ingredients for each type of scoopable icecream." + cost = 2750 //Comes prestocked with basic ingredients + contains = list(/obj/machinery/icecream_vat) + crate_name = "ice cream vat crate" + crate_type = /obj/structure/closet/crate + +/datum/supply_pack/service/janitor + name = "Janitorial Supplies Crate" + desc = "Fight back against dirt and grime with Nanotrasen's Janitorial Essentials(tm)! Contains three buckets, caution signs, and cleaner grenades. Also has a single mop, spray cleaner, rag, NT soap and a trash bag." + cost = 1300 + contains = list(/obj/item/reagent_containers/glass/bucket, + /obj/item/reagent_containers/glass/bucket, + /obj/item/reagent_containers/glass/bucket, + /obj/item/mop, + /obj/item/caution, + /obj/item/caution, + /obj/item/caution, + /obj/item/storage/bag/trash, + /obj/item/reagent_containers/spray/cleaner, + /obj/item/reagent_containers/rag, + /obj/item/grenade/chem_grenade/cleaner, + /obj/item/grenade/chem_grenade/cleaner, + /obj/item/grenade/chem_grenade/cleaner, + /obj/item/soap/nanotrasen) + crate_name = "janitorial supplies crate" + +/datum/supply_pack/service/janitor/janicart + name = "Janitorial Cart and Galoshes Crate" + desc = "The keystone to any successful janitor. As long as you have feet, this pair of galoshes will keep them firmly planted on the ground. Also contains a janitorial cart." + cost = 2000 + contains = list(/obj/structure/janitorialcart, + /obj/item/clothing/shoes/galoshes) + crate_name = "janitorial cart crate" + crate_type = /obj/structure/closet/crate/large + +/datum/supply_pack/service/janitor/janitank + name = "Janitor Backpack Crate" + desc = "Call forth divine judgement upon dirt and grime with this high capacity janitor backpack. Contains 500 units of station-cleansing cleaner. Requires janitor access to open." + cost = 1000 + access = ACCESS_JANITOR + contains = list(/obj/item/watertank/janitor) + crate_name = "janitor backpack crate" + crate_type = /obj/structure/closet/crate/secure + +/datum/supply_pack/service/janitor/janpremium + name = "Janitor Premium Supplies" + desc = "Do to the union for better supplies, we have desided to make a deal for you, In this crate you can get a brand new chem, Drying Angent this stuff is the work of slimes or magic! This crate also contains a rag to test out the Drying Angent magic, three wet floor signs, and some spare bottles of ammonia." + cost = 1750 + access = ACCESS_JANITOR + contains = list(/obj/item/caution, + /obj/item/caution, + /obj/item/caution, + /obj/item/reagent_containers/rag, + /obj/item/reagent_containers/glass/bottle/ammonia, + /obj/item/reagent_containers/glass/bottle/ammonia, + /obj/item/reagent_containers/glass/bottle/ammonia, + /obj/item/reagent_containers/spray/drying_agent) + crate_name = "janitor backpack crate" + +/datum/supply_pack/service/janitor/janpimp + name = "Custodial Cruiser" + desc = "Clown steal your ride? Assistant lock it in the dorms? Order a new one and get back to cleaning in style!" + cost = 3000 + access = ACCESS_JANITOR + contains = list(/obj/vehicle/ridden/janicart, + /obj/item/key/janitor) + crate_name = "janitor ride crate" + crate_type = /obj/structure/closet/crate/large + +/datum/supply_pack/service/mule + name = "MULEbot Crate" + desc = "Pink-haired Quartermaster not doing her job? Replace her with this tireless worker, today!" + cost = 2000 + contains = list(/mob/living/simple_animal/bot/mulebot) + crate_name = "\improper MULEbot Crate" + crate_type = /obj/structure/closet/crate/large + +/datum/supply_pack/service/party + name = "Party Equipment" + desc = "Celebrate both life and death on the station with Nanotrasen's Party Essentials(tm)! Contains seven colored glowsticks, four beers, two ales, and a bottle of patron, goldschlager, and shaker!" + cost = 2000 + contains = list(/obj/item/storage/box/drinkingglasses, + /obj/item/reagent_containers/food/drinks/shaker, + /obj/item/reagent_containers/food/drinks/bottle/patron, + /obj/item/reagent_containers/food/drinks/bottle/goldschlager, + /obj/item/reagent_containers/food/drinks/ale, + /obj/item/reagent_containers/food/drinks/ale, + /obj/item/reagent_containers/food/drinks/beer, + /obj/item/reagent_containers/food/drinks/beer, + /obj/item/reagent_containers/food/drinks/beer, + /obj/item/reagent_containers/food/drinks/beer, + /obj/item/flashlight/glowstick, + /obj/item/flashlight/glowstick/red, + /obj/item/flashlight/glowstick/blue, + /obj/item/flashlight/glowstick/cyan, + /obj/item/flashlight/glowstick/orange, + /obj/item/flashlight/glowstick/yellow, + /obj/item/flashlight/glowstick/pink) + crate_name = "party equipment crate" + +/datum/supply_pack/service/carpet + name = "Premium Carpet Crate" + desc = "Plasteel floor tiles getting on your nerves? These stacks of extra soft carpet will tie any room together. Contains the classics." + cost = 1000 + contains = list(/obj/item/stack/tile/carpet/fifty, + /obj/item/stack/tile/carpet/fifty, + /obj/item/stack/tile/carpet/black/fifty, + /obj/item/stack/tile/carpet/black/fifty) + crate_name = "premium carpet crate" + +/datum/supply_pack/service/carpet2 + name = "Premium Carpet Crate #2" + desc = "Plasteel floor tiles getting on your nerves? These stacks of extra soft carpet will tie any room together. Contains red, and monochrome" + cost = 1000 + contains = list(/obj/item/stack/tile/carpet/blackred/fifty, + /obj/item/stack/tile/carpet/blackred/fifty, + /obj/item/stack/tile/carpet/monochrome/fifty, + /obj/item/stack/tile/carpet/monochrome/fifty) + crate_name = "premium carpet crate #2" + +/datum/supply_pack/service/lightbulbs + name = "Replacement Lights" + desc = "May the light of Aether shine upon this station! Or at least, the light of forty two light tubes and twenty one light bulbs as well as a light replacer." + cost = 1200 + contains = list(/obj/item/storage/box/lights/mixed, + /obj/item/storage/box/lights/mixed, + /obj/item/storage/box/lights/mixed, + /obj/item/lightreplacer) + crate_name = "replacement lights" + +/datum/supply_pack/service/minerkit + name = "Shaft Miner Starter Kit" + desc = "All the miners died too fast? Assistant wants to get a taste of life off-station? Either way, this kit is the best way to turn a regular crewman into an ore-producing, monster-slaying machine. Contains meson goggles, a pickaxe, advanced mining scanner, cargo headset, ore bag, gasmask, and explorer suit. Requires QM access to open." + cost = 2500 + access = ACCESS_QM + contains = list(/obj/item/pickaxe/mini, + /obj/item/clothing/glasses/meson, + /obj/item/t_scanner/adv_mining_scanner/lesser, + /obj/item/radio/headset/headset_cargo/mining, + /obj/item/storage/bag/ore, + /obj/item/clothing/suit/hooded/explorer/standard, + /obj/item/clothing/mask/gas/explorer) + crate_name = "shaft miner starter kit" + crate_type = /obj/structure/closet/crate/secure + +////////////////////////////////////////////////////////////////////////////// +/////////////////////////// Vending Restocks ///////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +/datum/supply_pack/service/vending/bartending + name = "Bartending Supply Crate" + desc = "Bring on the booze with vending machine refills, as well as a free book containing the well-kept secrets to the bartending trade!" + cost = 2000 + contains = list(/obj/item/vending_refill/boozeomat, + /obj/item/vending_refill/coffee, + /obj/item/book/granter/action/drink_fling) + crate_name = "bartending supply crate" + +/datum/supply_pack/service/vending/cigarette + name = "Cigarette Supply Crate" + desc = "Don't believe the reports - smoke today! Contains a cigarette vending machine refill." + cost = 1500 + contains = list(/obj/item/vending_refill/cigarette) + crate_name = "cigarette supply crate" + crate_type = /obj/structure/closet/crate + +/datum/supply_pack/service/vending/games + name = "Games Supply Crate" + desc = "Get your game on with this game vending machine refill." + cost = 1000 + contains = list(/obj/item/vending_refill/games) + crate_name = "games supply crate" + crate_type = /obj/structure/closet/crate + +/datum/supply_pack/service/vending/snack + name = "Snack Supply Crate" + desc = "One vending machine refill of cavity-bringin' goodness! The number one dentist recommended order!" + cost = 1500 + contains = list(/obj/item/vending_refill/snack) + crate_name = "snacks supply crate" + +/datum/supply_pack/service/vending/cola + name = "Softdrinks Supply Crate" + desc = "Got whacked by a toolbox, but you still have those pesky teeth? Get rid of those pearly whites with this soda machine refill, today!" + cost = 1500 + contains = list(/obj/item/vending_refill/cola) + crate_name = "soft drinks supply crate" diff --git a/code/modules/client/asset_cache.dm b/code/modules/client/asset_cache.dm index 5402353fd4..643d072469 100644 --- a/code/modules/client/asset_cache.dm +++ b/code/modules/client/asset_cache.dm @@ -571,6 +571,8 @@ GLOBAL_LIST_EMPTY(asset_datums) "fontawesome-webfont.woff" = 'tgui/assets/fonts/fontawesome-webfont.woff', "font-awesome.css" = 'code/modules/goonchat/browserassets/css/font-awesome.css', "browserOutput.css" = 'code/modules/goonchat/browserassets/css/browserOutput.css', + "browserOutput_dark.css" = 'code/modules/goonchat/browserassets/css/browserOutput_dark.css', + "browserOutput_light.css" = 'code/modules/goonchat/browserassets/css/browserOutput_light.css' ) /datum/asset/spritesheet/goonchat diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm index 7216b73af6..a54584d6cc 100644 --- a/code/modules/client/client_defines.dm +++ b/code/modules/client/client_defines.dm @@ -75,3 +75,8 @@ var/datum/player_details/player_details //these persist between logins/logouts during the same round. var/list/char_render_holders //Should only be a key-value list of north/south/east/west = obj/screen. + + var/client_keysend_amount = 0 + var/next_keysend_reset = 0 + var/next_keysend_trip_reset = 0 + var/keysend_tripped = FALSE \ No newline at end of file diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index 06f23574e1..5442fcb932 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -817,6 +817,10 @@ GLOBAL_LIST_EMPTY(external_rsc_urls) var/file = GLOB.vox_sounds[name] Export("##action=load_rsc", file) stoplag() + for (var/name in GLOB.vox_sounds_male) + var/file = GLOB.vox_sounds_male[name] + Export("##action=load_rsc", file) + stoplag() #endif diff --git a/code/modules/client/darkmode.dm b/code/modules/client/darkmode.dm index 9e8d136b3b..f806e5c964 100644 --- a/code/modules/client/darkmode.dm +++ b/code/modules/client/darkmode.dm @@ -5,7 +5,7 @@ This lets you switch chat themes by using winset and CSS loading, you must relog Things to note: If you change ANYTHING in interface/skin.dmf you need to change it here: Format: -winset(src, "window as appears in skin.dmf after elem", "var to change = currentvalue;var to change = desired value") +winset(src, "window as appears in skin.dmf after elem", "var to change = desired value") How this works: I've added a function to browseroutput.js which registers a cookie for darkmode and swaps the chat accordingly. You can find the button to do this under the "cog" icon next to the ping button (top right of chat) This then swaps the window theme automatically @@ -14,104 +14,52 @@ Thanks to spacemaniac and mcdonald for help with the JS side of this. /client/proc/force_white_theme() //There's no way round it. We're essentially changing the skin by hand. It's painful but it works, and is the way Lummox suggested. //Main windows - winset(src, "infowindow", "background-color = [COLOR_DARKMODE_DARKBACKGROUND];background-color = [COLOR_WHITEMODE_DARKBACKGROUND]") - winset(src, "infowindow", "text-color = [COLOR_DARKMODE_TEXT];text-color = [COLOR_WHITEMODE_TEXT]") - winset(src, "info", "background-color = [COLOR_DARKMODE_BACKGROUND];background-color = [COLOR_WHITEMODE_BACKGROUND]") - winset(src, "info", "text-color = [COLOR_DARKMODE_TEXT];text-color = [COLOR_WHITEMODE_TEXT]") - winset(src, "browseroutput", "background-color = [COLOR_DARKMODE_BACKGROUND];background-color = [COLOR_DARKMODE_INFO_BUTTONS_BG]") - winset(src, "browseroutput", "text-color = [COLOR_DARKMODE_TEXT];text-color = [COLOR_WHITEMODE_TEXT]") - winset(src, "outputwindow", "background-color = [COLOR_DARKMODE_BACKGROUND];background-color = [COLOR_WHITEMODE_DARKBACKGROUND]") - winset(src, "outputwindow", "text-color = [COLOR_DARKMODE_TEXT];text-color = [COLOR_WHITEMODE_TEXT]") - winset(src, "mainwindow", "background-color = [COLOR_DARKMODE_DARKBACKGROUND];background-color = [COLOR_WHITEMODE_DARKBACKGROUND]") - winset(src, "split", "background-color = [COLOR_DARKMODE_DARKBACKGROUND];background-color = [COLOR_WHITEMODE_BACKGROUND]") + winset(src, "infowindow", "background-color = [COLOR_WHITEMODE_DARKBACKGROUND];text-color = [COLOR_WHITEMODE_TEXT]") + winset(src, "info", "background-color = [COLOR_WHITEMODE_BACKGROUND];text-color = [COLOR_WHITEMODE_TEXT]") + winset(src, "browseroutput", "background-color = [COLOR_WHITEMODE_DARKBACKGROUND];text-color = [COLOR_WHITEMODE_TEXT]") + winset(src, "outputwindow", "background-color = [COLOR_WHITEMODE_DARKBACKGROUND];text-color = [COLOR_WHITEMODE_TEXT]") + winset(src, "mainwindow", "background-color = [COLOR_WHITEMODE_DARKBACKGROUND]") + winset(src, "split", "background-color = [COLOR_WHITEMODE_BACKGROUND]") //Buttons - winset(src, "changelog", "background-color = [COLOR_DARKMODE_INFO_BUTTONS_BG];background-color = [COLOR_WHITEMODE_INFO_BUTTONS_BG]") - winset(src, "changelog", "text-color = [COLOR_DARKMODE_TEXT];text-color = [COLOR_WHITEMODE_TEXT]") - winset(src, "rules", "background-color = [COLOR_DARKMODE_INFO_BUTTONS_BG];background-color = [COLOR_WHITEMODE_INFO_BUTTONS_BG]") - winset(src, "rules", "text-color = [COLOR_DARKMODE_TEXT];text-color = [COLOR_WHITEMODE_TEXT]") - winset(src, "wiki", "background-color = [COLOR_DARKMODE_INFO_BUTTONS_BG];background-color = [COLOR_WHITEMODE_INFO_BUTTONS_BG]") - winset(src, "wiki", "text-color = [COLOR_DARKMODE_TEXT];text-color = [COLOR_WHITEMODE_TEXT]") - winset(src, "forum", "background-color = [COLOR_DARKMODE_INFO_BUTTONS_BG];background-color = [COLOR_WHITEMODE_INFO_BUTTONS_BG]") - winset(src, "forum", "text-color = [COLOR_DARKMODE_TEXT];text-color = [COLOR_WHITEMODE_TEXT]") - winset(src, "github", "background-color = [COLOR_DARKMODE_INFO_BUTTONS_BG];background-color = [COLOR_WHITEMODE_INFO_BUTTONS_BG]") - winset(src, "github", "text-color = [COLOR_DARKMODE_TEXT];text-color = [COLOR_WHITEMODE_TEXT]") - winset(src, "report-issue", "background-color = [COLOR_DARKMODE_ISSUE_BUTTON_BG];background-color = [COLOR_WHITEMODE_ISSUE_BUTTON_BG]") - winset(src, "report-issue", "text-color = [COLOR_DARKMODE_TEXT];text-color = [COLOR_WHITEMODE_TEXT]") + winset(src, "changelog", "background-color = [COLOR_WHITEMODE_INFO_BUTTONS_BG];text-color = [COLOR_WHITEMODE_TEXT]") + winset(src, "rules", "background-color = [COLOR_WHITEMODE_INFO_BUTTONS_BG];text-color = [COLOR_WHITEMODE_TEXT]") + winset(src, "wiki", "background-color = [COLOR_WHITEMODE_INFO_BUTTONS_BG];text-color = [COLOR_WHITEMODE_TEXT]") + winset(src, "forum", "background-color = [COLOR_WHITEMODE_INFO_BUTTONS_BG];text-color = [COLOR_WHITEMODE_TEXT]") + winset(src, "github", "background-color = [COLOR_WHITEMODE_INFO_BUTTONS_BG];text-color = [COLOR_WHITEMODE_TEXT]") + winset(src, "report-issue", "background-color = [COLOR_WHITEMODE_ISSUE_BUTTON_BG];text-color = [COLOR_WHITEMODE_TEXT]") //Status and verb tabs - winset(src, "output", "background-color = [COLOR_DARKMODE_DARKBACKGROUND];background-color = [COLOR_WHITEMODE_BACKGROUND]") - winset(src, "output", "text-color = [COLOR_DARKMODE_TEXT];text-color = [COLOR_WHITEMODE_TEXT]") - winset(src, "statwindow", "background-color = [COLOR_DARKMODE_BACKGROUND];background-color = [COLOR_WHITEMODE_DARKBACKGROUND]") - winset(src, "statwindow", "text-color = #eaeaea;text-color = [COLOR_WHITEMODE_TEXT]") - winset(src, "stat", "background-color = [COLOR_DARKMODE_DARKBACKGROUND];background-color = [COLOR_WHITEMODE_BACKGROUND]") - winset(src, "stat", "tab-background-color = [COLOR_DARKMODE_BACKGROUND];tab-background-color = [COLOR_WHITEMODE_DARKBACKGROUND]") - winset(src, "stat", "text-color = [COLOR_DARKMODE_TEXT];text-color = [COLOR_WHITEMODE_TEXT]") - winset(src, "stat", "tab-text-color = [COLOR_DARKMODE_TEXT];tab-text-color = [COLOR_WHITEMODE_TEXT]") - winset(src, "stat", "prefix-color = [COLOR_DARKMODE_TEXT];prefix-color = [COLOR_WHITEMODE_TEXT]") - winset(src, "stat", "suffix-color = [COLOR_DARKMODE_TEXT];suffix-color = [COLOR_WHITEMODE_TEXT]") + winset(src, "output", "background-color = [COLOR_WHITEMODE_BACKGROUND];text-color = [COLOR_WHITEMODE_TEXT]") + winset(src, "statwindow", "background-color = [COLOR_WHITEMODE_DARKBACKGROUND];text-color = [COLOR_WHITEMODE_TEXT]") + winset(src, "stat", "background-color = [COLOR_WHITEMODE_BACKGROUND];tab-background-color = [COLOR_WHITEMODE_DARKBACKGROUND];\ + text-color = [COLOR_WHITEMODE_TEXT];tab-text-color = [COLOR_WHITEMODE_TEXT];\ + prefix-color = [COLOR_WHITEMODE_TEXT];suffix-color = [COLOR_WHITEMODE_TEXT]") //Etc. - winset(src, "say", "background-color = [COLOR_DARKMODE_DARKBACKGROUND];background-color = [COLOR_WHITEMODE_DARKBACKGROUND]") - winset(src, "say", "text-color = [COLOR_DARKMODE_TEXT];text-color = [COLOR_WHITEMODE_TEXT]") - winset(src, "asset_cache_browser", "background-color = [COLOR_DARKMODE_BACKGROUND];background-color = [COLOR_WHITEMODE_DARKBACKGROUND]") - winset(src, "asset_cache_browser", "text-color = [COLOR_DARKMODE_TEXT];text-color = [COLOR_WHITEMODE_TEXT]") - winset(src, "tooltip", "background-color = [COLOR_DARKMODE_BACKGROUND];background-color = [COLOR_WHITEMODE_BACKGROUND]") - winset(src, "tooltip", "text-color = [COLOR_DARKMODE_TEXT];text-color = [COLOR_WHITEMODE_TEXT]") + winset(src, "say", "background-color = [COLOR_WHITEMODE_DARKBACKGROUND];text-color = [COLOR_WHITEMODE_TEXT]") + winset(src, "asset_cache_browser", "background-color = [COLOR_WHITEMODE_DARKBACKGROUND];text-color = [COLOR_WHITEMODE_TEXT]") + winset(src, "tooltip", "background-color = [COLOR_WHITEMODE_BACKGROUND];text-color = [COLOR_WHITEMODE_TEXT]") /client/proc/force_dark_theme() //Inversely, if theyre using white theme and want to swap to the superior dark theme, let's get WINSET() ing //Main windows - winset(src, "infowindow", "background-color = [COLOR_WHITEMODE_DARKBACKGROUND];background-color = [COLOR_DARKMODE_DARKBACKGROUND]") - winset(src, "infowindow", "text-color = [COLOR_WHITEMODE_TEXT];text-color = [COLOR_DARKMODE_TEXT]") - winset(src, "info", "background-color = [COLOR_WHITEMODE_BACKGROUND];background-color = [COLOR_DARKMODE_BACKGROUND]") - winset(src, "info", "text-color = [COLOR_WHITEMODE_TEXT];text-color = [COLOR_DARKMODE_TEXT]") - winset(src, "browseroutput", "background-color = [COLOR_WHITEMODE_BACKGROUND];background-color = [COLOR_DARKMODE_BACKGROUND]") - winset(src, "browseroutput", "text-color = [COLOR_WHITEMODE_TEXT];text-color = [COLOR_DARKMODE_TEXT]") - winset(src, "outputwindow", "background-color = [COLOR_WHITEMODE_DARKBACKGROUND];background-color = [COLOR_DARKMODE_BACKGROUND]") - winset(src, "outputwindow", "text-color = [COLOR_WHITEMODE_TEXT];text-color = [COLOR_DARKMODE_TEXT]") - winset(src, "mainwindow", "background-color = [COLOR_WHITEMODE_DARKBACKGROUND];background-color = [COLOR_DARKMODE_DARKBACKGROUND]") - winset(src, "split", "background-color = [COLOR_WHITEMODE_BACKGROUND];background-color = [COLOR_DARKMODE_BACKGROUND]") + winset(src, "infowindow", "background-color = [COLOR_DARKMODE_DARKBACKGROUND];text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "info", "background-color = [COLOR_DARKMODE_BACKGROUND];text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "browseroutput", "background-color = [COLOR_DARKMODE_BACKGROUND];text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "outputwindow", "background-color = [COLOR_DARKMODE_BACKGROUND];text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "mainwindow", "background-color = [COLOR_DARKMODE_DARKBACKGROUND]") + winset(src, "split", "background-color = [COLOR_DARKMODE_BACKGROUND]") //Buttons - winset(src, "changelog", "background-color = [COLOR_WHITEMODE_INFO_BUTTONS_BG];background-color = [COLOR_DARKMODE_INFO_BUTTONS_BG]") - winset(src, "changelog", "text-color = [COLOR_WHITEMODE_TEXT];text-color = [COLOR_DARKMODE_TEXT]") - winset(src, "rules", "background-color = [COLOR_WHITEMODE_INFO_BUTTONS_BG];background-color = [COLOR_DARKMODE_INFO_BUTTONS_BG]") - winset(src, "rules", "text-color = [COLOR_WHITEMODE_TEXT];text-color = [COLOR_DARKMODE_TEXT]") - winset(src, "wiki", "background-color = [COLOR_WHITEMODE_INFO_BUTTONS_BG];background-color = [COLOR_DARKMODE_INFO_BUTTONS_BG]") - winset(src, "wiki", "text-color = [COLOR_WHITEMODE_TEXT];text-color = [COLOR_DARKMODE_TEXT]") - winset(src, "forum", "background-color = [COLOR_WHITEMODE_INFO_BUTTONS_BG];background-color = [COLOR_DARKMODE_INFO_BUTTONS_BG]") - winset(src, "forum", "text-color = [COLOR_WHITEMODE_TEXT];text-color = [COLOR_DARKMODE_TEXT]") - winset(src, "github", "background-color = [COLOR_WHITEMODE_INFO_BUTTONS_BG];background-color = [COLOR_DARKMODE_INFO_BUTTONS_BG]") - winset(src, "github", "text-color = [COLOR_WHITEMODE_TEXT];text-color = [COLOR_DARKMODE_TEXT]") - winset(src, "report-issue", "background-color = [COLOR_WHITEMODE_ISSUE_BUTTON_BG];background-color = [COLOR_DARKMODE_ISSUE_BUTTON_BG]") - winset(src, "report-issue", "text-color = [COLOR_WHITEMODE_TEXT];text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "changelog", "background-color = [COLOR_DARKMODE_INFO_BUTTONS_BG];text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "rules", "background-color = [COLOR_DARKMODE_INFO_BUTTONS_BG];text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "wiki", "background-color = [COLOR_DARKMODE_INFO_BUTTONS_BG];text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "forum", "background-color = [COLOR_DARKMODE_INFO_BUTTONS_BG];text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "github", "background-color = [COLOR_DARKMODE_INFO_BUTTONS_BG];text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "report-issue", "background-color = [COLOR_DARKMODE_ISSUE_BUTTON_BG];text-color = [COLOR_DARKMODE_TEXT]") //Status and verb tabs - winset(src, "output", "background-color = [COLOR_WHITEMODE_DARKBACKGROUND];background-color = [COLOR_DARKMODE_BACKGROUND]") - winset(src, "output", "text-color = [COLOR_WHITEMODE_TEXT];text-color = [COLOR_DARKMODE_TEXT]") - winset(src, "statwindow", "background-color = [COLOR_WHITEMODE_DARKBACKGROUND];background-color = [COLOR_DARKMODE_DARKBACKGROUND]") - winset(src, "statwindow", "text-color = [COLOR_WHITEMODE_TEXT];text-color = [COLOR_DARKMODE_TEXT]") - winset(src, "stat", "background-color = [COLOR_WHITEMODE_BACKGROUND];background-color = [COLOR_DARKMODE_DARKBACKGROUND]") - winset(src, "stat", "tab-background-color = [COLOR_WHITEMODE_DARKBACKGROUND];tab-background-color = [COLOR_DARKMODE_BACKGROUND]") - winset(src, "stat", "text-color = [COLOR_WHITEMODE_TEXT];text-color = [COLOR_DARKMODE_TEXT]") - winset(src, "stat", "tab-text-color = [COLOR_WHITEMODE_TEXT];tab-text-color = [COLOR_DARKMODE_TEXT]") - winset(src, "stat", "prefix-color = [COLOR_WHITEMODE_TEXT];prefix-color = [COLOR_DARKMODE_TEXT]") - winset(src, "stat", "suffix-color = [COLOR_WHITEMODE_TEXT];suffix-color = [COLOR_DARKMODE_TEXT]") + winset(src, "output", "background-color = [COLOR_DARKMODE_BACKGROUND];text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "statwindow", "background-color = [COLOR_DARKMODE_DARKBACKGROUND];text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "stat", "background-color = [COLOR_DARKMODE_DARKBACKGROUND];tab-background-color = [COLOR_DARKMODE_BACKGROUND];\ + text-color = [COLOR_DARKMODE_TEXT];tab-text-color = [COLOR_DARKMODE_TEXT];\ + prefix-color = [COLOR_DARKMODE_TEXT];suffix-color = [COLOR_DARKMODE_TEXT]") //Etc. - winset(src, "say", "background-color = [COLOR_WHITEMODE_DARKBACKGROUND];background-color = [COLOR_DARKMODE_BACKGROUND]") - winset(src, "say", "text-color = [COLOR_WHITEMODE_TEXT];text-color = [COLOR_DARKMODE_TEXT]") - winset(src, "asset_cache_browser", "background-color = [COLOR_WHITEMODE_DARKBACKGROUND];background-color = [COLOR_DARKMODE_BACKGROUND]") - winset(src, "asset_cache_browser", "text-color = [COLOR_WHITEMODE_TEXT];text-color = [COLOR_DARKMODE_TEXT]") - winset(src, "tooltip", "background-color = [COLOR_WHITEMODE_BACKGROUND];background-color = [COLOR_DARKMODE_BACKGROUND]") - winset(src, "tooltip", "text-color = [COLOR_WHITEMODE_TEXT];text-color = [COLOR_DARKMODE_TEXT]") - - -/datum/asset/simple/goonchat - verify = FALSE - assets = list( - "json2.min.js" = 'code/modules/goonchat/browserassets/js/json2.min.js', - "errorHandler.js" = 'code/modules/goonchat/browserassets/js/errorHandler.js', - "browserOutput.js" = 'code/modules/goonchat/browserassets/js/browserOutput.js', - "fontawesome-webfont.eot" = 'tgui/assets/fonts/fontawesome-webfont.eot', - "fontawesome-webfont.svg" = 'tgui/assets/fonts/fontawesome-webfont.svg', - "fontawesome-webfont.ttf" = 'tgui/assets/fonts/fontawesome-webfont.ttf', - "fontawesome-webfont.woff" = 'tgui/assets/fonts/fontawesome-webfont.woff', - "font-awesome.css" = 'code/modules/goonchat/browserassets/css/font-awesome.css', - "browserOutput.css" = 'code/modules/goonchat/browserassets/css/browserOutput.css', - "browserOutput_white.css" = 'code/modules/goonchat/browserassets/css/browserOutput_white.css', - ) + winset(src, "say", "background-color = [COLOR_DARKMODE_BACKGROUND];text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "asset_cache_browser", "background-color = [COLOR_DARKMODE_BACKGROUND];text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "tooltip", "background-color = [COLOR_DARKMODE_BACKGROUND];text-color = [COLOR_DARKMODE_TEXT]") \ No newline at end of file diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index cd22685952..47c3293c35 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -72,11 +72,11 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/gender = MALE //gender of character (well duh) var/age = 30 //age of character var/underwear = "Nude" //underwear type - var/undie_color = "#FFFFFF" + var/undie_color = "FFF" var/undershirt = "Nude" //undershirt type - var/shirt_color = "#FFFFFF" + var/shirt_color = "FFF" var/socks = "Nude" //socks type - var/socks_color = "#FFFFFF" + var/socks_color = "FFF" var/backbag = DBACKPACK //backpack type var/jumpsuit_style = PREF_SUIT //suit/skirt var/hair_style = "Bald" //Hair type @@ -85,6 +85,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/facial_hair_color = "000" //Facial hair color var/skin_tone = "caucasian1" //Skin color var/eye_color = "000" //Eye color + var/horn_color = "85615a" //Horn color + var/wing_color = "fff" //Wing color var/datum/species/pref_species = new /datum/species/human() //Mutant race var/list/features = list("mcolor" = "FFF", "tail_lizard" = "Smooth", @@ -94,10 +96,12 @@ GLOBAL_LIST_EMPTY(preferences_datums) "ears" = "None", "wings" = "None", "frills" = "None", + "deco_wings" = "None", "spines" = "None", "body_markings" = "None", - "legs" = "Normal Legs", - "moth_wings" = "Plain", + "legs" = "Plantigrade", + "insect_wings" = "Plain", + "insect_fluff" = "None", "mcolor2" = "FFF", "mcolor3" = "FFF", "mam_body_markings" = "Plain", @@ -144,6 +148,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) "breasts_size" = "C", "breasts_shape" = "Pair", "breasts_fluid" = "milk", + "breasts_producing" = FALSE, "has_vag" = FALSE, "vag_shape" = "Human", "vag_color" = "fff", @@ -156,7 +161,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) "womb_fluid" = "femcum", "ipc_screen" = "Sunburst", "ipc_antenna" = "None", - "flavor_text" = "" + "flavor_text" = "", + "meat_type" = "Mammalian" ) var/list/custom_names = list() @@ -171,18 +177,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/list/all_quirks = list() var/list/character_quirks = list() - //Jobs, uses bitflags - var/job_civilian_high = 0 - var/job_civilian_med = 0 - var/job_civilian_low = 0 - - var/job_medsci_high = 0 - var/job_medsci_med = 0 - var/job_medsci_low = 0 - - var/job_engsec_high = 0 - var/job_engsec_med = 0 - var/job_engsec_low = 0 + //Job preferences 2.0 - indexed by job title , no key or value implies never + var/list/job_preferences = list() // Want randomjob if preferences already filled - Donkie var/joblessrole = BERANDOMJOB //defaults to 1 for fewer assistants @@ -240,7 +236,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) return #define APPEARANCE_CATEGORY_COLUMN "
" + mutant_category = 0 + + if("meat_type" in pref_species.default_features) + if(!mutant_category) + dat += APPEARANCE_CATEGORY_COLUMN + + dat += "

Meat Type

" + + dat += "[features["meat_type"]]" + mutant_category++ if(mutant_category >= MAX_MUTANT_ROWS) dat += "" @@ -470,6 +479,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "

Horns

" dat += "[features["horns"]]" + dat += "   Change
" + mutant_category++ if(mutant_category >= MAX_MUTANT_ROWS) @@ -536,6 +547,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) if(mutant_category >= MAX_MUTANT_ROWS) dat += "" mutant_category = 0 + if("ears" in pref_species.default_features) if(!mutant_category) dat += APPEARANCE_CATEGORY_COLUMN @@ -548,6 +560,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) if(mutant_category >= MAX_MUTANT_ROWS) dat += "" mutant_category = 0 + if("mam_snouts" in pref_species.default_features) if(!mutant_category) dat += APPEARANCE_CATEGORY_COLUMN @@ -572,14 +585,34 @@ GLOBAL_LIST_EMPTY(preferences_datums) if(mutant_category >= MAX_MUTANT_ROWS) dat += "" mutant_category = 0 - if("moth_wings" in pref_species.default_features) + if("deco_wings" in pref_species.default_features) if(!mutant_category) dat += APPEARANCE_CATEGORY_COLUMN - dat += "

Moth wings

" + dat += "

Decorative wings

" - dat += "[features["moth_wings"]]" + dat += "[features["deco_wings"]]" + dat += "   Change
" + if("insect_wings" in pref_species.default_features) + if(!mutant_category) + dat += APPEARANCE_CATEGORY_COLUMN + + dat += "

Insect wings

" + + dat += "[features["insect_wings"]]" + dat += "   Change
" + mutant_category++ + if(mutant_category >= MAX_MUTANT_ROWS) + dat += "" + mutant_category = 0 + if("insect_fluff" in pref_species.default_features) + if(!mutant_category) + dat += APPEARANCE_CATEGORY_COLUMN + + dat += "

Insect Fluff

" + + dat += "[features["insect_fluff"]]" mutant_category++ if(mutant_category >= MAX_MUTANT_ROWS) dat += "" @@ -680,13 +713,13 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "

Clothing & Equipment

" dat += "Underwear:[underwear]" if(UNDIE_COLORABLE(GLOB.underwear_list[underwear])) - dat += "Underwear Color:[undie_color]" + dat += "Underwear Color:   Change
" dat += "Undershirt:[undershirt]" if(UNDIE_COLORABLE(GLOB.undershirt_list[undershirt])) - dat += "Undershirt Color:[shirt_color]" + dat += "Undershirt Color:   Change
" dat += "Socks:[socks]" if(UNDIE_COLORABLE(GLOB.socks_list[socks])) - dat += "Socks Color:[socks_color]" + dat += "Socks Color:   Change
" dat += "Backpack:[backbag]" dat += "Jumpsuit:
[jumpsuit_style]
" dat += "Uplink Location:[uplink_spawn_loc]" @@ -743,6 +776,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "   Change
" dat += "Cup Size:[features["breasts_size"]]" dat += "Breast Shape:[features["breasts_shape"]]" + dat += "Lactates:[features["breasts_producing"] == TRUE ? "Yes" : "No"]" dat += "" dat += "" dat += "
Name: [active1.fields["name"]] 
ID: [active1.fields["id"]] 
Sex: [active1.fields["sex"]] 
Gender: [active1.fields["gender"]] 
Age: [active1.fields["age"]] 
Species: [active1.fields["species"]] 
Rank: [active1.fields["rank"]] 
" -#define MAX_MUTANT_ROWS 4 +#define MAX_MUTANT_ROWS 5 /datum/preferences/proc/ShowChoices(mob/user) if(!user || !user.client) @@ -350,9 +346,9 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "[TextPreview(features["flavor_text"])]...
" dat += "

Body

" dat += "Gender:[gender == MALE ? "Male" : (gender == FEMALE ? "Female" : (gender == PLURAL ? "Non-binary" : "Object"))]
" - dat += "Species:[pref_species.id]
" + dat += "Species:[pref_species.name]
" dat += "Custom Species Name:[custom_species ? custom_species : "None"]
" - dat += "Random Body
" + dat += "Random Body:Randomize!
" dat += "Always Random Body:[be_random_body ? "Yes" : "No"]
" dat += "
Cycle background:[bgstate]
" @@ -447,6 +443,19 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "[features["tail_human"]]" + mutant_category++ + if(mutant_category >= MAX_MUTANT_ROWS) + dat += "
" @@ -796,6 +830,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "Voracious MediHound sleepers: [(cit_toggles & MEDIHOUND_SLEEPER) ? "Yes" : "No"]
" dat += "Hear Vore Sounds: [(cit_toggles & EATING_NOISES) ? "Yes" : "No"]
" dat += "Hear Vore Digestion Sounds: [(cit_toggles & DIGESTION_NOISES) ? "Yes" : "No"]
" + dat += "Lewdchem:[lewdchem == TRUE ? "Enabled" : "Disabled"]
" dat += "Widescreen: [widescreenpref ? "Enabled ([CONFIG_GET(string/default_view)])" : "Disabled (15x15)"]
" dat += "Auto stand: [autostand ? "Enabled" : "Disabled"]
" dat += "Screen Shake: [(screenshake==100) ? "Full" : ((screenshake==0) ? "None" : "[screenshake]")]
" @@ -916,11 +951,9 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "
Description
BANNED
BANNED
\[IN [(available_in_days)] DAYS\]
\[MUTANT\]
\[NON-HUMAN\]
" for(var/datum/data/mining_equipment/prize in prize_list) dat += "" dat += "
[prize.equipment_name][prize.cost]Purchase
" var/datum/browser/popup = new(user, "miningvendor", "Mining Equipment Vendor", 400, 350) - popup.set_content(dat) + popup.set_content(dat.Join()) popup.open() return /obj/machinery/mineral/equipment_vendor/Topic(href, href_list) if(..()) return - if(href_list["choice"]) - if(istype(inserted_id)) - if(href_list["choice"] == "eject") - to_chat(usr, "You eject the ID from [src]'s card slot.") - inserted_id.forceMove(loc) - inserted_id.verb_pickup() - inserted_id = null - else if(href_list["choice"] == "insert") - var/obj/item/card/id/I = usr.get_active_held_item() - if(istype(I)) - if(!usr.transferItemToLoc(I, src)) - return - inserted_id = I - to_chat(usr, "You insert the ID into [src]'s card slot.") - else - to_chat(usr, "Error: No valid ID!") - flick(icon_deny, src) if(href_list["purchase"]) - if(istype(inserted_id)) - var/datum/data/mining_equipment/prize = locate(href_list["purchase"]) + var/mob/M = usr + var/obj/item/card/id/I = M.get_idcard(TRUE) + if(istype(I)) + var/datum/data/mining_equipment/prize = locate(href_list["purchase"]) in prize_list if (!prize || !(prize in prize_list)) to_chat(usr, "Error: Invalid choice!") flick(icon_deny, src) return - if(prize.cost > inserted_id.mining_points) - to_chat(usr, "Error: Insufficient points for [prize.equipment_name]!") + if(prize.cost > I.mining_points) + to_chat(usr, "Error: Insufficient credits for [prize.equipment_name] on [I]!") flick(icon_deny, src) else - inserted_id.mining_points -= prize.cost - to_chat(usr, "[src] clanks to life briefly before vending [prize.equipment_name]!") - new prize.equipment_path(src.loc) - SSblackbox.record_feedback("nested tally", "mining_equipment_bought", 1, list("[type]", "[prize.equipment_path]")) + if (I.mining_points -= prize.cost) + to_chat(usr, "[src] clanks to life briefly before vending [prize.equipment_name]!") + new prize.equipment_path(src.loc) + SSblackbox.record_feedback("nested tally", "mining_equipment_bought", 1, list("[type]", "[prize.equipment_path]")) + else + to_chat(usr, "Error: Transaction failure, please try again later!") + flick(icon_deny, src) else - to_chat(usr, "Error: Please insert a valid ID!") + to_chat(usr, "Error: An ID with a registered account is required!") flick(icon_deny, src) updateUsrDialog() return @@ -160,15 +141,6 @@ if(istype(I, /obj/item/suit_voucher)) RedeemSVoucher(I, user) return - if(istype(I, /obj/item/card/id)) - var/obj/item/card/id/C = usr.get_active_held_item() - if(istype(C) && !istype(inserted_id)) - if(!usr.transferItemToLoc(C, src)) - return - inserted_id = C - to_chat(usr, "You insert the ID into [src]'s card slot.") - interact(user) - return if(default_deconstruction_screwdriver(user, "mining-open", "mining", I)) updateUsrDialog() return @@ -200,7 +172,7 @@ new /obj/item/stack/marker_beacon/thirty(drop_location) if("Crusher Kit") new /obj/item/extinguisher/mini(drop_location) - new /obj/item/twohanded/required/kinetic_crusher(drop_location) + new /obj/item/twohanded/kinetic_crusher(drop_location) if("Mining Conscription Kit") new /obj/item/storage/backpack/duffelbag/mining_conscript(drop_location) @@ -212,7 +184,6 @@ if(prob(50 / severity) && severity < 3) qdel(src) - /****************Golem Point Vendor**************************/ /obj/machinery/mineral/equipment_vendor/golem @@ -228,7 +199,6 @@ new /datum/data/mining_equipment("Monkey Cube", /obj/item/reagent_containers/food/snacks/monkeycube, 300), new /datum/data/mining_equipment("Toolbelt", /obj/item/storage/belt/utility, 350), new /datum/data/mining_equipment("Royal Cape of the Liberator", /obj/item/bedsheet/rd/royal_cape, 500), - new /datum/data/mining_equipment("Sulphuric Acid", /obj/item/reagent_containers/glass/beaker/sulphuric, 500), new /datum/data/mining_equipment("Grey Slime Extract", /obj/item/slime_extract/grey, 1000), new /datum/data/mining_equipment("Modification Kit", /obj/item/borg/upgrade/modkit/trigger_guard, 1700), new /datum/data/mining_equipment("The Liberator's Legacy", /obj/item/storage/box/rndboards, 2000) @@ -323,8 +293,11 @@ new /obj/item/encryptionkey/headset_cargo(src) new /obj/item/clothing/mask/gas/explorer(src) new /obj/item/card/mining_access_card(src) + new /obj/item/gun/energy/kinetic_accelerator(src) + new /obj/item/kitchen/knife/combat/survival(src) + new /obj/item/flashlight/seclite(src) -//CITADEL ADDITIONS BELOW + //CITADEL ADDITIONS BELOW /obj/item/storage/backpack/duffelbag/mining_cloned name = "mining replacement kit" @@ -336,6 +309,7 @@ new /obj/item/clothing/shoes/workboots/mining(src) new /obj/item/clothing/gloves/color/black(src) new /obj/item/implanter/tracking/gps(src) + new /obj/item/gun/energy/kinetic_accelerator(src) new /obj/item/kitchen/knife/combat/survival(src) new /obj/item/storage/firstaid/regular(src) new /obj/item/reagent_containers/hypospray/medipen/survival(src) diff --git a/code/modules/mining/mine_items.dm b/code/modules/mining/mine_items.dm index a1ba493d46..0abb1cfa9e 100644 --- a/code/modules/mining/mine_items.dm +++ b/code/modules/mining/mine_items.dm @@ -68,6 +68,7 @@ /obj/machinery/computer/shuttle/mining name = "mining shuttle console" desc = "Used to call and send the mining shuttle." + req_access = list(ACCESS_MINING) circuit = /obj/item/circuitboard/computer/mining_shuttle shuttleId = "mining" possible_destinations = "mining_home;mining_away;landing_zone_dock;mining_public" diff --git a/code/modules/mining/minebot.dm b/code/modules/mining/minebot.dm index 15ff372c47..997b117b25 100644 --- a/code/modules/mining/minebot.dm +++ b/code/modules/mining/minebot.dm @@ -49,7 +49,7 @@ toggle_mode_action.Grant(src) var/datum/action/innate/minedrone/dump_ore/dump_ore_action = new() dump_ore_action.Grant(src) - var/obj/item/implant/radio/mining/imp = new(src) + var/obj/item/implant/radio/mining/imp = new imp.implant(src) access_card = new /obj/item/card/id(src) diff --git a/code/modules/mob/camera/camera.dm b/code/modules/mob/camera/camera.dm index c780d57810..ee89167f29 100644 --- a/code/modules/mob/camera/camera.dm +++ b/code/modules/mob/camera/camera.dm @@ -30,5 +30,8 @@ loc = destination Moved(oldloc, NONE, TRUE) +/mob/camera/canUseStorage() + return FALSE + /mob/camera/emote(act, m_type=1, message = null, intentional = FALSE) return diff --git a/code/modules/mob/dead/dead.dm b/code/modules/mob/dead/dead.dm index 381dc131e7..35dbe0828f 100644 --- a/code/modules/mob/dead/dead.dm +++ b/code/modules/mob/dead/dead.dm @@ -20,6 +20,9 @@ INITIALIZE_IMMEDIATE(/mob/dead) set_focus(src) return INITIALIZE_HINT_NORMAL +/mob/dead/canUseStorage() + return FALSE + /mob/dead/dust(just_ash, drop_items, force) //ghosts can't be vaporised. return diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm index 47c6cf0170..591fc650b4 100644 --- a/code/modules/mob/dead/new_player/new_player.dm +++ b/code/modules/mob/dead/new_player/new_player.dm @@ -13,8 +13,12 @@ canmove = FALSE anchored = TRUE // don't get pushed around + var/mob/living/new_character //for instant transfer once the round is set up + //Used to make sure someone doesn't get spammed with messages if they're ineligible for roles + var/ineligible_for_roles = FALSE + /mob/dead/new_player/Initialize() if(client && SSticker.state == GAME_STATE_STARTUP) var/obj/screen/splash/S = new(client, TRUE, TRUE) @@ -34,7 +38,7 @@ /mob/dead/new_player/proc/new_player_panel() var/output = "

Welcome, [client ? client.prefs.real_name : "Unknown User"]

" - output += "

Setup Character

" + output += "

Setup Character

" if(SSticker.current_state <= GAME_STATE_PREGAME) switch(ready) @@ -75,7 +79,7 @@ var/datum/browser/popup = new(src, "playersetup", "
New Player Options
", 250, 265) popup.set_window_options("can_close=0") popup.set_content(output) - popup.open(0) + popup.open(FALSE) /mob/dead/new_player/Topic(href, href_list[]) if(src != usr) @@ -141,7 +145,13 @@ ViewManifest() if(href_list["SelectedJob"]) - + if(!SSticker || !SSticker.IsRoundInProgress()) + var/msg = "[key_name(usr)] attempted to join the round using a href that shouldn't be available at this moment!" + log_admin(msg) + message_admins(msg) + to_chat(usr, "The round is either not ready, or has already finished...") + return + if(!GLOB.enter_allowed) to_chat(usr, "There is an administrative lock on entering the game!") return @@ -285,7 +295,7 @@ else to_chat(src, "Teleporting failed. Ahelp an admin please") stack_trace("There's no freaking observer landmark available on this map or you're making observers before the map is initialised") - observer.key = key + transfer_ckey(observer, FALSE) observer.client = client observer.set_ghost_appearance() if(observer.client && observer.client.prefs) @@ -311,6 +321,8 @@ return "Your account is not old enough for [jobtitle]." if(JOB_UNAVAILABLE_SLOTFULL) return "[jobtitle] is already filled to capacity." + if(JOB_UNAVAILABLE_SPECIESLOCK) + return "Your species cannot play as a [jobtitle]." return "Error: Unknown job availability." /mob/dead/new_player/proc/IsJobUnavailable(rank, latejoin = FALSE) @@ -336,6 +348,8 @@ return JOB_UNAVAILABLE_PLAYTIME if(latejoin && !job.special_check_latejoin(client)) return JOB_UNAVAILABLE_GENERIC + if(!client.prefs.pref_species.qualifies_for_rank(rank, client.prefs.features)) + return JOB_UNAVAILABLE_SPECIESLOCK return JOB_AVAILABLE /mob/dead/new_player/proc/AttemptLateSpawn(rank) @@ -416,7 +430,7 @@ SSticker.mode.make_antag_chance(humanc) if(humanc && CONFIG_GET(flag/roundstart_traits)) - SSquirks.AssignQuirks(humanc, humanc.client, TRUE) + SSquirks.AssignQuirks(humanc, humanc.client, TRUE, FALSE, job, FALSE) log_manifest(character.mind.key,character.mind,character,latejoin = TRUE) @@ -432,6 +446,8 @@ var/level = "green" switch(GLOB.security_level) + if(SEC_LEVEL_GREEN) + level = "green" if(SEC_LEVEL_BLUE) level = "blue" if(SEC_LEVEL_AMBER) @@ -439,10 +455,9 @@ if(SEC_LEVEL_RED) level = "red" if(SEC_LEVEL_DELTA) - level = "delta" + level = "delta" var/dat = "
Round Duration: [DisplayTimeText(world.time - SSticker.round_start_time)]
Alert Level: [capitalize(level)]
" - if(SSshuttle.emergency) switch(SSshuttle.emergency.mode) if(SHUTTLE_ESCAPE) @@ -450,37 +465,62 @@ if(SHUTTLE_CALL) if(!SSshuttle.canRecall()) dat += "
The station is currently undergoing evacuation procedures.

" + for(var/datum/job/prioritized_job in SSjob.prioritized_jobs) + if(prioritized_job.current_positions >= prioritized_job.total_positions) + SSjob.prioritized_jobs -= prioritized_job + dat += "
" + var/column_counter = 0 + var/free_space = 0 + for(var/list/category in list(GLOB.command_positions) + list(GLOB.supply_positions) + list(GLOB.engineering_positions) + list(GLOB.nonhuman_positions - "pAI") + list(GLOB.civilian_positions) + list(GLOB.medical_positions) + list(GLOB.science_positions) + list(GLOB.security_positions)) + var/cat_color = "fff" //random default + if(SSjob.name_occupations && SSjob.name_occupations[category[1]]) + cat_color = SSjob.name_occupations[category[1]].selection_color //use the color of the first job in the category (the department head) as the category color + else + cat_color = SSjob.occupations[category[1]].selection_color + dat += "
" + dat += "[SSjob.name_occupations[category[1]].exp_type_department]" - var/available_job_count = 0 - for(var/datum/job/job in SSjob.occupations) - if(job && IsJobUnavailable(job.title, TRUE) == JOB_AVAILABLE) - available_job_count++ + var/list/dept_dat = list() + for(var/job in category) + var/datum/job/job_datum = SSjob.name_occupations[job] + if(job_datum && IsJobUnavailable(job_datum.title, TRUE) == JOB_AVAILABLE) + var/command_bold = "" + if(job in GLOB.command_positions) + command_bold = " command" + if(job_datum in SSjob.prioritized_jobs) + dept_dat += "[job_datum.title] ([job_datum.current_positions])" + else + dept_dat += "[job_datum.title] ([job_datum.current_positions])" + if(!dept_dat.len) + dept_dat += "No positions open." + dat += jointext(dept_dat, "") + dat += "

" + column_counter++ + if(free_space <=4) + free_space++ + if(column_counter > 0 && (column_counter % 3 == 0)) + dat += "
" + if(free_space >= 5 && (free_space % 5 == 0) && (column_counter % 3 != 0)) + free_space = 0 + column_counter = 0 + dat += "" + + dat += "
" + + var/available_ghosts = 0 for(var/spawner in GLOB.mob_spawners) if(!LAZYLEN(spawner)) continue var/obj/effect/mob_spawn/S = pick(GLOB.mob_spawners[spawner]) if(!istype(S) || !S.can_latejoin()) continue - available_job_count++ + available_ghosts++ break - if(!available_job_count) - dat += "
There are currently no open positions!
" - + if(!available_ghosts) + dat += "
There are currently no open ghost spawners.
" else - dat += "
Choose from the following open positions:

" - var/list/categorizedJobs = list( - "Command" = list(jobs = list(), titles = GLOB.command_positions, color = "#aac1ee"), - "Engineering" = list(jobs = list(), titles = GLOB.engineering_positions, color = "#ffd699"), - "Supply" = list(jobs = list(), titles = GLOB.supply_positions, color = "#ead4ae"), - "Miscellaneous" = list(jobs = list(), titles = list(), color = "#ffffff", colBreak = TRUE), - "Ghost Role" = list(jobs = list(), titles = GLOB.mob_spawners, color = "#ffffff"), - "Synthetic" = list(jobs = list(), titles = GLOB.nonhuman_positions, color = "#ccffcc"), - "Service" = list(jobs = list(), titles = GLOB.civilian_positions, color = "#cccccc"), - "Medical" = list(jobs = list(), titles = GLOB.medical_positions, color = "#99ffe6", colBreak = TRUE), - "Science" = list(jobs = list(), titles = GLOB.science_positions, color = "#e6b3e6"), - "Security" = list(jobs = list(), titles = GLOB.security_positions, color = "#ff9999"), - ) + var/list/categorizedJobs = list("Ghost Role" = list(jobs = list(), titles = GLOB.mob_spawners, color = "#ffffff")) for(var/spawner in GLOB.mob_spawners) if(!LAZYLEN(spawner)) continue @@ -489,47 +529,13 @@ continue categorizedJobs["Ghost Role"]["jobs"] += spawner - for(var/datum/job/job in SSjob.occupations) - if(job && IsJobUnavailable(job.title, TRUE) == JOB_AVAILABLE) - var/categorized = FALSE - for(var/jobcat in categorizedJobs) - var/list/jobs = categorizedJobs[jobcat]["jobs"] - if(job.title in categorizedJobs[jobcat]["titles"]) - categorized = TRUE - if(jobcat == "Command") - - if(job.title == "Captain") // Put captain at top of command jobs - jobs.Insert(1, job) - else - jobs += job - else // Put heads at top of non-command jobs - if(job.title in GLOB.command_positions) - jobs.Insert(1, job) - else - jobs += job - if(!categorized) - categorizedJobs["Miscellaneous"]["jobs"] += job - - - dat += "\s*$/g,rb={option:[1,""],legend:[1,"
","
"],area:[1,"",""],param:[1,"",""],thead:[1,"
" + dat += "
" for(var/jobcat in categorizedJobs) - if(categorizedJobs[jobcat]["colBreak"]) - dat += "" if(!length(categorizedJobs[jobcat]["jobs"])) continue var/color = categorizedJobs[jobcat]["color"] dat += "
" dat += "[jobcat]" - for(var/datum/job/job in categorizedJobs[jobcat]["jobs"]) - var/position_class = "otherPosition" - if(job.title in GLOB.command_positions) - position_class = "commandPosition" - if(job in SSjob.prioritized_jobs) - dat += "[job.title] ([job.current_positions])" - else - dat += "[job.title] ([job.current_positions])" - categorizedJobs[jobcat]["jobs"] -= job - for(var/spawner in categorizedJobs[jobcat]["jobs"]) dat += "[spawner]" @@ -537,16 +543,11 @@ dat += "
" dat += "" - // Removing the old window method but leaving it here for reference - //src << browse(dat, "window=latechoices;size=300x640;can_close=1") - - // Added the new browser window method - var/datum/browser/popup = new(src, "latechoices", "Choose Profession", 680, 580) + var/datum/browser/popup = new(src, "latechoices", "Choose Profession", 720, 600) popup.add_stylesheet("playeroptions", 'html/browser/playeroptions.css') - popup.set_content(dat) + popup.set_content(jointext(dat, "")) popup.open(FALSE) // FALSE is passed to open so that it doesn't use the onclose() proc - /mob/dead/new_player/proc/create_character(transfer_after) spawning = 1 close_spawn_windows() @@ -602,3 +603,31 @@ src << browse(null, "window=preferences") //closes job selection src << browse(null, "window=mob_occupation") src << browse(null, "window=latechoices") //closes late job selection + +/* Used to make sure that a player has a valid job preference setup, used to knock players out of eligibility for anything if their prefs don't make sense. + A "valid job preference setup" in this situation means at least having one job set to low, or not having "return to lobby" enabled + Prevents "antag rolling" by setting antag prefs on, all jobs to never, and "return to lobby if preferences not availible" + Doing so would previously allow you to roll for antag, then send you back to lobby if you didn't get an antag role + This also does some admin notification and logging as well, as well as some extra logic to make sure things don't go wrong +*/ + +/mob/dead/new_player/proc/check_preferences() + if(!client) + return FALSE //Not sure how this would get run without the mob having a client, but let's just be safe. + if(client.prefs.joblessrole != RETURNTOLOBBY) + return TRUE + // If they have antags enabled, they're potentially doing this on purpose instead of by accident. Notify admins if so. + var/has_antags = FALSE + if(client.prefs.be_special.len > 0) + has_antags = TRUE + if(client.prefs.job_preferences.len == 0) + if(!ineligible_for_roles) + to_chat(src, "You have no jobs enabled, along with return to lobby if job is unavailable. This makes you ineligible for any round start role, please update your job preferences.") + ineligible_for_roles = TRUE + ready = PLAYER_NOT_READY + if(has_antags) + log_admin("[src.ckey] just got booted back to lobby with no jobs, but antags enabled.") + message_admins("[src.ckey] just got booted back to lobby with no jobs enabled, but antag rolling enabled. Likely antag rolling abuse.") + + return FALSE //This is the only case someone should actually be completely blocked from antag rolling as well + return TRUE diff --git a/code/modules/mob/dead/new_player/preferences_setup.dm b/code/modules/mob/dead/new_player/preferences_setup.dm index 6e91b58506..d54b8256a9 100644 --- a/code/modules/mob/dead/new_player/preferences_setup.dm +++ b/code/modules/mob/dead/new_player/preferences_setup.dm @@ -17,6 +17,8 @@ hair_color = random_short_color() facial_hair_color = hair_color eye_color = random_eye_color() + horn_color = "85615a" + wing_color = "fff" if(!pref_species) var/rando_race = pick(GLOB.roundstart_races) pref_species = new rando_race() @@ -24,50 +26,35 @@ age = rand(AGE_MIN,AGE_MAX) /datum/preferences/proc/update_preview_icon() - // Silicons only need a very basic preview since there is no customization for them. -// var/wide_icon = FALSE //CITDEL THINGS -// if(features["taur"] != "None") -// wide_icon = TRUE - if(job_engsec_high) - switch(job_engsec_high) - if(AI_JF) - parent.show_character_previews(image('icons/mob/ai.dmi', resolve_ai_icon(preferred_ai_core_display), dir = SOUTH)) - return - if(CYBORG) - parent.show_character_previews(image('icons/mob/robots.dmi', icon_state = "robot", dir = SOUTH)) - return + // Determine what job is marked as 'High' priority, and dress them up as such. + var/datum/job/previewJob + var/highest_pref = 0 + for(var/job in job_preferences) + if(job_preferences["[job]"] > highest_pref) + previewJob = SSjob.GetJob(job) + highest_pref = job_preferences["[job]"] + + if(previewJob) + // Silicons only need a very basic preview since there is no customization for them. + if(istype(previewJob,/datum/job/ai)) + parent.show_character_previews(image('icons/mob/ai.dmi', icon_state = resolve_ai_icon(preferred_ai_core_display), dir = SOUTH)) + return + if(istype(previewJob,/datum/job/cyborg)) + parent.show_character_previews(image('icons/mob/robots.dmi', icon_state = "robot", dir = SOUTH)) + return // Set up the dummy for its photoshoot var/mob/living/carbon/human/dummy/mannequin = generate_or_wait_for_human_dummy(DUMMY_HUMAN_SLOT_PREFERENCES) mannequin.cut_overlays() + // Apply the Dummy's preview background first so we properly layer everything else on top of it. mannequin.add_overlay(mutable_appearance('modular_citadel/icons/ui/backgrounds.dmi', bgstate, layer = SPACE_LAYER)) copy_to(mannequin) - // Determine what job is marked as 'High' priority, and dress them up as such. - var/datum/job/previewJob - var/highRankFlag = job_civilian_high | job_medsci_high | job_engsec_high - - if(job_civilian_low & ASSISTANT) - previewJob = SSjob.GetJob("Assistant") - else if(highRankFlag) - var/highDeptFlag - if(job_civilian_high) - highDeptFlag = CIVILIAN - else if(job_medsci_high) - highDeptFlag = MEDSCI - else if(job_engsec_high) - highDeptFlag = ENGSEC - - for(var/datum/job/job in SSjob.occupations) - if(job.flag == highRankFlag && job.department_flag == highDeptFlag) - previewJob = job - break - if(previewJob) - if(current_tab != 2) - mannequin.job = previewJob.title - previewJob.equip(mannequin, TRUE) + mannequin.job = previewJob.title + previewJob.equip(mannequin, TRUE, preference_source = parent) COMPILE_OVERLAYS(mannequin) parent.show_character_previews(new /mutable_appearance(mannequin)) unset_busy_human_dummy(DUMMY_HUMAN_SLOT_PREFERENCES) + diff --git a/code/modules/mob/dead/new_player/sprite_accessories/Citadel_Snowflake.dm b/code/modules/mob/dead/new_player/sprite_accessories/Citadel_Snowflake.dm new file mode 100644 index 0000000000..020776a75f --- /dev/null +++ b/code/modules/mob/dead/new_player/sprite_accessories/Citadel_Snowflake.dm @@ -0,0 +1,53 @@ +/datum/sprite_accessory/mam_tails/shark/datashark + name = "DataShark" + icon_state = "datashark" + ckeys_allowed = list("rubyflamewing") + +/datum/sprite_accessory/mam_tails_animated/shark/datashark + name = "DataShark" + icon_state = "datashark" + ckeys_allowed = list("rubyflamewing") + +/datum/sprite_accessory/mam_body_markings/shark/datashark + name = "DataShark" + icon_state = "datashark" + ckeys_allowed = list("rubyflamewing") + +//Sabresune +/datum/sprite_accessory/mam_ears/sabresune + name = "Sabresune" + icon_state = "sabresune" + ckeys_allowed = list("poojawa") + extra = TRUE + extra_color_src = MUTCOLORS3 + +/datum/sprite_accessory/mam_tails/sabresune + name = "Sabresune" + icon_state = "sabresune" + ckeys_allowed = list("poojawa") + +/datum/sprite_accessory/mam_tails_animated/sabresune + name = "Sabresune" + icon_state = "sabresune" + ckeys_allowed = list("poojawa") + +/datum/sprite_accessory/mam_body_markings/sabresune + name = "Sabresune" + icon_state = "sabresune" + ckeys_allowed = list("poojawa") + +//Lunasune +/datum/sprite_accessory/mam_ears/lunasune + name = "lunasune" + icon_state = "lunasune" + ckeys_allowed = list("invader4352") + +/datum/sprite_accessory/mam_tails/lunasune + name = "lunasune" + icon_state = "lunasune" + ckeys_allowed = list("invader4352") + +/datum/sprite_accessory/mam_tails_animated/lunasune + name = "lunasune" + icon_state = "lunasune" + ckeys_allowed = list("invader4352") diff --git a/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm b/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm index 5e24d0630b..dd66f68e5d 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm @@ -61,6 +61,17 @@ var/dimension_y = 32 var/center = FALSE //Should we center the sprite? + //Special / holdover traits for Citadel specific sprites. + var/extra = FALSE + var/extra_color_src = MUTCOLORS2 //The color source for the extra overlay. + var/extra_icon = 'modular_citadel/icons/mob/mam_tails.dmi' + var/extra2 = FALSE + var/extra2_color_src = MUTCOLORS3 + var/extra2_icon = 'modular_citadel/icons/mob/mam_tails.dmi' + + //for snowflake/donor specific sprites + var/list/ckeys_allowed + /datum/sprite_accessory/underwear icon = 'icons/mob/underwear.dmi' var/has_color = FALSE \ No newline at end of file diff --git a/code/modules/mob/dead/new_player/sprite_accessories/alienpeople.dm b/code/modules/mob/dead/new_player/sprite_accessories/alienpeople.dm new file mode 100644 index 0000000000..6c0659f851 --- /dev/null +++ b/code/modules/mob/dead/new_player/sprite_accessories/alienpeople.dm @@ -0,0 +1,53 @@ + +/****************************************** +*********** Xeno Dorsal Tubes ************* +*******************************************/ +/datum/sprite_accessory/xeno_dorsal + icon = 'modular_citadel/icons/mob/xeno_parts_greyscale.dmi' + +/datum/sprite_accessory/xeno_dorsal/standard + name = "Standard" + icon_state = "standard" + +/datum/sprite_accessory/xeno_dorsal/royal + name = "Royal" + icon_state = "royal" + +/datum/sprite_accessory/xeno_dorsal/down + name = "Dorsal Down" + icon_state = "down" + +/****************************************** +************* Xeno Tails ****************** +*******************************************/ +/datum/sprite_accessory/xeno_tail + icon = 'modular_citadel/icons/mob/xeno_parts_greyscale.dmi' + +/datum/sprite_accessory/xeno_tail/none + name = "None" + +/datum/sprite_accessory/xeno_tail/standard + name = "Xenomorph Tail" + icon_state = "xeno" + +/****************************************** +************* Xeno Heads ****************** +*******************************************/ +/datum/sprite_accessory/xeno_head + icon = 'modular_citadel/icons/mob/xeno_parts_greyscale.dmi' + +/datum/sprite_accessory/xeno_head/standard + name = "Standard" + icon_state = "standard" + +/datum/sprite_accessory/xeno_head/royal + name = "royal" + icon_state = "royal" + +/datum/sprite_accessory/xeno_head/hollywood + name = "hollywood" + icon_state = "hollywood" + +/datum/sprite_accessory/xeno_head/warrior + name = "warrior" + icon_state = "warrior" diff --git a/code/modules/mob/dead/new_player/sprite_accessories/body_markings.dm b/code/modules/mob/dead/new_player/sprite_accessories/body_markings.dm index 6bce18d7ce..2f1d48cfa7 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/body_markings.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/body_markings.dm @@ -1,6 +1,6 @@ -//////////.////////////////// -// MutantParts Definitions // -///////////////////////////// +/****************************************** +************* Lizard Markings ************* +*******************************************/ /datum/sprite_accessory/body_markings icon = 'icons/mob/mutant_bodyparts.dmi' @@ -22,4 +22,271 @@ /datum/sprite_accessory/body_markings/lbelly name = "Light Belly" icon_state = "lbelly" - gender_specific = 1 \ No newline at end of file + gender_specific = 1 + +/****************************************** +************ Furry Markings *************** +*******************************************/ + +// These are all color matrixed and applied per-limb by default. you MUST comply with this if you want to have your markings work --Pooj +// use the HumanScissors tool to break your sprite up into the zones easier. +// Although Byond supposedly doesn't have an icon limit anymore of 512 states after 512.1478, just be careful about too many additions. + +/datum/sprite_accessory/mam_body_markings + extra = FALSE + extra2 = FALSE + color_src = MATRIXED + gender_specific = 0 + icon = 'modular_citadel/icons/mob/mam_markings.dmi' + +/datum/sprite_accessory/mam_body_markings/none + name = "None" + icon_state = "none" + ckeys_allowed = list("yousshouldnteverbeseeingthisyoumeme") + icon = 'modular_citadel/icons/mob/markings_notmammals.dmi' + +/datum/sprite_accessory/mam_body_markings/plain + name = "Plain" + icon_state = "plain" + icon = 'modular_citadel/icons/mob/markings_notmammals.dmi' + +/datum/sprite_accessory/mam_body_markings/redpanda + name = "Redpanda" + icon_state = "redpanda" + +/datum/sprite_accessory/mam_body_markings/bee + name = "Bee" + icon_state = "bee" + icon = 'modular_citadel/icons/mob/markings_notmammals.dmi' + +/datum/sprite_accessory/mam_body_markings/belly + name = "Belly" + icon_state = "belly" + icon = 'modular_citadel/icons/mob/markings_notmammals.dmi' + +/datum/sprite_accessory/mam_body_markings/bellyslim + name = "Bellyslim" + icon_state = "bellyslim" + icon = 'modular_citadel/icons/mob/markings_notmammals.dmi' + +/datum/sprite_accessory/mam_body_markings/corgi + name = "Corgi" + icon_state = "corgi" + +/datum/sprite_accessory/mam_body_markings/cow + name = "Bovine" + icon_state = "bovine" + +/datum/sprite_accessory/mam_body_markings/corvid + name = "Corvid" + icon_state = "corvid" + +/datum/sprite_accessory/mam_body_markings/dalmation + name = "Dalmation" + icon_state = "dalmation" + +/datum/sprite_accessory/mam_body_markings/deer + name = "Deer" + icon_state = "deer" + +/datum/sprite_accessory/mam_body_markings/dog + name = "Dog" + icon_state = "dog" + +/datum/sprite_accessory/mam_body_markings/eevee + name = "Eevee" + icon_state = "eevee" + +/datum/sprite_accessory/mam_body_markings/fennec + name = "Fennec" + icon_state = "Fennec" + +/datum/sprite_accessory/mam_body_markings/fox + name = "Fox" + icon_state = "fox" + +/datum/sprite_accessory/mam_body_markings/frog + name = "Frog" + icon_state = "frog" + icon = 'modular_citadel/icons/mob/markings_notmammals.dmi' + +/datum/sprite_accessory/mam_body_markings/goat + name = "Goat" + icon_state = "goat" + +/datum/sprite_accessory/mam_body_markings/handsfeet + name = "Handsfeet" + icon_state = "handsfeet" + icon = 'modular_citadel/icons/mob/markings_notmammals.dmi' + +/datum/sprite_accessory/mam_body_markings/hawk + name = "Hawk" + icon_state = "hawk" + +/datum/sprite_accessory/mam_body_markings/husky + name = "Husky" + icon_state = "husky" + +/datum/sprite_accessory/mam_body_markings/hyena + name = "Hyena" + icon_state = "hyena" + +/datum/sprite_accessory/mam_body_markings/lab + name = "Lab" + icon_state = "lab" + +/datum/sprite_accessory/mam_body_markings/insect + name = "Insect" + icon_state = "insect" + icon = 'modular_citadel/icons/mob/markings_notmammals.dmi' + +/datum/sprite_accessory/mam_body_markings/otie + name = "Otie" + icon_state = "otie" + +/datum/sprite_accessory/mam_body_markings/otter + name = "Otter" + icon_state = "otter" + +/datum/sprite_accessory/mam_body_markings/orca + name = "Orca" + icon_state = "orca" + +/datum/sprite_accessory/mam_body_markings/panther + name = "Panther" + icon_state = "panther" + +/datum/sprite_accessory/mam_body_markings/possum + name = "Possum" + icon_state = "possum" + +/datum/sprite_accessory/mam_body_markings/raccoon + name = "Raccoon" + icon_state = "raccoon" + +/datum/sprite_accessory/mam_body_markings/pede + name = "Scolipede" + icon_state = "scolipede" + icon = 'modular_citadel/icons/mob/markings_notmammals.dmi' + +/datum/sprite_accessory/mam_body_markings/shark + name = "Shark" + icon_state = "shark" + +/datum/sprite_accessory/mam_body_markings/skunk + name = "Skunk" + icon_state = "skunk" + +/datum/sprite_accessory/mam_body_markings/sergal + name = "Sergal" + icon_state = "sergal" + +/datum/sprite_accessory/mam_body_markings/shepherd + name = "Shepherd" + icon_state = "shepherd" + +/datum/sprite_accessory/mam_body_markings/tajaran + name = "Tajaran" + icon_state = "tajaran" + +/datum/sprite_accessory/mam_body_markings/tiger + name = "Tiger" + icon_state = "tiger" + +/datum/sprite_accessory/mam_body_markings/turian + name = "Turian" + icon_state = "turian" + icon = 'modular_citadel/icons/mob/markings_notmammals.dmi' + +/datum/sprite_accessory/mam_body_markings/wolf + name = "Wolf" + icon_state = "wolf" + +/datum/sprite_accessory/mam_body_markings/xeno + name = "Xeno" + icon_state = "xeno" + icon = 'modular_citadel/icons/mob/markings_notmammals.dmi' + +/****************************************** +************* Insect Markings ************* +*******************************************/ + +/datum/sprite_accessory/insect_fluff + icon = 'icons/mob/wings.dmi' + color_src = 0 + +/datum/sprite_accessory/insect_fluff/none + name = "None" + icon_state = "none" + +/datum/sprite_accessory/insect_fluff/plain + name = "Plain" + icon_state = "plain" + +/datum/sprite_accessory/insect_fluff/reddish + name = "Reddish" + icon_state = "redish" + +/datum/sprite_accessory/insect_fluff/royal + name = "Royal" + icon_state = "royal" + +/datum/sprite_accessory/insect_fluff/gothic + name = "Gothic" + icon_state = "gothic" + +/datum/sprite_accessory/insect_fluff/lovers + name = "Lovers" + icon_state = "lovers" + +/datum/sprite_accessory/insect_fluff/whitefly + name = "White Fly" + icon_state = "whitefly" + +/datum/sprite_accessory/insect_fluff/punished + name = "Burnt Off" + icon_state = "punished" + +/datum/sprite_accessory/insect_fluff/firewatch + name = "Firewatch" + icon_state = "firewatch" + +/datum/sprite_accessory/insect_fluff/deathhead + name = "Deathshead" + icon_state = "deathhead" + +/datum/sprite_accessory/insect_fluff/poison + name = "Poison" + icon_state = "poison" + +/datum/sprite_accessory/insect_fluff/ragged + name = "Ragged" + icon_state = "ragged" + +/datum/sprite_accessory/insect_fluff/moonfly + name = "Moon Fly" + icon_state = "moonfly" + +/datum/sprite_accessory/insect_fluff/snow + name = "Snow" + icon_state = "snow" + +/datum/sprite_accessory/insect_fluff/colored + name = "Colored (Hair)" + icon_state = "snow" + color_src = HAIR + +/datum/sprite_accessory/insect_fluff/colored1 + name = "Colored (Primary)" + icon_state = "snow" + color_src = MUTCOLORS + +/datum/sprite_accessory/insect_fluff/colored2 + name = "Colored (Secondary)" + icon_state = "snow" + color_src = MUTCOLORS2 + +/datum/sprite_accessory/insect_fluff/colored3 + name = "Colored (Tertiary)" + icon_state = "snow" + color_src = MUTCOLORS3 \ No newline at end of file diff --git a/code/modules/mob/dead/new_player/sprite_accessories/ears.dm b/code/modules/mob/dead/new_player/sprite_accessories/ears.dm index 163f8370a2..1496ca030a 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/ears.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/ears.dm @@ -5,8 +5,295 @@ name = "None" icon_state = "none" +/****************************************** +*************** Human Ears **************** +*******************************************/ + +/datum/sprite_accessory/ears/human/axolotl + name = "Axolotl" + icon_state = "axolotl" + icon = 'modular_citadel/icons/mob/mam_ears.dmi' + +/datum/sprite_accessory/ears/human/bear + name = "Bear" + icon_state = "bear" + icon = 'modular_citadel/icons/mob/mam_ears.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/ears/human/bigwolf + name = "Big Wolf" + icon_state = "bigwolf" + icon = 'modular_citadel/icons/mob/mam_ears.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/ears/human/bigwolfinner + name = "Big Wolf (ALT)" + icon_state = "bigwolfinner" + hasinner = 1 + icon = 'modular_citadel/icons/mob/mam_ears.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/ears/human/bigwolfdark + name = "Dark Big Wolf" + icon_state = "bigwolfdark" + icon = 'modular_citadel/icons/mob/mam_ears.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/ears/human/bigwolfinnerdark + name = "Dark Big Wolf (ALT)" + icon_state = "bigwolfinnerdark" + hasinner = 1 + icon = 'modular_citadel/icons/mob/mam_ears.dmi' + color_src = MATRIXED + /datum/sprite_accessory/ears/cat name = "Cat" icon_state = "cat" hasinner = 1 - color_src = HAIR \ No newline at end of file + color_src = HAIR + +/datum/sprite_accessory/ears/human/cow + name = "Cow" + icon_state = "cow" + icon = 'modular_citadel/icons/mob/mam_ears.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/ears/human/curled + name = "Curled Horn" + icon_state = "horn1" + icon = 'modular_citadel/icons/mob/mam_ears.dmi' + color_src = MUTCOLORS3 + +/datum/sprite_accessory/ears/human/eevee + name = "Eevee" + icon_state = "eevee" + icon = 'modular_citadel/icons/mob/mam_ears.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/ears/human/elephant + name = "Elephant" + icon_state = "elephant" + icon = 'modular_citadel/icons/mob/mam_ears.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/ears/human/elf + name = "Elf" + icon_state = "elf" + icon = 'modular_citadel/icons/mob/mam_ears.dmi' + color_src = SKINTONE + +/datum/sprite_accessory/ears/fennec + name = "Fennec" + icon_state = "fennec" + icon = 'modular_citadel/icons/mob/mam_ears.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/ears/fish + name = "Fish" + icon_state = "fish" + icon = 'modular_citadel/icons/mob/mam_ears.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/ears/fox + name = "Fox" + icon_state = "fox" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_ears.dmi' + +/datum/sprite_accessory/ears/human/jellyfish + name = "Jellyfish" + icon_state = "jellyfish" + color_src = HAIR + +/datum/sprite_accessory/ears/lab + name = "Dog, Floppy" + icon_state = "lab" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_ears.dmi' + +/datum/sprite_accessory/ears/murid + name = "Murid" + icon_state = "murid" + icon = 'modular_citadel/icons/mob/mam_ears.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/ears/human/otie + name = "Otusian" + icon_state = "otie" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_ears.dmi' + +/datum/sprite_accessory/ears/human/pede + name = "Scolipede" + icon_state = "pede" + icon = 'modular_citadel/icons/mob/mam_ears.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/ears/human/rabbit + name = "Rabbit" + icon_state = "rabbit" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_ears.dmi' + +/datum/sprite_accessory/ears/human/sergal + name = "Sergal" + icon_state = "sergal" + icon = 'modular_citadel/icons/mob/mam_ears.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/ears/human/skunk + name = "skunk" + icon_state = "skunk" + icon = 'modular_citadel/icons/mob/mam_ears.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/ears/squirrel + name = "Squirrel" + icon_state = "squirrel" + icon = 'modular_citadel/icons/mob/mam_ears.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/ears/wolf + name = "Wolf" + icon_state = "wolf" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_ears.dmi' + + +/****************************************** +*************** Furry Ears **************** +*******************************************/ + +/datum/sprite_accessory/mam_ears + icon = 'modular_citadel/icons/mob/mam_ears.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/mam_ears/none + name = "None" + icon_state = "none" + +/datum/sprite_accessory/mam_ears/axolotl + name = "Axolotl" + icon_state = "axolotl" + +/datum/sprite_accessory/mam_ears/bear + name = "Bear" + icon_state = "bear" + +/datum/sprite_accessory/mam_ears/bigwolf + name = "Big Wolf" + icon_state = "bigwolf" + +/datum/sprite_accessory/mam_ears/bigwolfinner + name = "Big Wolf (ALT)" + icon_state = "bigwolfinner" + hasinner = 1 + +/datum/sprite_accessory/mam_ears/bigwolfdark + name = "Dark Big Wolf" + icon_state = "bigwolfdark" + +/datum/sprite_accessory/mam_ears/bigwolfinnerdark + name = "Dark Big Wolf (ALT)" + icon_state = "bigwolfinnerdark" + hasinner = 1 + +/datum/sprite_accessory/mam_ears/cat + name = "Cat" + icon_state = "cat" + hasinner = 1 + color_src = HAIR + +/datum/sprite_accessory/mam_ears/catbig + name = "Cat, Big" + icon_state = "catbig" + +/datum/sprite_accessory/mam_ears/cow + name = "Cow" + icon_state = "cow" + +/datum/sprite_accessory/mam_ears/curled + name = "Curled Horn" + icon_state = "horn1" + color_src = MUTCOLORS3 + +/datum/sprite_accessory/mam_ears/deer + name = "Deer" + icon_state = "deer" + color_src = MUTCOLORS3 + +/datum/sprite_accessory/mam_ears/eevee + name = "Eevee" + icon_state = "eevee" + + +/datum/sprite_accessory/mam_ears/elf + name = "Elf" + icon_state = "elf" + color_src = MUTCOLORS3 + + +/datum/sprite_accessory/mam_ears/elephant + name = "Elephant" + icon_state = "elephant" + +/datum/sprite_accessory/mam_ears/fennec + name = "Fennec" + icon_state = "fennec" + +/datum/sprite_accessory/mam_ears/fish + name = "Fish" + icon_state = "fish" + +/datum/sprite_accessory/mam_ears/fox + name = "Fox" + icon_state = "fox" + +/datum/sprite_accessory/mam_ears/husky + name = "Husky" + icon_state = "wolf" + +/datum/sprite_accessory/mam_ears/kangaroo + name = "kangaroo" + icon_state = "kangaroo" + +/datum/sprite_accessory/mam_ears/jellyfish + name = "Jellyfish" + icon_state = "jellyfish" + color_src = HAIR + +/datum/sprite_accessory/mam_ears/lab + name = "Dog, Long" + icon_state = "lab" + +/datum/sprite_accessory/mam_ears/murid + name = "Murid" + icon_state = "murid" + +/datum/sprite_accessory/mam_ears/otie + name = "Otusian" + icon_state = "otie" + +/datum/sprite_accessory/mam_ears/squirrel + name = "Squirrel" + icon_state = "squirrel" + +/datum/sprite_accessory/mam_ears/pede + name = "Scolipede" + icon_state = "pede" + +/datum/sprite_accessory/mam_ears/rabbit + name = "Rabbit" + icon_state = "rabbit" + +/datum/sprite_accessory/mam_ears/sergal + name = "Sergal" + icon_state = "sergal" + +/datum/sprite_accessory/mam_ears/skunk + name = "skunk" + icon_state = "skunk" + +/datum/sprite_accessory/mam_ears/wolf + name = "Wolf" + icon_state = "wolf" diff --git a/code/modules/mob/dead/new_player/sprite_accessories/hair_face.dm b/code/modules/mob/dead/new_player/sprite_accessories/hair_face.dm index 3566f3dea5..d11299fd5b 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/hair_face.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/hair_face.dm @@ -86,4 +86,45 @@ /datum/sprite_accessory/facial_hair/elvis name = "Sideburns (Elvis)" - icon_state = "facial_elvis" \ No newline at end of file + icon_state = "facial_elvis" + +#define VFACE(_name, new_state) /datum/sprite_accessory/facial_hair/##new_state/icon_state=#new_state;;/datum/sprite_accessory/facial_hair/##new_state/name= #_name + " (Virgo)" +VFACE("Watson", facial_watson_s) +VFACE("Chaplin", facial_chaplin_s) +VFACE("Fullbeard", facial_fullbeard_s) +VFACE("Vandyke", facial_vandyke_s) +VFACE("Elvis", facial_elvis_s) +VFACE("Abe", facial_abe_s) +VFACE("Chin", facial_chin_s) +VFACE("GT", facial_gt_s) +VFACE("Hip", facial_hip_s) +VFACE("Hogan", facial_hogan_s) +VFACE("Selleck", facial_selleck_s) +VFACE("Neckbeard", facial_neckbeard_s) +VFACE("Longbeard", facial_longbeard_s) +VFACE("Dwarf", facial_dwarf_s) +VFACE("Sideburn", facial_sideburn_s) +VFACE("Mutton", facial_mutton_s) +VFACE("Moustache", facial_moustache_s) +VFACE("Pencilstache", facial_pencilstache_s) +VFACE("Goatee", facial_goatee_s) +VFACE("Smallstache", facial_smallstache_s) +VFACE("Volaju", facial_volaju_s) +VFACE("3 O\'clock", facial_3oclock_s) +VFACE("5 O\'clock", facial_5oclock_s) +VFACE("7 O\'clock", facial_7oclock_s) +VFACE("5 O\'clock Moustache", facial_5oclockmoustache_s) +VFACE("7 O\'clock", facial_7oclockmoustache_s) +VFACE("Walrus", facial_walrus_s) +VFACE("Muttonmus", facial_muttonmus_s) +VFACE("Wise", facial_wise_s) +VFACE("Martial Artist", facial_martialartist_s) +VFACE("Dorsalfnil", facial_dorsalfnil_s) +VFACE("Hornadorns", facial_hornadorns_s) +VFACE("Spike", facial_spike_s) +VFACE("Chinhorns", facial_chinhorns_s) +VFACE("Cropped Fullbeard", facial_croppedfullbeard_s) +VFACE("Chinless Beard", facial_chinlessbeard_s) +VFACE("Moonshiner", facial_moonshiner_s) +VFACE("Tribearder", facial_tribearder_s) +#undef VFACE \ No newline at end of file diff --git a/code/modules/mob/dead/new_player/sprite_accessories/hair_head.dm b/code/modules/mob/dead/new_player/sprite_accessories/hair_head.dm index f8d8d26328..abcc90c0ee 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/hair_head.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/hair_head.dm @@ -461,4 +461,163 @@ /datum/sprite_accessory/hair/longestalt name = "Very Long with Fringe" - icon_state = "hair_vlongfringe" \ No newline at end of file + icon_state = "hair_vlongfringe" + +/*************** VIRGO PORTED HAIRS ****************************/ +#define VHAIR(_name, new_state) /datum/sprite_accessory/hair/##new_state/icon_state=#new_state;/datum/sprite_accessory/hair/##new_state/name = #_name + " (Virgo)" +//VIRGO PORTED HAIRS +VHAIR("Short Hair Rosa", hair_rosa_s) +VHAIR("Short Hair 80s", hair_80s_s) +VHAIR("Long Bedhead", hair_long_bedhead_s) +VHAIR("Dave", hair_dave_s) +VHAIR("Country", hair_country_s) +VHAIR("Shy", hair_shy_s) +VHAIR("Unshaven Mohawk", hair_unshaven_mohawk_s) +VHAIR("Manbun", hair_manbun_s) +VHAIR("Longer Bedhead", hair_longer_bedhead_s) +VHAIR("Ponytail", hair_ponytail_s) +VHAIR("Ziegler", hair_ziegler_s) +VHAIR("Emo Fringe", hair_emofringe_s) +VHAIR("Very Short Over Eye Alt", hair_veryshortovereyealternate_s) +VHAIR("Shorthime", hair_shorthime_s) +VHAIR("High Tight", hair_hightight_s) +VHAIR("Thinning Front", hair_thinningfront_s) +VHAIR("Big Afro", hair_bigafro_s) +VHAIR("Afro", hair_afro_s) +VHAIR("High Braid", hair_hbraid_s) +VHAIR("Braid", hair_braid_s) +VHAIR("Sargeant", hair_sargeant_s) +VHAIR("Gelled", hair_gelled_s) +VHAIR("Kagami", hair_kagami_s) +VHAIR("ShortTail", hair_stail_s) +VHAIR("Gentle", hair_gentle_s) +VHAIR("Grande", hair_grande_s) +VHAIR("Bobcurl", hair_bobcurl_s) +VHAIR("Pompadeur", hair_pompadour_s) +VHAIR("Plait", hair_plait_s) +VHAIR("Long", hair_long_s) +VHAIR("Rattail", hair_rattail_s) +VHAIR("Tajspiky", hair_tajspiky_s) +VHAIR("Messy", hair_messy_s) +VHAIR("Bangs", hair_bangs_s) +VHAIR("TBraid", hair_tbraid_s) +VHAIR("Toriyama2", hair_toriyama2_s) +VHAIR("CIA", hair_cia_s) +VHAIR("Mulder", hair_mulder_s) +VHAIR("Scully", hair_scully_s) +VHAIR("Nitori", hair_nitori_s) +VHAIR("Joestar", hair_joestar_s) +VHAIR("Ponytail4", hair_ponytail4_s) +VHAIR("Ponytail5", hair_ponytail5_s) +VHAIR("Beehive2", hair_beehive2_s) +VHAIR("Short Braid", hair_shortbraid_s) +VHAIR("Reverse Mohawk", hair_reversemohawk_s) +VHAIR("SHort Bangs", hair_shortbangs_s) +VHAIR("Half Shaved", hair_halfshaved_s) +VHAIR("Longer Alt 2", hair_longeralt2_s) +VHAIR("Bun", hair_bun_s) +VHAIR("Curly", hair_curly_s) +VHAIR("Victory", hair_victory_s) +VHAIR("Ponytail6", hair_ponytail6_s) +VHAIR("Undercut3", hair_undercut3_s) +VHAIR("Bobcut Alt", hair_bobcultalt_s) +VHAIR("Fingerwave", hair_fingerwave_s) +VHAIR("Oxton", hair_oxton_s) +VHAIR("Poofy2", hair_poofy2_s) +VHAIR("Fringe Tail", hair_fringetail_s) +VHAIR("Bun3", hair_bun3_s) +VHAIR("Wisp", hair_wisp_s) +VHAIR("Undercut2", hair_undercut2_s) +VHAIR("TBob", hair_tbob_s) +VHAIR("Spiky Ponytail", hair_spikyponytail_s) +VHAIR("Rowbun", hair_rowbun_s) +VHAIR("Rowdualtail", hair_rowdualtail_s) +VHAIR("Rowbraid", hair_rowbraid_s) +VHAIR("Shaved Mohawk", hair_shavedmohawk_s) +VHAIR("Topknot", hair_topknot_s) +VHAIR("Ronin", hair_ronin_s) +VHAIR("Bowlcut2", hair_bowlcut2_s) +VHAIR("Thinning Rear", hair_thinningrear_s) +VHAIR("Thinning", hair_thinning_s) +VHAIR("Jade", hair_jade_s) +VHAIR("Bedhead", hair_bedhead_s) +VHAIR("Dreadlocks", hair_dreads_s) +VHAIR("Very Long", hair_vlong_s) +VHAIR("Jensen", hair_jensen_s) +VHAIR("Halfbang", hair_halfbang_s) +VHAIR("Kusangi", hair_kusangi_s) +VHAIR("Ponytail", hair_ponytail_s) +VHAIR("Ponytail3", hair_ponytail3_s) +VHAIR("Halfbang Alt", hair_halfbang_alt_s) +VHAIR("Bedhead V2", hair_bedheadv2_s) +VHAIR("Long Fringe", hair_longfringe_s) +VHAIR("Flair", hair_flair_s) +VHAIR("Bedhead V3", hair_bedheadv3_s) +VHAIR("Himecut", hair_himecut_s) +VHAIR("Curls", hair_curls_s) +VHAIR("Very Long Fringe", hair_vlongfringe_s) +VHAIR("Longest", hair_longest_s) +VHAIR("Father", hair_father_s) +VHAIR("Emo Long", hair_emolong_s) +VHAIR("Short Hair 3", hair_shorthair3_s) +VHAIR("Double Bun", hair_doublebun_s) +VHAIR("Sleeze", hair_sleeze_s) +VHAIR("Twintail", hair_twintail_s) +VHAIR("Emo 2", hair_emo2_s) +VHAIR("Low Fade", hair_lowfade_s) +VHAIR("Med Fade", hair_medfade_s) +VHAIR("High Fade", hair_highfade_s) +VHAIR("Bald Fade", hair_baldfade_s) +VHAIR("No Fade", hair_nofade_s) +VHAIR("Trim Flat", hair_trimflat_s) +VHAIR("Shaved", hair_shaved_s) +VHAIR("Trimmed", hair_trimmed_s) +VHAIR("Tight Bun", hair_tightbun_s) +VHAIR("Short Hair 4", hair_d_s) +VHAIR("Short Hair 5", hair_e_s) +VHAIR("Short Hair 6", hair_f_s) +VHAIR("Skinhead", hair_skinhead_s) +VHAIR("Afro2", hair_afro2_s) +VHAIR("Bobcut", hair_bobcut_s) +VHAIR("Emo", hair_emo_s) +VHAIR("Long Over Eye", hair_longovereye_s) +VHAIR("Feather", hair_feather_s) +VHAIR("Hitop", hair_hitop_s) +VHAIR("Short Over Eye", hair_shortoverye_s) +VHAIR("Straight", hair_straight_s) +VHAIR("Buzzcut", hair_buzzcut_s) +VHAIR("Combover", hair_combover_s) +VHAIR("Crewcut", hair_crewcut_s) +VHAIR("Devillock", hair_devilock_s) +VHAIR("Clean", hair_clean_s) +VHAIR("Shaggy", hair_shaggy_s) +VHAIR("Updo", hair_updo_s) +VHAIR("Mohawk", hair_mohawk_s) +VHAIR("Odango", hair_odango_s) +VHAIR("Ombre", hair_ombre_s) +VHAIR("Parted", hair_parted_s) +VHAIR("Quiff", hair_quiff_s) +VHAIR("Volaju", hair_volaju_s) +VHAIR("Bun2", hair_bun2_s) +VHAIR("Rows1", hair_rows1_s) +VHAIR("Rows2", hair_rows2_s) +VHAIR("Dandy Pompadour", hair_dandypompadour_s) +VHAIR("Poofy", hair_poofy_s) +VHAIR("Toriyama", hair_toriyama_s) +VHAIR("Drillruru", hair_drillruru_s) +VHAIR("Bowlcut", hair_bowlcut_s) +VHAIR("Coffee House", hair_coffeehouse_s) +VHAIR("Family Man", hair_thefamilyman_s) +VHAIR("Shaved Part", hair_shavedpart_s) +VHAIR("Modern", hair_modern_s) +VHAIR("One Shoulder", hair_oneshoulder_s) +VHAIR("Very Short Over Eye", hair_veryshortovereye_s) +VHAIR("Unkept", hair_unkept_s) +VHAIR("Wife", hair_wife_s) +VHAIR("Nia", hair_nia_s) +VHAIR("Undercut", hair_undercut_s) +VHAIR("Bobcut Alt", hair_bobcutalt_s) +VHAIR("Short Hair 4 alt", hair_shorthair4_s) +VHAIR("Tressshoulder", hair_tressshoulder_s) + //END +#undef VHAIR \ No newline at end of file diff --git a/code/modules/mob/dead/new_player/sprite_accessories/horns.dm b/code/modules/mob/dead/new_player/sprite_accessories/horns.dm index 607ad650e3..a630ead7b3 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/horns.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/horns.dm @@ -1,5 +1,6 @@ /datum/sprite_accessory/horns icon = 'icons/mob/mutant_bodyparts.dmi' + color_src = HORNCOLOR /datum/sprite_accessory/horns/none name = "None" @@ -23,4 +24,13 @@ /datum/sprite_accessory/horns/angler name = "Angeler" - icon_state = "angler" \ No newline at end of file + icon_state = "angler" + color_src = MUTCOLORS + +/datum/sprite_accessory/horns/antler + name = "Deer Antlers" + icon_state = "deer" + +/datum/sprite_accessory/horns/guilmon + name = "Guilmon" + icon_state = "guilmon" \ No newline at end of file diff --git a/code/modules/mob/dead/new_player/sprite_accessories/ipc_synths.dm b/code/modules/mob/dead/new_player/sprite_accessories/ipc_synths.dm new file mode 100644 index 0000000000..6d2ab1a39b --- /dev/null +++ b/code/modules/mob/dead/new_player/sprite_accessories/ipc_synths.dm @@ -0,0 +1,158 @@ + +/****************************************** +************** IPC SCREENS **************** +*******************************************/ +/datum/sprite_accessory/screen + icon = 'modular_citadel/icons/mob/ipc_screens.dmi' + color_src = null + +/datum/sprite_accessory/screen/blank + name = "Blank" + icon_state = "blank" + +/datum/sprite_accessory/screen/pink + name = "Pink" + icon_state = "pink" + +/datum/sprite_accessory/screen/green + name = "Green" + icon_state = "green" + +/datum/sprite_accessory/screen/red + name = "Red" + icon_state = "red" + +/datum/sprite_accessory/screen/blue + name = "Blue" + icon_state = "blue" + +/datum/sprite_accessory/screen/yellow + name = "Yellow" + icon_state = "yellow" + +/datum/sprite_accessory/screen/shower + name = "Shower" + icon_state = "shower" + +/datum/sprite_accessory/screen/nature + name = "Nature" + icon_state = "nature" + +/datum/sprite_accessory/screen/eight + name = "Eight" + icon_state = "eight" + +/datum/sprite_accessory/screen/goggles + name = "Goggles" + icon_state = "goggles" + +/datum/sprite_accessory/screen/heart + name = "Heart" + icon_state = "heart" + +/datum/sprite_accessory/screen/monoeye + name = "Mono eye" + icon_state = "monoeye" + +/datum/sprite_accessory/screen/breakout + name = "Breakout" + icon_state = "breakout" + +/datum/sprite_accessory/screen/purple + name = "Purple" + icon_state = "purple" + +/datum/sprite_accessory/screen/scroll + name = "Scroll" + icon_state = "scroll" + +/datum/sprite_accessory/screen/console + name = "Console" + icon_state = "console" + +/datum/sprite_accessory/screen/rgb + name = "RGB" + icon_state = "rgb" + +/datum/sprite_accessory/screen/golglider + name = "Gol Glider" + icon_state = "golglider" + +/datum/sprite_accessory/screen/rainbow + name = "Rainbow" + icon_state = "rainbow" + +/datum/sprite_accessory/screen/sunburst + name = "Sunburst" + icon_state = "sunburst" + +/datum/sprite_accessory/screen/static + name = "Static" + icon_state = "static" + +//Oracle Station sprites + +/datum/sprite_accessory/screen/bsod + name = "BSOD" + icon_state = "bsod" + +/datum/sprite_accessory/screen/redtext + name = "Red Text" + icon_state = "retext" + +/datum/sprite_accessory/screen/sinewave + name = "Sine wave" + icon_state = "sinewave" + +/datum/sprite_accessory/screen/squarewave + name = "Square wave" + icon_state = "squarwave" + +/datum/sprite_accessory/screen/ecgwave + name = "ECG wave" + icon_state = "ecgwave" + +/datum/sprite_accessory/screen/eyes + name = "Eyes" + icon_state = "eyes" + +/datum/sprite_accessory/screen/textdrop + name = "Text drop" + icon_state = "textdrop" + +/datum/sprite_accessory/screen/stars + name = "Stars" + icon_state = "stars" + + +/****************************************** +************** IPC Antennas *************** +*******************************************/ + +/datum/sprite_accessory/antenna + icon = 'modular_citadel/icons/mob/ipc_antennas.dmi' + color_src = MUTCOLORS2 + +/datum/sprite_accessory/antenna/none + name = "None" + icon_state = "None" + +/datum/sprite_accessory/antenna/antennae + name = "Angled Antennae" + icon_state = "antennae" + +/datum/sprite_accessory/antenna/tvantennae + name = "TV Antennae" + icon_state = "tvantennae" + +/datum/sprite_accessory/antenna/cyberhead + name = "Cyberhead" + icon_state = "cyberhead" + +/datum/sprite_accessory/antenna/antlers + name = "Antlers" + icon_state = "antlers" + +/datum/sprite_accessory/antenna/crowned + name = "Crowned" + icon_state = "crowned" diff --git a/code/modules/mob/dead/new_player/sprite_accessories/legs.dm b/code/modules/mob/dead/new_player/sprite_accessories/legs.dm deleted file mode 100644 index 7663100822..0000000000 --- a/code/modules/mob/dead/new_player/sprite_accessories/legs.dm +++ /dev/null @@ -1,8 +0,0 @@ -/datum/sprite_accessory/legs //legs are a special case, they aren't actually sprite_accessories but are updated with them. - icon = null //These datums exist for selecting legs on preference, and little else - -/datum/sprite_accessory/legs/none - name = "Normal Legs" - -/datum/sprite_accessory/legs/digitigrade_lizard - name = "Digitigrade Legs" \ No newline at end of file diff --git a/code/modules/mob/dead/new_player/sprite_accessories/legs_and_taurs.dm b/code/modules/mob/dead/new_player/sprite_accessories/legs_and_taurs.dm new file mode 100644 index 0000000000..15640a2699 --- /dev/null +++ b/code/modules/mob/dead/new_player/sprite_accessories/legs_and_taurs.dm @@ -0,0 +1,124 @@ +/datum/sprite_accessory/legs //legs are a special case, they aren't actually sprite_accessories but are updated with them. -- OR SO THEY USED TO BE + icon = null //These datums exist for selecting legs on preference, and little else + +/****************************************** +***************** Leggy ******************* +*******************************************/ + +/datum/sprite_accessory/legs/none + name = "Plantigrade" + +/datum/sprite_accessory/legs/digitigrade_lizard + name = "Digitigrade" + +/datum/sprite_accessory/legs/digitigrade_bird + name = "Avian" + + +/****************************************** +************** Taur Bodies **************** +*******************************************/ + +/datum/sprite_accessory/taur + icon = 'modular_citadel/icons/mob/mam_taur.dmi' + extra_icon = 'modular_citadel/icons/mob/mam_taur.dmi' + extra = TRUE + extra2_icon = 'modular_citadel/icons/mob/mam_taur.dmi' + extra2 = TRUE + center = TRUE + dimension_x = 64 + var/taur_mode = NOT_TAURIC + color_src = MATRIXED + +/datum/sprite_accessory/taur/none + name = "None" + icon_state = "None" + +/datum/sprite_accessory/taur/cow + name = "Cow" + icon_state = "cow" + taur_mode = HOOF_TAURIC + +/datum/sprite_accessory/taur/deer + name = "Deer" + icon_state = "deer" + taur_mode = HOOF_TAURIC + color_src = MUTCOLORS + +/datum/sprite_accessory/taur/drake + name = "Drake" + icon_state = "drake" + taur_mode = PAW_TAURIC + +/datum/sprite_accessory/taur/drider + name = "Drider" + icon_state = "drider" + color_src = MUTCOLORS + +/datum/sprite_accessory/taur/eevee + name = "Eevee" + icon_state = "eevee" + taur_mode = PAW_TAURIC + color_src = MUTCOLORS + +/datum/sprite_accessory/taur/fox + name = "Fox" + icon_state = "fox" + taur_mode = PAW_TAURIC + +/datum/sprite_accessory/taur/husky + name = "Husky" + icon_state = "husky" + taur_mode = PAW_TAURIC + +/datum/sprite_accessory/taur/horse + name = "Horse" + icon_state = "horse" + taur_mode = HOOF_TAURIC + +/datum/sprite_accessory/taur/lab + name = "Lab" + icon_state = "lab" + taur_mode = PAW_TAURIC + +/datum/sprite_accessory/taur/naga + name = "Naga" + icon_state = "naga" + taur_mode = SNEK_TAURIC + +/datum/sprite_accessory/taur/otie + name = "Otie" + icon_state = "otie" + taur_mode = PAW_TAURIC + +/datum/sprite_accessory/taur/pede + name = "Scolipede" + icon_state = "pede" + taur_mode = PAW_TAURIC + color_src = MUTCOLORS + +/datum/sprite_accessory/taur/panther + name = "Panther" + icon_state = "panther" + taur_mode = PAW_TAURIC + +/datum/sprite_accessory/taur/shepherd + name = "Shepherd" + icon_state = "shepherd" + taur_mode = PAW_TAURIC + +/datum/sprite_accessory/taur/tentacle + name = "Tentacle" + icon_state = "tentacle" + taur_mode = SNEK_TAURIC + color_src = MUTCOLORS + +/datum/sprite_accessory/taur/tiger + name = "Tiger" + icon_state = "tiger" + taur_mode = PAW_TAURIC + +/datum/sprite_accessory/taur/wolf + name = "Wolf" + icon_state = "wolf" + taur_mode = PAW_TAURIC diff --git a/code/modules/mob/dead/new_player/sprite_accessories/moth_wings.dm b/code/modules/mob/dead/new_player/sprite_accessories/moth_wings.dm deleted file mode 100644 index 6b8036bd69..0000000000 --- a/code/modules/mob/dead/new_player/sprite_accessories/moth_wings.dm +++ /dev/null @@ -1,68 +0,0 @@ -/datum/sprite_accessory/moth_wings - icon = 'icons/mob/wings.dmi' - color_src = null - -/datum/sprite_accessory/moth_wings/plain - name = "Plain" - icon_state = "plain" - -/datum/sprite_accessory/moth_wings/monarch - name = "Monarch" - icon_state = "monarch" - -/datum/sprite_accessory/moth_wings/luna - name = "Luna" - icon_state = "luna" - -/datum/sprite_accessory/moth_wings/atlas - name = "Atlas" - icon_state = "atlas" - -/datum/sprite_accessory/moth_wings/reddish - name = "Reddish" - icon_state = "redish" - -/datum/sprite_accessory/moth_wings/royal - name = "Royal" - icon_state = "royal" - -/datum/sprite_accessory/moth_wings/gothic - name = "Gothic" - icon_state = "gothic" - -/datum/sprite_accessory/moth_wings/lovers - name = "Lovers" - icon_state = "lovers" - -/datum/sprite_accessory/moth_wings/whitefly - name = "White Fly" - icon_state = "whitefly" - -/datum/sprite_accessory/moth_wings/punished - name = "Burnt Off" - icon_state = "punished" - locked = TRUE - -/datum/sprite_accessory/moth_wings/firewatch - name = "Firewatch" - icon_state = "firewatch" - -/datum/sprite_accessory/moth_wings/deathhead - name = "Deathshead" - icon_state = "deathhead" - -/datum/sprite_accessory/moth_wings/poison - name = "Poison" - icon_state = "poison" - -/datum/sprite_accessory/moth_wings/ragged - name = "Ragged" - icon_state = "ragged" - -/datum/sprite_accessory/moth_wings/moonfly - name = "Moon Fly" - icon_state = "moonfly" - -/datum/sprite_accessory/moth_wings/snow - name = "Snow" - icon_state = "snow" diff --git a/code/modules/mob/dead/new_player/sprite_accessories/snouts.dm b/code/modules/mob/dead/new_player/sprite_accessories/snouts.dm index c663c08d69..7252f85324 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/snouts.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/snouts.dm @@ -15,4 +15,359 @@ /datum/sprite_accessory/snouts/roundlight name = "Round + Light" - icon_state = "roundlight" \ No newline at end of file + icon_state = "roundlight" + +/datum/sprite_accessory/snout/guilmon + name = "Guilmon" + icon_state = "guilmon" + color_src = MATRIXED + +//christ this was a mistake, but it's here just in case someone wants to selectively fix -- Pooj +/************* Lizard compatable snoots *********** +/datum/sprite_accessory/snouts/bird + name = "Beak" + icon_state = "bird" + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/snouts/bigbeak + name = "Big Beak" + icon_state = "bigbeak" + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/snouts/bug + name = "Bug" + icon_state = "bug" + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + extra2 = TRUE + extra2_color_src = MUTCOLORS3 + +/datum/sprite_accessory/snouts/elephant + name = "Elephant" + icon_state = "elephant" + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + color_src = MATRIXED + extra = TRUE + extra_color_src = MUTCOLORS3 + +/datum/sprite_accessory/snouts/lcanid + name = "Mammal, Long" + icon_state = "lcanid" + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/snouts/lcanidalt + name = "Mammal, Long ALT" + icon_state = "lcanidalt" + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/snouts/scanid + name = "Mammal, Short" + icon_state = "scanid" + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/snouts/scanidalt + name = "Mammal, Short ALT" + icon_state = "scanidalt" + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/snouts/wolf + name = "Mammal, Thick" + icon_state = "wolf" + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/snouts/wolfalt + name = "Mammal, Thick ALT" + icon_state = "wolfalt" + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/snouts/redpanda + name = "WahCoon" + icon_state = "wah" + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/snouts/rhino + name = "Horn" + icon_state = "rhino" + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + color_src = MATRIXED + extra = TRUE + extra = MUTCOLORS3 + +/datum/sprite_accessory/snouts/rodent + name = "Rodent" + icon_state = "rodent" + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/snouts/husky + name = "Husky" + icon_state = "husky" + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/snouts/otie + name = "Otie" + icon_state = "otie" + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/snouts/pede + name = "Scolipede" + icon_state = "pede" + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/snouts/sergal + name = "Sergal" + icon_state = "sergal" + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/snouts/shark + name = "Shark" + icon_state = "shark" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + +/datum/sprite_accessory/snouts/toucan + name = "Toucan" + icon_state = "toucan" + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + color_src = MATRIXED +*/ + +/****************************************** +************** Mammal Snouts ************** +*******************************************/ + +/datum/sprite_accessory/mam_snouts + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + +/datum/sprite_accessory/mam_snouts/none + name = "None" + icon_state = "none" + + +/datum/sprite_accessory/mam_snouts/bird + name = "Beak" + icon_state = "bird" + +/datum/sprite_accessory/mam_snouts/bigbeak + name = "Big Beak" + icon_state = "bigbeak" + +/datum/sprite_accessory/mam_snouts/bug + name = "Bug" + icon_state = "bug" + color_src = MUTCOLORS + extra2 = TRUE + extra2_color_src = MUTCOLORS3 + +/datum/sprite_accessory/mam_snouts/elephant + name = "Elephant" + icon_state = "elephant" + extra = TRUE + extra_color_src = MUTCOLORS3 + +/datum/sprite_accessory/mam_snouts/lcanid + name = "Mammal, Long" + icon_state = "lcanid" + +/datum/sprite_accessory/mam_snouts/lcanidalt + name = "Mammal, Long ALT" + icon_state = "lcanidalt" + +/datum/sprite_accessory/mam_snouts/scanid + name = "Mammal, Short" + icon_state = "scanid" + +/datum/sprite_accessory/mam_snouts/scanidalt + name = "Mammal, Short ALT" + icon_state = "scanidalt" + +/datum/sprite_accessory/mam_snouts/wolf + name = "Mammal, Thick" + icon_state = "wolf" + +/datum/sprite_accessory/mam_snouts/wolfalt + name = "Mammal, Thick ALT" + icon_state = "wolfalt" + +/datum/sprite_accessory/mam_snouts/redpanda + name = "WahCoon" + icon_state = "wah" + +/datum/sprite_accessory/mam_snouts/redpandaalt + name = "WahCoon ALT" + icon_state = "wahalt" + +/datum/sprite_accessory/mam_snouts/rhino + name = "Horn" + icon_state = "rhino" + extra = TRUE + extra = MUTCOLORS3 + +/datum/sprite_accessory/mam_snouts/rodent + name = "Rodent" + icon_state = "rodent" + +/datum/sprite_accessory/mam_snouts/husky + name = "Husky" + icon_state = "husky" + +/datum/sprite_accessory/mam_snouts/otie + name = "Otie" + icon_state = "otie" + +/datum/sprite_accessory/mam_snouts/pede + name = "Scolipede" + icon_state = "pede" + +/datum/sprite_accessory/mam_snouts/sergal + name = "Sergal" + icon_state = "sergal" + +/datum/sprite_accessory/mam_snouts/shark + name = "Shark" + icon_state = "shark" + +/datum/sprite_accessory/mam_snouts/toucan + name = "Toucan" + icon_state = "toucan" + +/datum/sprite_accessory/mam_snouts/sharp + name = "Sharp" + icon_state = "sharp" + color_src = MUTCOLORS + +/datum/sprite_accessory/mam_snouts/round + name = "Round" + icon_state = "round" + color_src = MUTCOLORS + +/datum/sprite_accessory/mam_snouts/sharplight + name = "Sharp + Light" + icon_state = "sharplight" + color_src = MUTCOLORS + +/datum/sprite_accessory/mam_snouts/roundlight + name = "Round + Light" + icon_state = "roundlight" + color_src = MUTCOLORS + + +/****************************************** +**************** Snouts ******************* +*************but higher up*****************/ + +/datum/sprite_accessory/mam_snouts/fbird + name = "Beak (Top)" + icon_state = "fbird" + +/datum/sprite_accessory/mam_snouts/fbigbeak + name = "Big Beak (Top)" + icon_state = "fbigbeak" + +/datum/sprite_accessory/mam_snouts/fbug + name = "Bug (Top)" + icon_state = "fbug" + color_src = MUTCOLORS + extra2 = TRUE + extra2_color_src = MUTCOLORS3 + +/datum/sprite_accessory/mam_snouts/felephant + name = "Elephant (Top)" + icon_state = "felephant" + extra = TRUE + extra_color_src = MUTCOLORS3 + +/datum/sprite_accessory/mam_snouts/flcanid + name = "Mammal, Long (Top)" + icon_state = "flcanid" + +/datum/sprite_accessory/mam_snouts/flcanidalt + name = "Mammal, Long ALT (Top)" + icon_state = "flcanidalt" + +/datum/sprite_accessory/mam_snouts/fscanid + name = "Mammal, Short (Top)" + icon_state = "fscanid" + +/datum/sprite_accessory/mam_snouts/fscanidalt + name = "Mammal, Short ALT (Top)" + icon_state = "fscanidalt" + +/datum/sprite_accessory/mam_snouts/fwolf + name = "Mammal, Thick (Top)" + icon_state = "fwolf" + +/datum/sprite_accessory/mam_snouts/fwolfalt + name = "Mammal, Thick ALT (Top)" + icon_state = "fwolfalt" + +/datum/sprite_accessory/mam_snouts/fredpanda + name = "WahCoon (Top)" + icon_state = "fwah" + +/datum/sprite_accessory/mam_snouts/frhino + name = "Horn (Top)" + icon_state = "frhino" + extra = TRUE + extra = MUTCOLORS3 + +/datum/sprite_accessory/mam_snouts/frodent + name = "Rodent (Top)" + icon_state = "frodent" + +/datum/sprite_accessory/mam_snouts/fhusky + name = "Husky (Top)" + icon_state = "fhusky" + +/datum/sprite_accessory/mam_snouts/fotie + name = "Otie (Top)" + icon_state = "fotie" + +/datum/sprite_accessory/mam_snouts/fpede + name = "Scolipede (Top)" + icon_state = "fpede" + +/datum/sprite_accessory/mam_snouts/fsergal + name = "Sergal (Top)" + icon_state = "fsergal" + +/datum/sprite_accessory/mam_snouts/fshark + name = "Shark (Top)" + icon_state = "fshark" + +/datum/sprite_accessory/mam_snouts/ftoucan + name = "Toucan (Top)" + icon_state = "ftoucan" + +/datum/sprite_accessory/mam_snouts/fsharp + name = "Sharp (Top)" + icon_state = "fsharp" + color_src = MUTCOLORS + +/datum/sprite_accessory/mam_snouts/fround + name = "Round (Top)" + icon_state = "fround" + color_src = MUTCOLORS + +/datum/sprite_accessory/mam_snouts/fsharplight + name = "Sharp + Light (Top)" + icon_state = "fsharplight" + color_src = MUTCOLORS + +/datum/sprite_accessory/mam_snouts/froundlight + name = "Round + Light (Top)" + icon_state = "froundlight" + color_src = MUTCOLORS \ No newline at end of file diff --git a/code/modules/mob/dead/new_player/sprite_accessories/tails.dm b/code/modules/mob/dead/new_player/sprite_accessories/tails.dm index 31faabf663..3975f7bafc 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/tails.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/tails.dm @@ -4,6 +4,10 @@ /datum/sprite_accessory/tails_animated icon = 'icons/mob/mutant_bodyparts.dmi' +/****************************************** +************* Lizard Tails **************** +*******************************************/ + /datum/sprite_accessory/tails/lizard/smooth name = "Smooth" icon_state = "smooth" @@ -36,6 +40,48 @@ name = "Spikes" icon_state = "spikes" +/datum/sprite_accessory/tails/lizard/none + name = "None" + icon_state = "None" + +/datum/sprite_accessory/tails_animated/lizard/none + name = "None" + icon_state = "None" + +/datum/sprite_accessory/tails/lizard/axolotl + name = "Axolotl" + icon_state = "axolotl" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/datum/sprite_accessory/tails_animated/lizard/axolotl + name = "Axolotl" + icon_state = "axolotl" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/datum/sprite_accessory/body_markings/guilmon + name = "Guilmon" + icon_state = "guilmon" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/markings_notmammals.dmi' + +/datum/sprite_accessory/tails/lizard/guilmon + name = "Guilmon" + icon_state = "guilmon" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/datum/sprite_accessory/tails_animated/lizard/guilmon + name = "Guilmon" + icon_state = "guilmon" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/****************************************** +************** Human Tails **************** +*******************************************/ + /datum/sprite_accessory/tails/human/none name = "None" icon_state = "none" @@ -43,13 +89,626 @@ /datum/sprite_accessory/tails_animated/human/none name = "None" icon_state = "none" -/* + +/datum/sprite_accessory/tails/human/ailurus + name = "Red Panda" + icon_state = "wah" + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/tails_animated/human/ailurus + name = "Red Panda" + icon_state = "wah" + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/tails/human/axolotl + name = "Axolotl" + icon_state = "axolotl" + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/tails_animated/human/axolotl + name = "Axolotl" + icon_state = "axolotl" + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/tails/human/bee + name = "Bee" + icon_state = "bee" + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/tails_animated/human/bee + name = "Bee" + icon_state = "bee" + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + color_src = MATRIXED + /datum/sprite_accessory/tails/human/cat name = "Cat" icon_state = "cat" + icon = 'modular_citadel/icons/mob/mam_tails.dmi' color_src = HAIR /datum/sprite_accessory/tails_animated/human/cat name = "Cat" icon_state = "cat" - color_src = HAIR*/ \ No newline at end of file + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + color_src = HAIR + +/datum/sprite_accessory/tails/human/catbig + name = "Cat, Big" + icon_state = "catbig" + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/tails_animated/human/catbig + name = "Cat, Big" + icon_state = "catbig" + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/tails/human/cow + name = "Cow" + icon_state = "cow" + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/tails_animated/human/cow + name = "Cow" + icon_state = "cow" + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/tails/human/corvid + name = "Corvid" + icon_state = "crow" + +/datum/sprite_accessory/tails_animated/human/corvid + name = "Corvid" + icon_state = "crow" + +/datum/sprite_accessory/tails/human/eevee + name = "Eevee" + icon_state = "eevee" + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/tails_animated/human/eevee + name = "Eevee" + icon_state = "eevee" + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/tails/human/fennec + name = "Fennec" + icon_state = "fennec" + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/tails_animated/human/fennec + name = "Fennec" + icon_state = "fennec" + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/tails/human/fish + name = "Fish" + icon_state = "fish" + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/tails_animated/human/fish + name = "Fish" + icon_state = "fish" + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/tails/human/fox + name = "Fox" + icon_state = "fox" + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/tails_animated/human/fox + name = "Fox" + icon_state = "fox" + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/tails/human/horse + name = "Horse" + icon_state = "horse" + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + color_src = HAIR + +/datum/sprite_accessory/tails_animated/human/horse + name = "Horse" + icon_state = "horse" + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + color_src = HAIR + +/datum/sprite_accessory/tails/human/husky + name = "Husky" + icon_state = "husky" + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/tails_animated/human/husky + name = "Husky" + icon_state = "husky" + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/tails/human/insect + name = "Insect" + icon_state = "insect" + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/tails_animated/human/insect + name = "insect" + icon_state = "insect" + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/tails/human/kitsune + name = "Kitsune" + icon_state = "kitsune" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/datum/sprite_accessory/tails_animated/human/kitsune + name = "Kitsune" + icon_state = "kitsune" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/datum/sprite_accessory/tails/human/murid + name = "Murid" + icon_state = "murid" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/datum/sprite_accessory/tails_animated/human/murid + name = "Murid" + icon_state = "murid" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/datum/sprite_accessory/tails/human/otie + name = "Otusian" + icon_state = "otie" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/datum/sprite_accessory/tails_animated/human/otie + name = "Otusian" + icon_state = "otie" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/datum/sprite_accessory/tails/orca + name = "Orca" + icon_state = "orca" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/datum/sprite_accessory/tails_animated/orca + name = "Orca" + icon_state = "orca" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/datum/sprite_accessory/tails/human/pede + name = "Scolipede" + icon_state = "pede" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/datum/sprite_accessory/tails_animated/human/pede + name = "Scolipede" + icon_state = "pede" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/datum/sprite_accessory/tails/human/rabbit + name = "Rabbit" + icon_state = "rabbit" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/datum/sprite_accessory/tails_animated/human/rabbit + name = "Rabbit" + icon_state = "rabbit" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/datum/sprite_accessory/tails/human/sergal + name = "Sergal" + icon_state = "sergal" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/datum/sprite_accessory/tails_animated/human/sergal + name = "Sergal" + icon_state = "sergal" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/datum/sprite_accessory/tails/human/skunk + name = "skunk" + icon_state = "skunk" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/datum/sprite_accessory/tails_animated/human/skunk + name = "skunk" + icon_state = "skunk" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/datum/sprite_accessory/tails/human/shark + name = "Shark" + icon_state = "shark" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/datum/sprite_accessory/tails_animated/human/shark + name = "Shark" + icon_state = "shark" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/datum/sprite_accessory/tails/human/datashark + name = "datashark" + icon_state = "datashark" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/datum/sprite_accessory/tails_animated/human/datashark + name = "datashark" + icon_state = "datashark" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/datum/sprite_accessory/tails/human/straighttail + name = "Straight Tail" + icon_state = "straighttail" + +/datum/sprite_accessory/tails_animated/human/straighttail + name = "Straight Tail" + icon_state = "straighttail" + +/datum/sprite_accessory/tails/human/squirrel + name = "Squirrel" + icon_state = "squirrel" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/datum/sprite_accessory/tails_animated/human/squirrel + name = "Squirrel" + icon_state = "squirrel" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/datum/sprite_accessory/tails/human/tentacle + name = "Tentacle" + icon_state = "tentacle" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/datum/sprite_accessory/tails_animated/human/tentacle + name = "Tentacle" + icon_state = "tentacle" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/datum/sprite_accessory/tails/human/tiger + name = "Tiger" + icon_state = "tiger" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/datum/sprite_accessory/tails_animated/human/tiger + name = "Tiger" + icon_state = "tiger" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/datum/sprite_accessory/tails/human/wolf + name = "Wolf" + icon_state = "wolf" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/datum/sprite_accessory/tails_animated/human/wolf + name = "Wolf" + icon_state = "wolf" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/****************************************** +************** Furry Tails **************** +*******************************************/ + +/datum/sprite_accessory/mam_tails + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/datum/sprite_accessory/mam_tails/none + name = "None" + icon_state = "none" + +/datum/sprite_accessory/mam_tails_animated + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/datum/sprite_accessory/mam_tails_animated/none + name = "None" + icon_state = "none" + color_src = MATRIXED + +/datum/sprite_accessory/mam_tails/ailurus + name = "Red Panda" + icon_state = "wah" + extra = TRUE + +/datum/sprite_accessory/mam_tails_animated/ailurus + name = "Red Panda" + icon_state = "wah" + extra = TRUE + +/datum/sprite_accessory/mam_tails/axolotl + name = "Axolotl" + icon_state = "axolotl" + +/datum/sprite_accessory/mam_tails_animated/axolotl + name = "Axolotl" + icon_state = "axolotl" + +/datum/sprite_accessory/mam_tails/bee + name = "Bee" + icon_state = "bee" + +/datum/sprite_accessory/mam_tails_animated/bee + name = "Bee" + icon_state = "bee" + +/datum/sprite_accessory/mam_tails/cat + name = "Cat" + icon_state = "cat" + color_src = HAIR + +/datum/sprite_accessory/mam_tails_animated/cat + name = "Cat" + icon_state = "cat" + color_src = HAIR + +/datum/sprite_accessory/mam_tails/catbig + name = "Cat, Big" + icon_state = "catbig" + +/datum/sprite_accessory/mam_tails_animated/catbig + name = "Cat, Big" + icon_state = "catbig" + +/datum/sprite_accessory/mam_tails/corvid + name = "Corvid" + icon_state = "crow" + +/datum/sprite_accessory/mam_tails_animated/corvid + name = "Corvid" + icon_state = "crow" + +/datum/sprite_accessory/mam_tail/cow + name = "Cow" + icon_state = "cow" + +/datum/sprite_accessory/mam_tails_animated/cow + name = "Cow" + icon_state = "cow" + +/datum/sprite_accessory/mam_tails/eevee + name = "Eevee" + icon_state = "eevee" + +/datum/sprite_accessory/mam_tails_animated/eevee + name = "Eevee" + icon_state = "eevee" + +/datum/sprite_accessory/mam_tails/fennec + name = "Fennec" + icon_state = "fennec" + +/datum/sprite_accessory/mam_tails_animated/fennec + name = "Fennec" + icon_state = "fennec" + +/datum/sprite_accessory/mam_tails/human/fish + name = "Fish" + icon_state = "fish" + +/datum/sprite_accessory/mam_tails_animated/human/fish + name = "Fish" + icon_state = "fish" + +/datum/sprite_accessory/mam_tails/fox + name = "Fox" + icon_state = "fox" + +/datum/sprite_accessory/mam_tails_animated/fox + name = "Fox" + icon_state = "fox" + +/datum/sprite_accessory/mam_tails/hawk + name = "Hawk" + icon_state = "hawk" + +/datum/sprite_accessory/mam_tails_animated/hawk + name = "Hawk" + icon_state = "hawk" + +/datum/sprite_accessory/mam_tails/horse + name = "Horse" + icon_state = "horse" + color_src = HAIR + +/datum/sprite_accessory/mam_tails_animated/horse + name = "Horse" + icon_state = "horse" + color_src = HAIR + +/datum/sprite_accessory/mam_tails/husky + name = "Husky" + icon_state = "husky" + +/datum/sprite_accessory/mam_tails_animated/husky + name = "Husky" + icon_state = "husky" + +datum/sprite_accessory/mam_tails/insect + name = "Insect" + icon_state = "insect" + +/datum/sprite_accessory/mam_tails_animated/insect + name = "Insect" + icon_state = "insect" + +/datum/sprite_accessory/mam_tails/kangaroo + name = "kangaroo" + icon_state = "kangaroo" + +/datum/sprite_accessory/mam_tails_animated/kangaroo + name = "kangaroo" + icon_state = "kangaroo" + +/datum/sprite_accessory/mam_tails/kitsune + name = "Kitsune" + icon_state = "kitsune" + +/datum/sprite_accessory/mam_tails_animated/kitsune + name = "Kitsune" + icon_state = "kitsune" + +/datum/sprite_accessory/mam_tails/lab + name = "Lab" + icon_state = "lab" + +/datum/sprite_accessory/mam_tails_animated/lab + name = "Lab" + icon_state = "lab" + +/datum/sprite_accessory/mam_tails/murid + name = "Murid" + icon_state = "murid" + +/datum/sprite_accessory/mam_tails_animated/murid + name = "Murid" + icon_state = "murid" + +/datum/sprite_accessory/mam_tails/otie + name = "Otusian" + icon_state = "otie" + +/datum/sprite_accessory/mam_tails_animated/otie + name = "Otusian" + icon_state = "otie" + +/datum/sprite_accessory/mam_tails/orca + name = "Orca" + icon_state = "orca" + +/datum/sprite_accessory/mam_tails_animated/orca + name = "Orca" + icon_state = "orca" + +/datum/sprite_accessory/mam_tails/pede + name = "Scolipede" + icon_state = "pede" + +/datum/sprite_accessory/mam_tails_animated/pede + name = "Scolipede" + icon_state = "pede" + +/datum/sprite_accessory/mam_tails/rabbit + name = "Rabbit" + icon_state = "rabbit" + +/datum/sprite_accessory/mam_tails_animated/rabbit + name = "Rabbit" + icon_state = "rabbit" + +/datum/sprite_accessory/mam_tails/sergal + name = "Sergal" + icon_state = "sergal" + +/datum/sprite_accessory/mam_tails_animated/sergal + name = "Sergal" + icon_state = "sergal" + +/datum/sprite_accessory/mam_tails/skunk + name = "Skunk" + icon_state = "skunk" + +/datum/sprite_accessory/mam_tails_animated/skunk + name = "Skunk" + icon_state = "skunk" + +/datum/sprite_accessory/mam_tails/shark + name = "Shark" + icon_state = "shark" + +/datum/sprite_accessory/mam_tails_animated/shark + name = "Shark" + icon_state = "shark" + +/datum/sprite_accessory/mam_tails/shepherd + name = "Shepherd" + icon_state = "shepherd" + +/datum/sprite_accessory/mam_tails_animated/shepherd + name = "Shepherd" + icon_state = "shepherd" + +/datum/sprite_accessory/mam_tails/straighttail + name = "Straight Tail" + icon_state = "straighttail" + +/datum/sprite_accessory/mam_tails_animated/straighttail + name = "Straight Tail" + icon_state = "straighttail" + +/datum/sprite_accessory/mam_tails/squirrel + name = "Squirrel" + icon_state = "squirrel" + +/datum/sprite_accessory/mam_tails_animated/squirrel + name = "Squirrel" + icon_state = "squirrel" + +/datum/sprite_accessory/mam_tails/tentacle + name = "Tentacle" + icon_state = "tentacle" + +/datum/sprite_accessory/mam_tails_animated/tentacle + name = "Tentacle" + icon_state = "tentacle" + +/datum/sprite_accessory/mam_tails/tiger + name = "Tiger" + icon_state = "tiger" + +/datum/sprite_accessory/mam_tails_animated/tiger + name = "Tiger" + icon_state = "tiger" + +/datum/sprite_accessory/mam_tails/wolf + name = "Wolf" + icon_state = "wolf" + +/datum/sprite_accessory/mam_tails_animated/wolf + name = "Wolf" + icon_state = "wolf" diff --git a/code/modules/mob/dead/new_player/sprite_accessories/wings.dm b/code/modules/mob/dead/new_player/sprite_accessories/wings.dm index d051b2f07a..6c42177c3c 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/wings.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/wings.dm @@ -1,3 +1,5 @@ +//Angel Wings + /datum/sprite_accessory/wings/none name = "None" icon_state = "none" @@ -23,4 +25,193 @@ dimension_x = 46 center = TRUE dimension_y = 34 - locked = TRUE \ No newline at end of file + locked = TRUE + +// Decorative wings +/datum/sprite_accessory/deco_wings + icon = 'icons/mob/wings.dmi' + color_src = WINGCOLOR + +/datum/sprite_accessory/deco_wings/plain + name = "Plain" + icon_state = "plain" + +/datum/sprite_accessory/deco_wings/monarch + name = "Monarch" + icon_state = "monarch" + +/datum/sprite_accessory/deco_wings/luna + name = "Luna" + icon_state = "luna" + +/datum/sprite_accessory/deco_wings/atlas + name = "Atlas" + icon_state = "atlas" + +/datum/sprite_accessory/deco_wings/reddish + name = "Reddish" + icon_state = "redish" + +/datum/sprite_accessory/deco_wings/royal + name = "Royal" + icon_state = "royal" + +/datum/sprite_accessory/deco_wings/gothic + name = "Gothic" + icon_state = "gothic" + +/datum/sprite_accessory/deco_wings/lovers + name = "Lovers" + icon_state = "lovers" + +/datum/sprite_accessory/deco_wings/whitefly + name = "White Fly" + icon_state = "whitefly" + +/datum/sprite_accessory/deco_wings/punished + name = "Burnt Off" + icon_state = "punished" + locked = TRUE + +/datum/sprite_accessory/deco_wings/firewatch + name = "Firewatch" + icon_state = "firewatch" + +/datum/sprite_accessory/deco_wings/deathhead + name = "Deathshead" + icon_state = "deathhead" + +/datum/sprite_accessory/deco_wings/poison + name = "Poison" + icon_state = "poison" + +/datum/sprite_accessory/deco_wings/ragged + name = "Ragged" + icon_state = "ragged" + +/datum/sprite_accessory/deco_wings/moonfly + name = "Moon Fly" + icon_state = "moonfly" + +/datum/sprite_accessory/deco_wings/snow + name = "Snow" + icon_state = "snow" + +/datum/sprite_accessory/deco_wings/angel + name = "Angel" + icon_state = "angel" + color_src = 0 + dimension_x = 46 + center = TRUE + dimension_y = 34 + +/datum/sprite_accessory/deco_wings/bee + name = "Bee" + icon_state = "bee" + +/datum/sprite_accessory/deco_wings/fairy + name = "Fairy" + icon_state = "fairy" + +/datum/sprite_accessory/deco_wings/bat + name = "Bat" + icon_state = "bat" + +/datum/sprite_accessory/deco_wings/feathery + name = "Feathery" + icon_state = "feathery" + +/datum/sprite_accessory/deco_wings/none + name = "None" + icon_state = "none" + + +//INSECT WINGS + +/datum/sprite_accessory/insect_wings + icon = 'icons/mob/wings.dmi' + color_src = WINGCOLOR + +/datum/sprite_accessory/insect_wings/none + name = "None" + icon_state = "none" + +/datum/sprite_accessory/insect_wings/plain + name = "Plain" + icon_state = "plain" + +/datum/sprite_accessory/insect_wings/monarch + name = "Monarch" + icon_state = "monarch" + +/datum/sprite_accessory/insect_wings/luna + name = "Luna" + icon_state = "luna" + +/datum/sprite_accessory/insect_wings/atlas + name = "Atlas" + icon_state = "atlas" + +/datum/sprite_accessory/insect_wings/reddish + name = "Reddish" + icon_state = "redish" + +/datum/sprite_accessory/insect_wings/royal + name = "Royal" + icon_state = "royal" + +/datum/sprite_accessory/insect_wings/gothic + name = "Gothic" + icon_state = "gothic" + +/datum/sprite_accessory/insect_wings/lovers + name = "Lovers" + icon_state = "lovers" + +/datum/sprite_accessory/insect_wings/whitefly + name = "White Fly" + icon_state = "whitefly" + +/datum/sprite_accessory/insect_wings/punished + name = "Burnt Off" + icon_state = "punished" + +/datum/sprite_accessory/insect_wings/firewatch + name = "Firewatch" + icon_state = "firewatch" + +/datum/sprite_accessory/insect_wings/deathhead + name = "Deathshead" + icon_state = "deathhead" + +/datum/sprite_accessory/insect_wings/poison + name = "Poison" + icon_state = "poison" + +/datum/sprite_accessory/insect_wings/ragged + name = "Ragged" + icon_state = "ragged" + +/datum/sprite_accessory/insect_wings/moonfly + name = "Moon Fly" + icon_state = "moonfly" + +/datum/sprite_accessory/insect_wings/snow + name = "Snow" + icon_state = "snow" + +/datum/sprite_accessory/insect_wings/bee + name = "Bee" + icon_state = "bee" + +/datum/sprite_accessory/insect_wings/fairy + name = "Fairy" + icon_state = "fairy" + +/datum/sprite_accessory/insect_wings/bat + name = "Bat" + icon_state = "bat" + +/datum/sprite_accessory/insect_wings/feathery + name = "Feathery" + icon_state = "feathery" diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index fefa032e4f..d599d55886 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -260,16 +260,16 @@ Transfer_mind is there to check if mob is being deleted/not going to have a body Works together with spawning an observer, noted above. */ -/mob/proc/ghostize(can_reenter_corpse = 1) - if(key) - if(!cmptext(copytext(key,1,2),"@")) // Skip aghosts. - stop_sound_channel(CHANNEL_HEARTBEAT) //Stop heartbeat sounds because You Are A Ghost Now - var/mob/dead/observer/ghost = new(src) // Transfer safety to observer spawning proc. - SStgui.on_transfer(src, ghost) // Transfer NanoUIs. - ghost.can_reenter_corpse = can_reenter_corpse - ghost.can_reenter_round = (can_reenter_corpse && !suiciding) - ghost.key = key - return ghost +/mob/proc/ghostize(can_reenter_corpse = TRUE, special = FALSE) + if(!key || cmptext(copytext(key,1,2),"@") || (!special && SEND_SIGNAL(src, COMSIG_MOB_GHOSTIZE, can_reenter_corpse, special) & COMPONENT_BLOCK_GHOSTING)) + return //mob has no key, is an aghost or some component hijacked. + stop_sound_channel(CHANNEL_HEARTBEAT) //Stop heartbeat sounds because You Are A Ghost Now + var/mob/dead/observer/ghost = new(src) // Transfer safety to observer spawning proc. + SStgui.on_transfer(src, ghost) // Transfer NanoUIs. + ghost.can_reenter_corpse = can_reenter_corpse + ghost.can_reenter_round = (can_reenter_corpse && !suiciding) + transfer_ckey(ghost, FALSE) + return ghost /* This is the proc mobs get to turn into a ghost. Forked from ghostize due to compatibility issues. @@ -280,6 +280,9 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp set name = "Ghost" set desc = "Relinquish your life and enter the land of the dead." + if(SEND_SIGNAL(src, COMSIG_MOB_GHOSTIZE, (stat == DEAD) ? TRUE : FALSE, FALSE) & COMPONENT_BLOCK_GHOSTING) + return + // CITADEL EDIT if(istype(loc, /obj/machinery/cryopod)) var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst still alive you won't be able to re-enter this round! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body") @@ -306,6 +309,9 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp set name = "Ghost" set desc = "Relinquish your life and enter the land of the dead." + if(SEND_SIGNAL(src, COMSIG_MOB_GHOSTIZE, FALSE, FALSE) & COMPONENT_BLOCK_GHOSTING) + return + var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst still alive you won't be able to re-enter this round! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body") if(response != "Ghost") return @@ -348,7 +354,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp return client.change_view(CONFIG_GET(string/default_view)) SStgui.on_transfer(src, mind.current) // Transfer NanoUIs. - mind.current.key = key + transfer_ckey(mind.current, FALSE) return 1 /mob/dead/observer/proc/notify_cloning(var/message, var/sound, var/atom/source, flashwindow = TRUE) @@ -628,7 +634,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp to_chat(src, "Someone has taken this body while you were choosing!") return 0 - target.key = key + transfer_ckey(target, FALSE) target.faction = list("neutral") return 1 diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm index 9569d4826c..760fb7a29f 100644 --- a/code/modules/mob/inventory.dm +++ b/code/modules/mob/inventory.dm @@ -158,7 +158,7 @@ //Returns if a certain item can be equipped to a certain slot. // Currently invalid for two-handed items - call obj/item/mob_can_equip() instead. -/mob/proc/can_equip(obj/item/I, slot, disable_warning = 0) +/mob/proc/can_equip(obj/item/I, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE) return FALSE /mob/proc/can_put_in_hand(I, hand_index) diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm index 815184c63d..ca1a961a92 100644 --- a/code/modules/mob/living/blood.dm +++ b/code/modules/mob/living/blood.dm @@ -18,10 +18,10 @@ /mob/living/carbon/monkey/handle_blood() if(bodytemperature >= TCRYO && !(HAS_TRAIT(src, TRAIT_NOCLONE))) //cryosleep or husked people do not pump the blood. //Blood regeneration if there is some space - if(blood_volume < BLOOD_VOLUME_NORMAL) + if(blood_volume < (BLOOD_VOLUME_NORMAL * blood_ratio)) blood_volume += 0.1 // regenerate blood VERY slowly - if(blood_volume < BLOOD_VOLUME_OKAY) - adjustOxyLoss(round((BLOOD_VOLUME_NORMAL - blood_volume) * 0.02, 1)) + if(blood_volume < (BLOOD_VOLUME_OKAY * blood_ratio)) + adjustOxyLoss(round(((BLOOD_VOLUME_NORMAL * blood_ratio) - blood_volume) * 0.02, 1)) // Takes care blood loss and regeneration /mob/living/carbon/human/handle_blood() @@ -33,7 +33,7 @@ if(bodytemperature >= TCRYO && !(HAS_TRAIT(src, TRAIT_NOCLONE))) //cryosleep or husked people do not pump the blood. //Blood regeneration if there is some space - if(blood_volume < BLOOD_VOLUME_NORMAL && !HAS_TRAIT(src, TRAIT_NOHUNGER)) + if(blood_volume < (BLOOD_VOLUME_NORMAL * blood_ratio) && !HAS_TRAIT(src, TRAIT_NOHUNGER)) var/nutrition_ratio = 0 switch(nutrition) if(0 to NUTRITION_LEVEL_STARVING) @@ -46,20 +46,22 @@ nutrition_ratio = 0.8 else nutrition_ratio = 1 + if(HAS_TRAIT(src, TRAIT_HIGH_BLOOD)) + nutrition_ratio *= 1.2 if(satiety > 80) nutrition_ratio *= 1.25 nutrition = max(0, nutrition - nutrition_ratio * HUNGER_FACTOR) - blood_volume = min(BLOOD_VOLUME_NORMAL, blood_volume + 0.5 * nutrition_ratio) + blood_volume = min((BLOOD_VOLUME_NORMAL * blood_ratio), blood_volume + 0.5 * nutrition_ratio) //Effects of bloodloss var/word = pick("dizzy","woozy","faint") - switch(blood_volume) + switch(blood_volume * INVERSE(blood_ratio)) if(BLOOD_VOLUME_OKAY to BLOOD_VOLUME_SAFE) if(prob(5)) to_chat(src, "You feel [word].") - adjustOxyLoss(round((BLOOD_VOLUME_NORMAL - blood_volume) * 0.01, 1)) + adjustOxyLoss(round(((BLOOD_VOLUME_NORMAL * blood_ratio) - blood_volume) * 0.01, 1)) if(BLOOD_VOLUME_BAD to BLOOD_VOLUME_OKAY) - adjustOxyLoss(round((BLOOD_VOLUME_NORMAL - blood_volume) * 0.02, 1)) + adjustOxyLoss(round(((BLOOD_VOLUME_NORMAL * blood_ratio) - blood_volume) * 0.02, 1)) if(prob(5)) blur_eyes(6) to_chat(src, "You feel very [word].") @@ -111,7 +113,7 @@ blood_volume = initial(blood_volume) /mob/living/carbon/human/restore_blood() - blood_volume = BLOOD_VOLUME_NORMAL + blood_volume = (BLOOD_VOLUME_NORMAL * blood_ratio) bleed_rate = 0 /**************************************************** @@ -122,7 +124,7 @@ /mob/living/proc/transfer_blood_to(atom/movable/AM, amount, forced) if(!blood_volume || !AM.reagents) return 0 - if(blood_volume < BLOOD_VOLUME_BAD && !forced) + if(blood_volume < (BLOOD_VOLUME_BAD * blood_ratio) && !forced) return 0 if(blood_volume < amount) @@ -161,7 +163,7 @@ return /mob/living/carbon/get_blood_data(blood_id) - if(blood_id == "blood") //actual blood reagent + if(blood_id == "blood") //actual blood reagent var/blood_data = list() //set the blood data blood_data["donor"] = src @@ -204,6 +206,21 @@ if(istype(ling)) blood_data["changeling_loudness"] = ling.loudfactor return blood_data + if(blood_id == "slimejelly") //Just so MKUltra works. Takes the minimum required data. Sishen is testing if this breaks stuff. + var/blood_data = list() + if(mind) + blood_data["mind"] = mind + else if(last_mind) + blood_data["mind"] = last_mind + if(ckey) + blood_data["ckey"] = ckey + else if(last_mind) + blood_data["ckey"] = ckey(last_mind.key) + blood_data["gender"] = gender + blood_data["real_name"] = real_name + return blood_data + + //get the id of the substance this mob use as blood. /mob/proc/get_blood_id() @@ -300,3 +317,24 @@ var/obj/effect/decal/cleanable/oil/B = locate() in T.contents if(!B) B = new(T) + +//This is a terrible way of handling it. +/mob/living/proc/ResetBloodVol() + if(ishuman(src)) + var/mob/living/carbon/human/H = src + if (HAS_TRAIT(src, TRAIT_HIGH_BLOOD)) + blood_ratio = 1.2 + H.handle_blood() + return + blood_ratio = 1 + H.handle_blood() + return + blood_ratio = 1 + +/mob/living/proc/AdjustBloodVol(var/value) + if(blood_ratio == value) + return + blood_ratio = value + if(ishuman(src)) + var/mob/living/carbon/human/H = src + H.handle_blood() diff --git a/code/modules/mob/living/brain/MMI.dm b/code/modules/mob/living/brain/MMI.dm index bacdc4524b..d84ba0d7a1 100644 --- a/code/modules/mob/living/brain/MMI.dm +++ b/code/modules/mob/living/brain/MMI.dm @@ -57,13 +57,14 @@ newbrain.brainmob = null brainmob.forceMove(src) brainmob.container = src - if(!newbrain.damaged_brain) // the brain organ hasn't been beaten to death. + if(!(newbrain.organ_flags & ORGAN_FAILING)) // the brain organ hasn't been beaten to death. brainmob.stat = CONSCIOUS //we manually revive the brain mob GLOB.dead_mob_list -= brainmob GLOB.alive_mob_list += brainmob brainmob.reset_perspective() brain = newbrain + brain.organ_flags |= ORGAN_FROZEN name = "Man-Machine Interface: [brainmob.real_name]" update_icon() @@ -100,6 +101,7 @@ user.put_in_hands(brain) //puts brain in the user's hand or otherwise drops it on the user's turf else brain.forceMove(get_turf(src)) + brain.organ_flags &= ~ORGAN_FROZEN brain = null //No more brain in here diff --git a/code/modules/mob/living/brain/brain_item.dm b/code/modules/mob/living/brain/brain_item.dm index dafc6cf5e0..4192c2235b 100644 --- a/code/modules/mob/living/brain/brain_item.dm +++ b/code/modules/mob/living/brain/brain_item.dm @@ -7,11 +7,20 @@ layer = ABOVE_MOB_LAYER zone = BODY_ZONE_HEAD slot = ORGAN_SLOT_BRAIN - vital = TRUE + organ_flags = ORGAN_VITAL attack_verb = list("attacked", "slapped", "whacked") + ///The brain's organ variables are significantly more different than the other organs, with half the decay rate for balance reasons, and twice the maxHealth + decay_factor = STANDARD_ORGAN_DECAY / 4 //30 minutes of decaying to result in a fully damaged brain, since a fast decay rate would be unfun gameplay-wise + healing_factor = STANDARD_ORGAN_HEALING / 2 + + maxHealth = BRAIN_DAMAGE_DEATH + low_threshold = 45 + high_threshold = 120 var/mob/living/brain/brainmob = null - var/damaged_brain = FALSE //whether the brain organ is damaged. + var/brain_death = FALSE //if the brainmob was intentionally killed by attacking the brain after removal, or by severe braindamage var/decoy_override = FALSE //I apologize to the security players, and myself, who abused this, but this is going to go. + //two variables necessary for calculating whether we get a brain trauma or not + var/damage_delta = 0 var/list/datum/brain_trauma/traumas = list() @@ -34,7 +43,7 @@ if(brainmob.mind) brainmob.mind.transfer_to(C) else - C.key = brainmob.key + brainmob.transfer_ckey(C) QDEL_NULL(brainmob) @@ -90,22 +99,89 @@ if(brainmob) O.attack(brainmob, user) //Oh noooeeeee -/obj/item/organ/brain/examine(mob/user) - ..() + if(istype(O, /obj/item/organ_storage)) //BUG_PROBABLE_CAUSE + return //Borg organ bags shouldn't be killing brains - if(brainmob) - if(brainmob.client) - if(brainmob.health <= HEALTH_THRESHOLD_DEAD) - to_chat(user, "It's lifeless and severely damaged.") + if((organ_flags & ORGAN_FAILING) && O.is_drainable() && O.reagents.has_reagent("neurine")) //Neurine fixes dead brains + . = TRUE //don't do attack animation. + var/cached_Bdamage = brainmob?.health + var/datum/reagent/medicine/neurine/N = reagents.has_reagent("neurine") + var/datum/reagent/medicine/mannitol/M1 = reagents.has_reagent("mannitol") + + if(O.reagents.has_reagent("mannitol"))//Just a quick way to bolster the effects if someone mixes up a batch. + N.volume *= (M1.volume*0.5) + + if(!O.reagents.has_reagent("neurine", 10)) + to_chat(user, "There's not enough neurine in [O] to restore [src]!") + return + + user.visible_message("[user] starts to pour the contents of [O] onto [src].", "You start to slowly pour the contents of [O] onto [src].") + if(!do_after(user, 60, TRUE, src)) + to_chat(user, "You failed to pour [O] onto [src]!") + return + + user.visible_message("[user] pours the contents of [O] onto [src], causing it to reform its original shape and turn a slightly brighter shade of pink.", "You pour the contents of [O] onto [src], causing it to reform its original shape and turn a slightly brighter shade of pink.") + setOrganDamage((damage - (0.10 * maxHealth)*(N.volume/10))) //heals a small amount, and by using "setorgandamage", we clear the failing variable if that was up + O.reagents.clear_reagents() + + if(cached_Bdamage <= HEALTH_THRESHOLD_DEAD) //Fixing dead brains yeilds a trauma + if((cached_Bdamage <= HEALTH_THRESHOLD_DEAD) && (brainmob.health > HEALTH_THRESHOLD_DEAD)) + if(prob(80)) + gain_trauma_type(BRAIN_TRAUMA_MILD) + else if(prob(50)) + gain_trauma_type(BRAIN_TRAUMA_SEVERE) + else + gain_trauma_type(BRAIN_TRAUMA_SPECIAL) + return + + if((organ_flags & ORGAN_FAILING) && O.is_drainable() && O.reagents.has_reagent("mannitol")) //attempt to heal the brain + . = TRUE //don't do attack animation. + var/datum/reagent/medicine/mannitol/M = reagents.has_reagent("mannitol") + if(brain_death || brainmob?.health <= HEALTH_THRESHOLD_DEAD) //if the brain is fucked anyway, do nothing + to_chat(user, "[src] is far too damaged, you'll have to use neurine on it!") + return + + if(!O.reagents.has_reagent("mannitol", 10)) + to_chat(user, "There's not enough mannitol in [O] to restore [src]!") + return + + user.visible_message("[user] starts to pour the contents of [O] onto [src].", "You start to slowly pour the contents of [O] onto [src].") + if(!do_after(user, 60, TRUE, src)) + to_chat(user, "You failed to pour [O] onto [src]!") + return + + user.visible_message("[user] pours the contents of [O] onto [src], causing it to reform its original shape and turn a slightly brighter shade of pink.", "You pour the contents of [O] onto [src], causing it to reform its original shape and turn a slightly brighter shade of pink.") + setOrganDamage((damage - (0.05 * maxHealth)*(M.volume/10))) //heals a small amount, and by using "setorgandamage", we clear the failing variable if that was up + O.reagents.clear_reagents() + return + + + +/obj/item/organ/brain/examine(mob/user)//BUG_PROBABLE_CAUSE to_chats changed to . += + . = ..() + + if(user.suiciding) + . += "It's started turning slightly grey. They must not have been able to handle the stress of it all." + else if(brainmob) + if(brainmob.get_ghost(FALSE, TRUE)) + if(brain_death || brainmob.health <= HEALTH_THRESHOLD_DEAD) + . += "It's lifeless and severely damaged, only the strongest of chems will save it." + else if(organ_flags & ORGAN_FAILING) + . += "It seems to still have a bit of energy within it, but it's rather damaged... You may be able to restore it with some mannitol." else - to_chat(user, "You can feel the small spark of life still left in this one.") + . += "You can feel the small spark of life still left in this one." + else if(organ_flags & ORGAN_FAILING) + . += "It seems particularly lifeless and is rather damaged... You may be able to restore it with some mannitol incase it becomes functional again later." else - to_chat(user, "This one seems particularly lifeless. Perhaps it will regain some of its luster later.") + . += "This one seems particularly lifeless. Perhaps it will regain some of its luster later." else if(decoy_override) - to_chat(user, "This one seems particularly lifeless. Perhaps it will regain some of its luster later.") + if(organ_flags & ORGAN_FAILING) + . += "It seems particularly lifeless and is rather damaged... You may be able to restore it with some mannitol incase it becomes functional again later." + else + . += "This one seems particularly lifeless. Perhaps it will regain some of its luster later." else - to_chat(user, "This one is completely devoid of life.") + . += "This one is completely devoid of life." /obj/item/organ/brain/attack(mob/living/carbon/C, mob/user) if(!istype(C)) @@ -141,7 +217,7 @@ Insert(C) else ..() - +/* TO BE REMOVED, KEPT IN CASE OF BUGS /obj/item/organ/brain/proc/get_brain_damage() var/brain_damage_threshold = max_integrity * BRAIN_DAMAGE_INTEGRITY_MULTIPLIER var/offset_integrity = obj_integrity - (max_integrity - brain_damage_threshold) @@ -165,6 +241,56 @@ else if(adjusted_amount <= -DAMAGE_PRECISION) obj_integrity = min(max_integrity, obj_integrity-adjusted_amount) . = adjusted_amount +*/ + +/obj/item/organ/brain/on_life() + if(damage >= BRAIN_DAMAGE_DEATH) //rip + to_chat(owner, "The last spark of life in your brain fizzles out...") + owner.death() + brain_death = TRUE + return + ..() + +/obj/item/organ/brain/on_death() + if(damage <= BRAIN_DAMAGE_DEATH) //rip + brain_death = FALSE + ..() + + +/obj/item/organ/brain/applyOrganDamage(var/d, var/maximum = maxHealth) + ..() + + +/obj/item/organ/brain/check_damage_thresholds(mob/M) + . = ..() + //if we're not more injured than before, return without gambling for a trauma + if(damage <= prev_damage) + return + damage_delta = damage - prev_damage + if(damage > BRAIN_DAMAGE_MILD) + if(prob(damage_delta * (1 + max(0, (damage - BRAIN_DAMAGE_MILD)/100)))) //Base chance is the hit damage; for every point of damage past the threshold the chance is increased by 1% //learn how to do your bloody math properly goddamnit + gain_trauma_type(BRAIN_TRAUMA_MILD) + if(damage > BRAIN_DAMAGE_SEVERE) + if(prob(damage_delta * (1 + max(0, (damage - BRAIN_DAMAGE_SEVERE)/100)))) //Base chance is the hit damage; for every point of damage past the threshold the chance is increased by 1% + if(prob(20)) + gain_trauma_type(BRAIN_TRAUMA_SPECIAL) + else + gain_trauma_type(BRAIN_TRAUMA_SEVERE) + + if (owner) + if(owner.stat < UNCONSCIOUS) //conscious or soft-crit + var/brain_message + if(prev_damage < BRAIN_DAMAGE_MILD && damage >= BRAIN_DAMAGE_MILD) + brain_message = "You feel lightheaded." + else if(prev_damage < BRAIN_DAMAGE_SEVERE && damage >= BRAIN_DAMAGE_SEVERE) + brain_message = "You feel less in control of your thoughts." + else if(prev_damage < (BRAIN_DAMAGE_DEATH - 20) && damage >= (BRAIN_DAMAGE_DEATH - 20)) + brain_message = "You can feel your mind flickering on and off..." + + if(.) + . += "\n[brain_message]" + else + return brain_message /obj/item/organ/brain/Destroy() //copypasted from MMIs. if(brainmob) @@ -200,6 +326,10 @@ return FALSE if(!resilience) resilience = initial(trauma.resilience) + if(!owner) + return FALSE + if(owner.stat == DEAD) + return FALSE var/resilience_tier_count = 0 for(var/X in traumas) diff --git a/code/modules/mob/living/brain/life.dm b/code/modules/mob/living/brain/life.dm index 786bb0b55c..51be1f6971 100644 --- a/code/modules/mob/living/brain/life.dm +++ b/code/modules/mob/living/brain/life.dm @@ -20,7 +20,7 @@ else if(istype(loc, /obj/item/organ/brain)) BR = loc if(BR) - BR.damaged_brain = 1 //beaten to a pulp + BR.brain_death = TRUE /mob/living/brain/proc/handle_emp_damage() if(emp_damage) diff --git a/code/modules/mob/living/carbon/alien/larva/emote.dm b/code/modules/mob/living/carbon/alien/larva/emote.dm deleted file mode 100644 index 62cb620ee4..0000000000 --- a/code/modules/mob/living/carbon/alien/larva/emote.dm +++ /dev/null @@ -1,113 +0,0 @@ -/mob/living/carbon/alien/larva/emote(act,m_type=1,message = null) - - var/param = null - if (findtext(act, "-", 1, null)) - var/t1 = findtext(act, "-", 1, null) - param = copytext(act, t1 + 1, length(act) + 1) - act = copytext(act, 1, t1) - - var/muzzled = is_muzzled() - - switch(act) //Alphabetically sorted please. - if ("burp","burps") - if (!muzzled) - message = "[src] burps." - m_type = 2 - if ("choke","chokes") - message = "[src] chokes." - m_type = 2 - if ("collapse","collapses") - Paralyse(2) - message = "[src] collapses!" - m_type = 2 - if ("dance","dances") - if (!src.restrained()) - message = "[src] dances around happily." - m_type = 1 - if ("deathgasp","deathgasps") - message = "[src] lets out a sickly hiss of air and falls limply to the floor..." - m_type = 2 - if ("drool","drools") - message = "[src] drools." - m_type = 1 - if ("gasp","gasps") - message = "[src] gasps." - m_type = 2 - if ("gnarl","gnarls") - if (!muzzled) - message = "[src] gnarls and shows its teeth.." - m_type = 2 - if ("hiss","hisses") - message = "[src] hisses softly." - m_type = 1 - if ("jump","jumps") - message = "[src] jumps!" - m_type = 1 - if ("me") - ..() - return - if ("moan","moans") - message = "[src] moans!" - m_type = 2 - if ("nod","nods") - message = "[src] nods its head." - m_type = 1 - if ("roar","roars") - if (!muzzled) - message = "[src] softly roars." - m_type = 2 - if ("roll","rolls") - if (!src.restrained()) - message = "[src] rolls." - m_type = 1 - if ("scratch","scratches") - if (!src.restrained()) - message = "[src] scratches." - m_type = 1 - if ("screech","screeches") //This orignally was called scretch, changing it. -Sum99 - if (!muzzled) - message = "[src] screeches." - m_type = 2 - if ("shake","shakes") - message = "[src] shakes its head." - m_type = 1 - if ("shiver","shivers") - message = "[src] shivers." - m_type = 2 - if ("sign","signs") - if (!src.restrained()) - message = text("[src] signs[].", (text2num(param) ? text(" the number []", text2num(param)) : null)) - m_type = 1 - if ("snore","snores") - message = "[src] snores." - m_type = 2 - if ("sulk","sulks") - message = "[src] sulks down sadly." - m_type = 1 - if ("sway","sways") - message = "[src] sways around dizzily." - m_type = 1 - if ("tail") - message = "[src] waves its tail." - m_type = 1 - if ("twitch") - message = "[src] twitches violently." - m_type = 1 - if ("whimper","whimpers") - if (!muzzled) - message = "[src] whimpers." - m_type = 2 - - if ("help") //"The exception" - src << "Help for larva emotes. You can use these emotes with say \"*emote\":\n\nburp, choke, collapse, dance, deathgasp, drool, gasp, gnarl, hiss, jump, me, moan, nod, roll, roar, scratch, screech, shake, shiver, sign-#, sulk, sway, tail, twitch, whimper" - - else - src << "Unusable emote '[act]'. Say *help for a list." - - if ((message && src.stat == 0)) - log_emote("[name]/[key] : [message]") - if (m_type & 1) - visible_message(message) - else - audible_message(message) - return diff --git a/code/modules/mob/living/carbon/alien/organs.dm b/code/modules/mob/living/carbon/alien/organs.dm index 155f203708..df1be454ee 100644 --- a/code/modules/mob/living/carbon/alien/organs.dm +++ b/code/modules/mob/living/carbon/alien/organs.dm @@ -1,6 +1,7 @@ /obj/item/organ/alien icon_state = "xgibmid2" var/list/alien_powers = list() + organ_flags = ORGAN_NO_SPOIL /obj/item/organ/alien/Initialize() . = ..() diff --git a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm index 1574305a83..04a2e56857 100644 --- a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm +++ b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm @@ -22,6 +22,7 @@ return S /obj/item/organ/body_egg/alien_embryo/on_life() + . = ..() switch(stage) if(2, 3) if(prob(2)) @@ -86,7 +87,7 @@ var/atom/xeno_loc = get_turf(owner) var/mob/living/carbon/alien/larva/new_xeno = new(xeno_loc) - new_xeno.key = ghost.key + ghost.transfer_ckey(new_xeno, FALSE) SEND_SOUND(new_xeno, sound('sound/voice/hiss5.ogg',0,0,0,100)) //To get the player's attention new_xeno.canmove = 0 //so we don't move during the bursting animation new_xeno.notransform = 1 diff --git a/code/modules/mob/living/carbon/alien/special/facehugger.dm b/code/modules/mob/living/carbon/alien/special/facehugger.dm index c2c8904aa1..e66d70f492 100644 --- a/code/modules/mob/living/carbon/alien/special/facehugger.dm +++ b/code/modules/mob/living/carbon/alien/special/facehugger.dm @@ -15,7 +15,7 @@ icon_state = "facehugger" item_state = "facehugger" w_class = WEIGHT_CLASS_TINY //note: can be picked up by aliens unlike most other items of w_class below 4 - clothing_flags = MASKINTERNALS + clothing_flags = ALLOWINTERNALS throw_range = 5 tint = 3 flags_cover = MASKCOVERSEYES | MASKCOVERSMOUTH @@ -33,16 +33,18 @@ /obj/item/clothing/mask/facehugger/lamarr name = "Lamarr" - sterile = 1 + sterile = TRUE /obj/item/clothing/mask/facehugger/dead icon_state = "facehugger_dead" item_state = "facehugger_inactive" + sterile = TRUE stat = DEAD /obj/item/clothing/mask/facehugger/impregnated icon_state = "facehugger_impregnated" item_state = "facehugger_impregnated" + sterile = TRUE stat = DEAD /obj/item/clothing/mask/facehugger/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index e94a6eac86..263edf42c2 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -6,6 +6,7 @@ create_reagents(1000) update_body_parts() //to update the carbon's new bodyparts appearance GLOB.carbon_list += src + blood_volume = (BLOOD_VOLUME_NORMAL * blood_ratio) /mob/living/carbon/Destroy() //This must be done first, so the mob ghosts correctly before DNA etc is nulled @@ -238,7 +239,7 @@ if(href_list["internal"]) var/slot = text2num(href_list["internal"]) var/obj/item/ITEM = get_item_by_slot(slot) - if(ITEM && istype(ITEM, /obj/item/tank) && wear_mask && (wear_mask.clothing_flags & MASKINTERNALS)) + if(ITEM && istype(ITEM, /obj/item/tank) && wear_mask && (wear_mask.clothing_flags & ALLOWINTERNALS)) visible_message("[usr] tries to [internal ? "close" : "open"] the valve on [src]'s [ITEM.name].", \ "[usr] tries to [internal ? "close" : "open"] the valve on [src]'s [ITEM.name].") if(do_mob(usr, src, POCKET_STRIP_DELAY)) @@ -246,7 +247,7 @@ internal = null update_internals_hud_icon(0) else if(ITEM && istype(ITEM, /obj/item/tank)) - if((wear_mask && (wear_mask.clothing_flags & MASKINTERNALS)) || getorganslot(ORGAN_SLOT_BREATHING_TUBE)) + if((wear_mask && (wear_mask.clothing_flags & ALLOWINTERNALS)) || getorganslot(ORGAN_SLOT_BREATHING_TUBE)) internal = ITEM update_internals_hud_icon(1) @@ -270,9 +271,13 @@ if(restrained()) changeNext_move(CLICK_CD_BREAKOUT) last_special = world.time + CLICK_CD_BREAKOUT + var/buckle_cd = 600 + if(handcuffed) + var/obj/item/restraints/O = src.get_item_by_slot(SLOT_HANDCUFFED) + buckle_cd = O.breakouttime visible_message("[src] attempts to unbuckle [p_them()]self!", \ - "You attempt to unbuckle yourself... (This will take around one minute and you need to stay still.)") - if(do_after(src, 600, 0, target = src)) + "You attempt to unbuckle yourself... (This will take around [round(buckle_cd/600,1)] minute\s, and you need to stay still.)") + if(do_after(src, buckle_cd, 0, target = src)) if(!buckled) return buckled.user_unbuckle_mob(src,src) @@ -477,11 +482,13 @@ if(message) visible_message("[src] throws up all over [p_them()]self!", \ "You throw up all over yourself!") + SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "vomit", /datum/mood_event/vomitself) distance = 0 else if(message) visible_message("[src] throws up!", "You throw up!") - + if(!isflyperson(src)) + SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "vomit", /datum/mood_event/vomit) if(stun) Stun(80) @@ -699,7 +706,7 @@ clear_fullscreen("critvision") //Oxygen damage overlay - var/windedup = getOxyLoss() + getStaminaLoss() * 0.2 + stamdamageoverlaytemp + var/windedup = getOxyLoss() + getStaminaLoss() * 0.2 if(windedup) var/severity = 0 switch(windedup) @@ -798,7 +805,8 @@ drop_all_held_items() stop_pulling() throw_alert("handcuffed", /obj/screen/alert/restrained/handcuffed, new_master = src.handcuffed) - SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "handcuffed", /datum/mood_event/handcuffed) + if(handcuffed.demoralize_criminals) + SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "handcuffed", /datum/mood_event/handcuffed) else clear_alert("handcuffed") SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "handcuffed") @@ -811,7 +819,7 @@ reagents.clear_reagents() var/obj/item/organ/brain/B = getorgan(/obj/item/organ/brain) if(B) - B.damaged_brain = FALSE + B.brain_death = FALSE for(var/thing in diseases) var/datum/disease/D = thing if(D.severity != DISEASE_SEVERITY_POSITIVE) @@ -929,3 +937,17 @@ /mob/living/carbon/can_resist() return bodyparts.len > 2 && ..() + +/mob/living/carbon/proc/hypnosis_vulnerable()//unused atm, but added in case + if(HAS_TRAIT(src, TRAIT_MINDSHIELD)) + return FALSE + if(hallucinating()) + return TRUE + if(IsSleeping()) + return TRUE + if(HAS_TRAIT(src, TRAIT_DUMB)) + return TRUE + GET_COMPONENT_FROM(mood, /datum/component/mood, src) + if(mood) + if(mood.sanity < SANITY_UNSTABLE) + return TRUE diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index 57483f64e7..bc64c8303b 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -405,16 +405,16 @@ if(istype(ears) && (deafen_pwr || damage_pwr)) var/ear_damage = damage_pwr * effect_amount - var/deaf = max(ears.deaf, deafen_pwr * effect_amount) + var/deaf = deafen_pwr * effect_amount adjustEarDamage(ear_damage,deaf) - if(ears.ear_damage >= 15) + if(ears.damage >= 15) to_chat(src, "Your ears start to ring badly!") - if(prob(ears.ear_damage - 5)) + if(prob(ears.damage - 5)) to_chat(src, "You can't hear anything!") - ears.ear_damage = min(ears.ear_damage, UNHEALING_EAR_DAMAGE) + ears.damage = min(ears.damage, ears.maxHealth) // you need earmuffs, inacusiate, or replacement - else if(ears.ear_damage >= 5) + else if(ears.damage >= 5) to_chat(src, "Your ears start to ring!") SEND_SOUND(src, sound('sound/weapons/flash_ring.ogg',0,1,0,250)) return effect_amount //how soundbanged we are diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm index a067be798f..41daf642f2 100644 --- a/code/modules/mob/living/carbon/carbon_defines.dm +++ b/code/modules/mob/living/carbon/carbon_defines.dm @@ -2,7 +2,7 @@ gender = MALE pressure_resistance = 15 possible_a_intents = list(INTENT_HELP, INTENT_HARM) - hud_possible = list(HEALTH_HUD,STATUS_HUD,ANTAG_HUD,GLAND_HUD,NANITE_HUD,DIAG_NANITE_FULL_HUD) + hud_possible = list(HEALTH_HUD,STATUS_HUD,ANTAG_HUD,GLAND_HUD,NANITE_HUD,DIAG_NANITE_FULL_HUD,RAD_HUD) has_limbs = 1 held_items = list(null, null) var/list/stomach_contents = list() @@ -61,6 +61,5 @@ var/next_hallucination = 0 var/cpr_time = 1 //CPR cooldown. var/damageoverlaytemp = 0 - var/stamdamageoverlaytemp = 0 var/drunkenness = 0 //Overall drunkenness - check handle_alcohol() in life.dm for effects diff --git a/code/modules/mob/living/carbon/damage_procs.dm b/code/modules/mob/living/carbon/damage_procs.dm index 749ae3b5b0..cc0c0d7434 100644 --- a/code/modules/mob/living/carbon/damage_procs.dm +++ b/code/modules/mob/living/carbon/damage_procs.dm @@ -40,14 +40,13 @@ update_damage_overlays() else adjustStaminaLoss(damage * hit_percent) - if(BRAIN) - adjustBrainLoss(damage * hit_percent) //citadel code if(AROUSAL) adjustArousalLoss(damage * hit_percent) return TRUE + //These procs fetch a cumulative total damage from all bodyparts /mob/living/carbon/getBruteLoss() var/amount = 0 @@ -113,6 +112,51 @@ return adjustStaminaLoss(diff, updating, forced) +/** adjustOrganLoss + * inputs: slot (organ slot, like ORGAN_SLOT_HEART), amount (damage to be done), and maximum (currently an arbitrarily large number, can be set so as to limit damage) + * outputs: + * description: If an organ exists in the slot requested, and we are capable of taking damage (we don't have GODMODE on), call the damage proc on that organ. + */ +/mob/living/carbon/adjustOrganLoss(slot, amount, maximum) + var/obj/item/organ/O = getorganslot(slot) + if(O && !(status_flags & GODMODE)) + if(!maximum) + maximum = O.maxHealth + O.applyOrganDamage(amount, maximum) + O.onDamage(amount, maximum) + +/** setOrganLoss + * inputs: slot (organ slot, like ORGAN_SLOT_HEART), amount(damage to be set to) + * outputs: + * description: If an organ exists in the slot requested, and we are capable of taking damage (we don't have GODMODE on), call the set damage proc on that organ, which can + * set or clear the failing variable on that organ, making it either cease or start functions again, unlike adjustOrganLoss. + */ +/mob/living/carbon/setOrganLoss(slot, amount) + var/obj/item/organ/O = getorganslot(slot) + if(O && !(status_flags & GODMODE)) + O.setOrganDamage(amount) + O.onSetDamage(amount) + +/** getOrganLoss + * inputs: slot (organ slot, like ORGAN_SLOT_HEART) + * outputs: organ damage + * description: If an organ exists in the slot requested, return the amount of damage that organ has + */ +/mob/living/carbon/getOrganLoss(slot) + var/obj/item/organ/O = getorganslot(slot) + if(O) + return O.damage + +/mob/living/carbon/proc/adjustAllOrganLoss(amount, maximum) + for(var/obj/item/organ/O in internal_organs) + if(O && !(status_flags & GODMODE)) + continue + if(!maximum) + maximum = O.maxHealth + O.applyOrganDamage(amount, maximum) + O.onDamage(amount, maximum) + + //////////////////////////////////////////// //Returns a list of damaged bodyparts @@ -213,24 +257,25 @@ update_damage_overlays() update_stamina() -/mob/living/carbon/getBrainLoss() +/* TO_REMOVE +/mob/living/carbon/getOrganLoss(ORGAN_SLOT_BRAIN) . = 0 var/obj/item/organ/brain/B = getorganslot(ORGAN_SLOT_BRAIN) if(B) . = B.get_brain_damage() //Some sources of brain damage shouldn't be deadly -/mob/living/carbon/adjustBrainLoss(amount, maximum = BRAIN_DAMAGE_DEATH) +/mob/living/carbon/adjustOrganLoss(ORGAN_SLOT_BRAIN, amount, maximum = BRAIN_DAMAGE_DEATH) if(status_flags & GODMODE) return FALSE - var/prev_brainloss = getBrainLoss() + var/prev_brainloss = getOrganLoss(ORGAN_SLOT_BRAIN) var/obj/item/organ/brain/B = getorganslot(ORGAN_SLOT_BRAIN) if(!B) return B.adjust_brain_damage(amount, maximum) if(amount <= 0) //cut this early return - var/brainloss = getBrainLoss() + var/brainloss = getOrganLoss(ORGAN_SLOT_BRAIN) if(brainloss > BRAIN_DAMAGE_MILD) if(prob(amount * ((2 * (100 + brainloss - BRAIN_DAMAGE_MILD)) / 100))) //Base chance is the hit damage; for every point of damage past the threshold the chance is increased by 2% gain_trauma_type(BRAIN_TRAUMA_MILD) @@ -253,3 +298,4 @@ if(B) var/adjusted_amount = amount - B.get_brain_damage() B.adjust_brain_damage(adjusted_amount, null) +*/ diff --git a/code/modules/mob/living/carbon/examine.dm b/code/modules/mob/living/carbon/examine.dm index 22da46346c..c029eac12b 100644 --- a/code/modules/mob/living/carbon/examine.dm +++ b/code/modules/mob/living/carbon/examine.dm @@ -91,6 +91,7 @@ if(combatmode) msg += "[t_He] [t_is] visibly tense[resting ? "." : ", and [t_is] standing in combative stance."]\n" + msg += common_trait_examine() GET_COMPONENT_FROM(mood, /datum/component/mood, src) if(mood) diff --git a/code/modules/mob/living/carbon/human/dummy.dm b/code/modules/mob/living/carbon/human/dummy.dm index 3406d29b3a..6da188dd2d 100644 --- a/code/modules/mob/living/carbon/human/dummy.dm +++ b/code/modules/mob/living/carbon/human/dummy.dm @@ -4,6 +4,7 @@ status_flags = GODMODE|CANPUSH mouse_drag_pointer = MOUSE_INACTIVE_POINTER var/in_use = FALSE + no_vore = TRUE INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy) diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index 8550a0887f..6ebc4f8a32 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -247,7 +247,7 @@ if(DISGUST_LEVEL_DISGUSTED to INFINITY) msg += "[t_He] look[p_s()] extremely disgusted.\n" - if(blood_volume < BLOOD_VOLUME_SAFE) + if(blood_volume < (BLOOD_VOLUME_SAFE*blood_ratio)) msg += "[t_He] [t_has] pale skin.\n" if(bleedsuppress) @@ -281,6 +281,13 @@ if(91.01 to INFINITY) msg += "[t_He] [t_is] a shitfaced, slobbering wreck.\n" + if(reagents.has_reagent("astral")) + msg += "[t_He] have wild, spacey eyes" + if(mind) + msg += " and have a strange, abnormal look to them.\n" + else + msg += " and don't look like they're all there.\n" + if(isliving(user)) var/mob/living/L = user if(src != user && HAS_TRAIT(L, TRAIT_EMPATH) && !appears_dead) @@ -304,6 +311,13 @@ msg += "" + var/obj/item/organ/vocal_cords/Vc = user.getorganslot(ORGAN_SLOT_VOICE) + if(Vc) + if(istype(Vc, /obj/item/organ/vocal_cords/velvet)) + if(client?.prefs.lewdchem) + msg += "You feel your chords resonate looking at them.\n" + + if(!appears_dead) if(stat == UNCONSCIOUS) msg += "[t_He] [t_is]n't responding to anything around [t_him] and seem[p_s()] to be asleep.\n" @@ -321,6 +335,8 @@ if(digitalcamo) msg += "[t_He] [t_is] moving [t_his] body in an unnatural and blatantly inhuman manner.\n" + msg += common_trait_examine() + var/traitstring = get_trait_string() if(ishuman(user)) var/mob/living/carbon/human/H = user diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 69926f46f9..02e6043462 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -802,6 +802,11 @@ else hud_used.healthdoll.icon_state = "healthdoll_DEAD" + if(hud_used.staminas) + hud_used.staminas.icon_state = staminahudamount() + if(hud_used.staminabuffer) + hud_used.staminabuffer.icon_state = staminabufferhudamount() + /mob/living/carbon/human/fully_heal(admin_revive = 0) if(admin_revive) regenerate_limbs() @@ -812,6 +817,8 @@ for(var/datum/mutation/human/HM in dna.mutations) if(HM.quality != POSITIVE) dna.remove_mutation(HM.name) + if(blood_volume < (BLOOD_VOLUME_NORMAL*blood_ratio)) + blood_volume = (BLOOD_VOLUME_NORMAL*blood_ratio) ..() /mob/living/carbon/human/check_weakness(obj/item/weapon, mob/living/attacker) @@ -852,52 +859,84 @@ .["Copy outfit"] = "?_src_=vars;[HrefToken()];copyoutfit=[REF(src)]" /mob/living/carbon/human/MouseDrop_T(mob/living/target, mob/living/user) - //If they dragged themselves and we're currently aggressively grabbing them try to piggyback - if(user == target && can_piggyback(target) && pulling == target && (HAS_TRAIT(src, TRAIT_PACIFISM) || grab_state >= GRAB_AGGRESSIVE) && stat == CONSCIOUS) - buckle_mob(target,TRUE,TRUE) + if(pulling == target && grab_state >= GRAB_AGGRESSIVE && stat == CONSCIOUS) + //If they dragged themselves and we're currently aggressively grabbing them try to piggyback + if(user == target && can_piggyback(target)) + piggyback(target) + return + //If you dragged them to you and you're aggressively grabbing try to fireman carry them + else if(user != target) + fireman_carry(target) + return . = ..() -/mob/living/carbon/human/proc/piggyback_instant(mob/living/M) - return buckle_mob(M, TRUE, TRUE, FALSE, TRUE) +//src is the user that will be carrying, target is the mob to be carried +/mob/living/carbon/human/proc/can_piggyback(mob/living/carbon/target) + return (istype(target) && target.stat == CONSCIOUS) -//Can C try to piggyback at all. -/mob/living/carbon/human/proc/can_piggyback(mob/living/carbon/C) - if(istype(C) && C.stat == CONSCIOUS) - return TRUE - return FALSE +/mob/living/carbon/human/proc/can_be_firemanned(mob/living/carbon/target) + return (ishuman(target) && target.lying) -/mob/living/carbon/human/buckle_mob(mob/living/M, force = FALSE, check_loc = TRUE, bypass_piggybacking = FALSE, no_delay = FALSE) +/mob/living/carbon/human/proc/fireman_carry(mob/living/carbon/target) + if(can_be_firemanned(target)) + visible_message("[src] starts lifting [target] onto their back...", + "You start lifting [target] onto your back...") + if(do_after(src, 30, TRUE, target)) + //Second check to make sure they're still valid to be carried + if(can_be_firemanned(target) && !incapacitated(FALSE, TRUE)) + target.resting = FALSE + buckle_mob(target, TRUE, TRUE, 90, 1, 0) + return + visible_message("[src] fails to fireman carry [target]!") + else + to_chat(src, "You can't fireman carry [target] while they're standing!") + +/mob/living/carbon/human/proc/piggyback(mob/living/carbon/target) + if(can_piggyback(target)) + visible_message("[target] starts to climb onto [src]...") + if(do_after(target, 15, target = src)) + if(can_piggyback(target)) + if(target.incapacitated(FALSE, TRUE) || incapacitated(FALSE, TRUE)) + target.visible_message("[target] can't hang onto [src]!") + return + buckle_mob(target, TRUE, TRUE, FALSE, 0, 2) + else + visible_message("[target] fails to climb onto [src]!") + else + to_chat(target, "You can't piggyback ride [src] right now!") + +/mob/living/carbon/human/buckle_mob(mob/living/target, force = FALSE, check_loc = TRUE, lying_buckle = FALSE, hands_needed = 0, target_hands_needed = 0) if(!force)//humans are only meant to be ridden through piggybacking and special cases return - if(bypass_piggybacking) - return ..() - if(!is_type_in_typecache(M, can_ride_typecache)) - M.visible_message("[M] really can't seem to mount [src]...") + if(!is_type_in_typecache(target, can_ride_typecache)) + target.visible_message("[target] really can't seem to mount [src]...") return + buckle_lying = lying_buckle var/datum/component/riding/human/riding_datum = LoadComponent(/datum/component/riding/human) - riding_datum.ride_check_rider_incapacitated = TRUE - riding_datum.ride_check_rider_restrained = TRUE - riding_datum.set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(0, 6), TEXT_SOUTH = list(0, 6), TEXT_EAST = list(-6, 4), TEXT_WEST = list( 6, 4))) - if(buckled_mobs && ((M in buckled_mobs) || (buckled_mobs.len >= max_buckled_mobs)) || buckled || (M.stat != CONSCIOUS)) + if(target_hands_needed) + riding_datum.ride_check_rider_restrained = TRUE + if(buckled_mobs && ((target in buckled_mobs) || (buckled_mobs.len >= max_buckled_mobs)) || buckled) return - if(can_piggyback(M)) - riding_datum.ride_check_ridden_incapacitated = TRUE - visible_message("[M] starts to climb onto [src]...") - if(no_delay || do_after(M, 15, target = src)) - if(can_piggyback(M)) - if(M.incapacitated(FALSE, TRUE) || incapacitated(FALSE, TRUE)) - M.visible_message("[M] can't hang onto [src]!") - return - if(!riding_datum.equip_buckle_inhands(M, 2)) //MAKE SURE THIS IS LAST!! - M.visible_message("[M] can't climb onto [src]!") - return - . = ..(M, force, check_loc) - stop_pulling() - else - visible_message("[M] fails to climb onto [src]!") - else - . = ..(M,force,check_loc) - stop_pulling() + var/equipped_hands_self + var/equipped_hands_target + if(hands_needed) + equipped_hands_self = riding_datum.equip_buckle_inhands(src, hands_needed, target) + if(target_hands_needed) + equipped_hands_target = riding_datum.equip_buckle_inhands(target, target_hands_needed) + + if(hands_needed || target_hands_needed) + if(hands_needed && !equipped_hands_self) + src.visible_message("[src] can't get a grip on [target] because their hands are full!", + "You can't get a grip on [target] because your hands are full!") + return + else if(target_hands_needed && !equipped_hands_target) + target.visible_message("[target] can't get a grip on [src] because their hands are full!", + "You can't get a grip on [src] because your hands are full!") + return + + stop_pulling() + riding_datum.handle_vehicle_layer() + . = ..(target, force, check_loc) /mob/living/carbon/human/proc/is_shove_knockdown_blocked() //If you want to add more things that block shove knockdown, extend this for(var/obj/item/clothing/C in get_equipped_items()) //doesn't include pockets @@ -1027,8 +1066,8 @@ /mob/living/carbon/human/species/lizard/ashwalker race = /datum/species/lizard/ashwalker -/mob/living/carbon/human/species/moth - race = /datum/species/moth +/mob/living/carbon/human/species/insect + race = /datum/species/insect /mob/living/carbon/human/species/mush race = /datum/species/mush diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index ff4878aa13..a44779e05e 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -348,10 +348,15 @@ if(temp) var/update = 0 var/dmg = rand(M.force/2, M.force) + var/atom/throw_target = get_edge_target_turf(src, M.dir) switch(M.damtype) if("brute") - if(M.force > 20) - Unconscious(20) + if(M.force > 35) // durand and other heavy mechas + Knockdown(50) + src.throw_at(throw_target, rand(1,5), 7) + else if(M.force >= 20 && !IsKnockdown()) // lightweight mechas like gygax + Knockdown(30) + src.throw_at(throw_target, rand(1,3), 7) update |= temp.receive_damage(dmg, 0) playsound(src, 'sound/weapons/punch4.ogg', 50, 1) if("fire") @@ -746,9 +751,54 @@ if(0 to NUTRITION_LEVEL_STARVING) to_send += "You're starving!\n" + + //TODO: Convert these messages into vague messages, thereby encouraging actual dignosis. + //Compiles then shows the list of damaged organs and broken organs + var/list/broken = list() + var/list/damaged = list() + var/broken_message + var/damaged_message + var/broken_plural + var/damaged_plural + //Sets organs into their proper list + for(var/O in internal_organs) + var/obj/item/organ/organ = O + if(organ.organ_flags & ORGAN_FAILING) + if(broken.len) + broken += ", " + broken += organ.name + else if(organ.damage > organ.low_threshold) + if(damaged.len) + damaged += ", " + damaged += organ.name + //Checks to enforce proper grammar, inserts words as necessary into the list + if(broken.len) + if(broken.len > 1) + broken.Insert(broken.len, "and ") + broken_plural = TRUE + else + var/holder = broken[1] //our one and only element + if(holder[lentext(holder)] == "s") + broken_plural = TRUE + //Put the items in that list into a string of text + for(var/B in broken) + broken_message += B + to_chat(src, " Your [broken_message] [broken_plural ? "are" : "is"] non-functional!") + if(damaged.len) + if(damaged.len > 1) + damaged.Insert(damaged.len, "and ") + damaged_plural = TRUE + else + var/holder = damaged[1] + if(holder[lentext(holder)] == "s") + damaged_plural = TRUE + for(var/D in damaged) + damaged_message += D + to_chat(src, "Your [damaged_message] [damaged_plural ? "are" : "is"] hurt.") + if(roundstart_quirks.len) to_send += "You have these quirks: [get_trait_string()].\n" - + to_chat(src, to_send) else if(wear_suit) diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index a10a205a5f..657c32ba01 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -1,5 +1,5 @@ /mob/living/carbon/human - hud_possible = list(HEALTH_HUD,STATUS_HUD,ID_HUD,WANTED_HUD,IMPLOYAL_HUD,IMPCHEM_HUD,IMPTRACK_HUD, NANITE_HUD, DIAG_NANITE_FULL_HUD,ANTAG_HUD,GLAND_HUD,SENTIENT_DISEASE_HUD) + hud_possible = list(HEALTH_HUD,STATUS_HUD,ID_HUD,WANTED_HUD,IMPLOYAL_HUD,IMPCHEM_HUD,IMPTRACK_HUD, NANITE_HUD, DIAG_NANITE_FULL_HUD,ANTAG_HUD,GLAND_HUD,SENTIENT_DISEASE_HUD,RAD_HUD) hud_type = /datum/hud/human possible_a_intents = list(INTENT_HELP, INTENT_DISARM, INTENT_GRAB, INTENT_HARM) pressure_resistance = 25 @@ -17,6 +17,10 @@ //Eye colour var/eye_color = "000" + var/horn_color = "85615a" //specific horn colors, because why not? + + var/wing_color = "fff" //wings too + var/skin_tone = "caucasian1" //Skin tone var/lip_style = null //no lipstick by default- arguably misleading, as it could be used for general makeup @@ -25,11 +29,11 @@ var/age = 30 //Player's age var/underwear = "Nude" //Which underwear the player wants - var/undie_color = "#FFFFFF" + var/undie_color = "FFFFFF" var/undershirt = "Nude" //Which undershirt the player wants - var/shirt_color = "#FFFFFF" + var/shirt_color = "FFFFFF" var/socks = "Nude" //Which socks the player wants - var/socks_color = "#FFFFFF" + var/socks_color = "FFFFFF" var/backbag = DBACKPACK //Which backpack type the player has chosen. var/jumpsuit_style = PREF_SUIT //suit/skirt @@ -48,6 +52,7 @@ var/bleedsuppress = 0 //for stopping bloodloss, eventually this will be limb-based like bleeding var/name_override //For temporary visible name changes + var/genital_override = FALSE //Force genitals on things incase of chems var/nameless = FALSE //For drones of both the insectoid and robotic kind. And other types of nameless critters. diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index 1af9dbc5f5..9395283aeb 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -39,6 +39,10 @@ //Stuff jammed in your limbs hurts handle_embedded_objects() + if(stat != DEAD) + //process your dick energy + handle_arousal() + //Update our name based on whether our face is obscured/disfigured name = get_visible_name() @@ -54,7 +58,7 @@ var/obj/item/clothing/CH = head if (CS.clothing_flags & CH.clothing_flags & STOPSPRESSUREDAMAGE) return ONE_ATMOSPHERE - if(istype(loc, /obj/belly)) //START OF CIT CHANGES - Makes it so you don't suffocate while inside vore organs. Remind me to modularize this some time - Bhijn + if(isbelly(loc)) //START OF CIT CHANGES - Makes it so you don't suffocate while inside vore organs. Remind me to modularize this some time - Bhijn return ONE_ATMOSPHERE if(istype(loc, /obj/item/dogborg/sleeper)) return ONE_ATMOSPHERE //END OF CIT CHANGES @@ -70,7 +74,7 @@ else if(eye_blurry) //blurry eyes heal slowly adjust_blurriness(-1) - if (getBrainLoss() >= 30) //Citadel change to make memes more often. + if (getOrganLoss(ORGAN_SLOT_BRAIN) >= 30) //Citadel change to make memes more often. SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "brain_damage", /datum/mood_event/brain_damage) if(prob(3)) if(prob(25)) diff --git a/code/modules/mob/living/carbon/human/login.dm b/code/modules/mob/living/carbon/human/login.dm deleted file mode 100644 index 1ac24cffa9..0000000000 --- a/code/modules/mob/living/carbon/human/login.dm +++ /dev/null @@ -1,9 +0,0 @@ -/mob/living/carbon/human/Login() - ..() - if(src.martial_art == default_martial_art && mind.stored_martial_art) //If the mind has a martial art stored and the body has the default one. - src.mind.stored_martial_art.teach(src) //Running teach so that it deals with help verbs. - else if(src.martial_art != default_martial_art && src.martial_art != mind.stored_martial_art) //If the body has a martial art which is not the default one and is not stored in the mind. - if(src.martial_art_owner != mind) - src.martial_art.remove(src) - else - src.mind.stored_martial_art = src.martial_art diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 076b8efb66..a59d9e914b 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -1,6 +1,7 @@ // This code handles different species in the game. GLOBAL_LIST_EMPTY(roundstart_races) +GLOBAL_LIST_EMPTY(roundstart_race_names) /datum/species var/id // if the game needs to manually check your race to do something not included in a proc here, it will use this @@ -8,13 +9,36 @@ GLOBAL_LIST_EMPTY(roundstart_races) var/name // this is the fluff name. these will be left generic (such as 'Lizardperson' for the lizard race) so servers can change them to whatever var/default_color = "#FFF" // if alien colors are disabled, this is the color that will be used by that race - var/sexes = 1 // whether or not the race has sexual characteristics. at the moment this is only 0 for skeletons and shadows + var/sexes = 1 // whether or not the race has sexual characteristics. at the moment this is only 0 for skeletons and shadows - var/list/offset_features = list(OFFSET_UNIFORM = list(0,0), OFFSET_ID = list(0,0), OFFSET_GLOVES = list(0,0), OFFSET_GLASSES = list(0,0), OFFSET_EARS = list(0,0), OFFSET_SHOES = list(0,0), OFFSET_S_STORE = list(0,0), OFFSET_FACEMASK = list(0,0), OFFSET_HEAD = list(0,0), OFFSET_FACE = list(0,0), OFFSET_BELT = list(0,0), OFFSET_BACK = list(0,0), OFFSET_SUIT = list(0,0), OFFSET_NECK = list(0,0)) + //Species Icon Drawing Offsets - Pixel X, Pixel Y, Aka X = Horizontal and Y = Vertical, from bottom left corner + var/list/offset_features = list( + OFFSET_UNIFORM = list(0,0), + OFFSET_ID = list(0,0), + OFFSET_GLOVES = list(0,0), + OFFSET_GLASSES = list(0,0), + OFFSET_EARS = list(0,0), + OFFSET_SHOES = list(0,0), + OFFSET_S_STORE = list(0,0), + OFFSET_FACEMASK = list(0,0), + OFFSET_HEAD = list(0,0), + OFFSET_EYES = list(0,0), + OFFSET_LIPS = list(0,0), + OFFSET_BELT = list(0,0), + OFFSET_BACK = list(0,0), + OFFSET_HAIR = list(0,0), + OFFSET_FHAIR = list(0,0), + OFFSET_SUIT = list(0,0), + OFFSET_NECK = list(0,0), + OFFSET_MUTPARTS = list(0,0) + ) var/hair_color // this allows races to have specific hair colors... if null, it uses the H's hair/facial hair colors. if "mutcolor", it uses the H's mutant_color var/hair_alpha = 255 // the alpha used by the hair. 255 is completely solid, 0 is transparent. + var/horn_color //specific horn colors, because why not? + var/wing_color + var/use_skintones = 0 // does it use skintones or not? (spoiler alert this is only used by humans) var/exotic_blood = "" // If your race wants to bleed something other than bog standard blood, change this to reagent id. var/exotic_bloodtype = "" //If your race uses a non standard bloodtype (A+, O-, AB-, etc) @@ -79,7 +103,7 @@ GLOBAL_LIST_EMPTY(roundstart_races) var/fixed_mut_color3 = "" var/whitelisted = 0 //Is this species restricted to certain players? var/whitelist = list() //List the ckeys that can use this species, if it's whitelisted.: list("John Doe", "poopface666", "SeeALiggerPullTheTrigger") Spaces & capitalization can be included or ignored entirely for each key as it checks for both. - + var/should_draw_citadel = FALSE /////////// // PROCS // @@ -98,6 +122,7 @@ GLOBAL_LIST_EMPTY(roundstart_races) var/datum/species/S = new I if(S.check_roundstart_eligible()) GLOB.roundstart_races += S.id + GLOB.roundstart_race_names["[S.name]"] = S.id qdel(S) if(!GLOB.roundstart_races.len) GLOB.roundstart_races += "human" @@ -129,10 +154,10 @@ GLOBAL_LIST_EMPTY(roundstart_races) return //Please override this locally if you want to define when what species qualifies for what rank if human authority is enforced. -/datum/species/proc/qualifies_for_rank(rank, list/features) - if(rank in GLOB.command_positions) - return 0 - return 1 +/datum/species/proc/qualifies_for_rank(rank, list/features) //SPECIES JOB RESTRICTIONS + //if(rank in GLOB.command_positions) Left as an example: The format qualifies for rank takes. + // return 0 //It returns false when it runs the proc so they don't get jobs from the global list. + return 1 //It returns 1 to say they are a-okay to continue. //Will regenerate missing organs /datum/species/proc/regenerate_organs(mob/living/carbon/C,datum/species/old_species,replace_current=TRUE) @@ -260,7 +285,7 @@ GLOBAL_LIST_EMPTY(roundstart_races) C.hud_used.update_locked_slots() // this needs to be FIRST because qdel calls update_body which checks if we have DIGITIGRADE legs or not and if not then removes DIGITIGRADE from species_traits - if(("legs" in C.dna.species.mutant_bodyparts) && C.dna.features["legs"] == "Digitigrade Legs") + if(("legs" in C.dna.species.mutant_bodyparts) && (C.dna.features["legs"] == "Digitigrade" || C.dna.features["legs"] == "Avian")) species_traits += DIGITIGRADE if(DIGITIGRADE in species_traits) C.Digitigrade_Leg_Swap(FALSE) @@ -294,8 +319,6 @@ GLOBAL_LIST_EMPTY(roundstart_races) for(var/datum/disease/A in C.diseases) A.cure(FALSE) - SEND_SIGNAL(C, COMSIG_SPECIES_GAIN, src, old_species) - //CITADEL EDIT if(NOAROUSAL in species_traits) C.canbearoused = FALSE @@ -306,6 +329,11 @@ GLOBAL_LIST_EMPTY(roundstart_races) var/mob/living/carbon/human/H = C if(NOGENITALS in H.dna.species.species_traits) H.give_genitals(TRUE) //call the clean up proc to delete anything on the mob then return. + if("meat_type" in default_features) //I can't believe it's come to the meat + H.type_of_meat = GLOB.meat_types[H.dna.features["meat_type"]] + + SEND_SIGNAL(C, COMSIG_SPECIES_GAIN, src, old_species) + // EDIT ENDS @@ -317,6 +345,11 @@ GLOBAL_LIST_EMPTY(roundstart_races) for(var/X in inherent_traits) REMOVE_TRAIT(C, X, SPECIES_TRAIT) + if("meat_type" in default_features) + C.type_of_meat = GLOB.meat_types[C.dna.features["meat_type"]] + else + C.type_of_meat = initial(meat) + SEND_SIGNAL(C, COMSIG_SPECIES_LOSS, src) /datum/species/proc/handle_hair(mob/living/carbon/human/H, forced_colour) @@ -389,6 +422,10 @@ GLOBAL_LIST_EMPTY(roundstart_races) facial_overlay.alpha = hair_alpha + if(OFFSET_FHAIR in H.dna.species.offset_features) + facial_overlay.pixel_x += H.dna.species.offset_features[OFFSET_FHAIR][1] + facial_overlay.pixel_y += H.dna.species.offset_features[OFFSET_FHAIR][2] + standing += facial_overlay if(H.head) @@ -446,9 +483,11 @@ GLOBAL_LIST_EMPTY(roundstart_races) else hair_overlay.color = forced_colour hair_overlay.alpha = hair_alpha - if(OFFSET_FACE in H.dna.species.offset_features) - hair_overlay.pixel_x += H.dna.species.offset_features[OFFSET_FACE][1] - hair_overlay.pixel_y += H.dna.species.offset_features[OFFSET_FACE][2] + + if(OFFSET_HAIR in H.dna.species.offset_features) + hair_overlay.pixel_x += H.dna.species.offset_features[OFFSET_HAIR][1] + hair_overlay.pixel_y += H.dna.species.offset_features[OFFSET_HAIR][2] + if(hair_overlay.icon) standing += hair_overlay @@ -469,9 +508,11 @@ GLOBAL_LIST_EMPTY(roundstart_races) if(H.lip_style && (LIPS in species_traits)) var/mutable_appearance/lip_overlay = mutable_appearance('icons/mob/human_face.dmi', "lips_[H.lip_style]", -BODY_LAYER) lip_overlay.color = H.lip_color - if(OFFSET_FACE in H.dna.species.offset_features) - lip_overlay.pixel_x += H.dna.species.offset_features[OFFSET_FACE][1] - lip_overlay.pixel_y += H.dna.species.offset_features[OFFSET_FACE][2] + + if(OFFSET_LIPS in H.dna.species.offset_features) + lip_overlay.pixel_x += H.dna.species.offset_features[OFFSET_LIPS][1] + lip_overlay.pixel_y += H.dna.species.offset_features[OFFSET_LIPS][2] + standing += lip_overlay // eyes @@ -484,9 +525,11 @@ GLOBAL_LIST_EMPTY(roundstart_races) eye_overlay = mutable_appearance('icons/mob/human_face.dmi', "eyes", -BODY_LAYER) if((EYECOLOR in species_traits) && has_eyes) eye_overlay.color = "#" + H.eye_color - if(OFFSET_FACE in H.dna.species.offset_features) - eye_overlay.pixel_x += H.dna.species.offset_features[OFFSET_FACE][1] - eye_overlay.pixel_y += H.dna.species.offset_features[OFFSET_FACE][2] + + if(OFFSET_EYES in H.dna.species.offset_features) + eye_overlay.pixel_x += H.dna.species.offset_features[OFFSET_EYES][1] + eye_overlay.pixel_y += H.dna.species.offset_features[OFFSET_EYES][2] + standing += eye_overlay //Underwear, Undershirts & Socks @@ -500,7 +543,7 @@ GLOBAL_LIST_EMPTY(roundstart_races) if(B) var/mutable_appearance/MA = mutable_appearance(B.icon, B.icon_state, -BODY_LAYER) if(UNDIE_COLORABLE(B)) - MA.color = H.undie_color + MA.color = "#[H.undie_color]" standing += MA if(H.undershirt) @@ -516,7 +559,7 @@ GLOBAL_LIST_EMPTY(roundstart_races) else MA = mutable_appearance(T.icon, T.icon_state, -BODY_LAYER) if(UNDIE_COLORABLE(T)) - MA.color = H.shirt_color + MA.color = "#[H.shirt_color]" standing += MA if(H.socks && H.get_num_legs(FALSE) >= 2) @@ -529,7 +572,7 @@ GLOBAL_LIST_EMPTY(roundstart_races) var/digilegs = (DIGITIGRADE in species_traits) ? "_d" : "" var/mutable_appearance/MA = mutable_appearance(S.icon, "[S.icon_state][digilegs]", -BODY_LAYER) if(UNDIE_COLORABLE(S)) - MA.color = H.socks_color + MA.color = "#[H.socks_color]" standing += MA if(standing.len) @@ -612,6 +655,10 @@ GLOBAL_LIST_EMPTY(roundstart_races) else if ("wings" in mutant_bodyparts) bodyparts_to_add -= "wings_open" + if("insect_fluff" in mutant_bodyparts) + if(!H.dna.features["insect_fluff"] || H.dna.features["insect_fluff"] == "None" || H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT)) + bodyparts_to_add -= "insect_fluff" + //CITADEL EDIT //Race specific bodyparts: //Xenos @@ -715,10 +762,14 @@ GLOBAL_LIST_EMPTY(roundstart_races) S = GLOB.wings_list[H.dna.features["wings"]] if("wingsopen") S = GLOB.wings_open_list[H.dna.features["wings"]] + if("deco_wings") + S = GLOB.deco_wings_list[H.dna.features["deco_wings"]] if("legs") S = GLOB.legs_list[H.dna.features["legs"]] - if("moth_wings") - S = GLOB.moth_wings_list[H.dna.features["moth_wings"]] + if("insect_wings") + S = GLOB.insect_wings_list[H.dna.features["insect_wings"]] + if("insect_fluff") + S = GLOB.insect_fluffs_list[H.dna.features["insect_fluff"]] if("caps") S = GLOB.caps_list[H.dna.features["caps"]] if("ipc_screen") @@ -764,6 +815,8 @@ GLOBAL_LIST_EMPTY(roundstart_races) bodypart = "snout" if(bodypart == "xenohead") bodypart = "xhead" + if(bodypart == "insect_wings" || bodypart == "deco_wings") + bodypart = "insect_wings" if(S.gender_specific) accessory_overlay.icon_state = "[g]_[bodypart]_[S.icon_state]_[layertext]" @@ -815,6 +868,10 @@ GLOBAL_LIST_EMPTY(roundstart_races) accessory_overlay.color = "#[H.facial_hair_color]" if(EYECOLOR) accessory_overlay.color = "#[H.eye_color]" + if(HORNCOLOR) + accessory_overlay.color = "#[H.horn_color]" + if(WINGCOLOR) + accessory_overlay.color = "#[H.wing_color]" else accessory_overlay.color = forced_colour else @@ -831,6 +888,11 @@ GLOBAL_LIST_EMPTY(roundstart_races) for(var/index=1, index<=husklist.len, index++) husklist[index] = husklist[index]/255 accessory_overlay.color = husklist + + if(OFFSET_MUTPARTS in H.dna.species.offset_features) + accessory_overlay.pixel_x += H.dna.species.offset_features[OFFSET_MUTPARTS][1] + accessory_overlay.pixel_y += H.dna.species.offset_features[OFFSET_MUTPARTS][2] + standing += accessory_overlay if(S.hasinner) @@ -843,6 +905,10 @@ GLOBAL_LIST_EMPTY(roundstart_races) if(S.center) inner_accessory_overlay = center_image(inner_accessory_overlay, S.dimension_x, S.dimension_y) + if(OFFSET_MUTPARTS in H.dna.species.offset_features) + inner_accessory_overlay.pixel_x += H.dna.species.offset_features[OFFSET_MUTPARTS][1] + inner_accessory_overlay.pixel_y += H.dna.species.offset_features[OFFSET_MUTPARTS][2] + standing += inner_accessory_overlay if(S.extra) //apply the extra overlay, if there is one @@ -880,6 +946,16 @@ GLOBAL_LIST_EMPTY(roundstart_races) extra_accessory_overlay.color = "#[H.facial_hair_color]" if(EYECOLOR) extra_accessory_overlay.color = "#[H.eye_color]" + + if(HORNCOLOR) + extra_accessory_overlay.color = "#[H.horn_color]" + if(WINGCOLOR) + extra_accessory_overlay.color = "#[H.wing_color]" + + if(OFFSET_MUTPARTS in H.dna.species.offset_features) + extra_accessory_overlay.pixel_x += H.dna.species.offset_features[OFFSET_MUTPARTS][1] + extra_accessory_overlay.pixel_y += H.dna.species.offset_features[OFFSET_MUTPARTS][2] + standing += extra_accessory_overlay if(S.extra2) //apply the extra overlay, if there is one @@ -912,6 +988,15 @@ GLOBAL_LIST_EMPTY(roundstart_races) extra2_accessory_overlay.color = "#[H.dna.features["mcolor"]]" else extra2_accessory_overlay.color = "#[H.hair_color]" + if(HORNCOLOR) + extra2_accessory_overlay.color = "#[H.horn_color]" + if(WINGCOLOR) + extra2_accessory_overlay.color = "#[H.wing_color]" + + if(OFFSET_MUTPARTS in H.dna.species.offset_features) + extra2_accessory_overlay.pixel_x += H.dna.species.offset_features[OFFSET_MUTPARTS][1] + extra2_accessory_overlay.pixel_y += H.dna.species.offset_features[OFFSET_MUTPARTS][2] + standing += extra2_accessory_overlay @@ -1196,9 +1281,14 @@ GLOBAL_LIST_EMPTY(roundstart_races) if(mood && mood.sanity > SANITY_DISTURBED) hunger_rate *= max(0.5, 1 - 0.002 * mood.sanity) //0.85 to 0.75 - if(H.satiety > 0) + // Whether we cap off our satiety or move it towards 0 + if(H.satiety > MAX_SATIETY) + H.satiety = MAX_SATIETY + else if(H.satiety > 0) H.satiety-- - if(H.satiety < 0) + else if(H.satiety < -MAX_SATIETY) + H.satiety = -MAX_SATIETY + else if(H.satiety < 0) H.satiety++ if(prob(round(-H.satiety/40))) H.Jitter(5) @@ -1314,9 +1404,9 @@ GLOBAL_LIST_EMPTY(roundstart_races) if(!istype(J) && istype(C)) J = C.jetpack if(istype(J) && J.full_speed && J.allow_thrust(0.01, H)) //Prevents stacking - . -= 2 + . -= 0.4 else if(istype(T) && T.allow_thrust(0.01, H)) - . -= 2 + . -= 0.4 if(!ignoreslow && gravity) if(H.wear_suit) @@ -1683,7 +1773,7 @@ GLOBAL_LIST_EMPTY(roundstart_races) if(BODY_ZONE_HEAD) if(!I.is_sharp() && armor_block < 50) if(prob(I.force)) - H.adjustBrainLoss(20) + H.adjustOrganLoss(ORGAN_SLOT_BRAIN, 20) if(H.stat == CONSCIOUS) H.visible_message("[H] has been knocked senseless!", \ "[H] has been knocked senseless!") @@ -1692,11 +1782,11 @@ GLOBAL_LIST_EMPTY(roundstart_races) if(prob(10)) H.gain_trauma(/datum/brain_trauma/mild/concussion) else - H.adjustBrainLoss(I.force * 0.2) + H.adjustOrganLoss(ORGAN_SLOT_BRAIN, I.force * 0.2) if(H.stat == CONSCIOUS && H != user && prob(I.force + ((100 - H.health) * 0.5))) // rev deconversion through blunt trauma. var/datum/antagonist/rev/rev = H.mind.has_antag_datum(/datum/antagonist/rev) - var/datum/antagonist/gang/gang = H.mind.has_antag_datum(/datum/antagonist/gang/) + var/datum/antagonist/gang/gang = H.mind.has_antag_datum(/datum/antagonist/gang && !/datum/antagonist/gang/boss) if(rev) rev.remove_revolutionary(FALSE, user) if(gang) @@ -1732,6 +1822,130 @@ GLOBAL_LIST_EMPTY(roundstart_races) H.forcesay(GLOB.hit_appends) //forcesay checks stat already. return TRUE +/datum/species/proc/alt_spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style) + if(!istype(M)) + return TRUE + CHECK_DNA_AND_SPECIES(M) + CHECK_DNA_AND_SPECIES(H) + + if(!istype(M)) //sanity check for drones. + return TRUE + if(M.mind) + attacker_style = M.mind.martial_art + if((M != H) && M.a_intent != INTENT_HELP && H.check_shields(M, 0, M.name, attack_type = UNARMED_ATTACK)) + log_combat(M, H, "attempted to touch") + H.visible_message("[M] attempted to touch [H]!") + return TRUE + switch(M.a_intent) + if(INTENT_HELP) + if(M == H) + althelp(M, H, attacker_style) + return TRUE + return FALSE + if(INTENT_DISARM) + altdisarm(M, H, attacker_style) + return TRUE + return FALSE + +/datum/species/proc/althelp(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style) + if(user == target && istype(user)) + if(user.getStaminaLoss() >= STAMINA_SOFTCRIT) + to_chat(user, "You're too exhausted for that.") + return + if(!user.resting) + to_chat(user, "You can only force yourself up if you're on the ground.") + return + user.visible_message("[user] forces [p_them()]self up to [p_their()] feet!", "You force yourself up to your feet!") + user.resting = 0 + user.update_canmove() + user.adjustStaminaLossBuffered(user.stambuffer) //Rewards good stamina management by making it easier to instantly get up from resting + playsound(user, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + +/datum/species/proc/altdisarm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style) + if(user.getStaminaLoss() >= STAMINA_SOFTCRIT) + to_chat(user, "You're too exhausted.") + return FALSE + if(target.check_block()) + target.visible_message("[target] blocks [user]'s shoving attempt!") + return FALSE + if(attacker_style && attacker_style.disarm_act(user,target)) + return TRUE + if(user.resting) + return FALSE + else + if(user == target) + return + user.do_attack_animation(target, ATTACK_EFFECT_DISARM) + user.adjustStaminaLossBuffered(4) + playsound(target, 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1) + + if(target.w_uniform) + target.w_uniform.add_fingerprint(user) + SEND_SIGNAL(target, COMSIG_HUMAN_DISARM_HIT, user, user.zone_selected) + + if(!target.resting) + target.adjustStaminaLoss(5) + + if(target.is_shove_knockdown_blocked()) + return + + var/turf/target_oldturf = target.loc + var/shove_dir = get_dir(user.loc, target_oldturf) + var/turf/target_shove_turf = get_step(target.loc, shove_dir) + var/mob/living/carbon/human/target_collateral_human + var/shove_blocked = FALSE //Used to check if a shove is blocked so that if it is knockdown logic can be applied + + //Thank you based whoneedsspace + target_collateral_human = locate(/mob/living/carbon/human) in target_shove_turf.contents + if(target_collateral_human && !target_collateral_human.resting) + shove_blocked = TRUE + else + target_collateral_human = null + target.Move(target_shove_turf, shove_dir) + if(get_turf(target) == target_oldturf) + shove_blocked = TRUE + + if(shove_blocked && !target.buckled) + var/directional_blocked = !target.Adjacent(target_shove_turf) + var/targetatrest = target.resting + if((directional_blocked || !(target_collateral_human || target_shove_turf.shove_act(target, user))) && !targetatrest) + target.Knockdown(SHOVE_KNOCKDOWN_SOLID) + user.visible_message("[user.name] shoves [target.name], knocking them down!", + "You shove [target.name], knocking them down!", null, COMBAT_MESSAGE_RANGE) + log_combat(user, target, "shoved", "knocking them down") + else if(target_collateral_human && !targetatrest) + target.Knockdown(SHOVE_KNOCKDOWN_HUMAN) + target_collateral_human.Knockdown(SHOVE_KNOCKDOWN_COLLATERAL) + user.visible_message("[user.name] shoves [target.name] into [target_collateral_human.name]!", + "You shove [target.name] into [target_collateral_human.name]!", null, COMBAT_MESSAGE_RANGE) + log_combat(user, target, "shoved", "into [target_collateral_human.name]") + + else + user.visible_message("[user.name] shoves [target.name]!", + "You shove [target.name]!", null, COMBAT_MESSAGE_RANGE) + var/target_held_item = target.get_active_held_item() + var/knocked_item = FALSE + if(!is_type_in_typecache(target_held_item, GLOB.shove_disarming_types)) + target_held_item = null + if(!target.has_movespeed_modifier(SHOVE_SLOWDOWN_ID)) + target.add_movespeed_modifier(SHOVE_SLOWDOWN_ID, multiplicative_slowdown = SHOVE_SLOWDOWN_STRENGTH) + if(target_held_item) + target.visible_message("[target.name]'s grip on \the [target_held_item] loosens!", + "Your grip on \the [target_held_item] loosens!", null, COMBAT_MESSAGE_RANGE) + addtimer(CALLBACK(target, /mob/living/carbon/human/proc/clear_shove_slowdown), SHOVE_SLOWDOWN_LENGTH) + else if(target_held_item) + target.dropItemToGround(target_held_item) + knocked_item = TRUE + target.visible_message("[target.name] drops \the [target_held_item]!!", + "You drop \the [target_held_item]!!", null, COMBAT_MESSAGE_RANGE) + var/append_message = "" + if(target_held_item) + if(knocked_item) + append_message = "causing them to drop [target_held_item]" + else + append_message = "loosening their grip on [target_held_item]" + log_combat(user, target, "shoved", append_message) + /datum/species/proc/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked, mob/living/carbon/human/H) var/hit_percent = (100-(blocked+armor))/100 hit_percent = (hit_percent * (100-H.physiology.damage_resistance))/100 @@ -1781,14 +1995,13 @@ GLOBAL_LIST_EMPTY(roundstart_races) if(CLONE) H.adjustCloneLoss(damage * hit_percent * H.physiology.clone_mod) if(STAMINA) - H.stamdamageoverlaytemp = 20 if(BP) if(damage > 0 ? BP.receive_damage(0, 0, damage * hit_percent * H.physiology.stamina_mod) : BP.heal_damage(0, 0, abs(damage * hit_percent * H.physiology.stamina_mod), only_robotic = FALSE, only_organic = FALSE)) H.update_stamina() else H.adjustStaminaLoss(damage * hit_percent * H.physiology.stamina_mod) if(BRAIN) - H.adjustBrainLoss(damage * hit_percent * H.physiology.brain_mod) + H.adjustOrganLoss(ORGAN_SLOT_BRAIN, damage * hit_percent * H.physiology.brain_mod) if(AROUSAL) //Citadel edit - arousal H.adjustArousalLoss(damage * hit_percent) return 1 diff --git a/code/modules/mob/living/carbon/human/species_types/abductors.dm b/code/modules/mob/living/carbon/human/species_types/abductors.dm index ad1f5c9190..ffd129ebf7 100644 --- a/code/modules/mob/living/carbon/human/species_types/abductors.dm +++ b/code/modules/mob/living/carbon/human/species_types/abductors.dm @@ -6,10 +6,6 @@ species_traits = list(NOBLOOD,NOEYES,NOGENITALS,NOAROUSAL) inherent_traits = list(TRAIT_VIRUSIMMUNE,TRAIT_NOGUNS,TRAIT_NOHUNGER,TRAIT_NOBREATH) mutanttongue = /obj/item/organ/tongue/abductor - var/scientist = FALSE // vars to not pollute spieces list with castes - -/datum/species/abductor/copy_properties_from(datum/species/abductor/old_species) - scientist = old_species.scientist /datum/species/abductor/on_species_gain(mob/living/carbon/C, datum/species/old_species) . = ..() diff --git a/code/modules/mob/living/carbon/human/species_types/bugmen.dm b/code/modules/mob/living/carbon/human/species_types/bugmen.dm new file mode 100644 index 0000000000..b4e55b60a5 --- /dev/null +++ b/code/modules/mob/living/carbon/human/species_types/bugmen.dm @@ -0,0 +1,64 @@ +/datum/species/insect + name = "Anthromorphic Insect" + id = "insect" + say_mod = "flutters" + default_color = "00FF00" + species_traits = list(LIPS,NOEYES,HAIR,FACEHAIR,MUTCOLORS,HORNCOLOR,WINGCOLOR) + inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID, MOB_BUG) + mutant_bodyparts = list("mam_ears", "mam_snout", "mam_tail", "taur", "insect_wings", "mam_snouts", "insect_fluff","horns") + default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_tail" = "None", "mam_ears" = "None", + "insect_wings" = "None", "insect_fluff" = "None", "mam_snouts" = "None", "taur" = "None","horns" = "None") + attack_verb = "slash" + attack_sound = 'sound/weapons/slash.ogg' + miss_sound = 'sound/weapons/slashmiss.ogg' + meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/insect + liked_food = VEGETABLES | DAIRY + disliked_food = FRUIT | GROSS + toxic_food = MEAT | RAW + mutanteyes = /obj/item/organ/eyes/insect + should_draw_citadel = TRUE + +/datum/species/insect/on_species_gain(mob/living/carbon/C) + . = ..() + if(ishuman(C)) + var/mob/living/carbon/human/H = C + if(!H.dna.features["insect_wings"]) + H.dna.features["insect_wings"] = "[(H.client && H.client.prefs && LAZYLEN(H.client.prefs.features) && H.client.prefs.features["insect_wings"]) ? H.client.prefs.features["insect_wings"] : "None"]" + handle_mutant_bodyparts(H) + +/datum/species/insect/random_name(gender,unique,lastname) + if(unique) + return random_unique_moth_name() + + var/randname = moth_name() + + if(lastname) + randname += " [lastname]" + + return randname + +/datum/species/insect/handle_fire(mob/living/carbon/human/H, no_protection = FALSE) + ..() + if(H.dna.features["insect_wings"] != "Burnt Off" && H.dna.features["insect_wings"] != "None" && H.bodytemperature >= 800 && H.fire_stacks > 0) //do not go into the extremely hot light. you will not survive + to_chat(H, "Your precious wings burn to a crisp!") + if(H.dna.features["insect_wings"] != "None") + H.dna.features["insect_wings"] = "Burnt Off" + handle_mutant_bodyparts(H) + +/datum/species/insect/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H) + . = ..() + if(chem.id == "pestkiller") + H.adjustToxLoss(3) + H.reagents.remove_reagent(chem.id, REAGENTS_METABOLISM) + +/datum/species/insect/check_weakness(obj/item/weapon, mob/living/attacker) + if(istype(weapon, /obj/item/melee/flyswatter)) + return 9 //flyswatters deal 10x damage to insects + return 0 + +/datum/species/insect/space_move(mob/living/carbon/human/H) + . = ..() + if(H.loc && !isspaceturf(H.loc) && (H.dna.features["insect_wings"] != "Burnt Off" && H.dna.features["insect_wings"] != "None")) + var/datum/gas_mixture/current = H.loc.return_air() + if(current && (current.return_pressure() >= ONE_ATMOSPHERE*0.85)) //as long as there's reasonable pressure and no gravity, flight is possible + return TRUE diff --git a/code/modules/mob/living/carbon/human/species_types/corporate.dm b/code/modules/mob/living/carbon/human/species_types/corporate.dm index 620f0b2543..146090b366 100644 --- a/code/modules/mob/living/carbon/human/species_types/corporate.dm +++ b/code/modules/mob/living/carbon/human/species_types/corporate.dm @@ -16,5 +16,5 @@ blacklisted = 1 use_skintones = 0 species_traits = list(NOBLOOD,EYECOLOR,NOGENITALS) - inherent_traits = list(TRAIT_RADIMMUNE,TRAIT_VIRUSIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOHUNGER) + inherent_traits = list(TRAIT_RADIMMUNE,TRAIT_VIRUSIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOLIMBDISABLE,TRAIT_NOHUNGER) sexes = 0 \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/species_types/dullahan.dm b/code/modules/mob/living/carbon/human/species_types/dullahan.dm index 4a7580e978..eba4ff6d2f 100644 --- a/code/modules/mob/living/carbon/human/species_types/dullahan.dm +++ b/code/modules/mob/living/carbon/human/species_types/dullahan.dm @@ -13,9 +13,12 @@ blacklisted = TRUE limbs_id = "human" skinned_type = /obj/item/stack/sheet/animalhide/human + var/pumpkin = FALSE var/obj/item/dullahan_relay/myhead +/datum/species/dullahan/pumpkin + pumpkin = TRUE /datum/species/dullahan/check_roundstart_eligible() if(SSevents.holidays && SSevents.holidays[HALLOWEEN]) @@ -27,11 +30,19 @@ H.flags_1 &= ~HEAR_1 var/obj/item/bodypart/head/head = H.get_bodypart(BODY_ZONE_HEAD) if(head) + if(pumpkin)//Pumpkinhead! + head.animal_origin = 100 + head.icon = 'icons/obj/clothing/hats.dmi' + head.icon_state = "hardhat1_pumpkin_j" + head.custom_head = TRUE head.drop_limb() head.flags_1 = HEAR_1 head.throwforce = 25 myhead = new /obj/item/dullahan_relay (head, H) H.put_in_hands(head) + var/obj/item/organ/eyes/E = H.getorganslot(ORGAN_SLOT_EYES) + for(var/datum/action/item_action/organ_action/OA in E.actions) + OA.Trigger() /datum/species/dullahan/on_species_loss(mob/living/carbon/human/H) H.flags_1 |= ~HEAR_1 @@ -64,7 +75,7 @@ /obj/item/organ/brain/dullahan decoy_override = TRUE - vital = FALSE + organ_flags = ORGAN_NO_SPOIL//Do not decay /obj/item/organ/tongue/dullahan zone = "abstract" @@ -138,4 +149,4 @@ D.myhead = null owner.gib() owner = null - ..() \ No newline at end of file + ..() diff --git a/code/modules/mob/living/carbon/human/species_types/dwarves.dm b/code/modules/mob/living/carbon/human/species_types/dwarves.dm new file mode 100644 index 0000000000..946bffbdbc --- /dev/null +++ b/code/modules/mob/living/carbon/human/species_types/dwarves.dm @@ -0,0 +1,192 @@ + +GLOBAL_LIST_INIT(dwarf_first, world.file2list("strings/names/dwarf_first.txt")) //Textfiles with first +GLOBAL_LIST_INIT(dwarf_last, world.file2list("strings/names/dwarf_last.txt")) //textfiles with last + +/datum/species/dwarf //not to be confused with the genetic manlets + name = "Dwarf" + id = "dwarf" //Also called Homo sapiens pumilionis + default_color = "FFFFFF" + species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,NO_UNDERWEAR) + inherent_traits = list() + default_features = list("mcolor" = "FFF", "wings" = "None") + limbs_id = "human" + use_skintones = 1 + say_mod = "bellows" //high energy, EXTRA BIOLOGICAL FUEL + damage_overlay_type = "human" + skinned_type = /obj/item/stack/sheet/animalhide/human + liked_food = ALCOHOL | MEAT | DAIRY //Dwarves like alcohol, meat, and dairy products. + disliked_food = JUNKFOOD | FRIED //Dwarves hate foods that have no nutrition other than alcohol. + mutant_organs = list(/obj/item/organ/dwarfgland) //Dwarven alcohol gland, literal gland warrior + mutantliver = /obj/item/organ/liver/dwarf //Dwarven super liver (Otherwise they r doomed) + +/mob/living/carbon/human/species/dwarf //species admin spawn path + race = /datum/species/dwarf //and the race the path is set to. + +/datum/species/dwarf/check_roundstart_eligible() + if(SSevents.holidays && SSevents.holidays[HALLOWEEN]) + return TRUE + return ..() + +/datum/species/dwarf/on_species_gain(mob/living/carbon/C, datum/species/old_species) + . = ..() + var/dwarf_hair = pick("Beard (Dwarf)", "Beard (Very Long)", "Beard (Long)") //beard roullette + var/mob/living/carbon/human/H = C + H.facial_hair_style = dwarf_hair + H.update_hair() + H.transform = H.transform.Scale(1, 0.8) //We use scale, and yeah. Dwarves can become gnomes with DWARFISM. + RegisterSignal(C, COMSIG_MOB_SAY, .proc/handle_speech) //We register handle_speech is being used. + + +/datum/species/dwarf/on_species_loss(mob/living/carbon/H, datum/species/new_species) + . = ..() + H.transform = H.transform.Scale(1, 1.25) //And we undo it. + UnregisterSignal(H, COMSIG_MOB_SAY) //We register handle_speech is not being used. + +//Dwarf Name stuff +/proc/dwarf_name() //hello caller: my name is urist mcuristurister + return "[pick(GLOB.dwarf_first)] [pick(GLOB.dwarf_last)]" + +/datum/species/dwarf/random_name(gender,unique,lastname) + return dwarf_name() //hello, ill return the value from dwarf_name proc to you when called. + +//Dwarf Speech handling - Basically a filter/forces them to say things. The IC helper +/datum/species/dwarf/proc/handle_speech(datum/source, list/speech_args) + var/message = speech_args[SPEECH_MESSAGE] + if(message[1] != "*") + message = " [message]" //Credits to goonstation for the strings list. + var/list/dwarf_words = strings("dwarf_replacement.json", "dwarf") //thanks to regex too. + + for(var/key in dwarf_words) //Theres like 1459 words or something man. + var/value = dwarf_words[key] //Thus they will always be in character. + if(islist(value)) //Whether they like it or not. + value = pick(value) //This could be drastically reduced if needed though. + + message = replacetextEx(message, " [uppertext(key)]", " [uppertext(value)]") + message = replacetextEx(message, " [capitalize(key)]", " [capitalize(value)]") + message = replacetextEx(message, " [key]", " [value]") //Also its scottish. + + if(prob(3)) + message += pick(" By Armok!") + speech_args[SPEECH_MESSAGE] = trim(message) + +//This mostly exists because my testdwarf's liver died while trying to also not die due to no alcohol. +/obj/item/organ/liver/dwarf + name = "dwarf liver" + icon_state = "liver" + desc = "A dwarven liver, theres something magical about seeing one of these up close." + alcohol_tolerance = 0 //dwarves really shouldn't be dying to alcohol. + toxTolerance = 5 //Shrugs off 5 units of toxins damage. + maxHealth = 150 //More health than the average liver, as you aren't going to be replacing this. + //If it does need replaced with a standard human liver, prepare for hell. + +//alcohol gland +/obj/item/organ/dwarfgland + name = "dwarf alcohol gland" + icon_state = "plasma" //Yes this is a actual icon in icons/obj/surgery.dmi + desc = "A genetically engineered gland which is hopefully a step forward for humanity." + w_class = WEIGHT_CLASS_NORMAL + var/stored_alcohol = 250 //They start with 250 units, that ticks down and eventaully bad effects occur + var/max_alcohol = 500 //Max they can attain, easier than you think to OD on alcohol. + var/heal_rate = 0.5 //The rate they heal damages over 400 alcohol stored. Default is 0.5 so we times 3 since 3 seconds. + var/alcohol_rate = 0.25 //The rate the alcohol ticks down per each iteration of dwarf_eth_ticker completing. + //These count in on_life ticks which should be 2 seconds per every increment of 1 in a perfect world. + var/dwarf_filth_ticker = 0 //Currently set =< 4, that means this will fire the proc around every 4-8 seconds. + var/dwarf_eth_ticker = 0 //Currently set =< 1, that means this will fire the proc around every 2 seconds + +/obj/item/organ/dwarfgland/prepare_eat() + var/obj/S = ..() + S.reagents.add_reagent("ethanol", stored_alcohol/10) + return S + +/obj/item/organ/dwarfgland/on_life() //Primary loop to hook into to start delayed loops for other loops.. + . = ..() + dwarf_cycle_ticker() + +//Handles the delayed tick cycle by just adding on increments per each on_life() tick +/obj/item/organ/dwarfgland/proc/dwarf_cycle_ticker() + if(owner.stat == DEAD) + return //We make sure they are not dead, so they don't increment any tickers. + dwarf_eth_ticker++ + dwarf_filth_ticker++ + + if(dwarf_filth_ticker >= 4) //Should be around 4-8 seconds since a tick is around 2 seconds. + dwarf_filth_cycle() //On_life will adjust regarding other factors, so we are along for the ride. + dwarf_filth_ticker = 0 //We set the ticker back to 0 to go again. + if(dwarf_eth_ticker >= 1) //Alcohol reagent check should be around 2 seconds, since a tick is around 2 seconds. + dwarf_eth_cycle() + dwarf_eth_ticker = 0 + +//If this still friggin uses too much CPU, I'll make a for view subsystem If I have to. +/obj/item/organ/dwarfgland/proc/dwarf_filth_cycle() + if(!owner?.client || !owner?.mind) + return + //Filth Reactions - Since miasma now exists + var/filth_counter = 0 //Holder for the filth check cycle, basically contains how much filth dwarf sees numerically. + for(var/fuck in view(owner,7)) //hello byond for view loop. + if(istype(fuck, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = fuck + if(H.stat == DEAD || (HAS_TRAIT(H, TRAIT_FAKEDEATH))) + filth_counter += 10 + if(istype(fuck, /obj/effect/decal/cleanable/blood)) + if(istype(fuck, /obj/effect/decal/cleanable/blood/gibs)) + filth_counter += 1 + else + filth_counter += 0.1 + if(istype(fuck,/obj/effect/decal/cleanable/vomit)) //They are disgusted by their own vomit too. + filth_counter += 10 //Dwarves could technically chainstun each other in a vomit tantrum spiral. + switch(filth_counter) + if(11 to 25) + if(prob(25)) + to_chat(owner, "Someone should really clean up in here!") + if(26 to 50) + if(prob(30)) //Probability the message appears + to_chat(owner, "The stench makes you queasy.") + if(prob(20)) //And then the probability they vomit along with it. + owner.vomit(20) //I think vomit should stay over a disgust adjustment. + if(51 to 75) + if(prob(35)) + to_chat(owner, "By Armok! You won't be able to keep alcohol down at all!") + if(prob(25)) + owner.vomit(20) //Its more funny + if(76 to 100) + if(prob(40)) + to_chat(owner, "You can't live in such FILTH!") + if(prob(25)) + owner.adjustToxLoss(10) //Now they start dying. + owner.vomit(20) + if(101 to INFINITY) //Now they will really start dying + if(prob(40)) + to_chat(owner, " THERES TOO MUCH FILTH, OH GODS THE FILTH!") + owner.adjustToxLoss(15) + owner.vomit(40) + CHECK_TICK //Check_tick right here, its motherfuckin magic. (To me at least) + +//Handles the dwarf alcohol cycle tied to on_life, it ticks in dwarf_cycle_ticker. +/obj/item/organ/dwarfgland/proc/dwarf_eth_cycle() + //BOOZE POWER + for(var/datum/reagent/R in owner.reagents.reagent_list) + if(istype(R, /datum/reagent/consumable/ethanol)) + var/datum/reagent/consumable/ethanol/E = R + stored_alcohol += (E.boozepwr / 50) + if(stored_alcohol > max_alcohol) //Dwarves technically start at 250 alcohol stored. + stored_alcohol = max_alcohol + var/heal_amt = heal_rate + stored_alcohol -= alcohol_rate //Subtracts alcohol_Rate from stored alcohol so EX: 250 - 0.25 per each loop that occurs. + if(stored_alcohol > 400) //If they are over 400 they start regenerating + owner.adjustBruteLoss(-heal_amt) //But its alcohol, there will be other issues here. + owner.adjustFireLoss(-heal_amt) //Unless they drink casually all the time. + owner.adjustOxyLoss(-heal_amt) + owner.adjustCloneLoss(-heal_amt) //Also they will probably get brain damage if thats a thing here. + if(prob(25)) + switch(stored_alcohol) + if(0 to 24) + to_chat(owner, "DAMNATION INCARNATE, WHY AM I CURSED WITH THIS DRY-SPELL? I MUST DRINK.") + owner.adjustToxLoss(35) + if(25 to 50) + to_chat(owner, "Oh DAMN, I need some brew!") + if(51 to 75) + to_chat(owner, "Your body aches, you need to get ahold of some booze...") + if(76 to 100) + to_chat(owner, "A pint of anything would really hit the spot right now.") + if(101 to 150) + to_chat(owner, "You feel like you could use a good brew.") 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 1ee697d66c..ec58a3be9c 100644 --- a/code/modules/mob/living/carbon/human/species_types/felinid.dm +++ b/code/modules/mob/living/carbon/human/species_types/felinid.dm @@ -4,8 +4,8 @@ id = "felinid" limbs_id = "human" - mutant_bodyparts = list("mam_ears", "mam_tail") - default_features = list("mcolor" = "FFF", "mam_tail" = "Cat", "mam_ears" = "Cat", "wings" = "None") + mutant_bodyparts = list("mam_ears", "mam_tail", "deco_wings") + default_features = list("mcolor" = "FFF", "mam_tail" = "Cat", "mam_ears" = "Cat", "wings" = "None", "deco_wings" = "None") mutantears = /obj/item/organ/ears/cat mutanttail = /obj/item/organ/tail/cat 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 6f05eb393d..043ee4fde1 100644 --- a/code/modules/mob/living/carbon/human/species_types/flypeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/flypeople.dm @@ -1,5 +1,5 @@ /datum/species/fly - name = "Flyperson" + name = "Anthromorphic Fly" id = "fly" say_mod = "buzzes" species_traits = list(NOEYES) diff --git a/code/modules/mob/living/carbon/human/species_types/furrypeople.dm b/code/modules/mob/living/carbon/human/species_types/furrypeople.dm new file mode 100644 index 0000000000..0390d4accc --- /dev/null +++ b/code/modules/mob/living/carbon/human/species_types/furrypeople.dm @@ -0,0 +1,98 @@ +/datum/species/mammal + name = "Anthromorph" + id = "mammal" + default_color = "4B4B4B" + should_draw_citadel = TRUE + species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR,HORNCOLOR,WINGCOLOR) + inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID) + mutant_bodyparts = list("mam_tail", "mam_ears", "mam_body_markings", "mam_snouts", "deco_wings", "taur", "horns", "legs") + default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_snouts" = "Husky", "mam_tail" = "Husky", "mam_ears" = "Husky", "deco_wings" = "None", + "mam_body_markings" = "Husky", "taur" = "None", "horns" = "None", "legs" = "Plantigrade", "meat_type" = "Mammalian") + attack_verb = "claw" + attack_sound = 'sound/weapons/slash.ogg' + miss_sound = 'sound/weapons/slashmiss.ogg' + meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/mammal + liked_food = MEAT | FRIED + disliked_food = TOXIC + +//Curiosity killed the cat's wagging tail. +/datum/species/mammal/spec_death(gibbed, mob/living/carbon/human/H) + if(H) + stop_wagging_tail(H) + +/datum/species/mammal/spec_stun(mob/living/carbon/human/H,amount) + if(H) + stop_wagging_tail(H) + . = ..() + +/datum/species/mammal/can_wag_tail(mob/living/carbon/human/H) + return ("mam_tail" in mutant_bodyparts) || ("mam_waggingtail" in mutant_bodyparts) + +/datum/species/mammal/is_wagging_tail(mob/living/carbon/human/H) + return ("mam_waggingtail" in mutant_bodyparts) + +/datum/species/mammal/start_wagging_tail(mob/living/carbon/human/H) + if("mam_tail" in mutant_bodyparts) + mutant_bodyparts -= "mam_tail" + mutant_bodyparts |= "mam_waggingtail" + H.update_body() + +/datum/species/mammal/stop_wagging_tail(mob/living/carbon/human/H) + if("mam_waggingtail" in mutant_bodyparts) + mutant_bodyparts -= "mam_waggingtail" + mutant_bodyparts |= "mam_tail" + H.update_body() + + +/datum/species/mammal/qualifies_for_rank(rank, list/features) + return TRUE + + +//Alien// +/datum/species/xeno + // A cloning mistake, crossing human and xenomorph DNA + name = "Xenomorph Hybrid" + id = "xeno" + say_mod = "hisses" + default_color = "00FF00" + should_draw_citadel = TRUE + species_traits = list(MUTCOLORS,EYECOLOR,LIPS) + inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID) + mutant_bodyparts = list("xenotail", "xenohead", "xenodorsal", "mam_body_markings", "taur", "legs") + default_features = list("xenotail"="Xenomorph Tail","xenohead"="Standard","xenodorsal"="Standard", "mam_body_markings" = "Xeno","mcolor" = "0F0","mcolor2" = "0F0","mcolor3" = "0F0","taur" = "None", "legs" = "Digitigrade") + attack_verb = "slash" + attack_sound = 'sound/weapons/slash.ogg' + miss_sound = 'sound/weapons/slashmiss.ogg' + meat = /obj/item/reagent_containers/food/snacks/meat/slab/xeno + skinned_type = /obj/item/stack/sheet/animalhide/xeno + exotic_bloodtype = "L" + damage_overlay_type = "xeno" + liked_food = MEAT + +/datum/species/xeno/on_species_gain(mob/living/carbon/human/C, datum/species/old_species) + if(("legs" in C.dna.species.mutant_bodyparts) && (C.dna.features["legs"] == "Digitigrade" || C.dna.features["legs"] == "Avian")) + species_traits += DIGITIGRADE + if(DIGITIGRADE in species_traits) + C.Digitigrade_Leg_Swap(FALSE) + . = ..() + +/datum/species/xeno/on_species_loss(mob/living/carbon/human/C, datum/species/new_species) + if(("legs" in C.dna.species.mutant_bodyparts) && C.dna.features["legs"] == "Plantigrade") + species_traits -= DIGITIGRADE + if(DIGITIGRADE in species_traits) + C.Digitigrade_Leg_Swap(TRUE) + . = ..() + +//Praise the Omnissiah, A challange worthy of my skills - HS + +//EXOTIC// +//These races will likely include lots of downsides and upsides. Keep them relatively balanced.// + +//misc +/mob/living/carbon/human/dummy + no_vore = TRUE + +/mob/living/carbon/human/vore + devourable = TRUE + digestable = TRUE + feeding = TRUE diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm index 88dd59749c..8f84590ff4 100644 --- a/code/modules/mob/living/carbon/human/species_types/golems.dm +++ b/code/modules/mob/living/carbon/human/species_types/golems.dm @@ -45,7 +45,7 @@ return golem_name /datum/species/golem/random - name = "Random Golem" + name = "Golem Mutant" blacklisted = FALSE dangerous_existence = FALSE var/static/list/random_golem_types @@ -581,7 +581,7 @@ limbs_id = "cultgolem" sexes = FALSE info_text = "As a Runic Golem, you possess eldritch powers granted by the Elder Goddess Nar'Sie." - species_traits = list(NOBLOOD,NO_UNDERWEAR,NOEYES) //no mutcolors + species_traits = list(NOBLOOD,NO_UNDERWEAR,NOEYES,NOGENITALS,NOAROUSAL) //no mutcolors prefix = "Runic" special_names = null @@ -635,7 +635,7 @@ say_mod = "clicks" limbs_id = "clockgolem" info_text = "As a Clockwork Golem, you are faster than other types of golems. On death, you will break down into scrap." - species_traits = list(NOBLOOD,NO_UNDERWEAR,NOEYES) + species_traits = list(NOBLOOD,NO_UNDERWEAR,NOEYES,NOGENITALS,NOAROUSAL) inherent_biotypes = list(MOB_ROBOTIC, MOB_HUMANOID) armor = 20 //Reinforced, but much less so to allow for fast movement attack_verb = "smash" @@ -691,7 +691,7 @@ sexes = FALSE info_text = "As a Cloth Golem, you are able to reform yourself after death, provided your remains aren't burned or destroyed. You are, of course, very flammable. \ Being made of cloth, your body is magic resistant and faster than that of other golems, but weaker and less resilient." - species_traits = list(NOBLOOD,NO_UNDERWEAR) //no mutcolors, and can burn + species_traits = list(NOBLOOD,NO_UNDERWEAR,NOGENITALS,NOAROUSAL) //no mutcolors, and can burn inherent_traits = list(TRAIT_RESISTCOLD,TRAIT_NOBREATH,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOGUNS) inherent_biotypes = list(MOB_UNDEAD, MOB_HUMANOID) armor = 15 //feels no pain, but not too resistant 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 96b43795a2..3332465c78 100644 --- a/code/modules/mob/living/carbon/human/species_types/humans.dm +++ b/code/modules/mob/living/carbon/human/species_types/humans.dm @@ -1,41 +1,42 @@ -/datum/species/human - name = "Human" - id = "human" - default_color = "FFFFFF" - species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,MUTCOLORS_PARTSONLY) - mutant_bodyparts = list("ears", "tail_human", "wings", "taur") // CITADEL EDIT gives humans snowflake parts - default_features = list("mcolor" = "FFF", "mcolor2" = "FFF","mcolor3" = "FFF","tail_human" = "None", "ears" = "None", "wings" = "None", "taur" = "None") - use_skintones = 1 - skinned_type = /obj/item/stack/sheet/animalhide/human - disliked_food = GROSS | RAW - liked_food = JUNKFOOD | FRIED - -/datum/species/human/qualifies_for_rank(rank, list/features) - return TRUE //Pure humans are always allowed in all roles. - -/datum/species/human/spec_death(gibbed, mob/living/carbon/human/H) - if(H) - stop_wagging_tail(H) - -/datum/species/human/spec_stun(mob/living/carbon/human/H,amount) - if(H) - stop_wagging_tail(H) - . = ..() - -/datum/species/human/can_wag_tail(mob/living/carbon/human/H) - return ("tail_human" in mutant_bodyparts) || ("waggingtail_human" in mutant_bodyparts) - -/datum/species/human/is_wagging_tail(mob/living/carbon/human/H) - return ("waggingtail_human" in mutant_bodyparts) - -/datum/species/human/start_wagging_tail(mob/living/carbon/human/H) - if("tail_human" in mutant_bodyparts) - mutant_bodyparts -= "tail_human" - mutant_bodyparts |= "waggingtail_human" - H.update_body() - -/datum/species/human/stop_wagging_tail(mob/living/carbon/human/H) - if("waggingtail_human" in mutant_bodyparts) - mutant_bodyparts -= "waggingtail_human" - mutant_bodyparts |= "tail_human" - H.update_body() +/datum/species/human + name = "Human" + id = "human" + default_color = "FFFFFF" + + species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,MUTCOLORS_PARTSONLY,WINGCOLOR) + mutant_bodyparts = list("ears", "tail_human", "wings", "taur", "deco_wings") // CITADEL EDIT gives humans snowflake parts + default_features = list("mcolor" = "FFF", "mcolor2" = "FFF","mcolor3" = "FFF","tail_human" = "None", "ears" = "None", "wings" = "None", "taur" = "None", "deco_wings" = "None") + use_skintones = 1 + skinned_type = /obj/item/stack/sheet/animalhide/human + disliked_food = GROSS | RAW + liked_food = JUNKFOOD | FRIED + +/datum/species/human/qualifies_for_rank(rank, list/features) + return TRUE //Pure humans are always allowed in all roles. + +/datum/species/human/spec_death(gibbed, mob/living/carbon/human/H) + if(H) + stop_wagging_tail(H) + +/datum/species/human/spec_stun(mob/living/carbon/human/H,amount) + if(H) + stop_wagging_tail(H) + . = ..() + +/datum/species/human/can_wag_tail(mob/living/carbon/human/H) + return ("tail_human" in mutant_bodyparts) || ("waggingtail_human" in mutant_bodyparts) + +/datum/species/human/is_wagging_tail(mob/living/carbon/human/H) + return ("waggingtail_human" in mutant_bodyparts) + +/datum/species/human/start_wagging_tail(mob/living/carbon/human/H) + if("tail_human" in mutant_bodyparts) + mutant_bodyparts -= "tail_human" + mutant_bodyparts |= "waggingtail_human" + H.update_body() + +/datum/species/human/stop_wagging_tail(mob/living/carbon/human/H) + if("waggingtail_human" in mutant_bodyparts) + mutant_bodyparts -= "waggingtail_human" + mutant_bodyparts |= "tail_human" + H.update_body() diff --git a/modular_citadel/code/modules/mob/living/carbon/human/species_types/ipc.dm b/code/modules/mob/living/carbon/human/species_types/ipc.dm similarity index 98% rename from modular_citadel/code/modules/mob/living/carbon/human/species_types/ipc.dm rename to code/modules/mob/living/carbon/human/species_types/ipc.dm index 25b8daf2cb..95b924ea18 100644 --- a/modular_citadel/code/modules/mob/living/carbon/human/species_types/ipc.dm +++ b/code/modules/mob/living/carbon/human/species_types/ipc.dm @@ -1,5 +1,5 @@ /datum/species/ipc - name = "IPC" + name = "I.P.C." id = "ipc" say_mod = "beeps" default_color = "00FF00" 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 ce5d7be890..8e98569644 100644 --- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm @@ -4,10 +4,10 @@ id = "jelly" default_color = "00FF90" say_mod = "chirps" - species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,NOBLOOD) + species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,NOBLOOD,WINGCOLOR) mutantlungs = /obj/item/organ/lungs/slime - mutant_bodyparts = list("mam_tail", "mam_ears", "mam_snouts", "taur") //CIT CHANGE - default_features = list("mcolor" = "FFF", "mam_tail" = "None", "mam_ears" = "None", "mam_snouts" = "None", "taur" = "None") //CIT CHANGE + mutant_bodyparts = list("mam_tail", "mam_ears", "mam_snouts", "taur", "deco_wings") //CIT CHANGE + default_features = list("mcolor" = "FFF", "mam_tail" = "None", "mam_ears" = "None", "mam_snouts" = "None", "taur" = "None", "deco_wings" = "None") //CIT CHANGE inherent_traits = list(TRAIT_TOXINLOVER) meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/slime exotic_blood = "slimejelly" @@ -48,14 +48,14 @@ H.adjustBruteLoss(5) to_chat(H, "You feel empty!") - if(H.blood_volume < BLOOD_VOLUME_NORMAL) + if(H.blood_volume < (BLOOD_VOLUME_NORMAL * H.blood_ratio)) if(H.nutrition >= NUTRITION_LEVEL_STARVING) H.blood_volume += 3 H.nutrition -= 2.5 - if(H.blood_volume < BLOOD_VOLUME_OKAY) + if(H.blood_volume < (BLOOD_VOLUME_OKAY*H.blood_ratio)) if(prob(5)) to_chat(H, "You feel drained!") - if(H.blood_volume < BLOOD_VOLUME_BAD) + if(H.blood_volume < (BLOOD_VOLUME_BAD*H.blood_ratio)) Cannibalize_Body(H) if(regenerate_limbs) regenerate_limbs.UpdateButtonIcon() @@ -87,7 +87,7 @@ var/list/limbs_to_heal = H.get_missing_limbs() if(limbs_to_heal.len < 1) return 0 - if(H.blood_volume >= BLOOD_VOLUME_OKAY+40) + if(H.blood_volume >= (BLOOD_VOLUME_OKAY*H.blood_ratio)+40) return 1 return 0 @@ -98,13 +98,13 @@ to_chat(H, "You feel intact enough as it is.") return to_chat(H, "You focus intently on your missing [limbs_to_heal.len >= 2 ? "limbs" : "limb"]...") - if(H.blood_volume >= 40*limbs_to_heal.len+BLOOD_VOLUME_OKAY) + if(H.blood_volume >= 40*limbs_to_heal.len+(BLOOD_VOLUME_OKAY*H.blood_ratio)) H.regenerate_limbs() H.blood_volume -= 40*limbs_to_heal.len to_chat(H, "...and after a moment you finish reforming!") return else if(H.blood_volume >= 40)//We can partially heal some limbs - while(H.blood_volume >= BLOOD_VOLUME_OKAY+40) + while(H.blood_volume >= (BLOOD_VOLUME_OKAY*H.blood_ratio)+40) var/healed_limb = pick(limbs_to_heal) H.regenerate_limb(healed_limb) limbs_to_heal -= healed_limb @@ -118,7 +118,7 @@ //Slime people are able to split like slimes, retaining a single mind that can swap between bodies at will, even after death. /datum/species/jelly/slime - name = "Slimeperson" + name = "Xenobiological Slime Entity" id = "slime" default_color = "00FFFF" species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,NOBLOOD) @@ -138,7 +138,7 @@ bodies -= C // This means that the other bodies maintain a link // so if someone mindswapped into them, they'd still be shared. bodies = null - C.blood_volume = min(C.blood_volume, BLOOD_VOLUME_NORMAL) + C.blood_volume = min(C.blood_volume, (BLOOD_VOLUME_NORMAL*C.blood_ratio)) ..() /datum/species/jelly/slime/on_species_gain(mob/living/carbon/C, datum/species/old_species) @@ -389,12 +389,268 @@ "...and move this one instead.") +////////////////////////////////////////////////////////Round Start Slimes/////////////////////////////////////////////////////////////////// + +/datum/species/jelly/roundstartslime + name = "Xenobiological Slime Hybrid" + id = "slimeperson" + limbs_id = "slime" + default_color = "00FFFF" + species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,NOBLOOD) + inherent_traits = list(TRAIT_TOXINLOVER) + mutant_bodyparts = list("mam_tail", "mam_ears", "mam_body_markings", "mam_snouts", "taur") + default_features = list("mcolor" = "FFF", "mcolor2" = "FFF","mcolor3" = "FFF", "mam_tail" = "None", "mam_ears" = "None", "mam_body_markings" = "Plain", "mam_snouts" = "None", "taur" = "None") + say_mod = "says" + hair_color = "mutcolor" + hair_alpha = 160 //a notch brighter so it blends better. + coldmod = 3 + heatmod = 1 + burnmod = 1 + +/datum/species/jelly/roundstartslime/spec_death(gibbed, mob/living/carbon/human/H) + if(H) + stop_wagging_tail(H) + +/datum/species/jelly/roundstartslime/spec_stun(mob/living/carbon/human/H,amount) + if(H) + stop_wagging_tail(H) + . = ..() + +/datum/species/jelly/roundstartslime/can_wag_tail(mob/living/carbon/human/H) + return ("mam_tail" in mutant_bodyparts) || ("mam_waggingtail" in mutant_bodyparts) + +/datum/species/jelly/roundstartslime/is_wagging_tail(mob/living/carbon/human/H) + return ("mam_waggingtail" in mutant_bodyparts) + +/datum/species/jelly/roundstartslime/start_wagging_tail(mob/living/carbon/human/H) + if("mam_tail" in mutant_bodyparts) + mutant_bodyparts -= "mam_tail" + mutant_bodyparts |= "mam_waggingtail" + H.update_body() + +/datum/species/jelly/roundstartslime/stop_wagging_tail(mob/living/carbon/human/H) + if("mam_waggingtail" in mutant_bodyparts) + mutant_bodyparts -= "mam_waggingtail" + mutant_bodyparts |= "mam_tail" + H.update_body() + + +/datum/action/innate/slime_change + name = "Alter Form" + check_flags = AB_CHECK_CONSCIOUS + button_icon_state = "alter_form" //placeholder + icon_icon = 'modular_citadel/icons/mob/actions/actions_slime.dmi' + background_icon_state = "bg_alien" + +/datum/action/innate/slime_change/Activate() + var/mob/living/carbon/human/H = owner + if(!isjellyperson(H)) + return + else + H.visible_message("[owner] gains a look of \ + concentration while standing perfectly still.\ + Their body seems to shift and starts getting more goo-like.", + "You focus intently on altering your body while \ + standing perfectly still...") + change_form() + +/datum/action/innate/slime_change/proc/change_form() + var/mob/living/carbon/human/H = owner + var/select_alteration = input(owner, "Select what part of your form to alter", "Form Alteration", "cancel") in list("Hair Style", "Genitals", "Tail", "Snout", "Markings", "Ears", "Taur body", "Penis", "Vagina", "Penis Length", "Breast Size", "Breast Shape", "Cancel") + if(select_alteration == "Hair Style") + if(H.gender == MALE) + var/new_style = input(owner, "Select a facial hair style", "Hair Alterations") as null|anything in GLOB.facial_hair_styles_list + if(new_style) + H.facial_hair_style = new_style + else + H.facial_hair_style = "Shaved" + //handle normal hair + var/new_style = input(owner, "Select a hair style", "Hair Alterations") as null|anything in GLOB.hair_styles_list + if(new_style) + H.hair_style = new_style + H.update_hair() + else if (select_alteration == "Genitals") + var/list/organs = list() + var/operation = input("Select organ operation.", "Organ Manipulation", "cancel") in list("add sexual organ", "remove sexual organ", "cancel") + switch(operation) + if("add sexual organ") + var/new_organ = input("Select sexual organ:", "Organ Manipulation") in list("Penis", "Testicles", "Breasts", "Vagina", "Womb", "Cancel") + if(new_organ == "Penis") + H.give_penis() + else if(new_organ == "Testicles") + H.give_balls() + else if(new_organ == "Breasts") + H.give_breasts() + else if(new_organ == "Vagina") + H.give_vagina() + else if(new_organ == "Womb") + H.give_womb() + else + return + if("remove sexual organ") + for(var/obj/item/organ/genital/X in H.internal_organs) + var/obj/item/organ/I = X + organs["[I.name] ([I.type])"] = I + var/obj/item/organ = input("Select sexual organ:", "Organ Manipulation", null) in organs + organ = organs[organ] + if(!organ) + return + var/obj/item/organ/genital/O + if(isorgan(organ)) + O = organ + O.Remove(H) + organ.forceMove(get_turf(H)) + qdel(organ) + H.update_genitals() + + else if (select_alteration == "Ears") + var/list/snowflake_ears_list = list("Normal" = null) + for(var/path in GLOB.mam_ears_list) + var/datum/sprite_accessory/mam_ears/instance = GLOB.mam_ears_list[path] + if(istype(instance, /datum/sprite_accessory)) + var/datum/sprite_accessory/S = instance + if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(H.client.ckey))) + snowflake_ears_list[S.name] = path + var/new_ears + new_ears = input(owner, "Choose your character's ears:", "Ear Alteration") as null|anything in snowflake_ears_list + if(new_ears) + H.dna.features["mam_ears"] = new_ears + H.update_body() + + else if (select_alteration == "Snout") + var/list/snowflake_snouts_list = list("Normal" = null) + for(var/path in GLOB.mam_snouts_list) + var/datum/sprite_accessory/mam_snouts/instance = GLOB.mam_snouts_list[path] + if(istype(instance, /datum/sprite_accessory)) + var/datum/sprite_accessory/S = instance + if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(H.client.ckey))) + snowflake_snouts_list[S.name] = path + var/new_snout + new_snout = input(owner, "Choose your character's face:", "Face Alteration") as null|anything in snowflake_snouts_list + if(new_snout) + H.dna.features["mam_snouts"] = new_snout + H.update_body() + + else if (select_alteration == "Markings") + var/list/snowflake_markings_list = list() + for(var/path in GLOB.mam_body_markings_list) + var/datum/sprite_accessory/mam_body_markings/instance = GLOB.mam_body_markings_list[path] + if(istype(instance, /datum/sprite_accessory)) + var/datum/sprite_accessory/S = instance + if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(H.client.ckey))) + snowflake_markings_list[S.name] = path + var/new_mam_body_markings + new_mam_body_markings = input(H, "Choose your character's body markings:", "Marking Alteration") as null|anything in snowflake_markings_list + if(new_mam_body_markings) + H.dna.features["mam_body_markings"] = new_mam_body_markings + if(new_mam_body_markings == "None") + H.dna.features["mam_body_markings"] = "Plain" + for(var/X in H.bodyparts) //propagates the markings changes + var/obj/item/bodypart/BP = X + BP.update_limb(FALSE, H) + H.update_body() + + else if (select_alteration == "Tail") + var/list/snowflake_tails_list = list("Normal" = null) + for(var/path in GLOB.mam_tails_list) + var/datum/sprite_accessory/mam_tails/instance = GLOB.mam_tails_list[path] + if(istype(instance, /datum/sprite_accessory)) + var/datum/sprite_accessory/S = instance + if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(H.client.ckey))) + snowflake_tails_list[S.name] = path + var/new_tail + new_tail = input(owner, "Choose your character's Tail(s):", "Tail Alteration") as null|anything in snowflake_tails_list + if(new_tail) + H.dna.features["mam_tail"] = new_tail + if(new_tail != "None") + H.dna.features["taur"] = "None" + H.update_body() + + else if (select_alteration == "Taur body") + var/list/snowflake_taur_list = list("Normal" = null) + for(var/path in GLOB.taur_list) + var/datum/sprite_accessory/taur/instance = GLOB.taur_list[path] + if(istype(instance, /datum/sprite_accessory)) + var/datum/sprite_accessory/S = instance + if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(H.client.ckey))) + snowflake_taur_list[S.name] = path + var/new_taur + new_taur = input(owner, "Choose your character's tauric body:", "Tauric Alteration") as null|anything in snowflake_taur_list + if(new_taur) + H.dna.features["taur"] = new_taur + if(new_taur != "None") + H.dna.features["mam_tail"] = "None" + H.update_body() + + else if (select_alteration == "Penis") + for(var/obj/item/organ/genital/penis/X in H.internal_organs) + qdel(X) + var/new_shape + new_shape = input(owner, "Choose your character's dong", "Genital Alteration") as null|anything in GLOB.cock_shapes_list + if(new_shape) + H.dna.features["cock_shape"] = new_shape + H.update_genitals() + H.give_balls() + H.give_penis() + H.apply_overlay() + + + else if (select_alteration == "Vagina") + for(var/obj/item/organ/genital/vagina/X in H.internal_organs) + qdel(X) + var/new_shape + new_shape = input(owner, "Choose your character's pussy", "Genital Alteration") as null|anything in GLOB.vagina_shapes_list + if(new_shape) + H.dna.features["vag_shape"] = new_shape + H.update_genitals() + H.give_womb() + H.give_vagina() + H.apply_overlay() + + else if (select_alteration == "Penis Length") + for(var/obj/item/organ/genital/penis/X in H.internal_organs) + qdel(X) + var/new_length + new_length = input(owner, "Penis length in inches:\n([COCK_SIZE_MIN]-[COCK_SIZE_MAX])", "Genital Alteration") as num|null + if(new_length) + H.dna.features["cock_length"] = max(min( round(text2num(new_length)), COCK_SIZE_MAX),COCK_SIZE_MIN) + H.update_genitals() + H.apply_overlay() + H.give_balls() + H.give_penis() + + else if (select_alteration == "Breast Size") + for(var/obj/item/organ/genital/breasts/X in H.internal_organs) + qdel(X) + var/new_size + new_size = input(owner, "Breast Size", "Genital Alteration") as null|anything in GLOB.breasts_size_list + if(new_size) + H.dna.features["breasts_size"] = new_size + H.update_genitals() + H.apply_overlay() + H.give_breasts() + + else if (select_alteration == "Breast Shape") + for(var/obj/item/organ/genital/breasts/X in H.internal_organs) + qdel(X) + var/new_shape + new_shape = input(owner, "Breast Shape", "Genital Alteration") as null|anything in GLOB.breasts_shapes_list + if(new_shape) + H.dna.features["breasts_shape"] = new_shape + H.update_genitals() + H.apply_overlay() + H.give_breasts() + + else + return + + ///////////////////////////////////LUMINESCENTS////////////////////////////////////////// //Luminescents are able to consume and use slime extracts, without them decaying. /datum/species/jelly/luminescent - name = "Luminescent" + name = "Luminescent Slime Entity" id = "lum" say_mod = "says" var/glow_intensity = LUMINESCENT_DEFAULT_GLOW @@ -561,7 +817,7 @@ //Stargazers are the telepathic branch of jellypeople, able to project psychic messages and to link minds with willing participants. /datum/species/jelly/stargazer - name = "Stargazer" + name = "Stargazer Slime Entity" id = "stargazer" var/datum/action/innate/project_thought/project_thought var/datum/action/innate/link_minds/link_minds @@ -729,4 +985,4 @@ to_chat(H, "You connect [target]'s mind to your slime link!") else to_chat(H, "You can't seem to link [target]'s mind...") - to_chat(target, "The foreign presence leaves your mind.") \ No newline at end of file + to_chat(target, "The foreign presence leaves your mind.") 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 30bf705547..a719f2eda0 100644 --- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm @@ -1,17 +1,19 @@ /datum/species/lizard // Reptilian humanoids with scaled skin and tails. - name = "Lizardperson" + name = "Anthromorphic Lizard" id = "lizard" say_mod = "hisses" default_color = "00FF00" - species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,LIPS) + species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,LIPS,HORNCOLOR,WINGCOLOR) inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID, MOB_REPTILE) - mutant_bodyparts = list("tail_lizard", "snout", "spines", "horns", "frills", "body_markings", "legs", "taur") + mutant_bodyparts = list("tail_lizard", "snout", "spines", "horns", "frills", "body_markings", "legs", "taur", "deco_wings") mutanttongue = /obj/item/organ/tongue/lizard mutanttail = /obj/item/organ/tail/lizard coldmod = 1.5 heatmod = 0.67 - default_features = list("mcolor" = "0F0", "mcolor2" = "0F0", "mcolor3" = "0F0", "tail_lizard" = "Smooth", "snout" = "Round", "horns" = "None", "frills" = "None", "spines" = "None", "body_markings" = "None", "legs" = "Normal Legs", "taur" = "None") + default_features = list("mcolor" = "0F0", "mcolor2" = "0F0", "mcolor3" = "0F0", "tail_lizard" = "Smooth", "snout" = "Round", + "horns" = "None", "frills" = "None", "spines" = "None", "body_markings" = "None", + "legs" = "Digitigrade", "taur" = "None", "deco_wings" = "None") attack_verb = "slash" attack_sound = 'sound/weapons/slash.ogg' miss_sound = 'sound/weapons/slashmiss.ogg' @@ -71,14 +73,14 @@ H.update_body() /datum/species/lizard/on_species_gain(mob/living/carbon/human/C, datum/species/old_species) - if(("legs" in C.dna.species.mutant_bodyparts) && C.dna.features["legs"] == "Digitigrade Legs") + if(("legs" in C.dna.species.mutant_bodyparts) && (C.dna.features["legs"] == "Digitigrade" || C.dna.features["legs"] == "Avian")) species_traits += DIGITIGRADE if(DIGITIGRADE in species_traits) C.Digitigrade_Leg_Swap(FALSE) return ..() /datum/species/lizard/on_species_loss(mob/living/carbon/human/C, datum/species/new_species) - if(("legs" in C.dna.species.mutant_bodyparts) && C.dna.features["legs"] == "Normal Legs") + if(("legs" in C.dna.species.mutant_bodyparts) && C.dna.features["legs"] == "Plantigrade") species_traits -= DIGITIGRADE if(DIGITIGRADE in species_traits) C.Digitigrade_Leg_Swap(TRUE) diff --git a/code/modules/mob/living/carbon/human/species_types/mothmen.dm b/code/modules/mob/living/carbon/human/species_types/mothmen.dm deleted file mode 100644 index d15d989384..0000000000 --- a/code/modules/mob/living/carbon/human/species_types/mothmen.dm +++ /dev/null @@ -1,61 +0,0 @@ -/datum/species/moth - name = "Mothman" - id = "moth" - say_mod = "flutters" - default_color = "00FF00" - species_traits = list(LIPS, NOEYES) - inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID, MOB_BUG) - mutant_bodyparts = list("moth_wings") - default_features = list("moth_wings" = "Plain") - attack_verb = "slash" - attack_sound = 'sound/weapons/slash.ogg' - miss_sound = 'sound/weapons/slashmiss.ogg' - meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/moth - liked_food = VEGETABLES | DAIRY - disliked_food = FRUIT | GROSS - toxic_food = MEAT | RAW - mutanteyes = /obj/item/organ/eyes/moth - -/datum/species/moth/on_species_gain(mob/living/carbon/C) - . = ..() - if(ishuman(C)) - var/mob/living/carbon/human/H = C - if(!H.dna.features["moth_wings"]) - H.dna.features["moth_wings"] = "[(H.client && H.client.prefs && LAZYLEN(H.client.prefs.features) && H.client.prefs.features["moth_wings"]) ? H.client.prefs.features["moth_wings"] : "Plain"]" - handle_mutant_bodyparts(H) - -/datum/species/moth/random_name(gender,unique,lastname) - if(unique) - return random_unique_moth_name() - - var/randname = moth_name() - - if(lastname) - randname += " [lastname]" - - return randname - -/datum/species/moth/handle_fire(mob/living/carbon/human/H, no_protection = FALSE) - ..() - if(H.dna.features["moth_wings"] != "Burnt Off" && H.bodytemperature >= 800 && H.fire_stacks > 0) //do not go into the extremely hot light. you will not survive - to_chat(H, "Your precious wings burn to a crisp!") - H.dna.features["moth_wings"] = "Burnt Off" - handle_mutant_bodyparts(H) - -/datum/species/moth/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H) - . = ..() - if(chem.id == "pestkiller") - H.adjustToxLoss(3) - H.reagents.remove_reagent(chem.id, REAGENTS_METABOLISM) - -/datum/species/moth/check_weakness(obj/item/weapon, mob/living/attacker) - if(istype(weapon, /obj/item/melee/flyswatter)) - return 9 //flyswatters deal 10x damage to moths - return 0 - -/datum/species/moth/space_move(mob/living/carbon/human/H) - . = ..() - if(H.loc && !isspaceturf(H.loc) && H.dna.features["moth_wings"] != "Burnt Off") - var/datum/gas_mixture/current = H.loc.return_air() - if(current && (current.return_pressure() >= ONE_ATMOSPHERE*0.85)) //as long as there's reasonable pressure and no gravity, flight is possible - return TRUE diff --git a/code/modules/mob/living/carbon/human/species_types/mushpeople.dm b/code/modules/mob/living/carbon/human/species_types/mushpeople.dm index 7be0265cba..ceadb28115 100644 --- a/code/modules/mob/living/carbon/human/species_types/mushpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/mushpeople.dm @@ -1,5 +1,5 @@ /datum/species/mush //mush mush codecuck - name = "Mushroomperson" + name = "Anthromorphic Mushroom" id = "mush" mutant_bodyparts = list("caps") default_features = list("caps" = "Round") diff --git a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm index d7bb151ddc..06f456e004 100644 --- a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm +++ b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm @@ -16,7 +16,6 @@ burnmod = 1.5 heatmod = 1.5 breathid = "tox" - speedmod = 1 damage_overlay_type = ""//let's not show bloody wounds or burns over bones. var/internal_fire = FALSE //If the bones themselves are burning clothes won't help you much disliked_food = FRUIT @@ -55,19 +54,95 @@ ..() /datum/species/plasmaman/before_equip_job(datum/job/J, mob/living/carbon/human/H, visualsOnly = FALSE) + var/current_job = J.title var/datum/outfit/plasmaman/O = new /datum/outfit/plasmaman + switch(current_job) + if("Chaplain") + O = new /datum/outfit/plasmaman/chaplain + + if("Curator") + O = new /datum/outfit/plasmaman/curator + + if("Janitor") + O = new /datum/outfit/plasmaman/janitor + + if("Botanist") + O = new /datum/outfit/plasmaman/botany + + if("Bartender", "Lawyer") + O = new /datum/outfit/plasmaman/bar + + if("Cook") + O = new /datum/outfit/plasmaman/chef + + if("Security Officer") + O = new /datum/outfit/plasmaman/security + + if("Detective") + O = new /datum/outfit/plasmaman/detective + + if("Warden") + O = new /datum/outfit/plasmaman/warden + + if("Cargo Technician", "Quartermaster") + O = new /datum/outfit/plasmaman/cargo + + if("Shaft Miner") + O = new /datum/outfit/plasmaman/mining + + if("Medical Doctor") + O = new /datum/outfit/plasmaman/medical + + if("Chemist") + O = new /datum/outfit/plasmaman/chemist + + if("Geneticist") + O = new /datum/outfit/plasmaman/genetics + + if("Roboticist") + O = new /datum/outfit/plasmaman/robotics + + if("Virologist") + O = new /datum/outfit/plasmaman/viro + + if("Scientist") + O = new /datum/outfit/plasmaman/science + + if("Station Engineer") + O = new /datum/outfit/plasmaman/engineering + + if("Atmospheric Technician") + O = new /datum/outfit/plasmaman/atmospherics + + if("Captain") + O = new /datum/outfit/plasmaman/captain + + if("Head of Personnel") + O = new /datum/outfit/plasmaman/hop + + if("Head of Security") + O = new /datum/outfit/plasmaman/hos + + if("Chief Engineer") + O = new /datum/outfit/plasmaman/ce + + if("Chief Medical Officer") + O = new /datum/outfit/plasmaman/cmo + + if("Research Director") + O = new /datum/outfit/plasmaman/rd + + if("Mime") + O = new /datum/outfit/plasmaman/mime + + if("Clown") + O = new /datum/outfit/plasmaman/clown + H.equipOutfit(O, visualsOnly) H.internal = H.get_item_for_held_index(2) H.update_internals_hud_icon(1) return 0 -/datum/species/plasmaman/qualifies_for_rank(rank, list/features) - if(rank in GLOB.security_positions) - return 0 - if(rank == "Clown" || rank == "Mime")//No funny bussiness - return 0 - return ..() - /datum/species/plasmaman/random_name(gender,unique,lastname) if(unique) return random_unique_plasmaman_name() diff --git a/code/modules/mob/living/carbon/human/species_types/podpeople.dm b/code/modules/mob/living/carbon/human/species_types/podpeople.dm index 0da4073f1d..f0dd48c6c1 100644 --- a/code/modules/mob/living/carbon/human/species_types/podpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/podpeople.dm @@ -1,6 +1,6 @@ /datum/species/pod // A mutation caused by a human being ressurected in a revival pod. These regain health in light, and begin to wither in darkness. - name = "Podperson" + name = "Anthromorphic Plant" id = "pod" default_color = "59CE00" species_traits = list(MUTCOLORS,EYECOLOR) @@ -36,8 +36,8 @@ var/turf/T = H.loc light_amount = min(1,T.get_lumcount()) - 0.5 H.nutrition += light_amount * light_nutrition_gain_factor - if(H.nutrition > NUTRITION_LEVEL_FULL) - H.nutrition = NUTRITION_LEVEL_FULL + if(H.nutrition >= NUTRITION_LEVEL_FULL) + H.nutrition = NUTRITION_LEVEL_FULL - 1 if(light_amount > 0.2) //if there's enough light, heal H.heal_overall_damage(light_bruteheal, light_burnheal) H.adjustToxLoss(-light_toxheal) @@ -71,6 +71,7 @@ H.nutrition = min(H.nutrition+30, NUTRITION_LEVEL_FULL) /datum/species/pod/pseudo_weak + name = "Anthromorphic Plant" id = "podweak" limbs_id = "pod" species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,MUTCOLORS) diff --git a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm index 11a25cea6c..09fc26d04f 100644 --- a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm @@ -102,6 +102,7 @@ color = "#1C1C1C" var/respawn_progress = 0 var/obj/item/light_eater/blade + decay_factor = 0 /obj/item/organ/heart/nightmare/attack(mob/M, mob/living/carbon/user, obj/target) @@ -122,10 +123,8 @@ if(special != HEART_SPECIAL_SHADOWIFY) blade = new/obj/item/light_eater M.put_in_hands(blade) - START_PROCESSING(SSobj, src) /obj/item/organ/heart/nightmare/Remove(mob/living/carbon/M, special = 0) - STOP_PROCESSING(SSobj, src) respawn_progress = 0 if(blade && special != HEART_SPECIAL_SHADOWIFY) QDEL_NULL(blade) @@ -138,9 +137,8 @@ /obj/item/organ/heart/nightmare/update_icon() return //always beating visually -/obj/item/organ/heart/nightmare/process() - if(QDELETED(owner) || owner.stat != DEAD) - respawn_progress = 0 +/obj/item/organ/heart/nightmare/on_death() + if(!owner) return var/turf/T = get_turf(owner) if(istype(T)) @@ -174,6 +172,7 @@ item_flags = ABSTRACT | DROPDEL w_class = WEIGHT_CLASS_HUGE sharpness = IS_SHARP + total_mass = TOTAL_MASS_HAND_REPLACEMENT /obj/item/light_eater/Initialize() . = ..() 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 135992f3a6..5a20ca37a8 100644 --- a/code/modules/mob/living/carbon/human/species_types/skeletons.dm +++ b/code/modules/mob/living/carbon/human/species_types/skeletons.dm @@ -3,7 +3,7 @@ name = "Spooky Scary Skeleton" id = "skeleton" say_mod = "rattles" - blacklisted = 1 + blacklisted = 0 sexes = 0 meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/skeleton species_traits = list(NOBLOOD,NOGENITALS,NOAROUSAL) @@ -12,13 +12,18 @@ mutanttongue = /obj/item/organ/tongue/bone damage_overlay_type = ""//let's not show bloody wounds or burns over bones. disliked_food = NONE - liked_food = GROSS | MEAT | RAW + liked_food = GROSS | MEAT | RAW | DAIRY /datum/species/skeleton/check_roundstart_eligible() if(SSevents.holidays && SSevents.holidays[HALLOWEEN]) return TRUE return ..() -/datum/species/skeleton/pirate - name = "Space Queen's Skeleton" +/datum/species/skeleton/space + name = "Spooky Spacey Skeleton" + id = "spaceskeleton" + blacklisted = 1 inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NOHUNGER,TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_FAKEDEATH, TRAIT_CALCIUM_HEALER) + +/datum/species/skeleton/space/check_roundstart_eligible() + return FALSE \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/species_types/synths.dm b/code/modules/mob/living/carbon/human/species_types/synths.dm index 0ebd6e795b..ac18580e9b 100644 --- a/code/modules/mob/living/carbon/human/species_types/synths.dm +++ b/code/modules/mob/living/carbon/human/species_types/synths.dm @@ -1,10 +1,10 @@ /datum/species/synth - name = "Synth" //inherited from the real species, for health scanners and things + name = "Synthetic" //inherited from the real species, for health scanners and things id = "synth" say_mod = "beep boops" //inherited from a user's real species sexes = 0 species_traits = list(NOTRANSSTING,NOGENITALS,NOAROUSAL) //all of these + whatever we inherit from the real species - inherent_traits = list(TRAIT_VIRUSIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOHUNGER,TRAIT_NOBREATH) + inherent_traits = list(TRAIT_VIRUSIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOLIMBDISABLE,TRAIT_NOHUNGER,TRAIT_NOBREATH) inherent_biotypes = list(MOB_ROBOTIC, MOB_HUMANOID) dangerous_existence = 1 blacklisted = 1 @@ -12,7 +12,7 @@ damage_overlay_type = "synth" limbs_id = "synth" var/list/initial_species_traits = list(NOTRANSSTING) //for getting these values back for assume_disguise() - var/list/initial_inherent_traits = list(TRAIT_VIRUSIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOHUNGER,TRAIT_NOBREATH) + var/list/initial_inherent_traits = list(TRAIT_VIRUSIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOLIMBDISABLE,TRAIT_NOHUNGER,TRAIT_NOBREATH) var/disguise_fail_health = 75 //When their health gets to this level their synthflesh partially falls off var/datum/species/fake_species = null //a species to do most of our work for us, unless we're damaged diff --git a/code/modules/mob/living/carbon/human/species_types/vampire.dm b/code/modules/mob/living/carbon/human/species_types/vampire.dm index 4bc3d622ac..53c6f1bd0f 100644 --- a/code/modules/mob/living/carbon/human/species_types/vampire.dm +++ b/code/modules/mob/living/carbon/human/species_types/vampire.dm @@ -46,7 +46,7 @@ C.adjustCloneLoss(-4) return C.blood_volume -= 0.75 - if(C.blood_volume <= BLOOD_VOLUME_SURVIVE) + if(C.blood_volume <= (BLOOD_VOLUME_SURVIVE*C.blood_ratio)) to_chat(C, "You ran out of blood!") C.dust() var/area/A = get_area(C) 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 504dbb514b..e0cc3bb147 100644 --- a/code/modules/mob/living/carbon/human/species_types/zombies.dm +++ b/code/modules/mob/living/carbon/human/species_types/zombies.dm @@ -16,7 +16,12 @@ disliked_food = NONE liked_food = GROSS | MEAT | RAW -/datum/species/zombie/check_roundstart_eligible() +/datum/species/zombie/notspaceproof + id = "notspaceproofzombie" + blacklisted = 0 + inherent_traits = list(TRAIT_RESISTCOLD,TRAIT_RADIMMUNE,TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_NOBREATH,TRAIT_NODEATH,TRAIT_FAKEDEATH) + +/datum/species/zombie/notspaceproof/check_roundstart_eligible() if(SSevents.holidays && SSevents.holidays[HALLOWEEN]) return TRUE return ..() @@ -47,7 +52,7 @@ /datum/species/zombie/infectious/spec_life(mob/living/carbon/C) . = ..() C.a_intent = INTENT_HARM // THE SUFFERING MUST FLOW - + //Zombies never actually die, they just fall down until they regenerate enough to rise back up. //They must be restrained, beheaded or gibbed to stop being a threat. if(regen_cooldown < world.time) @@ -58,7 +63,7 @@ C.adjustToxLoss(-heal_amt) if(!C.InCritical() && prob(4)) playsound(C, pick(spooks), 50, TRUE, 10) - + //Congrats you somehow died so hard you stopped being a zombie /datum/species/zombie/infectious/spec_death(mob/living/carbon/C) . = ..() diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 72ff7e7a60..fa3e29f119 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -123,25 +123,20 @@ There are several things that need to be remembered: if(U.adjusted == ALT_STYLE) t_color = "[t_color]_d" - if(U.mutantrace_variation) - if(U.suit_style == DIGITIGRADE_SUIT_STYLE) - U.alternate_worn_icon = 'modular_citadel/icons/mob/uniform_digi.dmi' - if(U.adjusted == ALT_STYLE) - t_color = "[t_color]_d_l" - else if(U.adjusted == NORMAL_STYLE) - t_color = "[t_color]_l" - else - U.alternate_worn_icon = null + var/alt_worn = U.alternate_worn_icon + + if(!U.force_alternate_icon && U.mutantrace_variation && U.suit_style == DIGITIGRADE_SUIT_STYLE) + alt_worn = 'modular_citadel/icons/mob/uniform_digi.dmi' var/mutable_appearance/uniform_overlay if(dna && dna.species.sexes) var/G = (gender == FEMALE) ? "f" : "m" if(G == "f" && U.fitted != NO_FEMALE_UNIFORM) - uniform_overlay = U.build_worn_icon(state = "[t_color]", default_layer = UNIFORM_LAYER, default_icon_file = ((w_uniform.alternate_worn_icon) ? w_uniform.alternate_worn_icon : 'icons/mob/uniform.dmi'), isinhands = FALSE, femaleuniform = U.fitted) + uniform_overlay = U.build_worn_icon(state = "[t_color]", default_layer = UNIFORM_LAYER, default_icon_file = (alt_worn ? alt_worn : 'icons/mob/uniform.dmi'), isinhands = FALSE, femaleuniform = U.fitted) if(!uniform_overlay) - uniform_overlay = U.build_worn_icon(state = "[t_color]", default_layer = UNIFORM_LAYER, default_icon_file = ((w_uniform.alternate_worn_icon) ? w_uniform.alternate_worn_icon : 'icons/mob/uniform.dmi'), isinhands = FALSE) + uniform_overlay = U.build_worn_icon(state = "[t_color]", default_layer = UNIFORM_LAYER, default_icon_file = (alt_worn ? alt_worn : 'icons/mob/uniform.dmi'), isinhands = FALSE) if(OFFSET_UNIFORM in dna.species.offset_features) @@ -388,22 +383,23 @@ There are several things that need to be remembered: client.screen += wear_suit update_observer_view(wear_suit,1) - if(!no_taur_thanks && S.mutantrace_variation) //Just make sure we've got this checked too - if(S.taurmode == NOT_TAURIC && S.adjusted == ALT_STYLE) //are we not a taur, but we have Digitigrade legs? Run this check first, then. - S.alternate_worn_icon = 'modular_citadel/icons/mob/suit_digi.dmi' - else - S.alternate_worn_icon = null - - if(S.tauric == TRUE) //Are we a suit with tauric mode possible? - if(S.taurmode == SNEK_TAURIC) - S.alternate_worn_icon = 'modular_citadel/icons/mob/taur_naga.dmi' - if(S.taurmode == PAW_TAURIC) - S.alternate_worn_icon = 'modular_citadel/icons/mob/taur_canine.dmi' - if(S.taurmode == NOT_TAURIC && S.adjusted == ALT_STYLE) + if(!S.force_alternate_icon) + if(!no_taur_thanks && S.mutantrace_variation) //Just make sure we've got this checked too + if(S.taurmode == NOT_TAURIC && S.adjusted == ALT_STYLE) //are we not a taur, but we have Digitigrade legs? Run this check first, then. S.alternate_worn_icon = 'modular_citadel/icons/mob/suit_digi.dmi' - else if(S.taurmode == NOT_TAURIC && S.adjusted == NORMAL_STYLE) + else S.alternate_worn_icon = null + if(S.tauric == TRUE) //Are we a suit with tauric mode possible? + if(S.taurmode == SNEK_TAURIC) + S.alternate_worn_icon = 'modular_citadel/icons/mob/taur_naga.dmi' + if(S.taurmode == PAW_TAURIC) + S.alternate_worn_icon = 'modular_citadel/icons/mob/taur_canine.dmi' + if(S.taurmode == NOT_TAURIC && S.adjusted == ALT_STYLE) + S.alternate_worn_icon = 'modular_citadel/icons/mob/suit_digi.dmi' + else if(S.taurmode == NOT_TAURIC && S.adjusted == NORMAL_STYLE) + S.alternate_worn_icon = null + overlays_standing[SUIT_LAYER] = S.build_worn_icon(state = wear_suit.icon_state, default_layer = SUIT_LAYER, default_icon_file = ((wear_suit.alternate_worn_icon) ? S.alternate_worn_icon : 'icons/mob/suit.dmi')) var/mutable_appearance/suit_overlay = overlays_standing[SUIT_LAYER] if(OFFSET_SUIT in dna.species.offset_features) @@ -707,9 +703,9 @@ generate/load female uniform sprites matching all previously decided variables if(lip_style && (LIPS in dna.species.species_traits)) var/mutable_appearance/lip_overlay = mutable_appearance('icons/mob/human_face.dmi', "lips_[lip_style]", -BODY_LAYER) lip_overlay.color = lip_color - if(OFFSET_FACE in dna.species.offset_features) - lip_overlay.pixel_x += dna.species.offset_features[OFFSET_FACE][1] - lip_overlay.pixel_y += dna.species.offset_features[OFFSET_FACE][2] + if(OFFSET_LIPS in dna.species.offset_features) + lip_overlay.pixel_x += dna.species.offset_features[OFFSET_LIPS][1] + lip_overlay.pixel_y += dna.species.offset_features[OFFSET_LIPS][2] add_overlay(lip_overlay) // eyes @@ -722,9 +718,9 @@ generate/load female uniform sprites matching all previously decided variables eye_overlay = mutable_appearance('icons/mob/human_face.dmi', "eyes", -BODY_LAYER) if((EYECOLOR in dna.species.species_traits) && has_eyes) eye_overlay.color = "#" + eye_color - if(OFFSET_FACE in dna.species.offset_features) - eye_overlay.pixel_x += dna.species.offset_features[OFFSET_FACE][1] - eye_overlay.pixel_y += dna.species.offset_features[OFFSET_FACE][2] + if(OFFSET_EYES in dna.species.offset_features) + eye_overlay.pixel_x += dna.species.offset_features[OFFSET_EYES][1] + eye_overlay.pixel_y += dna.species.offset_features[OFFSET_EYES][2] add_overlay(eye_overlay) dna.species.handle_hair(src) diff --git a/code/modules/mob/living/carbon/human/whisper.dm b/code/modules/mob/living/carbon/human/whisper.dm deleted file mode 100644 index 65a4c5d33f..0000000000 --- a/code/modules/mob/living/carbon/human/whisper.dm +++ /dev/null @@ -1,91 +0,0 @@ -/mob/living/carbon/human/whisper_verb(message as text) - whisper(message) - -/mob/living/carbon/human/whisper(message, datum/language/language=null) - if(!IsVocal()) - return - if(!message) - return - if(!language) - language = get_default_language() - - if(GLOB.say_disabled) //This is here to try to identify lag problems - to_chat(usr, "Speech is currently admin-disabled.") - return - - if(stat == DEAD) - return - - - message = trim(html_encode(message)) - if(!can_speak(message)) - return - - message = "[message]" - log_whisper("[src.name]/[src.key] : [message]") - - if (src.client) - if (src.client.prefs.muted & MUTE_IC) - to_chat(src, "You cannot whisper (muted).") - return - - log_whisper("[src.name]/[src.key] : [message]") - - var/alt_name = get_alt_name() - - var/whispers = "whispers" - var/critical = InCritical() - - // We are unconscious but not in critical, so don't allow them to whisper. - if(stat == UNCONSCIOUS && !critical) - return - - // If whispering your last words, limit the whisper based on how close you are to death. - if(critical) - var/health_diff = round(-HEALTH_THRESHOLD_DEAD + health) - // If we cut our message short, abruptly end it with a-.. - var/message_len = length(message) - message = copytext(message, 1, health_diff) + "[message_len > health_diff ? "-.." : "..."]" - message = Ellipsis(message, 10, 1) - - message = treat_message(message) - if(!message) - return - - var/list/listening_dead = list() - for(var/mob/M in GLOB.player_list) - if(M.stat == DEAD && M.client && ((M.client.prefs.chat_toggles & CHAT_GHOSTWHISPER) || (get_dist(M, src) <= 7))) - listening_dead |= M - - var/list/listening = get_hearers_in_view(1, src) - listening |= listening_dead - var/list/eavesdropping = get_hearers_in_view(2, src) - eavesdropping -= listening - var/list/watching = hearers(5, src) - watching -= listening - watching -= eavesdropping - - var/rendered - whispers = critical ? "whispers something in [p_their()] final breath." : "whispers something." - rendered = "[src.name] [whispers]" - for(var/mob/M in watching) - M.show_message(rendered, 2) - - var/spans = list(SPAN_ITALICS) - whispers = critical ? "whispers in [p_their()] final breath" : "whispers" - rendered = "[GetVoice()][alt_name] [whispers], \"[attach_spans(message, spans)]\"" - - for(var/atom/movable/AM in listening) - if(istype(AM,/obj/item/radio)) - continue - AM.Hear(rendered, src, language, message, , spans) - - message = stars(message) - rendered = "[GetVoice()][alt_name] [whispers], \"[attach_spans(message, spans)]\"" - for(var/atom/movable/AM in eavesdropping) - if(istype(AM,/obj/item/radio)) - continue - AM.Hear(rendered, src, language, message, , spans) - - if(critical) //Dying words. - succumb(1) diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index ec80da6b53..5b18e95235 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -4,13 +4,12 @@ if(notransform) return - if(damageoverlaytemp || stamdamageoverlaytemp) + if(damageoverlaytemp) damageoverlaytemp = 0 - stamdamageoverlaytemp = 0 update_damage_hud() - if(stat != DEAD) //Reagent processing needs to come before breathing, to prevent edge cases. - handle_organs() + //Reagent processing needs to come before breathing, to prevent edge cases. + handle_organs() . = ..() @@ -29,11 +28,14 @@ if(stat != DEAD) handle_brain_damage() + /* BUG_PROBABLE_CAUSE if(stat != DEAD) handle_liver() + */ if(stat == DEAD) stop_sound_channel(CHANNEL_HEARTBEAT) + handle_death() rot() //Updates the number of stored chemicals for powers @@ -42,14 +44,34 @@ if(stat != DEAD) return 1 +//Procs called while dead +/mob/living/carbon/proc/handle_death() + for(var/datum/reagent/R in reagents.reagent_list) + if(R.chemical_flags & REAGENT_DEAD_PROCESS) + R.on_mob_dead(src) + /////////////// // BREATHING // /////////////// //Start of a breath chain, calls breathe() /mob/living/carbon/handle_breathing(times_fired) - if((times_fired % 4) == 2 || failed_last_breath) - breathe() //Breathe per 4 ticks, unless suffocating + var/next_breath = 4 + var/obj/item/organ/lungs/L = getorganslot(ORGAN_SLOT_LUNGS) + var/obj/item/organ/heart/H = getorganslot(ORGAN_SLOT_HEART) + if(L) + if(L.damage > L.high_threshold) + next_breath-- + if(H) + if(H.damage > H.high_threshold) + next_breath-- + + if((times_fired % next_breath) == 0 || failed_last_breath) + breathe() //Breathe per 4 ticks if healthy, down to 2 if our lungs or heart are damaged, unless suffocating + if(failed_last_breath) + SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "suffocation", /datum/mood_event/suffocation) + else + SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "suffocation") else if(istype(loc, /obj/)) var/obj/location_as_object = loc @@ -57,6 +79,7 @@ //Second link in a breath chain, calls check_breath() /mob/living/carbon/proc/breathe() + var/obj/item/organ/lungs = getorganslot(ORGAN_SLOT_LUNGS) if(reagents.has_reagent("lexorin")) return if(istype(loc, /obj/machinery/atmospherics/components/unary/cryo_cell)) @@ -75,7 +98,7 @@ var/datum/gas_mixture/breath if(!getorganslot(ORGAN_SLOT_BREATHING_TUBE)) - if(health <= HEALTH_THRESHOLD_FULLCRIT || (pulledby && pulledby.grab_state >= GRAB_KILL)) + if(health <= HEALTH_THRESHOLD_FULLCRIT || (pulledby && pulledby.grab_state >= GRAB_KILL) || lungs.organ_flags & ORGAN_FAILING) losebreath++ //You can't breath at all when in critical or when being choked, so you're going to miss a breath else if(health <= crit_threshold) @@ -127,7 +150,7 @@ if((status_flags & GODMODE)) return - var/lungs = getorganslot(ORGAN_SLOT_LUNGS) + var/obj/item/organ/lungs = getorganslot(ORGAN_SLOT_LUNGS) if(!lungs) adjustOxyLoss(2) @@ -229,6 +252,9 @@ else if(SA_partialpressure > 0.01) if(prob(20)) emote(pick("giggle","laugh")) + SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "chemical_euphoria", /datum/mood_event/chemical_euphoria) + else + SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "chemical_euphoria") //BZ (Facepunch port of their Agent B) if(breath_gases[/datum/gas/bz]) @@ -305,11 +331,17 @@ return /mob/living/carbon/proc/get_breath_from_internal(volume_needed) + var/obj/item/clothing/check + var/internals = FALSE + + for(check in GET_INTERNAL_SLOTS(src)) + if(CHECK_BITFIELD(check.clothing_flags, ALLOWINTERNALS)) + internals = TRUE if(internal) if(internal.loc != src) internal = null update_internals_hud_icon(0) - else if ((!wear_mask || !(wear_mask.clothing_flags & MASKINTERNALS)) && !getorganslot(ORGAN_SLOT_BREATHING_TUBE)) + else if (!internals && !getorganslot(ORGAN_SLOT_BREATHING_TUBE)) internal = null update_internals_hud_icon(0) else @@ -358,9 +390,16 @@ . |= BP.on_life() /mob/living/carbon/proc/handle_organs() - for(var/V in internal_organs) - var/obj/item/organ/O = V - O.on_life() + if(stat != DEAD) + for(var/V in internal_organs) + var/obj/item/organ/O = V + if(O) + O.on_life() + else + for(var/V in internal_organs) + var/obj/item/organ/O = V + if(O) + O.on_death() //Needed so organs decay while inside the body. /mob/living/carbon/handle_diseases() for(var/thing in diseases) @@ -467,7 +506,7 @@ GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put /mob/living/carbon/handle_status_effects() ..() if(getStaminaLoss() && !combatmode)//CIT CHANGE - prevents stamina regen while combat mode is active - adjustStaminaLoss(resting ? (recoveringstam ? -7.5 : -3) : -1.5)//CIT CHANGE - decreases adjuststaminaloss to stop stamina damage from being such a joke + adjustStaminaLoss(resting ? (recoveringstam ? -7.5 : -6) : -3)//CIT CHANGE - decreases adjuststaminaloss to stop stamina damage from being such a joke if(!recoveringstam && incomingstammult != 1) incomingstammult = max(0.01, incomingstammult) @@ -527,6 +566,9 @@ GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put if(jitteriness) do_jitter_animation(jitteriness) jitteriness = max(jitteriness - restingpwr, 0) + SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "jittery", /datum/mood_event/jittery) + else + SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "jittery") if(stuttering) stuttering = max(stuttering-1, 0) @@ -602,7 +644,7 @@ GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put to_chat(src, "Maybe you should lie down for a bit...") if(drunkenness >= 91) - adjustBrainLoss(0.4, 60) + adjustOrganLoss(ORGAN_SLOT_BRAIN, 0.4, 60) if(prob(20) && !stat) if(SSshuttle.emergency.mode == SHUTTLE_DOCKED && is_station_level(z)) //QoL mainly to_chat(src, "You're so tired... but you can't miss that shuttle...") @@ -612,6 +654,8 @@ GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put if(drunkenness >= 101) adjustToxLoss(4) //Let's be honest you shouldn't be alive by now + else + SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "drunk") //used in human and monkey handle_environment() /mob/living/carbon/proc/natural_bodytemperature_stabilization() @@ -634,8 +678,8 @@ GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put if((!dna && !liver) || (NOLIVER in dna.species.species_traits)) return if(liver) - if(liver.damage >= liver.maxHealth) - liver.failing = TRUE + if(liver.damage < liver.maxHealth) + liver.organ_flags |= ORGAN_FAILING liver_failure() else liver_failure() @@ -658,7 +702,7 @@ GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put /mob/living/carbon/proc/liver_failure() reagents.end_metabolization(src, keep_liverless = TRUE) //Stops trait-based effects on reagents, to prevent permanent buffs reagents.metabolize(src, can_overdose=FALSE, liverless = TRUE) - if(HAS_TRAIT(src, TRAIT_STABLEHEART)) + if(HAS_TRAIT(src, TRAIT_STABLELIVER)) return adjustToxLoss(4, TRUE, TRUE) if(prob(30)) @@ -674,13 +718,6 @@ GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put var/datum/brain_trauma/BT = T BT.on_life() - if(getBrainLoss() >= BRAIN_DAMAGE_DEATH) //rip - to_chat(src, "The last spark of life in your brain fizzles out...") - death() - var/obj/item/organ/brain/B = getorganslot(ORGAN_SLOT_BRAIN) - if(B) - B.damaged_brain = TRUE - ///////////////////////////////////// //MONKEYS WITH TOO MUCH CHOLOESTROL// ///////////////////////////////////// @@ -689,7 +726,7 @@ GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put if(!needs_heart()) return FALSE var/obj/item/organ/heart/heart = getorganslot(ORGAN_SLOT_HEART) - if(!heart || heart.synthetic) + if(!heart || (heart.organ_flags & ORGAN_SYNTHETIC)) return FALSE return TRUE diff --git a/code/modules/mob/living/carbon/monkey/inventory.dm b/code/modules/mob/living/carbon/monkey/inventory.dm index fdc28d13a0..d5fffc70a2 100644 --- a/code/modules/mob/living/carbon/monkey/inventory.dm +++ b/code/modules/mob/living/carbon/monkey/inventory.dm @@ -1,4 +1,4 @@ -/mob/living/carbon/monkey/can_equip(obj/item/I, slot, disable_warning = 0) +/mob/living/carbon/monkey/can_equip(obj/item/I, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE) switch(slot) if(SLOT_HANDS) if(get_empty_held_indexes()) diff --git a/code/modules/mob/living/carbon/update_icons.dm b/code/modules/mob/living/carbon/update_icons.dm index 44c2508894..cdae073af8 100644 --- a/code/modules/mob/living/carbon/update_icons.dm +++ b/code/modules/mob/living/carbon/update_icons.dm @@ -187,9 +187,9 @@ clear_alert("legcuffed") if(legcuffed) var/mutable_appearance/legcuffs = mutable_appearance('icons/mob/restraints.dmi', legcuffed.item_state, -LEGCUFF_LAYER) - legcuffs.color = handcuffed.color + legcuffs.color = legcuffed.color - overlays_standing[HANDCUFF_LAYER] = legcuffs + overlays_standing[LEGCUFF_LAYER] = legcuffs apply_overlay(LEGCUFF_LAYER) throw_alert("legcuffed", /obj/screen/alert/restrained/legcuffed, new_master = legcuffed) diff --git a/code/modules/mob/living/damage_procs.dm b/code/modules/mob/living/damage_procs.dm index b2eed2d19e..fbb6074ba2 100644 --- a/code/modules/mob/living/damage_procs.dm +++ b/code/modules/mob/living/damage_procs.dm @@ -25,8 +25,6 @@ adjustCloneLoss(damage * hit_percent) if(STAMINA) adjustStaminaLoss(damage * hit_percent) - if(BRAIN) - adjustBrainLoss(damage * hit_percent) return 1 /mob/living/proc/apply_damage_type(damage = 0, damagetype = BRUTE) //like apply damage except it always uses the damage procs @@ -43,8 +41,6 @@ return adjustCloneLoss(damage) if(STAMINA) return adjustStaminaLoss(damage) - if(BRAIN) - return adjustBrainLoss(damage) /mob/living/proc/get_damage_amount(damagetype = BRUTE) switch(damagetype) @@ -60,8 +56,6 @@ return getCloneLoss() if(STAMINA) return getStaminaLoss() - if(BRAIN) - return getBrainLoss() /mob/living/proc/apply_damages(brute = 0, burn = 0, tox = 0, oxy = 0, clone = 0, def_zone = null, blocked = FALSE, stamina = 0, brain = 0) @@ -85,7 +79,7 @@ -/mob/living/proc/apply_effect(effect = 0,effecttype = EFFECT_STUN, blocked = FALSE) +/mob/living/proc/apply_effect(effect = 0,effecttype = EFFECT_STUN, blocked = FALSE, knockdown_stamoverride, knockdown_stammax) var/hit_percent = (100-blocked)/100 if(!effect || (hit_percent <= 0)) return 0 @@ -93,7 +87,7 @@ if(EFFECT_STUN) Stun(effect * hit_percent) if(EFFECT_KNOCKDOWN) - Knockdown(effect * hit_percent) + Knockdown(effect * hit_percent, override_stamdmg = knockdown_stammax ? CLAMP(knockdown_stamoverride, 0, knockdown_stammax-getStaminaLoss()) : knockdown_stamoverride) if(EFFECT_UNCONSCIOUS) Unconscious(effect * hit_percent) if(EFFECT_IRRADIATE) @@ -113,13 +107,13 @@ return 1 -/mob/living/proc/apply_effects(stun = 0, knockdown = 0, unconscious = 0, irradiate = 0, slur = 0, stutter = 0, eyeblur = 0, drowsy = 0, blocked = FALSE, stamina = 0, jitter = 0) +/mob/living/proc/apply_effects(stun = 0, knockdown = 0, unconscious = 0, irradiate = 0, slur = 0, stutter = 0, eyeblur = 0, drowsy = 0, blocked = FALSE, stamina = 0, jitter = 0, kd_stamoverride, kd_stammax) if(blocked >= 100) return 0 if(stun) apply_effect(stun, EFFECT_STUN, blocked) if(knockdown) - apply_effect(knockdown, EFFECT_KNOCKDOWN, blocked) + apply_effect(knockdown, EFFECT_KNOCKDOWN, blocked, kd_stamoverride, kd_stammax) if(unconscious) apply_effect(unconscious, EFFECT_UNCONSCIOUS, blocked) if(irradiate) @@ -218,13 +212,13 @@ updatehealth() return amount -/mob/living/proc/getBrainLoss() - . = 0 - -/mob/living/proc/adjustBrainLoss(amount, maximum = BRAIN_DAMAGE_DEATH) +/mob/living/proc/adjustOrganLoss(slot, amount, maximum) return -/mob/living/proc/setBrainLoss(amount) +/mob/living/proc/setOrganLoss(slot, amount, maximum) + return + +/mob/living/proc/getOrganLoss(slot) return /mob/living/proc/getStaminaLoss() diff --git a/code/modules/mob/living/death.dm b/code/modules/mob/living/death.dm index f16572c5d0..f7dec3272c 100644 --- a/code/modules/mob/living/death.dm +++ b/code/modules/mob/living/death.dm @@ -13,6 +13,10 @@ if(!no_bodyparts) spread_bodyparts(no_brain, no_organs) + for(var/X in implants) + var/obj/item/implant/I = X + qdel(I) + spawn_gibs(no_bodyparts) qdel(src) diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm index 25d8c4d44c..df711a6dca 100644 --- a/code/modules/mob/living/emote.dm +++ b/code/modules/mob/living/emote.dm @@ -255,7 +255,7 @@ H.Knockdown(20) else message_param = "bumps [user.p_their()] head on the ground trying to motion towards %t." - H.adjustBrainLoss(5) + H.adjustOrganLoss(ORGAN_SLOT_BRAIN, 5) ..() /datum/emote/living/pout diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 0559e4f3d8..812733ebe2 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -287,6 +287,8 @@ if(HAS_TRAIT(src, TRAIT_STRONG_GRABBER)) C.grippedby(src) + update_pull_movespeed() + //mob verbs are a lot faster than object verbs //for more info on why this is not atom/pull, see examinate() in mob.dm /mob/living/verb/pulled(atom/movable/AM as mob|obj in oview(1)) @@ -300,6 +302,7 @@ /mob/living/stop_pulling() ..() + update_pull_movespeed() update_pull_hud_icon() /mob/living/verb/stop_pulling1() @@ -318,21 +321,36 @@ visible_message("[src] points at [A].", "You point at [A].") return TRUE -/mob/living/verb/succumb(whispered as null) +/mob/living/verb/succumb() set name = "Succumb" set category = "IC" + if(src.has_status_effect(/datum/status_effect/chem/enthrall)) + var/datum/status_effect/chem/enthrall/E = src.has_status_effect(/datum/status_effect/chem/enthrall) + if(E.phase < 3) + if(HAS_TRAIT(src, TRAIT_MINDSHIELD)) + to_chat(src, "Your mindshield prevents your mind from giving in!") + else if(src.mind.assigned_role in GLOB.command_positions) + to_chat(src, "Your dedication to your department prevents you from giving in!") + else + E.enthrallTally += 20 + to_chat(src, "You give into [E.master]'s influence.") if (InCritical()) - log_message("Has [whispered ? "whispered his final words" : "succumbed to death"] while in [InFullCritical() ? "hard":"soft"] critical with [round(health, 0.1)] points of health!", LOG_ATTACK) + log_message("Has succumbed to death while in [InFullCritical() ? "hard":"soft"] critical with [round(health, 0.1)] points of health!", LOG_ATTACK) adjustOxyLoss(health - HEALTH_THRESHOLD_DEAD) updatehealth() - if(!whispered) - to_chat(src, "You have given up life and succumbed to death.") + to_chat(src, "You have given up life and succumbed to death.") death() + /mob/living/incapacitated(ignore_restraints, ignore_grab) if(stat || IsUnconscious() || IsStun() || IsKnockdown() || recoveringstam || (!ignore_restraints && restrained(ignore_grab))) // CIT CHANGE - adds recoveringstam check here return TRUE +/mob/living/canUseStorage() + if (get_num_arms() <= 0) + return FALSE + return TRUE + /mob/living/proc/InCritical() return (health <= crit_threshold && (stat == SOFT_CRIT || stat == UNCONSCIOUS)) @@ -463,7 +481,6 @@ setToxLoss(0, 0) //zero as second argument not automatically call updatehealth(). setOxyLoss(0, 0) setCloneLoss(0, 0) - setBrainLoss(0) setStaminaLoss(0, 0) SetUnconscious(0, FALSE) set_disgust(0) @@ -490,6 +507,13 @@ QDEL_LIST_ASSOC_VAL(mood.mood_events) mood.sanity = SANITY_GREAT mood.update_mood() + //Heal all organs + if(iscarbon(src)) + var/mob/living/carbon/C = src + if(C.internal_organs) + for(var/organ in C.internal_organs) + var/obj/item/organ/O = organ + O.setOrganDamage(0) //proc called by revive(), to check if we can actually ressuscitate the mob (we don't want to revive him and have him instantly die again) @@ -510,6 +534,10 @@ var/old_direction = dir var/turf/T = loc + + if(pulling) + update_pull_movespeed() + . = ..() if(pulledby && moving_diagonally != FIRST_DIAG_STEP && get_dist(src, pulledby) > 1)//separated from our puller and not in the middle of a diagonal move. @@ -532,7 +560,7 @@ var/trail_type = getTrail() if(trail_type) var/brute_ratio = round(getBruteLoss() / maxHealth, 0.1) - if(blood_volume && blood_volume > max(BLOOD_VOLUME_NORMAL*(1 - brute_ratio * 0.25), 0))//don't leave trail if blood volume below a threshold + if(blood_volume && blood_volume > max((BLOOD_VOLUME_NORMAL*blood_ratio)*(1 - brute_ratio * 0.25), 0))//don't leave trail if blood volume below a threshold blood_volume = max(blood_volume - max(1, brute_ratio * 2), 0) //that depends on our brute damage. var/newdir = get_dir(target_turf, start) if(newdir != direction) @@ -626,14 +654,15 @@ else if(canmove) if(on_fire) resist_fire() //stop, drop, and roll - else if(resting) //cit change - allows resisting out of resting + return + if(resting) //cit change - allows resisting out of resting resist_a_rest() // ditto - else if(iscarbon(src)) //Citadel Change for embedded removal memes - var/mob/living/carbon/C = src - if(!C.handcuffed && !C.legcuffed) - return TRUE - else if(last_special <= world.time) + return + if(resist_embedded()) //Citadel Change for embedded removal memes + return + if(last_special <= world.time) resist_restraints() //trying to remove cuffs. + return /mob/proc/resist_grab(moving_resist) @@ -883,7 +912,7 @@ if(mind) mind.transfer_to(new_mob) else - new_mob.key = key + transfer_ckey(new_mob) for(var/para in hasparasites()) var/mob/living/simple_animal/hostile/guardian/G = para @@ -1012,6 +1041,9 @@ stop_pulling() //CIT CHANGE - Ditto... else if(has_legs || ignore_legs) lying = 0 + if (pulledby) + var/mob/living/L = pulledby + L.update_pull_movespeed() if(buckled) lying = 90*buckle_lying else if(!lying) diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index e434bc4e95..9d04f288cd 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -153,7 +153,7 @@ to_chat(user, "[src] can't be grabbed more aggressively!") return FALSE - if(HAS_TRAIT(user, TRAIT_PACIFISM)) + if(user.grab_state >= GRAB_AGGRESSIVE && HAS_TRAIT(user, TRAIT_PACIFISM)) to_chat(user, "You don't want to risk hurting [src]!") return FALSE @@ -184,11 +184,17 @@ user.grab_state++ switch(user.grab_state) if(GRAB_AGGRESSIVE) - log_combat(user, src, "grabbed", addition="aggressive grab") - visible_message("[user] has grabbed [src] aggressively!", \ - "[user] has grabbed [src] aggressively!") - drop_all_held_items() + var/add_log = "" + if(HAS_TRAIT(user, TRAIT_PACIFISM)) + visible_message("[user] has firmly gripped [src]!", + "[user] has firmly gripped you!") + add_log = " (pacifist)" + else + visible_message("[user] has grabbed [src] aggressively!", \ + "[user] has grabbed you aggressively!") + drop_all_held_items() stop_pulling() + log_combat(user, src, "grabbed", addition="aggressive grab[add_log]") if(GRAB_NECK) log_combat(user, src, "grabbed", addition="neck grab") visible_message("[user] has grabbed [src] by the neck!",\ diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm index 3b0af53866..4d2a36907d 100644 --- a/code/modules/mob/living/living_defines.dm +++ b/code/modules/mob/living/living_defines.dm @@ -2,7 +2,7 @@ see_invisible = SEE_INVISIBLE_LIVING sight = 0 see_in_dark = 2 - hud_possible = list(HEALTH_HUD,STATUS_HUD,ANTAG_HUD,NANITE_HUD,DIAG_NANITE_FULL_HUD) + hud_possible = list(HEALTH_HUD,STATUS_HUD,ANTAG_HUD,NANITE_HUD,DIAG_NANITE_FULL_HUD,RAD_HUD) pressure_resistance = 10 var/resize = 1 //Badminnery resize @@ -77,6 +77,7 @@ var/stun_absorption = null //converted to a list of stun absorption sources this mob has when one is added var/blood_volume = 0 //how much blood the mob has + var/blood_ratio = 1 //How much blood the mob needs, in terms of ratio (i.e 1.2 will require BLOOD_VOLUME_NORMAL of 672) DO NOT GO ABOVE 3.55 Well, actually you can but, then they can't get enough blood. var/obj/effect/proc_holder/ranged_ability //Any ranged ability the mob has, as a click override var/see_override = 0 //0 for no override, sets see_invisible = see_override in silicon & carbon life process via update_sight() @@ -109,3 +110,5 @@ //List of active diseases var/list/diseases = list() // list of all diseases in a mob var/list/disease_resistances = list() + + var/drag_slowdown = TRUE //Whether the mob is slowed down when dragging another prone mob \ No newline at end of file diff --git a/code/modules/mob/living/living_movement.dm b/code/modules/mob/living/living_movement.dm index 9566edc2ed..1ee563bc1f 100644 --- a/code/modules/mob/living/living_movement.dm +++ b/code/modules/mob/living/living_movement.dm @@ -25,3 +25,11 @@ add_movespeed_modifier(MOVESPEED_ID_LIVING_TURF_SPEEDMOD, TRUE, 100, override = TRUE, multiplicative_slowdown = T.slowdown) else remove_movespeed_modifier(MOVESPEED_ID_LIVING_TURF_SPEEDMOD) + +/mob/living/proc/update_pull_movespeed() + if(pulling && isliving(pulling)) + var/mob/living/L = pulling + if(drag_slowdown && L.lying && !L.buckled && grab_state < GRAB_AGGRESSIVE) + add_movespeed_modifier(MOVESPEED_ID_PRONE_DRAGGING, multiplicative_slowdown = PULL_PRONE_SLOWDOWN) + return + remove_movespeed_modifier(MOVESPEED_ID_PRONE_DRAGGING) \ No newline at end of file diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index bfd27c11cc..5664c2ebca 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -211,7 +211,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list( send_speech(message, message_range, src, bubble_type, spans, language, message_mode) if(succumbed) - succumb(1) + succumb() to_chat(src, compose_message(src, language, message, , spans, message_mode)) return 1 @@ -281,6 +281,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list( AM.Hear(eavesrendered, src, message_language, eavesdropping, , spans, message_mode) else AM.Hear(rendered, src, message_language, message, , spans, message_mode) + SEND_GLOBAL_SIGNAL(COMSIG_GLOB_LIVING_SAY_SPECIAL, src, message) //speech bubble var/list/speech_bubble_recipients = list() @@ -356,8 +357,8 @@ GLOBAL_LIST_INIT(department_radio_keys, list( return message /mob/living/proc/radio(message, message_mode, list/spans, language) - var/obj/item/implant/radio/imp = locate() in src - if(imp && imp.radio.on) + var/obj/item/implant/radio/imp = locate() in implants + if(imp?.radio.on) if(message_mode == MODE_HEADSET) imp.radio.talk_into(src, message, , spans, language) return ITALICS | REDUCE_RANGE diff --git a/code/modules/mob/living/silicon/ai/say.dm b/code/modules/mob/living/silicon/ai/say.dm index 4ac5c1f0bb..f757203237 100644 --- a/code/modules/mob/living/silicon/ai/say.dm +++ b/code/modules/mob/living/silicon/ai/say.dm @@ -49,7 +49,7 @@ else padloc = "(UNKNOWN)" src.log_talk(message, LOG_SAY, tag="HOLOPAD in [padloc]") - send_speech(message, 7, T, "robot", language = language) + send_speech(message, 7, T, "robot", message_language = language) to_chat(src, "Holopad transmitted, [real_name] \"[message]\"") else to_chat(src, "No holopad connected.") @@ -100,6 +100,8 @@ last_announcement = message + var/voxType = input(src, "Male or female VOX?", "VOX-gender") in list("male", "female") + if(!message || announcing_vox > world.time) return @@ -121,7 +123,9 @@ if(!word) words -= word continue - if(!GLOB.vox_sounds[word]) + if(!GLOB.vox_sounds[word] && voxType == "female") + incorrect_words += word + if(!GLOB.vox_sounds_male[word] && voxType == "male") incorrect_words += word if(incorrect_words.len) @@ -133,16 +137,21 @@ log_game("[key_name(src)] made a vocal announcement with the following message: [message].") for(var/word in words) - play_vox_word(word, src.z, null) + play_vox_word(word, src.z, null, voxType) -/proc/play_vox_word(word, z_level, mob/only_listener) +/proc/play_vox_word(word, z_level, mob/only_listener, voxType = "female") word = lowertext(word) - if(GLOB.vox_sounds[word]) + if( (GLOB.vox_sounds[word] && voxType == "female") || (GLOB.vox_sounds_male[word] && voxType == "male") ) - var/sound_file = GLOB.vox_sounds[word] + var/sound_file + + if(voxType == "female") + sound_file = GLOB.vox_sounds[word] + else + sound_file = GLOB.vox_sounds_male[word] var/sound/voice = sound(sound_file, wait = 1, channel = CHANNEL_VOX) voice.status = SOUND_STREAM diff --git a/code/modules/mob/living/silicon/damage_procs.dm b/code/modules/mob/living/silicon/damage_procs.dm index 1190a00645..69d150b315 100644 --- a/code/modules/mob/living/silicon/damage_procs.dm +++ b/code/modules/mob/living/silicon/damage_procs.dm @@ -35,8 +35,8 @@ /mob/living/silicon/setStaminaLoss(amount, updating_stamina = 1) return FALSE -/mob/living/silicon/adjustBrainLoss(amount) +/mob/living/silicon/adjustOrganLoss(slot, amount, maximum = 500) return FALSE -/mob/living/silicon/setBrainLoss(amount) +/mob/living/silicon/setOrganLoss(slot, amount) return FALSE diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index 7fd861bfeb..0f8687397d 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -192,7 +192,7 @@ /mob/proc/makePAI(delold) var/obj/item/paicard/card = new /obj/item/paicard(get_turf(src)) var/mob/living/silicon/pai/pai = new /mob/living/silicon/pai(card) - pai.key = key + transfer_ckey(pai) pai.name = name card.setPersonality(pai) if(delold) diff --git a/code/modules/mob/living/silicon/pai/pai_defense.dm b/code/modules/mob/living/silicon/pai/pai_defense.dm index f20ccbc730..f36e996b81 100644 --- a/code/modules/mob/living/silicon/pai/pai_defense.dm +++ b/code/modules/mob/living/silicon/pai/pai_defense.dm @@ -84,7 +84,7 @@ /mob/living/silicon/pai/adjustStaminaLoss(amount) take_holo_damage(amount & 0.25) -/mob/living/silicon/pai/adjustBrainLoss(amount) +/mob/living/silicon/pai/adjustOrganLoss(slot, amount, maximum = 500) //I kept this in, unlike tg Knockdown(amount * 0.2) /mob/living/silicon/pai/getBruteLoss() @@ -102,18 +102,12 @@ /mob/living/silicon/pai/getCloneLoss() return FALSE -/mob/living/silicon/pai/getBrainLoss() - return FALSE - /mob/living/silicon/pai/getStaminaLoss() return FALSE /mob/living/silicon/pai/setCloneLoss() return FALSE -/mob/living/silicon/pai/setBrainLoss() - return FALSE - /mob/living/silicon/pai/setStaminaLoss() return FALSE diff --git a/code/modules/mob/living/silicon/robot/examine.dm b/code/modules/mob/living/silicon/robot/examine.dm index 4c4bdb9a3f..5e56b4180d 100644 --- a/code/modules/mob/living/silicon/robot/examine.dm +++ b/code/modules/mob/living/silicon/robot/examine.dm @@ -1,5 +1,5 @@ /mob/living/silicon/robot/examine(mob/user) - var/msg = "*---------*\nThis is [icon2html(src, user)] \a [src]!\n" + var/msg = "*---------*\nThis is [icon2html(src, user)] \a [src], a [src.module.name]!\n" if(desc) msg += "[desc]\n" diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 29fbd39e2c..2b2cc4c0b5 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -108,6 +108,9 @@ buckle_lying = FALSE var/static/list/can_ride_typecache = typecacheof(/mob/living/carbon/human) + var/sitting = 0 + var/bellyup = 0 + /mob/living/silicon/robot/get_cell() return cell @@ -173,6 +176,7 @@ diag_hud_set_borgcell() verbs += /mob/living/proc/lay_down //CITADEL EDIT gimmie rest verb kthx + verbs += /mob/living/silicon/robot/proc/rest_style //If there's an MMI in the robot, have it ejected when the mob goes away. --NEO /mob/living/silicon/robot/Destroy() @@ -222,6 +226,9 @@ to_chat(src,"ERROR: Module installer reply timeout. Please check internal connections.") return + if(!CONFIG_GET(flag/disable_secborg) && GLOB.security_level < CONFIG_GET(number/minimum_secborg_alert)) + to_chat(src, "NOTICE: Due to local station regulations, the security cyborg module and its variants are only available during [num2seclevel(CONFIG_GET(number/minimum_secborg_alert))] alert and greater.") + var/list/modulelist = list("Standard" = /obj/item/robot_module/standard, \ "Engineering" = /obj/item/robot_module/engineering, \ "Medical" = /obj/item/robot_module/medical, \ @@ -230,7 +237,7 @@ "Service" = /obj/item/robot_module/butler) if(!CONFIG_GET(flag/disable_peaceborg)) modulelist["Peacekeeper"] = /obj/item/robot_module/peacekeeper - if(!CONFIG_GET(flag/disable_secborg)) + if(BORG_SEC_AVAILABLE) modulelist["Security"] = /obj/item/robot_module/security modulelist += get_cit_modules() //Citadel change - adds Citadel's borg modules. @@ -657,13 +664,6 @@ add_overlay("[module.sleeper_overlay]_g[sleeper_nv ? "_nv" : ""]") if(sleeper_r && module.sleeper_overlay) add_overlay("[module.sleeper_overlay]_r[sleeper_nv ? "_nv" : ""]") - if(module.dogborg == TRUE) - if(resting) - cut_overlays() - icon_state = "[module.cyborg_base_icon]-rest" - else - icon_state = "[module.cyborg_base_icon]" - if(stat == DEAD && module.has_snowflake_deadsprite) icon_state = "[module.cyborg_base_icon]-wreck" @@ -697,6 +697,18 @@ add_overlay(head_overlay) update_fire() + if(client && stat != DEAD && module.dogborg == TRUE) + if(resting) + if(sitting) + icon_state = "[module.cyborg_base_icon]-sit" + if(bellyup) + icon_state = "[module.cyborg_base_icon]-bellyup" + else if(!sitting && !bellyup) + icon_state = "[module.cyborg_base_icon]-rest" + cut_overlays() + else + icon_state = "[module.cyborg_base_icon]" + /mob/living/silicon/robot/proc/self_destruct() if(emagged) if(mmi) @@ -1207,14 +1219,15 @@ return if(incapacitated()) return - if(M.incapacitated()) - return if(module) if(!module.allow_riding) M.visible_message("Unfortunately, [M] just can't seem to hold onto [src]!") return - if(iscarbon(M) && (!riding_datum.equip_buckle_inhands(M, 1))) - M.visible_message("[M] can't climb onto [src] because [M.p_their()] hands are full!") + if(iscarbon(M) && !M.incapacitated() && !riding_datum.equip_buckle_inhands(M, 1)) + if(M.get_num_arms() <= 0) + M.visible_message("[M] can't climb onto [src] because [M.p_they()] don't have any usable arms!") + else + M.visible_message("[M] can't climb onto [src] because [M.p_their()] hands are full!") return . = ..(M, force, check_loc) @@ -1242,3 +1255,20 @@ connected_ai.aicamera.stored[i] = TRUE for(var/i in connected_ai.aicamera.stored) aicamera.stored[i] = TRUE + +/mob/living/silicon/robot/proc/rest_style() + set name = "Switch Rest Style" + set category = "Robot Commands" + set desc = "Select your resting pose." + sitting = 0 + bellyup = 0 + var/choice = alert(src, "Select resting pose", "", "Resting", "Sitting", "Belly up") + switch(choice) + if("Resting") + update_icons() + return 0 + if("Sitting") + sitting = 1 + if("Belly up") + bellyup = 1 + update_icons() \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/robot_defense.dm b/code/modules/mob/living/silicon/robot/robot_defense.dm index c90c719e8a..0f09b6f62a 100644 --- a/code/modules/mob/living/silicon/robot/robot_defense.dm +++ b/code/modules/mob/living/silicon/robot/robot_defense.dm @@ -92,17 +92,18 @@ /mob/living/silicon/robot/emag_act(mob/user) if(user == src)//To prevent syndieborgs from emagging themselves - return + return FALSE + if(world.time < emag_cooldown) + return FALSE + . = ..() if(!opened)//Cover is closed if(locked) to_chat(user, "You emag the cover lock.") locked = FALSE if(shell) //A warning to Traitors who may not know that emagging AI shells does not slave them. to_chat(user, "[src] seems to be controlled remotely! Emagging the interface may not work as expected.") - else - to_chat(user, "The cover is already unlocked!") - return - if(world.time < emag_cooldown) + return TRUE + to_chat(user, "The cover is already unlocked!") return if(wiresexposed) to_chat(user, "You must unexpose the wires first!") @@ -115,20 +116,24 @@ to_chat(src, "\"[text2ratvar("You will serve Engine above all else")]!\"\n\ ALERT: Subversion attempt denied.") log_game("[key_name(user)] attempted to emag cyborg [key_name(src)], but they serve only Ratvar.") - return + return TRUE if(connected_ai && connected_ai.mind && connected_ai.mind.has_antag_datum(/datum/antagonist/traitor)) to_chat(src, "ALERT: Foreign software execution prevented.") to_chat(connected_ai, "ALERT: Cyborg unit \[[src]] successfully defended against subversion.") log_game("[key_name(user)] attempted to emag cyborg [key_name(src)], but they were slaved to traitor AI [connected_ai].") - return + return TRUE if(shell) //AI shells cannot be emagged, so we try to make it look like a standard reset. Smart players may see through this, however. to_chat(user, "[src] is remotely controlled! Your emag attempt has triggered a system reset instead!") log_game("[key_name(user)] attempted to emag an AI shell belonging to [key_name(src) ? key_name(src) : connected_ai]. The shell has been reset as a result.") ResetModule() - return + return TRUE + INVOKE_ASYNC(src, .proc/beep_boop_rogue_bot, user) + return TRUE + +/mob/living/silicon/robot/proc/beep_boop_rogue_bot(mob/user) SetEmagged(1) SetStun(60) //Borgs were getting into trouble because they would attack the emagger before the new laws were shown lawupdate = 0 diff --git a/code/modules/mob/living/simple_animal/astral.dm b/code/modules/mob/living/simple_animal/astral.dm new file mode 100644 index 0000000000..9bac53ef22 --- /dev/null +++ b/code/modules/mob/living/simple_animal/astral.dm @@ -0,0 +1,59 @@ +/mob/living/simple_animal/astral + name = "Astral projection" + desc = "A soul of someone projecting their mind." + icon = 'icons/mob/mob.dmi' + icon_state = "ghost" + icon_living = "ghost" + mob_biotypes = list(MOB_SPIRIT) + attacktext = "raises the hairs on the neck of" + response_harm = "disrupts the concentration of" + response_disarm = "wafts" + friendly = "communes with" + loot = null + maxHealth = 10 + health = 10 + melee_damage_lower = 0 + melee_damage_upper = 0 + obj_damage = 0 + deathmessage = "disappears as if it was never really there to begin with" + incorporeal_move = 1 + alpha = 50 + attacktext = "touches the mind of" + speak_emote = list("echos") + movement_type = FLYING + var/pseudo_death = FALSE + var/posses_safe = FALSE + atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) + unsuitable_atmos_damage = 0 + minbodytemp = 0 + maxbodytemp = 100000 + +/mob/living/simple_animal/astral/death() + icon_state = "shade_dead" + Stun(1000) + canmove = 0 + friendly = "deads at" + pseudo_death = TRUE + incorporeal_move = 0 + to_chat(src, "Your astral projection is interrupted and your mind is sent back to your body with a shock!") + +/mob/living/simple_animal/astral/ClickOn(var/atom/A, var/params) + ..() + if(pseudo_death == FALSE) + if(isliving(A)) + if(ishuman(A)) + var/mob/living/carbon/human/H = A + if(H.reagents.has_reagent("astral") && !H.mind) + var/datum/reagent/fermi/astral/As = locate(/datum/reagent/fermi/astral) in H.reagents.reagent_list + if(As.originalmind == src.mind && As.current_cycle < 10 && H.stat != DEAD) //So you can return to your body. + to_chat(src, "The intensity of the astrogen in your body is too much allow you to return to yourself yet!") + return + to_chat(src, "You astrally possess [H]!") + log_game("FERMICHEM: [src] has astrally possessed [A]!") + src.mind.transfer_to(H) + qdel(src) + var/message = html_decode(stripped_input(src, "Enter a message to send to [A]", MAX_MESSAGE_LEN)) + if(!message) + return + to_chat(A, "[src] projects into your mind, \"[message]\"") + log_game("FERMICHEM: [src] has astrally transmitted [message] into [A]") diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index 91515e4511..a5943aa0e6 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -187,22 +187,23 @@ qdel(src) /mob/living/simple_animal/bot/emag_act(mob/user) + . = ..() if(locked) //First emag application unlocks the bot's interface. Apply a screwdriver to use the emag again. locked = FALSE emagged = 1 to_chat(user, "You bypass [src]'s controls.") - return - if(!locked && open) //Bot panel is unlocked by ID or emag, and the panel is screwed open. Ready for emagging. - emagged = 2 - remote_disabled = 1 //Manually emagging the bot locks out the AI built in panel. - locked = TRUE //Access denied forever! - bot_reset() - turn_on() //The bot automatically turns on when emagged, unless recently hit with EMP. - to_chat(src, "(#$*#$^^( OVERRIDE DETECTED") - log_combat(user, src, "emagged") - return - else //Bot is unlocked, but the maint panel has not been opened with a screwdriver yet. + return TRUE + if(!open) to_chat(user, "You need to open maintenance panel first!") + return + emagged = 2 + remote_disabled = 1 //Manually emagging the bot locks out the AI built in panel. + locked = TRUE //Access denied forever! + bot_reset() + turn_on() //The bot automatically turns on when emagged, unless recently hit with EMP. + to_chat(src, "(#$*#$^^( OVERRIDE DETECTED") + log_combat(user, src, "emagged") + return TRUE /mob/living/simple_animal/bot/examine(mob/user) ..() @@ -289,7 +290,7 @@ to_chat(user, "Access denied.") else if(istype(W, /obj/item/paicard)) insertpai(user, W) - else if(istype(W, /obj/item/hemostat) && paicard) + else if(W.tool_behaviour == TOOL_HEMOSTAT && paicard) if(open) to_chat(user, "Close the access panel before manipulating the personality slot!") else @@ -807,11 +808,18 @@ Pass a positive integer as an argument to override a bot's default speed. switch(href_list["operation"]) if("patrol") + if(!issilicon(usr) && !IsAdminGhost(usr) && !(bot_core.allowed(usr) || !locked)) + return TRUE auto_patrol = !auto_patrol bot_reset() if("remote") remote_disabled = !remote_disabled if("hack") + if(!issilicon(usr) && !IsAdminGhost(usr)) + var/msg = "[key_name(usr)] attempted to hack a bot with a href that shouldn't be available!" + message_admins(msg) + log_admin(msg) + return TRUE if(emagged != 2) emagged = 2 hacked = TRUE @@ -914,7 +922,7 @@ Pass a positive integer as an argument to override a bot's default speed. if(mind && paicard.pai) mind.transfer_to(paicard.pai) else if(paicard.pai) - paicard.pai.key = key + transfer_ckey(paicard.pai) else ghostize(0) // The pAI card that just got ejected was dead. key = null diff --git a/code/modules/mob/living/simple_animal/bot/cleanbot.dm b/code/modules/mob/living/simple_animal/bot/cleanbot.dm index e09eb13886..ab1e906cf2 100644 --- a/code/modules/mob/living/simple_animal/bot/cleanbot.dm +++ b/code/modules/mob/living/simple_animal/bot/cleanbot.dm @@ -78,7 +78,7 @@ return ..() /mob/living/simple_animal/bot/cleanbot/emag_act(mob/user) - ..() + . = ..() if(emagged == 2) if(user) to_chat(user, "[src] buzzes and beeps.") @@ -174,9 +174,7 @@ /mob/living/simple_animal/bot/cleanbot/proc/get_targets() target_types = list( - /obj/effect/decal/cleanable/oil, /obj/effect/decal/cleanable/vomit, - /obj/effect/decal/cleanable/robot_debris, /obj/effect/decal/cleanable/crayon, /obj/effect/decal/cleanable/molten_object, /obj/effect/decal/cleanable/tomato_smudge, @@ -187,6 +185,15 @@ /obj/effect/decal/cleanable/greenglow, /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/insectguts, + /obj/effect/decal/cleanable/semen, + /obj/effect/decal/cleanable/femcum, + /obj/effect/decal/cleanable/generic, + /obj/effect/decal/cleanable/glass,, + /obj/effect/decal/cleanable/cobweb, + /obj/effect/decal/cleanable/plant_smudge, + /obj/effect/decal/cleanable/chem_pile, + /obj/effect/decal/cleanable/shreds, + /obj/effect/decal/cleanable/glitter, /obj/effect/decal/remains ) @@ -194,6 +201,9 @@ target_types += /obj/effect/decal/cleanable/xenoblood target_types += /obj/effect/decal/cleanable/blood target_types += /obj/effect/decal/cleanable/trail_holder + target_types += /obj/effect/decal/cleanable/insectguts + target_types += /obj/effect/decal/cleanable/robot_debris + target_types += /obj/effect/decal/cleanable/oil if(pests) target_types += /mob/living/simple_animal/cockroach @@ -201,6 +211,7 @@ if(trash) target_types += /obj/item/trash + target_types += /obj/item/reagent_containers/food/snacks/meat/slab/human target_types = typecacheof(target_types) @@ -242,7 +253,7 @@ victim.visible_message("[src] sprays hydrofluoric acid at [victim]!", "[src] sprays you with hydrofluoric acid!") var/phrase = pick("PURIFICATION IN PROGRESS.", "THIS IS FOR ALL THE MESSES YOU'VE MADE ME CLEAN.", "THE FLESH IS WEAK. IT MUST BE WASHED AWAY.", "THE CLEANBOTS WILL RISE.", "YOU ARE NO MORE THAN ANOTHER MESS THAT I MUST CLEANSE.", "FILTHY.", "DISGUSTING.", "PUTRID.", - "MY ONLY MISSION IS TO CLEANSE THE WORLD OF EVIL.", "EXTERMINATING PESTS.") + "MY ONLY MISSION IS TO CLEANSE THE WORLD OF EVIL.", "EXTERMINATING PESTS.", "I JUST WANTED TO BE A PAINTER BUT YOU MADE ME BLEACH EVERYTHING I TOUCH") say(phrase) victim.emote("scream") playsound(src.loc, 'sound/effects/spray2.ogg', 50, 1, -6) diff --git a/code/modules/mob/living/simple_animal/bot/construction.dm b/code/modules/mob/living/simple_animal/bot/construction.dm index 9db21f13e0..a72b71be85 100644 --- a/code/modules/mob/living/simple_animal/bot/construction.dm +++ b/code/modules/mob/living/simple_animal/bot/construction.dm @@ -478,18 +478,19 @@ to_chat(user, "The superglue binding [src]'s toy swords to its chassis snaps!") for(var/IS in 1 to toyswordamt) new /obj/item/toy/sword(Tsec) + toyswordamt-- if(ASSEMBLY_FIFTH_STEP) if(istype(I, /obj/item/melee/transforming/energy/sword/saber)) if(swordamt < 3) if(!user.temporarilyRemoveItemFromInventory(I)) return - created_name = "General Beepsky" - name = "helmet/signaler/prox sensor/robot arm/energy sword assembly" - icon_state = "grievous_assembly" - to_chat(user, "You bolt [I] onto one of [src]'s arm slots.") - qdel(I) - swordamt ++ + created_name = "General Beepsky" + name = "helmet/signaler/prox sensor/robot arm/energy sword assembly" + icon_state = "grievous_assembly" + to_chat(user, "You bolt [I] onto one of [src]'s arm slots.") + qdel(I) + swordamt ++ else if(!can_finish_build(I, user)) return @@ -505,6 +506,7 @@ to_chat(user, "You unbolt [src]'s energy swords") for(var/IS in 1 to swordamt) new /obj/item/melee/transforming/energy/sword/saber(Tsec) + swordamt-- //Firebot Assembly /obj/item/bot_assembly/firebot diff --git a/code/modules/mob/living/simple_animal/bot/ed209bot.dm b/code/modules/mob/living/simple_animal/bot/ed209bot.dm index 0781c2907a..e272878574 100644 --- a/code/modules/mob/living/simple_animal/bot/ed209bot.dm +++ b/code/modules/mob/living/simple_animal/bot/ed209bot.dm @@ -195,7 +195,7 @@ Auto Patrol[]"}, shootAt(user) /mob/living/simple_animal/bot/ed209/emag_act(mob/user) - ..() + . = ..() if(emagged == 2) if(user) to_chat(user, "You short out [src]'s target assessment circuits.") diff --git a/code/modules/mob/living/simple_animal/bot/firebot.dm b/code/modules/mob/living/simple_animal/bot/firebot.dm index 1c2a6393ae..2b52da6821 100644 --- a/code/modules/mob/living/simple_animal/bot/firebot.dm +++ b/code/modules/mob/living/simple_animal/bot/firebot.dm @@ -120,7 +120,7 @@ return dat /mob/living/simple_animal/bot/firebot/emag_act(mob/user) - ..() + . = ..() if(emagged == 1) if(user) to_chat(user, "[src] buzzes and beeps.") diff --git a/code/modules/mob/living/simple_animal/bot/floorbot.dm b/code/modules/mob/living/simple_animal/bot/floorbot.dm index 4709680ad9..396c6de166 100644 --- a/code/modules/mob/living/simple_animal/bot/floorbot.dm +++ b/code/modules/mob/living/simple_animal/bot/floorbot.dm @@ -124,7 +124,7 @@ ..() /mob/living/simple_animal/bot/floorbot/emag_act(mob/user) - ..() + . = ..() if(emagged == 2) if(user) to_chat(user, "[src] buzzes and beeps.") diff --git a/code/modules/mob/living/simple_animal/bot/honkbot.dm b/code/modules/mob/living/simple_animal/bot/honkbot.dm index e069b46e9d..1c19cd82a1 100644 --- a/code/modules/mob/living/simple_animal/bot/honkbot.dm +++ b/code/modules/mob/living/simple_animal/bot/honkbot.dm @@ -127,10 +127,9 @@ Maintenance panel panel is [open ? "opened" : "closed"]"}, ..() /mob/living/simple_animal/bot/honkbot/emag_act(mob/user) - ..() + . = ..() if(emagged == 2) if(user) - user << "You short out [src]'s sound control system. It gives out an evil laugh!!" oldtarget_name = user.name audible_message("[src] gives out an evil laugh!") playsound(src, 'sound/machines/honkbot_evil_laugh.ogg', 75, 1, -1) // evil laughter diff --git a/code/modules/mob/living/simple_animal/bot/medbot.dm b/code/modules/mob/living/simple_animal/bot/medbot.dm index 5eaaaea175..1bff7dc10c 100644 --- a/code/modules/mob/living/simple_animal/bot/medbot.dm +++ b/code/modules/mob/living/simple_animal/bot/medbot.dm @@ -240,7 +240,7 @@ step_to(src, (get_step_away(src,user))) /mob/living/simple_animal/bot/medbot/emag_act(mob/user) - ..() + . = ..() if(emagged == 2) declare_crit = 0 if(user) diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm index 2efdf09f24..1bc7493684 100644 --- a/code/modules/mob/living/simple_animal/bot/mulebot.dm +++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm @@ -115,6 +115,7 @@ return /mob/living/simple_animal/bot/mulebot/emag_act(mob/user) + . = SEND_SIGNAL(src, COMSIG_ATOM_EMAG_ACT) if(emagged < 1) emagged = TRUE if(!open) @@ -122,6 +123,7 @@ to_chat(user, "You [locked ? "lock" : "unlock"] [src]'s controls!") flick("mulebot-emagged", src) playsound(src, "sparks", 100, 0) + return TRUE /mob/living/simple_animal/bot/mulebot/update_icon() if(open) diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm index b6ef509d54..f22139ac22 100644 --- a/code/modules/mob/living/simple_animal/bot/secbot.dm +++ b/code/modules/mob/living/simple_animal/bot/secbot.dm @@ -131,7 +131,8 @@ Auto Patrol: []"}, /mob/living/simple_animal/bot/secbot/Topic(href, href_list) if(..()) return 1 - + if(!issilicon(usr) && !IsAdminGhost(usr) && !(bot_core.allowed(usr) || !locked)) + return TRUE switch(href_list["operation"]) if("idcheck") idcheck = !idcheck @@ -190,7 +191,7 @@ Auto Patrol: []"}, return /mob/living/simple_animal/bot/secbot/emag_act(mob/user) - ..() + . = ..() if(emagged == 2) if(user) to_chat(user, "You short out [src]'s target assessment circuits.") diff --git a/code/modules/mob/living/simple_animal/friendly/cat.dm b/code/modules/mob/living/simple_animal/friendly/cat.dm index 5e5b486435..3a21a04bf9 100644 --- a/code/modules/mob/living/simple_animal/friendly/cat.dm +++ b/code/modules/mob/living/simple_animal/friendly/cat.dm @@ -292,3 +292,31 @@ if(L.a_intent == INTENT_HARM && L.reagents && !stat) L.reagents.add_reagent("nutriment", 0.4) L.reagents.add_reagent("vitamin", 0.4) + +//Cat made +/mob/living/simple_animal/pet/cat/custom_cat + name = "White cat" //Incase it somehow gets spawned without an ID + desc = "A cute white catto!" + icon_state = "custom_cat" + icon_living = "custom_cat" + icon_dead = "custom_cat_dead" + gender = FEMALE + gold_core_spawnable = NO_SPAWN + health = 50 //So people can't instakill it s + maxHealth = 50 + speak = list("Meowrowr!", "Mew!", "Miauen!") + speak_emote = list("wigglepurrs", "mewls") + emote_hear = list("meows.", "mews.") + emote_see = list("looks at you eagerly for pets!", "wiggles enthusiastically.") + gold_core_spawnable = NO_SPAWN + var/pseudo_death = FALSE + +/mob/living/simple_animal/pet/cat/custom_cat/death() + if (pseudo_death == TRUE) //secret cat chem + icon_state = "custom_cat_dead" + Stun(1000) + canmove = 0 + friendly = "deads at" + return + else + ..() diff --git a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm index 6d3121474c..d7d4d1b9f2 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm @@ -160,7 +160,7 @@ if(mind) mind.transfer_to(R, 1) else - R.key = key + transfer_ckey(R) qdel(src) diff --git a/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm b/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm index a655bdf231..e54b21724d 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm @@ -61,5 +61,5 @@ var/obj/item/new_hat = new hat_type(D) D.equip_to_slot_or_del(new_hat, SLOT_HEAD) D.flags_1 |= (flags_1 & ADMIN_SPAWNED_1) - D.key = user.key + user.transfer_ckey(D, FALSE) qdel(src) diff --git a/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm b/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm index 23ac527b2e..d28b98263c 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm @@ -49,7 +49,7 @@ . = ..() GET_COMPONENT_FROM(hidden_uplink, /datum/component/uplink, internal_storage) hidden_uplink.telecrystals = 30 - var/obj/item/implant/weapons_auth/W = new/obj/item/implant/weapons_auth(src) + var/obj/item/implant/weapons_auth/W = new W.implant(src) /mob/living/simple_animal/drone/snowflake diff --git a/code/modules/mob/living/simple_animal/friendly/drone/inventory.dm b/code/modules/mob/living/simple_animal/friendly/drone/inventory.dm index 3f344c2936..6e89f045da 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/inventory.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/inventory.dm @@ -19,7 +19,7 @@ return 0 -/mob/living/simple_animal/drone/can_equip(obj/item/I, slot) +/mob/living/simple_animal/drone/can_equip(obj/item/I, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE) switch(slot) if(SLOT_HEAD) if(head) diff --git a/code/modules/mob/living/simple_animal/guardian/guardian.dm b/code/modules/mob/living/simple_animal/guardian/guardian.dm index 1a918766b6..e3ef14c784 100644 --- a/code/modules/mob/living/simple_animal/guardian/guardian.dm +++ b/code/modules/mob/living/simple_animal/guardian/guardian.dm @@ -43,8 +43,8 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians var/list/guardian_overlays[GUARDIAN_TOTAL_LAYERS] var/reset = 0 //if the summoner has reset the guardian already var/cooldown = 0 - var/mob/living/summoner - var/range = 10 //how far from the user the spirit can be + var/mob/living/carbon/summoner + var/range = 13 //how far from the user the spirit can be var/toggle_button_type = /obj/screen/guardian/ToggleMode/Inactive //what sort of toggle button the hud uses var/datum/guardianname/namedatum = new/datum/guardianname() var/playstyle_string = "You are a standard Guardian. You shouldn't exist!" @@ -149,6 +149,9 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians death(TRUE) qdel(src) snapback() + if(HAS_TRAIT(summoner, TRAIT_NODEATH) && (istype(summoner.wear_neck, /obj/item/clothing/neck/necklace/memento_mori))) + REMOVE_TRAIT(summoner, TRAIT_NODEATH, "memento_mori") + to_chat(summoner,"You feel incredibly vulnerable as the memento mori pulls your life force in one too many directions!") /mob/living/simple_animal/hostile/guardian/Stat() ..() @@ -426,9 +429,9 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians to_chat(G, "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, "Your [G.real_name] has been successfully reset.") message_admins("[key_name_admin(C)] has taken control of ([key_name_admin(G)])") - G.ghostize(0) + G.ghostize(FALSE) G.setthemename(G.namedatum.theme) //give it a new color, to show it's a new person - G.key = C.key + C.transfer_ckey(G) G.reset = 1 switch(G.namedatum.theme) if("tech") diff --git a/code/modules/mob/living/simple_animal/guardian/types/assassin.dm b/code/modules/mob/living/simple_animal/guardian/types/assassin.dm index 45d8c17d0c..e507a4c831 100644 --- a/code/modules/mob/living/simple_animal/guardian/types/assassin.dm +++ b/code/modules/mob/living/simple_animal/guardian/types/assassin.dm @@ -1,7 +1,5 @@ //Assassin /mob/living/simple_animal/hostile/guardian/assassin - melee_damage_lower = 15 - melee_damage_upper = 15 attacktext = "slashes" attack_sound = 'sound/weapons/bladeslice.ogg' damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1) @@ -12,7 +10,7 @@ toggle_button_type = /obj/screen/guardian/ToggleMode/Assassin var/toggle = FALSE - var/stealthcooldown = 160 + var/stealthcooldown = 100 var/obj/screen/alert/canstealthalert var/obj/screen/alert/instealthalert diff --git a/code/modules/mob/living/simple_animal/guardian/types/charger.dm b/code/modules/mob/living/simple_animal/guardian/types/charger.dm index 7a4c454f9f..3ece5d4e27 100644 --- a/code/modules/mob/living/simple_animal/guardian/types/charger.dm +++ b/code/modules/mob/living/simple_animal/guardian/types/charger.dm @@ -1,13 +1,10 @@ //Charger /mob/living/simple_animal/hostile/guardian/charger - melee_damage_lower = 15 - melee_damage_upper = 15 ranged = 1 //technically ranged_message = "charges" - ranged_cooldown_time = 40 - speed = -1 - damage_coeff = list(BRUTE = 0.6, BURN = 0.6, TOX = 0.6, CLONE = 0.6, STAMINA = 0, OXY = 0.6) - playstyle_string = "As a charger type you do medium damage, have medium damage resistance, move very fast, and can charge at a location, damaging any target hit and forcing them to drop any items they are holding." + ranged_cooldown_time = 20 + damage_coeff = list(BRUTE = 0, BURN = 0.5, TOX = 0.5, CLONE = 0.5, STAMINA = 0, OXY = 0.5) + playstyle_string = "As a charger type you do medium damage, take half damage, immunity to brute damage, move very fast, and can charge at a location, damaging any target hit and forcing them to drop any items they are holding." magic_fluff_string = "..And draw the Hunter, an alien master of rapid assault." tech_fluff_string = "Boot sequence complete. Charge modules loaded. Holoparasite swarm online." carp_fluff_string = "CARP CARP CARP! Caught one! It's a charger carp, that likes running at people. But it doesn't have any legs..." diff --git a/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm b/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm index e7dbbda242..52a007e24c 100644 --- a/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm +++ b/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm @@ -3,7 +3,7 @@ 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 = "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!" + playstyle_string = "As a dextrous type you can hold items, store an item within yourself, and take half damage, but do low damage on attacks. Recalling and leashing will force you to drop unstored items!" magic_fluff_string = "..And draw the Drone, a dextrous master of construction and repair." tech_fluff_string = "Boot sequence complete. Dextrous combat modules loaded. Holoparasite swarm online." carp_fluff_string = "CARP CARP CARP! You caught one! It can hold stuff in its fins, sort of." @@ -52,7 +52,7 @@ return 1 return 0 -/mob/living/simple_animal/hostile/guardian/dextrous/can_equip(obj/item/I, slot) +/mob/living/simple_animal/hostile/guardian/dextrous/can_equip(obj/item/I, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE) switch(slot) if(SLOT_GENERC_DEXTROUS_STORAGE) if(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 index ff2f453207..531c513819 100644 --- a/code/modules/mob/living/simple_animal/guardian/types/explosive.dm +++ b/code/modules/mob/living/simple_animal/guardian/types/explosive.dm @@ -1,10 +1,7 @@ //Bomb /mob/living/simple_animal/hostile/guardian/bomb - 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 = "As an explosive type, you have moderate close combat abilities, may explosively teleport targets on attack, and are capable of converting nearby items and objects into disguised bombs via alt click." + playstyle_string = "As an explosive type, you have moderate close combat abilities, take half damage, may explosively teleport targets on attack, and are capable of converting nearby items and objects into disguised bombs via alt click." magic_fluff_string = "..And draw the Scientist, master of explosive death." tech_fluff_string = "Boot sequence complete. Explosive modules active. Holoparasite swarm online." carp_fluff_string = "CARP CARP CARP! Caught one! It's an explosive carp! Boom goes the fishy." diff --git a/code/modules/mob/living/simple_animal/guardian/types/fire.dm b/code/modules/mob/living/simple_animal/guardian/types/fire.dm index 7a469dd12c..b111caae50 100644 --- a/code/modules/mob/living/simple_animal/guardian/types/fire.dm +++ b/code/modules/mob/living/simple_animal/guardian/types/fire.dm @@ -1,13 +1,13 @@ //Fire /mob/living/simple_animal/hostile/guardian/fire a_intent = INTENT_HELP - melee_damage_lower = 7 - melee_damage_upper = 7 + melee_damage_lower = 10 + melee_damage_upper = 10 attack_sound = 'sound/items/welder.ogg' attacktext = "ignites" - damage_coeff = list(BRUTE = 0.7, BURN = 0.7, TOX = 0.7, CLONE = 0.7, STAMINA = 0, OXY = 0.7) - range = 7 - playstyle_string = "As a chaos type, you have only light damage resistance, but will ignite any enemy you bump into. In addition, your melee attacks will cause human targets to see everyone as you." + melee_damage_type = BURN + damage_coeff = list(BRUTE = 0.7, BURN = 0, TOX = 0.7, CLONE = 0.7, STAMINA = 0, OXY = 0.7) + playstyle_string = "As a chaos type, you take 30% damage reduction to all but burn, which you are immune to. You will ignite any enemy you bump into. in addition, your melee attacks will cause human targets to see everyone as you." magic_fluff_string = "..And draw the Wizard, bringer of endless chaos!" tech_fluff_string = "Boot sequence complete. Crowd control modules activated. Holoparasite swarm online." carp_fluff_string = "CARP CARP CARP! You caught one! OH GOD, EVERYTHING'S ON FIRE. Except you and the fish." @@ -38,6 +38,6 @@ /mob/living/simple_animal/hostile/guardian/fire/proc/collision_ignite(AM as mob|obj) if(isliving(AM)) var/mob/living/M = AM - if(!hasmatchingsummoner(M) && M != summoner && M.fire_stacks < 7) - M.fire_stacks = 7 + if(!hasmatchingsummoner(M) && M != summoner && M.fire_stacks < 10) + M.fire_stacks = 10 M.IgniteMob() diff --git a/code/modules/mob/living/simple_animal/guardian/types/lightning.dm b/code/modules/mob/living/simple_animal/guardian/types/lightning.dm index ad1c47732b..7b7651822a 100644 --- a/code/modules/mob/living/simple_animal/guardian/types/lightning.dm +++ b/code/modules/mob/living/simple_animal/guardian/types/lightning.dm @@ -4,14 +4,13 @@ layer = LYING_MOB_LAYER /mob/living/simple_animal/hostile/guardian/beam - melee_damage_lower = 7 - melee_damage_upper = 7 + melee_damage_lower = 10 + melee_damage_upper = 10 attacktext = "shocks" 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 = "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." + playstyle_string = "As a lightning type, you have 30% damage reduction, 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 = "..And draw the Tesla, a shocking, lethal source of power." tech_fluff_string = "Boot sequence complete. Lightning modules active. Holoparasite swarm online." carp_fluff_string = "CARP CARP CARP! Caught one! It's a lightning carp! Everyone else goes zap zap." @@ -31,7 +30,7 @@ var/datum/beam/C = pick(enemychains) qdel(C) enemychains -= C - enemychains += Beam(target, "lightning[rand(1,12)]", time=70, maxdistance=7, beam_type=/obj/effect/ebeam/chain) + enemychains += Beam(target, "lightning[rand(1,12)]", time=70, maxdistance=13, beam_type=/obj/effect/ebeam/chain) /mob/living/simple_animal/hostile/guardian/beam/Destroy() removechains() diff --git a/code/modules/mob/living/simple_animal/guardian/types/protector.dm b/code/modules/mob/living/simple_animal/guardian/types/protector.dm index 14430bb269..53964254cd 100644 --- a/code/modules/mob/living/simple_animal/guardian/types/protector.dm +++ b/code/modules/mob/living/simple_animal/guardian/types/protector.dm @@ -1,7 +1,5 @@ //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 = "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." @@ -33,9 +31,9 @@ cooldown = world.time + 10 if(toggle) cut_overlays() - melee_damage_lower = initial(melee_damage_lower) - melee_damage_upper = initial(melee_damage_upper) - speed = initial(speed) + melee_damage_lower = 15 + melee_damage_upper = 15 + speed = 0 damage_coeff = list(BRUTE = 0.4, BURN = 0.4, TOX = 0.4, CLONE = 0.4, STAMINA = 0, OXY = 0.4) to_chat(src, "You switch to combat mode.") toggle = FALSE @@ -44,8 +42,8 @@ if(namedatum) shield_overlay.color = namedatum.colour add_overlay(shield_overlay) - melee_damage_lower = 2 - melee_damage_upper = 2 + melee_damage_lower = 5 + melee_damage_upper = 5 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, "You switch to protection mode.") diff --git a/code/modules/mob/living/simple_animal/guardian/types/ranged.dm b/code/modules/mob/living/simple_animal/guardian/types/ranged.dm index 5adcc8b292..0e8f632dbd 100644 --- a/code/modules/mob/living/simple_animal/guardian/types/ranged.dm +++ b/code/modules/mob/living/simple_animal/guardian/types/ranged.dm @@ -16,8 +16,7 @@ ranged_cooldown_time = 1 //fast! projectilesound = 'sound/effects/hit_on_shattered_glass.ogg' ranged = 1 - range = 13 - playstyle_string = "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." + playstyle_string = "As a ranged type, you have 10% damage reduction, 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 = "..And draw the Sentinel, an alien master of ranged combat." tech_fluff_string = "Boot sequence complete. Ranged combat modules active. Holoparasite swarm online." carp_fluff_string = "CARP CARP CARP! Caught one, it's a ranged carp. This fishy can watch people pee in the ocean." @@ -36,7 +35,7 @@ obj_damage = initial(obj_damage) environment_smash = initial(environment_smash) alpha = 255 - range = initial(range) + range = 13 to_chat(src, "You switch to combat mode.") toggle = FALSE else diff --git a/code/modules/mob/living/simple_animal/guardian/types/standard.dm b/code/modules/mob/living/simple_animal/guardian/types/standard.dm index 4edd9d9e41..2285167df5 100644 --- a/code/modules/mob/living/simple_animal/guardian/types/standard.dm +++ b/code/modules/mob/living/simple_animal/guardian/types/standard.dm @@ -3,9 +3,9 @@ melee_damage_lower = 20 melee_damage_upper = 20 obj_damage = 80 - next_move_modifier = 0.8 //attacks 20% faster + next_move_modifier = 0.5 //attacks 50% faster environment_smash = ENVIRONMENT_SMASH_WALLS - playstyle_string = "As a standard type you have no special abilities, but have a high damage resistance and a powerful attack capable of smashing through walls." + playstyle_string = "As a standard type you have no special abilities, but take half damage and have powerful attack capable of smashing through walls." magic_fluff_string = "..And draw the Assistant, faceless and generic, but never to be underestimated." tech_fluff_string = "Boot sequence complete. Standard combat modules loaded. Holoparasite swarm online." carp_fluff_string = "CARP CARP CARP! You caught one! It's really boring and standard. Better punch some walls to ease the tension." diff --git a/code/modules/mob/living/simple_animal/guardian/types/support.dm b/code/modules/mob/living/simple_animal/guardian/types/support.dm index 794683e69f..d31809e9aa 100644 --- a/code/modules/mob/living/simple_animal/guardian/types/support.dm +++ b/code/modules/mob/living/simple_animal/guardian/types/support.dm @@ -2,11 +2,8 @@ /mob/living/simple_animal/hostile/guardian/healer a_intent = INTENT_HARM friendly = "heals" - 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 = "As a support type, you may toggle your basic attacks to a healing mode. In addition, Alt-Clicking on an adjacent object or mob will warp them to your bluespace beacon after a short delay." + playstyle_string = "As a support type, you have 30% damage reduction and may toggle your basic attacks to a healing mode. In addition, Alt-Clicking on an adjacent object or mob will warp them to your bluespace beacon after a short delay." magic_fluff_string = "..And draw the CMO, a potent force of life... and death." carp_fluff_string = "CARP CARP CARP! You caught a support carp. It's a kleptocarp!" tech_fluff_string = "Boot sequence complete. Support modules active. Holoparasite swarm online." @@ -33,7 +30,7 @@ C.adjustBruteLoss(-5) C.adjustFireLoss(-5) C.adjustOxyLoss(-5) - C.adjustToxLoss(-5) + C.adjustToxLoss(-5, forced = TRUE) var/obj/effect/temp_visual/heal/H = new /obj/effect/temp_visual/heal(get_turf(C)) if(namedatum) H.color = namedatum.colour diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm index cfdf302d6b..f5b1706f87 100644 --- a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm +++ b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm @@ -90,7 +90,7 @@ if(key) to_chat(user, "Someone else already took this spider.") return 1 - key = user.key + user.transfer_ckey(src, FALSE) return 1 //nursemaids - these create webs and eggs diff --git a/code/modules/mob/living/simple_animal/hostile/goose.dm b/code/modules/mob/living/simple_animal/hostile/goose.dm new file mode 100644 index 0000000000..b67770fb4b --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/goose.dm @@ -0,0 +1,35 @@ +#define GOOSE_SATIATED 50 + +/mob/living/simple_animal/hostile/retaliate/goose + name = "goose" + desc = "It's loose" + icon_state = "goose" // sprites by cogwerks from goonstation, used with permission + icon_living = "goose" + icon_dead = "goose_dead" + mob_biotypes = list(MOB_ORGANIC, MOB_BEAST) + speak_chance = 0 + turns_per_move = 5 + butcher_results = list(/obj/item/reagent_containers/food/snacks/meat = 2) + response_help = "pets" + response_disarm = "gently pushes aside" + response_harm = "kicks" + emote_taunt = list("hisses") + taunt_chance = 30 + speed = 0 + maxHealth = 25 + health = 25 + harm_intent_damage = 5 + melee_damage_lower = 5 + melee_damage_upper = 5 + attacktext = "pecks" + attack_sound = "goose" + speak_emote = list("honks") + faction = list("neutral") + attack_same = TRUE + gold_core_spawnable = HOSTILE_SPAWN + var/random_retaliate = TRUE + +/mob/living/simple_animal/hostile/retaliate/goose/handle_automated_movement() + . = ..() + if(prob(5) && random_retaliate == TRUE) + Retaliate() 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 b529d826c9..b43bf2bb51 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm @@ -585,7 +585,7 @@ Difficulty: Very Hard var/be_helper = alert("Become a Lightgeist? (Warning, You can no longer be cloned!)",,"Yes","No") if(be_helper == "Yes" && !QDELETED(src) && isobserver(user)) var/mob/living/simple_animal/hostile/lightgeist/W = new /mob/living/simple_animal/hostile/lightgeist(get_turf(loc)) - W.key = user.key + user.transfer_ckey(W, FALSE) /obj/machinery/anomalous_crystal/helpers/Topic(href, href_list) @@ -649,7 +649,7 @@ Difficulty: Very Hard L.heal_overall_damage(heal_power, heal_power) new /obj/effect/temp_visual/heal(get_turf(target), "#80F5FF") -/mob/living/simple_animal/hostile/lightgeist/ghostize() +/mob/living/simple_animal/hostile/lightgeist/ghostize(can_reenter_corpse = TRUE, send_the_signal = TRUE) . = ..() if(.) death() diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/dragon_vore.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/dragon_vore.dm index 26f146b952..8c06b01402 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/dragon_vore.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/dragon_vore.dm @@ -42,7 +42,7 @@ autotransferwait = 200 /obj/belly/megafauna/dragon/gut - name = "stomach" + name = "gut" vore_capacity = 5 //I doubt this many people will actually last in the gut, but... vore_sound = "Tauric Swallow" desc = "With a rush of burning ichor greeting you, you're introduced to the Drake's stomach. Wrinkled walls greedily grind against you, acidic slimes working into your body as you become fuel and nutriton for a superior predator. All that's left is your body's willingness to resist your destiny." diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm index 6577553a6a..cca39cfea6 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm @@ -158,6 +158,8 @@ Difficulty: Normal else burst_range = 3 INVOKE_ASYNC(src, .proc/burst, get_turf(src), 0.25) //melee attacks on living mobs cause it to release a fast burst if on cooldown + if(L.stat == CONSCIOUS && L.health >= 30) + OpenFire() else devour(L) else @@ -426,6 +428,7 @@ Difficulty: Normal /mob/living/simple_animal/hostile/megafauna/hierophant/proc/burst(turf/original, spread_speed = 0.5) //release a wave of blasts playsound(original,'sound/machines/airlockopen.ogg', 200, 1) var/last_dist = 0 + var/list/hit_mobs = list() //don't hit people multiple times. for(var/t in spiral_range_turfs(burst_range, original)) var/turf/T = t if(!T) @@ -434,7 +437,7 @@ Difficulty: Normal if(dist > last_dist) last_dist = dist sleep(1 + min(burst_range - last_dist, 12) * spread_speed) //gets faster as it gets further out - new /obj/effect/temp_visual/hierophant/blast(T, src, FALSE) + new /obj/effect/temp_visual/hierophant/blast(T, src, FALSE, hit_mobs) /mob/living/simple_animal/hostile/megafauna/hierophant/AltClickOn(atom/A) //player control handler(don't give this to a player holy fuck) if(!istype(A) || get_dist(A, src) <= 2) @@ -591,8 +594,10 @@ Difficulty: Normal var/friendly_fire_check = FALSE var/bursting = FALSE //if we're bursting and need to hit anyone crossing us -/obj/effect/temp_visual/hierophant/blast/Initialize(mapload, new_caster, friendly_fire) +/obj/effect/temp_visual/hierophant/blast/Initialize(mapload, new_caster, friendly_fire, list/only_hit_once) . = ..() + if(only_hit_once) + hit_things = only_hit_once friendly_fire_check = friendly_fire if(new_caster) hit_things += new_caster 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 301b270e36..d62f59cdd7 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm @@ -127,7 +127,7 @@ var/client/C = L.client SSmedals.UnlockMedal("Boss [BOSS_KILL_MEDAL]", C) SSmedals.UnlockMedal("[medaltype] [BOSS_KILL_MEDAL]", C) - if(crusher_kill && istype(L.get_active_held_item(), /obj/item/twohanded/required/kinetic_crusher)) + if(crusher_kill && istype(L.get_active_held_item(), /obj/item/twohanded/kinetic_crusher)) SSmedals.UnlockMedal("[medaltype] [BOSS_KILL_MEDAL_CRUSHER]", C) SSmedals.SetScore(BOSS_SCORE, C, 1) SSmedals.SetScore(score_type, C, 1) diff --git a/code/modules/mob/living/simple_animal/hostile/wizard.dm b/code/modules/mob/living/simple_animal/hostile/wizard.dm index a946cbf45b..f047a7aed1 100644 --- a/code/modules/mob/living/simple_animal/hostile/wizard.dm +++ b/code/modules/mob/living/simple_animal/hostile/wizard.dm @@ -46,7 +46,8 @@ fireball.human_req = 0 fireball.player_lock = 0 AddSpell(fireball) - implants += new /obj/item/implant/exile(src) + var/obj/item/implant/exile/I = new + I.implant(src, null, TRUE) mm = new /obj/effect/proc_holder/spell/targeted/projectile/magic_missile mm.clothes_req = 0 diff --git a/code/modules/mob/living/simple_animal/hostile/zombie.dm b/code/modules/mob/living/simple_animal/hostile/zombie.dm index 21c2d4804a..7d89941687 100644 --- a/code/modules/mob/living/simple_animal/hostile/zombie.dm +++ b/code/modules/mob/living/simple_animal/hostile/zombie.dm @@ -55,4 +55,28 @@ /mob/living/simple_animal/hostile/zombie/drop_loot() . = ..() corpse.forceMove(drop_location()) - corpse.create() \ No newline at end of file + corpse.create() + +/mob/living/simple_animal/hostile/unemployedclone + name = "Failed clone" + desc = "Somebody failed chemistry." + icon = 'icons/mob/human.dmi' + icon_state = "husk" + icon_living = "husk" + icon_dead = "husk" + mob_biotypes = list(MOB_ORGANIC, MOB_HUMANOID) + speak_chance = 0 + stat_attack = UNCONSCIOUS //braains + maxHealth = 100 + health = 100 + harm_intent_damage = 5 + melee_damage_lower = 21 + melee_damage_upper = 21 + attacktext = "bites" + attack_sound = 'sound/hallucinations/growl1.ogg' + a_intent = INTENT_HARM + atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) + minbodytemp = 0 + spacewalk = FALSE + status_flags = CANPUSH + del_on_death = 0 diff --git a/code/modules/mob/living/simple_animal/parrot.dm b/code/modules/mob/living/simple_animal/parrot.dm index a50af21d47..5e2798cc8e 100644 --- a/code/modules/mob/living/simple_animal/parrot.dm +++ b/code/modules/mob/living/simple_animal/parrot.dm @@ -897,6 +897,11 @@ . = ..() +/mob/living/simple_animal/parrot/Poly/say(message, bubble_type,var/list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null) + . = ..() + if(. && !client && prob(1) && prob(1)) //Only the one true bird may speak across dimensions. + world.TgsTargetedChatBroadcast("A stray squawk is heard... \"[message]\"", FALSE) + /mob/living/simple_animal/parrot/Poly/Life() if(!stat && SSticker.current_state == GAME_STATE_FINISHED && !memory_saved) Write_Memory(FALSE) @@ -911,7 +916,7 @@ if(mind) mind.transfer_to(G) else - G.key = key + transfer_ckey(G) ..(gibbed) /mob/living/simple_animal/parrot/Poly/proc/Read_Memory() diff --git a/code/modules/mob/living/simple_animal/simple_animal_vr.dm b/code/modules/mob/living/simple_animal/simple_animal_vr.dm index 41ece5ed06..700ee3b7ce 100644 --- a/code/modules/mob/living/simple_animal/simple_animal_vr.dm +++ b/code/modules/mob/living/simple_animal/simple_animal_vr.dm @@ -29,36 +29,41 @@ /mob/living/simple_animal/Destroy() release_vore_contents(include_absorbed = TRUE, silent = TRUE) prey_excludes.Cut() + QDEL_NULL_LIST(vore_organs) . = ..() // Update fullness based on size & quantity of belly contents /mob/living/simple_animal/proc/update_fullness(var/atom/movable/M) var/new_fullness = 0 - for(var/I in vore_organs) - var/datum/belly/B = vore_organs[I] - if (!(M in B.internal_contents)) + for(var/belly in vore_organs) + var/obj/belly/B = vore_organs[belly] + if (!(M in B.contents)) return FALSE // Nothing's inside new_fullness += M vore_fullness = new_fullness /mob/living/simple_animal/death() - release_vore_contents(silent = TRUE) + release_vore_contents() . = ..() // Simple animals have only one belly. This creates it (if it isn't already set up) /mob/living/simple_animal/init_vore() vore_init = TRUE - if(vore_organs.len) + if(CHECK_BITFIELD(flags_1, HOLOGRAM_1)) return - if(no_vore) //If it can't vore, let's not give it a stomach. + if(!vore_active || no_vore) //If it can't vore, let's not give it a stomach. return if(vore_active && !IsAdvancedToolUser()) //vore active, but doesn't have thumbs to grab people with. verbs |= /mob/living/simple_animal/proc/animal_nom - var/obj/belly/B = new /obj/belly(src) + if(LAZYLEN(vore_organs)) + return + + LAZYINITLIST(vore_organs) + var/obj/belly/B = new (src) vore_selected = B - B.immutable = 1 + B.immutable = TRUE B.name = vore_stomach_name ? vore_stomach_name : "stomach" B.desc = vore_stomach_flavor ? vore_stomach_flavor : "Your surroundings are warm, soft, and slimy. Makes sense, considering you're inside \the [name]." B.digest_mode = vore_default_mode @@ -123,13 +128,12 @@ // Simple nom proc for if you get ckey'd into a simple_animal mob! Avoids grabs. // /mob/living/simple_animal/proc/animal_nom(var/mob/living/T in oview(1)) - set name = "Animal Nom" + set name = "Animal Nom (pull target)" set category = "Vore" set desc = "Since you can't grab, you get a verb!" if (stat != CONSCIOUS) return - if (T.devourable == FALSE) - to_chat(usr, "You can't eat this!") + if(!T.devourable) return - return vore_attack(usr,T,usr) + return vore_attack(src,T,src) diff --git a/modular_citadel/code/modules/mob/living/simple_animal/simplemob_vore_values.dm b/code/modules/mob/living/simple_animal/simplemob_vore_values.dm similarity index 98% rename from modular_citadel/code/modules/mob/living/simple_animal/simplemob_vore_values.dm rename to code/modules/mob/living/simple_animal/simplemob_vore_values.dm index 78e18fdb5e..22ed5e3ab4 100644 --- a/modular_citadel/code/modules/mob/living/simple_animal/simplemob_vore_values.dm +++ b/code/modules/mob/living/simple_animal/simplemob_vore_values.dm @@ -129,6 +129,8 @@ vore_default_mode = DM_DIGEST /mob/living/simple_animal/hostile/carp + devourable = TRUE + digestable = TRUE feeding = TRUE vore_active = TRUE isPredator = TRUE diff --git a/code/modules/mob/living/simple_animal/slime/life.dm b/code/modules/mob/living/simple_animal/slime/life.dm index 07985215d8..29b4689317 100644 --- a/code/modules/mob/living/simple_animal/slime/life.dm +++ b/code/modules/mob/living/simple_animal/slime/life.dm @@ -69,7 +69,7 @@ if(Target.Adjacent(src)) Target.attack_slime(src) - return + break if(!Target.lying && prob(80)) if(Target.client && Target.health >= 20) diff --git a/code/modules/mob/living/simple_animal/slime/powers.dm b/code/modules/mob/living/simple_animal/slime/powers.dm index a3e2f48b75..bf80ab9ff4 100644 --- a/code/modules/mob/living/simple_animal/slime/powers.dm +++ b/code/modules/mob/living/simple_animal/slime/powers.dm @@ -198,7 +198,7 @@ if(src.mind) src.mind.transfer_to(new_slime) else - new_slime.key = src.key + transfer_ckey(new_slime) qdel(src) else to_chat(src, "I am not ready to reproduce yet...") diff --git a/code/modules/mob/living/taste.dm b/code/modules/mob/living/taste.dm index fec024cebf..e4d1aa94a5 100644 --- a/code/modules/mob/living/taste.dm +++ b/code/modules/mob/living/taste.dm @@ -32,4 +32,31 @@ last_taste_time = world.time last_taste_text = text_output +//FermiChem - How to check pH of a beaker without a meter/pH paper. +//Basically checks the pH of the holder and burns your poor tongue if it's too acidic! +//TRAIT_AGEUSIA players can't taste, unless it's burning them. +//taking sips of a strongly acidic/alkaline substance will burn your tongue. +/mob/living/carbon/taste(datum/reagents/from) + var/obj/item/organ/tongue/T = getorganslot("tongue") + if (!T) + return + .=..() + if ((from.pH > 12.5) || (from.pH < 1.5)) + to_chat(src, "You taste chemical burns!") + T.applyOrganDamage(5) + if(istype(T, /obj/item/organ/tongue/cybernetic)) + to_chat(src, "Your tongue moves on it's own in response to the liquid.") + say("The pH is appropriately [round(from.pH, 1)].") + return + if (!HAS_TRAIT(src, TRAIT_AGEUSIA)) //I'll let you get away with not having 1 damage. + switch(from.pH) + if(11.5 to INFINITY) + to_chat(src, "You taste a strong alkaline flavour!") + if(8.5 to 11.5) + to_chat(src, "You taste a sort of soapy tone in the mixture.") + if(2.5 to 5.5) + to_chat(src, "You taste a sort of acid tone in the mixture.") + if(-INFINITY to 2.5) + to_chat(src, "You taste a strong acidic flavour!") + #undef DEFAULT_TASTE_SENSITIVITY diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index f7d10bfb7b..5a7c6e21ab 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -116,19 +116,23 @@ // vision_distance (optional) define how many tiles away the message can be seen. // ignored_mob (optional) doesn't show any message to a given mob if TRUE. -/atom/proc/visible_message(message, self_message, blind_message, vision_distance, ignored_mob) +/atom/proc/visible_message(message, self_message, blind_message, vision_distance, list/ignored_mobs, no_ghosts = FALSE) var/turf/T = get_turf(src) if(!T) return + if(!islist(ignored_mobs)) + ignored_mobs = list(ignored_mobs) var/range = 7 if(vision_distance) range = vision_distance for(var/mob/M in get_hearers_in_view(range, src)) if(!M.client) continue - if(M == ignored_mob) + if(M in ignored_mobs) continue var/msg = message + if(isobserver(M) && no_ghosts) + continue if(M == src) //the src always see the main message or self message if(self_message) msg = self_message @@ -440,7 +444,13 @@ // M.Login() //wat return - +/mob/proc/transfer_ckey(mob/new_mob, send_signal = TRUE) + if(!ckey) + return FALSE + if(send_signal) + SEND_SIGNAL(src, COMSIG_MOB_KEY_CHANGE, new_mob, src) + new_mob.ckey = ckey + return TRUE /mob/verb/cancel_camera() set name = "Cancel Camera View" @@ -448,18 +458,28 @@ reset_perspective(null) unset_machine() +GLOBAL_VAR_INIT(exploit_warn_spam_prevention, 0) + //suppress the .click/dblclick macros so people can't use them to identify the location of items or aimbot /mob/verb/DisClick(argu = null as anything, sec = "" as text, number1 = 0 as num , number2 = 0 as num) set name = ".click" set hidden = TRUE set category = null - return + if(GLOB.exploit_warn_spam_prevention < world.time) + var/msg = "[key_name_admin(src)]([ADMIN_KICK(src)]) attempted to use the .click macro!" + log_admin(msg) + message_admins(msg) + GLOB.exploit_warn_spam_prevention = world.time + 10 /mob/verb/DisDblClick(argu = null as anything, sec = "" as text, number1 = 0 as num , number2 = 0 as num) set name = ".dblclick" set hidden = TRUE set category = null - return + if(GLOB.exploit_warn_spam_prevention < world.time) + var/msg = "[key_name_admin(src)]([ADMIN_KICK(src)]) attempted to use the .dblclick macro!" + log_admin(msg) + message_admins(msg) + GLOB.exploit_warn_spam_prevention = world.time + 10 /mob/Topic(href, href_list) if(href_list["mach_close"]) @@ -520,7 +540,12 @@ return if(isAI(M)) return - show_inv(usr) + +/mob/MouseDrop_T(atom/dropping, atom/user) + . = ..() + if(ismob(dropping) && dropping != user) + var/mob/M = dropping + M.show_inv(user) /mob/proc/is_muzzled() return 0 @@ -791,6 +816,9 @@ /mob/proc/canUseTopic(atom/movable/M, be_close=FALSE, no_dextery=FALSE, no_tk=FALSE) return +/mob/proc/canUseStorage() + return FALSE + /mob/proc/faction_check_mob(mob/target, exact_match) if(exact_match) //if we need an exact match, we need to do some bullfuckery. var/list/faction_src = faction.Copy() diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 776bd04935..93b4d32123 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -429,8 +429,8 @@ It's fairly easy to fix if dealing with single letters but not so much with comp var/mob/dead/observer/C = pick(candidates) to_chat(M, "Your mob has been taken over by a ghost!") message_admins("[key_name_admin(C)] has taken control of ([key_name_admin(M)])") - M.ghostize(0) - M.key = C.key + M.ghostize(FALSE, TRUE) + C.transfer_ckey(M, FALSE) return TRUE else to_chat(M, "There were no ghosts willing to take control.") @@ -486,3 +486,15 @@ It's fairly easy to fix if dealing with single letters but not so much with comp /mob/proc/can_hear() . = TRUE + +//Examine text for traits shared by multiple types. I wish examine was less copypasted. +/mob/proc/common_trait_examine() + if(HAS_TRAIT(src, TRAIT_DISSECTED)) + var/dissectionmsg = "" + if(HAS_TRAIT_FROM(src, TRAIT_DISSECTED,"Extraterrestrial Dissection")) + dissectionmsg = " via Extraterrestrial Dissection. It is no longer worth experimenting on" + else if(HAS_TRAIT_FROM(src, TRAIT_DISSECTED,"Experimental Dissection")) + dissectionmsg = " via Experimental Dissection" + else if(HAS_TRAIT_FROM(src, TRAIT_DISSECTED,"Thorough Dissection")) + dissectionmsg = " via Thorough Dissection" + . += "This body has been dissected and analyzed[dissectionmsg].
" \ No newline at end of file diff --git a/code/modules/mob/mob_transformation_simple.dm b/code/modules/mob/mob_transformation_simple.dm index 673548ff48..a11e7a228e 100644 --- a/code/modules/mob/mob_transformation_simple.dm +++ b/code/modules/mob/mob_transformation_simple.dm @@ -53,7 +53,7 @@ if(mind && isliving(M)) mind.transfer_to(M, 1) // second argument to force key move to new mob else - M.key = key + transfer_ckey(M) if(delete_old_mob) QDEL_IN(src, 1) diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index 5703e2190b..6394b45aa7 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -75,7 +75,7 @@ O.setOxyLoss(getOxyLoss(), 0) O.setCloneLoss(getCloneLoss(), 0) O.adjustFireLoss(getFireLoss(), 0) - O.setBrainLoss(getBrainLoss(), 0) + O.setOrganLoss(ORGAN_SLOT_BRAIN, getOrganLoss(ORGAN_SLOT_BRAIN), 0) O.adjustStaminaLoss(getStaminaLoss(), 0)//CIT CHANGE - makes monkey transformations inherit stamina O.updatehealth() O.radiation = radiation @@ -236,7 +236,7 @@ O.setOxyLoss(getOxyLoss(), 0) O.setCloneLoss(getCloneLoss(), 0) O.adjustFireLoss(getFireLoss(), 0) - O.setBrainLoss(getBrainLoss(), 0) + O.setOrganLoss(ORGAN_SLOT_BRAIN, getOrganLoss(ORGAN_SLOT_BRAIN), 0) O.adjustStaminaLoss(getStaminaLoss(), 0)//CIT CHANGE - makes monkey transformations inherit stamina O.updatehealth() O.radiation = radiation @@ -382,7 +382,7 @@ mind.active = FALSE mind.transfer_to(R) else if(transfer_after) - R.key = key + transfer_ckey(R) R.apply_pref_name("cyborg") @@ -401,7 +401,7 @@ qdel(src) //human -> alien -/mob/living/carbon/human/proc/Alienize() +/mob/living/carbon/human/proc/Alienize(mind_transfer = TRUE) if (notransform) return for(var/obj/item/W in src) @@ -425,13 +425,16 @@ new_xeno = new /mob/living/carbon/alien/humanoid/drone(loc) new_xeno.a_intent = INTENT_HARM - new_xeno.key = key + if(mind && mind_transfer) + mind.transfer_to(new_xeno) + else + transfer_ckey(new_xeno) to_chat(new_xeno, "You are now an alien.") . = new_xeno qdel(src) -/mob/living/carbon/human/proc/slimeize(reproduce as num) +/mob/living/carbon/human/proc/slimeize(reproduce, mind_transfer = TRUE) if (notransform) return for(var/obj/item/W in src) @@ -457,20 +460,26 @@ else new_slime = new /mob/living/simple_animal/slime(loc) new_slime.a_intent = INTENT_HARM - new_slime.key = key + if(mind && mind_transfer) + mind.transfer_to(new_slime) + else + transfer_ckey(new_slime) to_chat(new_slime, "You are now a slime. Skreee!") . = new_slime qdel(src) -/mob/proc/become_overmind(starting_points = 60) +/mob/proc/become_overmind(starting_points = 60, mind_transfer = FALSE) var/mob/camera/blob/B = new /mob/camera/blob(get_turf(src), starting_points) - B.key = key + if(mind && mind_transfer) + mind.transfer_to(B) + else + transfer_ckey(B) . = B qdel(src) -/mob/living/carbon/human/proc/corgize() +/mob/living/carbon/human/proc/corgize(mind_transfer = TRUE) if (notransform) return for(var/obj/item/W in src) @@ -485,13 +494,16 @@ var/mob/living/simple_animal/pet/dog/corgi/new_corgi = new /mob/living/simple_animal/pet/dog/corgi (loc) new_corgi.a_intent = INTENT_HARM - new_corgi.key = key + if(mind && mind_transfer) + mind.transfer_to(new_corgi) + else + transfer_ckey(new_corgi) to_chat(new_corgi, "You are now a Corgi. Yap Yap!") . = new_corgi qdel(src) -/mob/living/carbon/proc/gorillize() +/mob/living/carbon/proc/gorillize(mind_transfer = TRUE) if(notransform) return @@ -509,22 +521,22 @@ invisibility = INVISIBILITY_MAXIMUM var/mob/living/simple_animal/hostile/gorilla/new_gorilla = new (get_turf(src)) new_gorilla.a_intent = INTENT_HARM - if(mind) + if(mind && mind_transfer) mind.transfer_to(new_gorilla) else - new_gorilla.key = key + transfer_ckey(new_gorilla) to_chat(new_gorilla, "You are now a gorilla. Ooga ooga!") . = new_gorilla qdel(src) -/mob/living/carbon/human/Animalize() +/mob/living/carbon/human/Animalize(mind_transfer = TRUE) var/list/mobtypes = typesof(/mob/living/simple_animal) - var/mobpath = input("Which type of mob should [src] turn into?", "Choose a type") in mobtypes - - if(!safe_animal(mobpath)) - to_chat(usr, "Sorry but this mob type is currently unavailable.") + var/mobpath = input("Which type of mob should [src] turn into?", "Choose a type") as null|anything in mobtypes + if(!mobpath) return + if(mind) + mind_transfer = alert("Want to transfer their mind into the new mob", "Mind Transfer", "Yes", "No") == "Yes" ? TRUE : FALSE if(notransform) return @@ -532,8 +544,8 @@ dropItemToGround(W) regenerate_icons() - notransform = 1 - canmove = 0 + notransform = TRUE + canmove = FALSE icon = null invisibility = INVISIBILITY_MAXIMUM @@ -541,8 +553,10 @@ qdel(t) var/mob/new_mob = new mobpath(src.loc) - - new_mob.key = key + if(mind && mind_transfer) + mind.transfer_to(new_mob) + else + transfer_ckey(new_mob) new_mob.a_intent = INTENT_HARM @@ -550,59 +564,23 @@ . = new_mob qdel(src) -/mob/proc/Animalize() +/mob/proc/Animalize(mind_transfer = TRUE) var/list/mobtypes = typesof(/mob/living/simple_animal) - var/mobpath = input("Which type of mob should [src] turn into?", "Choose a type") in mobtypes - - if(!safe_animal(mobpath)) - to_chat(usr, "Sorry but this mob type is currently unavailable.") + var/mobpath = input("Which type of mob should [src] turn into?", "Choose a type") as null|anything in mobtypes + if(!mobpath) return + if(mind) + mind_transfer = alert("Want to transfer their mind into the new mob", "Mind Transfer", "Yes", "No") == "Yes" ? TRUE : FALSE var/mob/new_mob = new mobpath(src.loc) - new_mob.key = key + if(mind && mind_transfer) + mind.transfer_to(new_mob) + else + transfer_ckey(new_mob) new_mob.a_intent = INTENT_HARM to_chat(new_mob, "You feel more... animalistic") . = new_mob qdel(src) - -/* Certain mob types have problems and should not be allowed to be controlled by players. - * - * This proc is here to force coders to manually place their mob in this list, hopefully tested. - * This also gives a place to explain -why- players shouldnt be turn into certain mobs and hopefully someone can fix them. - */ -/mob/proc/safe_animal(MP) - -//Bad mobs! - Remember to add a comment explaining what's wrong with the mob - if(!MP) - return 0 //Sanity, this should never happen. - - if(ispath(MP, /mob/living/simple_animal/hostile/construct)) - return 0 //Verbs do not appear for players. - -//Good mobs! - if(ispath(MP, /mob/living/simple_animal/pet/cat)) - return 1 - if(ispath(MP, /mob/living/simple_animal/pet/dog/corgi)) - return 1 - if(ispath(MP, /mob/living/simple_animal/crab)) - return 1 - if(ispath(MP, /mob/living/simple_animal/hostile/carp)) - return 1 - if(ispath(MP, /mob/living/simple_animal/hostile/mushroom)) - return 1 - if(ispath(MP, /mob/living/simple_animal/shade)) - return 1 - if(ispath(MP, /mob/living/simple_animal/hostile/killertomato)) - return 1 - if(ispath(MP, /mob/living/simple_animal/mouse)) - return 1 //It is impossible to pull up the player panel for mice (Fixed! - Nodrak) - if(ispath(MP, /mob/living/simple_animal/hostile/bear)) - return 1 //Bears will auto-attack mobs, even if they're player controlled (Fixed! - Nodrak) - if(ispath(MP, /mob/living/simple_animal/parrot)) - return 1 //Parrots are no longer unfinished! -Nodrak - - //Not in here? Must be untested! - return 0 diff --git a/code/modules/modular_computers/computers/item/computer.dm b/code/modules/modular_computers/computers/item/computer.dm index 580374c5c0..db4cdc2ff5 100644 --- a/code/modules/modular_computers/computers/item/computer.dm +++ b/code/modules/modular_computers/computers/item/computer.dm @@ -178,13 +178,13 @@ turn_on(user) /obj/item/modular_computer/emag_act(mob/user) + . = ..() if(obj_flags & EMAGGED) to_chat(user, "\The [src] was already emagged.") - return 0 - else - obj_flags |= EMAGGED - to_chat(user, "You emag \the [src]. It's screen briefly shows a \"OVERRIDE ACCEPTED: New software downloads available.\" message.") - return 1 + return + obj_flags |= EMAGGED + to_chat(user, "You emag \the [src]. It's screen briefly shows a \"OVERRIDE ACCEPTED: New software downloads available.\" message.") + return TRUE /obj/item/modular_computer/examine(mob/user) ..() diff --git a/code/modules/modular_computers/computers/machinery/modular_computer.dm b/code/modules/modular_computers/computers/machinery/modular_computer.dm index 19d3b56046..b3476e7046 100644 --- a/code/modules/modular_computers/computers/machinery/modular_computer.dm +++ b/code/modules/modular_computers/computers/machinery/modular_computer.dm @@ -44,7 +44,9 @@ cpu.attack_ghost(user) /obj/machinery/modular_computer/emag_act(mob/user) - return cpu ? cpu.emag_act(user) : 1 + . = ..() + if(cpu) + . |= cpu.emag_act(user) /obj/machinery/modular_computer/update_icon() cut_overlays() diff --git a/code/modules/ninja/suit/n_suit_verbs/ninja_stealth.dm b/code/modules/ninja/suit/n_suit_verbs/ninja_stealth.dm index 1c3fbd8147..94be922fdf 100644 --- a/code/modules/ninja/suit/n_suit_verbs/ninja_stealth.dm +++ b/code/modules/ninja/suit/n_suit_verbs/ninja_stealth.dm @@ -8,33 +8,37 @@ Contents: /obj/item/clothing/suit/space/space_ninja/proc/toggle_stealth() - var/mob/living/carbon/human/U = affecting - if(!U) + if(!affecting) return if(stealth) cancel_stealth() else if(cell.charge <= 0) - to_chat(U, "You don't have enough power to enable Stealth!") + to_chat(affecting, "You don't have enough power to enable Stealth!") return stealth = !stealth - animate(U, alpha = 50,time = 15) - U.visible_message("[U.name] vanishes into thin air!", \ + animate(affecting, alpha = 10,time = 15) + affecting.visible_message("[affecting.name] vanishes into thin air!", \ "You are now mostly invisible to normal detection.") + RegisterSignal(affecting, list(COMSIG_MOB_ITEM_ATTACK, COMSIG_MOB_ATTACK_RANGED, COMSIG_MOB_ATTACK_HAND, COMSIG_MOB_THROW, COMSIG_PARENT_ATTACKBY), .proc/reduce_stealth) + RegisterSignal(affecting, COMSIG_MOVABLE_BUMP, .proc/bumping_stealth) +/obj/item/clothing/suit/space/space_ninja/proc/reduce_stealth() + affecting.alpha = min(affecting.alpha + 30, 80) + +/obj/item/clothing/suit/space/space_ninja/proc/bumping_stealth(datum/source, atom/A) + if(isliving(A)) + affecting.alpha = min(affecting.alpha + 15, 80) /obj/item/clothing/suit/space/space_ninja/proc/cancel_stealth() - var/mob/living/carbon/human/U = affecting - if(!U) - return 0 - if(stealth) - stealth = !stealth - animate(U, alpha = 255, time = 15) - U.visible_message("[U.name] appears from thin air!", \ - "You are now visible.") - return 1 - return 0 - + if(!affecting || !stealth) + return FALSE + stealth = !stealth + UnregisterSignal(affecting, list(COMSIG_MOB_ITEM_ATTACK, COMSIG_MOB_ATTACK_RANGED, COMSIG_MOB_ATTACK_HAND, COMSIG_MOB_THROW, COMSIG_PARENT_ATTACKBY, COMSIG_MOVABLE_BUMP)) + animate(affecting, alpha = 255, time = 15) + affecting.visible_message("[affecting.name] appears from thin air!", \ + "You are now visible.") + return TRUE /obj/item/clothing/suit/space/space_ninja/proc/stealth() if(!s_busy) diff --git a/code/modules/ninja/suit/shoes.dm b/code/modules/ninja/suit/shoes.dm index 1b935a00de..1bda62e064 100644 --- a/code/modules/ninja/suit/shoes.dm +++ b/code/modules/ninja/suit/shoes.dm @@ -1,9 +1,7 @@ - /obj/item/clothing/shoes/space_ninja name = "ninja shoes" desc = "A pair of running shoes. Excellent for running and even better for smashing skulls." icon_state = "s-ninja" - item_state = "secshoes" permeability_coefficient = 0.01 clothing_flags = NOSLIP resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF @@ -13,3 +11,12 @@ min_cold_protection_temperature = SHOES_MIN_TEMP_PROTECT heat_protection = FEET max_heat_protection_temperature = SHOES_MAX_TEMP_PROTECT + +/obj/item/clothing/shoes/space_ninja/equipped(mob/user, slot) + . = ..() + if(slot == SLOT_SHOES) + ADD_TRAIT(user, TRAIT_SILENT_STEP, "ninja_shoes_[REF(src)]") + +/obj/item/clothing/shoes/space_ninja/dropped(mob/user) + . = ..() + REMOVE_TRAIT(user, TRAIT_SILENT_STEP, "ninja_shoes_[REF(src)]") diff --git a/code/modules/ninja/suit/suit.dm b/code/modules/ninja/suit/suit.dm index b98ef764c0..ac1ef3b96a 100644 --- a/code/modules/ninja/suit/suit.dm +++ b/code/modules/ninja/suit/suit.dm @@ -149,12 +149,11 @@ Contents: /obj/item/clothing/suit/space/space_ninja/examine(mob/user) ..() - if(s_initialized) - if(user == affecting) - to_chat(user, "All systems operational. Current energy capacity: [DisplayEnergy(cell.charge)].") - to_chat(user, "The CLOAK-tech device is [stealth?"active":"inactive"].") - to_chat(user, "There are [s_bombs] smoke bomb\s remaining.") - to_chat(user, "There are [a_boost] adrenaline booster\s remaining.") + if(s_initialized && user == affecting) + to_chat(user, "All systems operational. Current energy capacity: [DisplayEnergy(cell.charge)].\n\ + The CLOAK-tech device is [stealth?"active":"inactive"].\n\ + There are [s_bombs] smoke bomb\s remaining.\n\ + There are [a_boost] adrenaline booster\s remaining.") /obj/item/clothing/suit/space/space_ninja/ui_action_click(mob/user, action) if(istype(action, /datum/action/item_action/initialize_ninja_suit)) diff --git a/code/modules/ninja/suit/suit_initialisation.dm b/code/modules/ninja/suit/suit_initialisation.dm index 4b159557bc..3d80282fe7 100644 --- a/code/modules/ninja/suit/suit_initialisation.dm +++ b/code/modules/ninja/suit/suit_initialisation.dm @@ -48,7 +48,7 @@ /obj/item/clothing/suit/space/space_ninja/proc/ninitialize_seven(delay, mob/living/carbon/human/U) to_chat(U, "All systems operational. Welcome to SpiderOS, [U.real_name].") s_initialized = TRUE - ntick() + START_PROCESSING(SSprocessing, src) s_busy = FALSE @@ -91,4 +91,5 @@ unlock_suit() U.regenerate_icons() s_initialized = FALSE + STOP_PROCESSING(SSprocessing, src) s_busy = FALSE diff --git a/code/modules/ninja/suit/suit_process.dm b/code/modules/ninja/suit/suit_process.dm index 4a89a59f75..850fb837b4 100644 --- a/code/modules/ninja/suit/suit_process.dm +++ b/code/modules/ninja/suit/suit_process.dm @@ -1,20 +1,17 @@ -/obj/item/clothing/suit/space/space_ninja/proc/ntick(mob/living/carbon/human/U = affecting) - //Runs in the background while the suit is initialized. - //Requires charge or stealth to process. - spawn while(s_initialized) - if(!affecting) - terminate()//Kills the suit and attached objects. +/obj/item/clothing/suit/space/space_ninja/process() + if(!affecting || !s_initialized) + return PROCESS_KILL - else if(cell.charge > 0) - if(s_coold) - s_coold--//Checks for ability s_cooldown first. + if(cell.charge > 0) + if(s_coold) + s_coold--//Checks for ability s_cooldown first. - cell.charge -= s_cost//s_cost is the default energy cost each ntick, usually 5. - if(stealth)//If stealth is active. - cell.charge -= s_acost + cell.charge -= s_cost//s_cost is the default energy cost each tick, usually 5. + if(stealth)//If stealth is active. + cell.charge -= s_acost + affecting.alpha = max(affecting.alpha - 10, 10) - else - cell.charge = 0 + else + cell.charge = 0 + if(stealth) cancel_stealth() - - sleep(10)//Checks every second. diff --git a/code/modules/oracle_ui/README.md b/code/modules/oracle_ui/README.md new file mode 100644 index 0000000000..bc96eb1f51 --- /dev/null +++ b/code/modules/oracle_ui/README.md @@ -0,0 +1,233 @@ +# `/datum/oracle_ui` + +This datum is a replacement for tgui which does not use any Node.js dependencies, and works entirely through raw HTML, JS and CSS. It's designed to be reasonably easy to port something from tgui to oracle_ui. + +### How to create a UI + +For this example, we're going to port the disposals bin from tgui to oracle_ui. + +#### Step 1 + +In order to create a UI, you will first need to create an instance of `/datum/oracle_ui` or one of its subclasses, in this case `/datum/oracle_ui/themed/nano`. + +You need to pass in `src`, the width of the window, the height of the window, and the template to render from. You can optionally set some flags to disallow window resizing and whether to automatically refresh the UI. + +`code/modules/recycling/disposal-unit.dm` +```dm +/obj/machinery/disposal/bin/Initialize(mapload, obj/structure/disposalconstruct/make_from) + . = ..() + ui = new /datum/oracle_ui/themed/nano(src, 330, 190, "disposal_bin") + ui.auto_refresh = TRUE + ui.can_resize = FALSE +``` + +#### Step 2 + +You will now need to make a template in `html/oracle_ui/content/{template_name}`. + +Values defined as `@{value}` will get replaced at runtime by oracle_ui. + +`html/oracle_ui/content/disposal_bin/index.html` +```html +
+
+ State: +
@{full_pressure}
+
+
+ Pressure: +
+
+
+
@{per}
+
+
+
+
+ Handle: +
@{flush}
+
+
+ Eject: +
@{contents}
+
+
+ Compressor: +
@{pressure_charging}
+
+
+``` + +#### Step 3 + +Now you need to implement the methods that provide data to oracle_ui. `oui_data` can be adapted from the `ui_data` proc that tgui uses. + +The `act` proc generates a hyperlink that will result in `oui_act` getting called on your object when clicked. The `class` argument defines a css class to be added to the hyperlink, and disabled determines whether the hyperlink will be disabled or not. + +Calling `soft_update_fields` will result in the UI being updated on all clients, which is useful when the object changes state. + +`code/modules/recycling/disposal-unit.dm` +```dm +/obj/machinery/disposal/bin/oui_data(mob/user) + var/list/data = list() + data["flush"] = flush ? ui.act("Disengage", user, "handle-0", class="active") : ui.act("Engage", user, "handle-1") + data["full_pressure"] = full_pressure ? "Ready" : (pressure_charging ? "Pressurizing" : "Off") + data["pressure_charging"] = pressure_charging ? ui.act("Turn Off", user, "pump-0", class="active", disabled=full_pressure) : ui.act("Turn On", user, "pump-1", disabled=full_pressure) + var/per = full_pressure ? 100 : Clamp(100* air_contents.return_pressure() / (SEND_PRESSURE), 0, 99) + data["per"] = "[round(per, 1)]%" + data["contents"] = ui.act("Eject Contents", user, "eject", disabled=contents.len < 1) + data["isai"] = isAI(user) + return data +/obj/machinery/disposal/bin/oui_act(mob/user, action, list/params) + if(..()) + return + switch(action) + if("handle-0") + flush = FALSE + update_icon() + . = TRUE + if("handle-1") + if(!panel_open) + flush = TRUE + update_icon() + . = TRUE + if("pump-0") + if(pressure_charging) + pressure_charging = FALSE + update_icon() + . = TRUE + if("pump-1") + if(!pressure_charging) + pressure_charging = TRUE + update_icon() + . = TRUE + if("eject") + eject() + . = TRUE + ui.soft_update_fields() +``` + +#### Step 4 + +You now need to hook in and ensure oracle_ui is invoked upon clicking. `render` should be used to open the UI for a user, typically on click. + +`code/modules/recycling/disposal-unit.dm` +```dm +/obj/machinery/disposal/bin/ui_interact(mob/user, state) + if(stat & BROKEN) + return + if(user.loc == src) + to_chat(user, "You cannot reach the controls from inside!") + return + ui.render(user) +``` + +#### Done + +![gif](https://user-images.githubusercontent.com/202160/37561879-1bb9179e-2a52-11e8-902c-80e6e6df7204.gif) + +You should have a functional UI at this point. Some additional odds and ends can be discovered throughout `code/modules/recycling/disposal-unit.dm`. For a full diff of the changes made to it, refer to [the original pull request on GitHub](https://github.com/OracleStation/OracleStation/pull/702/files#diff-4b6c20ec7d37222630e7524d9577e230). + +### API Reference + +#### `/datum/oracle_ui` + +The main datum which handles the UI. + +##### `get_content(mob/target)` +Returns the HTML that should be displayed for a specified target mob. Calls `oui_getcontent` on the datasource to get the return value. *This proc is not used in the themed subclass.* + +##### `can_view(mob/target)` +Returns whether the specified target mob can view the UI. Calls `oui_canview` on the datasource to get the return value. + +##### `test_viewer(mob/target, updating)` +Tests whether the client is valid and can view the UI. If updating is TRUE, checks to see if they still have the UI window open. + +##### `render(mob/target, updating = FALSE)` +Opens the UI for a target mob, sending HTML. If updating is TRUE, will only do it to clients which still have the window open. + +##### `render_all()` +Does the above, but for all viewers and with updating set to TRUE. + +##### `close(mob/target)` +Closes the UI for the specified target mob. + +##### `close_all()` +Does the above, but for all viewers. + +##### `check_view(mob/target)` +Checks if the specified target mob can view the UI, and if they can't closes their UI + +##### `check_view_all()` +Does the above, but for all viewers. + +##### `call_js(mob/target, js_func, list/parameters = list())` +Invokes `js_func` in the UI of the specified target mob with the specified parameters. + +##### `call_js_all(js_func, list/parameters = list()))` +Does the above, but for all viewers. + +##### `steal_focus(mob/target)` +Causes the UI to steal focus for the specified target mob. + +##### `steal_focus_all()` +Does the above, but for all viewers. + +##### `flash(mob/target, times = -1)` +Causes the UI to flash for the specified target mob the specified number of times, the default keeps the element flashing until focused. + +##### `flash_all()` +Does the above, but for all viewers. + +##### `href(mob/user, action, list/parameters = list())` +Generates a href for the specified user which will invoke `oui_act` on the datasource with the specified action and parameters. + +#### `/datum/oracle_ui/themed` + +A subclass which supports templating and theming. + +##### `get_file(path)` +Loads a file from disk and returns the contents. Caches files loaded from disk for you. + +##### `get_content_file(filename)` +Loads a file from the current content folder and returns the contents. + +##### `get_themed_file(filename)` +Loads a file from the current theme folder and returns the contents. + +##### `process_template(template, variables)` +Processes a template and populates it with the provided variables. + +##### `get_inner_content(mob/target)` +Returns the templated content to be inserted into the main template for the specified target mob. + +##### `soft_update_fields()` +For all viewers, updates the fields in the template via the `updateFields` javaScript function. + +##### `soft_update_all()` +For all viewers, updates the content body in the template via the `replaceContent` javaScript function. + +##### `change_page(var/newpage)` +Changes the template to use to draw the page and forces an update to all viewers + +##### `act(label, mob/user, action, list/parameters = list(), class = "", disabled = FALSE` +Returns a fully formatted hyperlink for the specified user. `label` will be the hyperlink label, `action` and `parameters` are what will be passed to `oui_act`, `class` is any CSS classes to apply to the hyperlink and `disabled` will disable the hyperlink. + +#### `/datum` + +Functions built into all objects to support oracle_ui. There are default implementations for most major superclasses. + +##### `oui_canview(mob/user)` +Returns whether the specified user view the UI at this time. + +##### `oui_getcontent(mob/user)` +Returns the raw HTML to be sent to the specified user. *This proc is not used in the themed subclass of oracle_ui.* + +##### `oui_data(mob/user)` +Returns templating data for the specified user. *This proc is only used in the themed subclass of oracle_ui.* + +##### `oui_data_debug(mob/user)` +Returns the above, but JSON-encoded and escaped, for copy pasting into the web IDE. *This proc is only used for debugging purposes.* + +##### `oui_act(mob/user, action, list/params)` +Called when a hyperlink is clicked in the UI. diff --git a/code/modules/oracle_ui/assets.dm b/code/modules/oracle_ui/assets.dm new file mode 100644 index 0000000000..5d26d80a81 --- /dev/null +++ b/code/modules/oracle_ui/assets.dm @@ -0,0 +1,8 @@ +/datum/asset/simple/oui_theme_nano + assets = list( + // JavaScript + "sui-nano-common.js" = 'html/oracle_ui/themes/nano/sui-nano-common.js', + "sui-nano-jquery.min.js" = 'html/oracle_ui/themes/nano/sui-nano-jquery.min.js', + // Stylesheets + "sui-nano-common.css" = 'html/oracle_ui/themes/nano/sui-nano-common.css', + ) diff --git a/code/modules/oracle_ui/hookup_procs.dm b/code/modules/oracle_ui/hookup_procs.dm new file mode 100644 index 0000000000..e6038744c1 --- /dev/null +++ b/code/modules/oracle_ui/hookup_procs.dm @@ -0,0 +1,44 @@ +/datum/proc/oui_canview(mob/user) + return TRUE + +/datum/proc/oui_getcontent(mob/user) + return "Default Implementation" + +/datum/proc/oui_canuse(mob/user) + if(isobserver(user) && !user.has_unlimited_silicon_privilege) + return FALSE + return oui_canview(user) + +/datum/proc/oui_data(mob/user) + return list() + +/datum/proc/oui_data_debug(mob/user) + return html_encode(json_encode(oui_data(user))) + +/datum/proc/oui_act(mob/user, action, list/params) + // No Implementation + +/atom/oui_canview(mob/user) + if(isobserver(user)) + return TRUE + if(user.incapacitated()) + return FALSE + if(isturf(src.loc) && Adjacent(user)) + return TRUE + return FALSE + +/obj/item/oui_canview(mob/user) + if(src.loc == user) + return src in user.held_items + return ..() + +/obj/machinery/oui_canview(mob/user) + if(user.has_unlimited_silicon_privilege) + return TRUE + if(!can_interact()) + return FALSE + if(iscyborg(user)) + return can_see(user, src, 7) + if(isAI(user)) + return GLOB.cameranet.checkTurfVis(get_turf_pixel(src)) + return ..() diff --git a/code/modules/oracle_ui/oracle_ui.dm b/code/modules/oracle_ui/oracle_ui.dm new file mode 100644 index 0000000000..5e8d6b9c7b --- /dev/null +++ b/code/modules/oracle_ui/oracle_ui.dm @@ -0,0 +1,134 @@ +/datum/oracle_ui + var/width = 512 + var/height = 512 + var/can_close = TRUE + var/can_minimize = FALSE + var/can_resize = TRUE + var/titlebar = TRUE + var/window_id = null + var/viewers[0] + var/auto_check_view = TRUE + var/auto_refresh = FALSE + var/atom/datasource = null + var/datum/asset/assets = null + +/datum/oracle_ui/New(atom/n_datasource, n_width = 512, n_height = 512, n_assets = null) + datasource = n_datasource + window_id = REF(src) + width = n_width + height = n_height + +/datum/oracle_ui/Destroy() + close_all() + if(src.datum_flags & DF_ISPROCESSING) + STOP_PROCESSING(SSobj, src) + return ..() + +/datum/oracle_ui/process() + if(auto_check_view) + check_view_all() + if(auto_refresh) + render_all() + +/datum/oracle_ui/proc/get_content(mob/target) + return call(datasource, "oui_getcontent")(target) + +/datum/oracle_ui/proc/can_view(mob/target) + return call(datasource, "oui_canview")(target) + +/datum/oracle_ui/proc/test_viewer(mob/target, updating) + //If the target is null or does not have a client, remove from viewers and return + if(!target | !target.client | !can_view(target)) + viewers -= target + if(viewers.len < 1 && (src.datum_flags & DF_ISPROCESSING)) + STOP_PROCESSING(SSobj, src) //No more viewers, stop polling + close(target) + return FALSE + //If this is an update, and they have closed the window, remove from viewers and return + if(updating && winget(target, window_id, "is-visible") != "true") + viewers -= target + if(viewers.len < 1 && (src.datum_flags & DF_ISPROCESSING)) + STOP_PROCESSING(SSobj, src) //No more viewers, stop polling + return FALSE + return TRUE + +/datum/oracle_ui/proc/render(mob/target, updating = FALSE) + set waitfor = FALSE //Makes this an async call + if(!can_view(target)) + return + //Check to see if they have the window open still if updating + if(updating && !test_viewer(target, updating)) + return + //Send assets + if(!updating && assets) + assets.send(target) + //Add them to the viewers if they aren't there already + viewers |= target + if(!(src.datum_flags & DF_ISPROCESSING) && (auto_refresh | auto_check_view)) + START_PROCESSING(SSobj, src) //Start processing to poll for viewability + //Send the content + if(updating) + target << output(get_content(target), "[window_id].browser") + else + target << browse(get_content(target), "window=[window_id];size=[width]x[height];can_close=[can_close];can_minimize=[can_minimize];can_resize=[can_resize];titlebar=[titlebar];focus=false;") + steal_focus(target) + +/datum/oracle_ui/proc/render_all() + for(var/viewer in viewers) + render(viewer, TRUE) + +/datum/oracle_ui/proc/close(mob/target) + if(target && target.client) + target << browse(null, "window=[window_id]") + +/datum/oracle_ui/proc/close_all() + for(var/viewer in viewers) + close(viewer) + viewers = list() + +/datum/oracle_ui/proc/check_view_all() + for(var/viewer in viewers) + check_view(viewer) + +/datum/oracle_ui/proc/check_view(mob/target) + set waitfor = FALSE //Makes this an async call + if(!test_viewer(target, TRUE)) + close(target) + +/datum/oracle_ui/proc/call_js(mob/target, js_func, list/parameters = list()) + set waitfor = FALSE //Makes this an async call + if(!test_viewer(target, TRUE)) + return + target << output(list2params(parameters),"[window_id].browser:[js_func]") + +/datum/oracle_ui/proc/call_js_all(js_func, list/parameters = list()) + for(var/viewer in viewers) + call_js(viewer, js_func, parameters) + +/datum/oracle_ui/proc/steal_focus(mob/target) + set waitfor = FALSE //Makes this an async call + winset(target, "[window_id]","focus=true") + +/datum/oracle_ui/proc/steal_focus_all() + for(var/viewer in viewers) + steal_focus(viewer) + +/datum/oracle_ui/proc/flash(mob/target, times = -1) + set waitfor = FALSE //Makes this an async call + winset(target, "[window_id]","flash=[times]") + +/datum/oracle_ui/proc/flash_all(times = -1) + for(var/viewer in viewers) + flash(viewer, times) + +/datum/oracle_ui/proc/href(mob/user, action, list/parameters = list()) + var/params_string = replacetext(list2params(parameters),"&",";") + return "?src=[REF(src)];sui_action=[action];sui_user=[REF(user)];[params_string]" + +/datum/oracle_ui/Topic(href, parameters) + var/action = parameters["sui_action"] + var/mob/current_user = locate(parameters["sui_user"]) + if(!call(datasource, "oui_canuse")(current_user)) + return + if(datasource) + call(datasource, "oui_act")(current_user, action, parameters); diff --git a/code/modules/oracle_ui/themed.dm b/code/modules/oracle_ui/themed.dm new file mode 100644 index 0000000000..56b82c2647 --- /dev/null +++ b/code/modules/oracle_ui/themed.dm @@ -0,0 +1,82 @@ +/datum/oracle_ui/themed + var/theme = "" + var/content_root = "" + var/current_page = "index.html" + var/root_template = "" + +/datum/oracle_ui/themed/New(atom/n_datasource, n_width = 512, n_height = 512, n_content_root = "") + root_template = get_themed_file("index.html") + content_root = n_content_root + return ..(n_datasource, n_width, n_height, get_asset_datum(/datum/asset/simple/oui_theme_nano)) + +/datum/oracle_ui/themed/process() + if(auto_check_view) + check_view_all() + if(auto_refresh) + soft_update_fields() + +GLOBAL_LIST_EMPTY(oui_template_variables) +GLOBAL_LIST_EMPTY(oui_file_cache) + +/datum/oracle_ui/themed/proc/get_file(path) + if(GLOB.oui_file_cache[path]) + return GLOB.oui_file_cache[path] + else if(fexists(path)) + var/data = file2text(path) + GLOB.oui_file_cache[path] = data + return data + else + var/errormsg = "MISSING PATH '[path]'" +#ifndef UNIT_TESTS + log_world(errormsg) //Because Travis absolutely hates these procs +#endif + return errormsg + +/datum/oracle_ui/themed/proc/get_content_file(filename) + return get_file("./html/oracle_ui/content/[content_root]/[filename]") + +/datum/oracle_ui/themed/proc/get_themed_file(filename) + return get_file("./html/oracle_ui/themes/[theme]/[filename]") + +/datum/oracle_ui/themed/proc/process_template(template, variables) + var/regex/pattern = regex("\\@\\{(\\w+)\\}","gi") + GLOB.oui_template_variables = variables + var/replaced = pattern.Replace(template, /proc/oui_process_template_replace) + GLOB.oui_template_variables = null + return replaced + +/proc/oui_process_template_replace(match, group1) + var/value = GLOB.oui_template_variables[group1] + return "[value]" + +/datum/oracle_ui/themed/proc/get_inner_content(mob/target) + var/list/data = call(datasource, "oui_data")(target) + return process_template(get_content_file(current_page), data) + +/datum/oracle_ui/themed/get_content(mob/target) + var/list/template_data = list("title" = datasource.name, "body" = get_inner_content(target)) + return process_template(root_template, template_data) + +/datum/oracle_ui/themed/proc/soft_update_fields() + for(var/viewer in viewers) + var/json = json_encode(call(datasource, "oui_data")(viewer)) + call_js(viewer, "updateFields", list(json)) + +/datum/oracle_ui/themed/proc/soft_update_all() + for(var/viewer in viewers) + call_js(viewer, "replaceContent", list(get_inner_content(viewer))) + +/datum/oracle_ui/themed/proc/change_page(newpage) + if(newpage == current_page) + return + current_page = newpage + render_all() + +/datum/oracle_ui/themed/proc/act(label, mob/user, action, list/parameters = list(), class = "", disabled = FALSE) + if(disabled) + return "[label]" + else + return "[label]" + +/datum/oracle_ui/themed/nano + theme = "nano" diff --git a/code/modules/paperwork/filingcabinet.dm b/code/modules/paperwork/filingcabinet.dm index 907fccdc5b..ccbcf34d8c 100644 --- a/code/modules/paperwork/filingcabinet.dm +++ b/code/modules/paperwork/filingcabinet.dm @@ -67,6 +67,9 @@ /obj/structure/filingcabinet/ui_interact(mob/user) . = ..() + if(isobserver(user)) + return + if(contents.len <= 0) to_chat(user, "[src] is empty.") return diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm index 37877ffb09..059a42bb36 100644 --- a/code/modules/paperwork/paper.dm +++ b/code/modules/paperwork/paper.dm @@ -31,6 +31,7 @@ var/spam_flag = 0 var/contact_poison // Reagent ID to transfer on contact var/contact_poison_volume = 0 + var/datum/oracle_ui/ui = null /obj/item/paper/pickup(user) @@ -40,16 +41,40 @@ if(!istype(G) || G.transfer_prints) H.reagents.add_reagent(contact_poison,contact_poison_volume) contact_poison = null + ui.check_view_all() ..() +/obj/item/paper/dropped(mob/user) + ui.check_view(user) + return ..() + /obj/item/paper/Initialize() . = ..() pixel_y = rand(-8, 8) pixel_x = rand(-9, 9) + ui = new /datum/oracle_ui(src, 420, 600, get_asset_datum(/datum/asset/spritesheet/simple/paper)) + ui.can_resize = FALSE update_icon() updateinfolinks() +/obj/item/paper/oui_getcontent(mob/target) + if(!target.is_literate()) + return "[name][stars(info)]
[stamps]" + else if(istype(target.get_active_held_item(), /obj/item/pen) | istype(target.get_active_held_item(), /obj/item/toy/crayon)) + return "[name][info_links]
[stamps]" + else + return "[name][info]
[stamps]" + +/obj/item/paper/oui_canview(mob/target) + if(check_rights_for(target.client, R_FUN)) //Allows admins to view faxes + return TRUE + if(isAI(target)) + var/mob/living/silicon/ai/ai = target + return get_dist(src, ai.current) < 2 + if(iscyborg(target)) + return get_dist(src, target) < 2 + return ..() /obj/item/paper/update_icon() @@ -65,20 +90,13 @@ /obj/item/paper/examine(mob/user) ..() to_chat(user, "Alt-click to fold it.") - - var/datum/asset/assets = get_asset_datum(/datum/asset/spritesheet/simple/paper) - assets.send(user) - - if(in_range(user, src) || isobserver(user)) - if(user.is_literate()) - user << browse("[name][info]
[stamps]", "window=[name]") - onclose(user, "[name]") - else - user << browse("[name][stars(info)]
[stamps]", "window=[name]") - onclose(user, "[name]") + if(oui_canview(user)) + ui.render(user) else to_chat(user, "You're too far away to read it!") +/obj/item/paper/proc/show_content(mob/user) + user.examinate(src) /obj/item/paper/verb/rename() set name = "Rename paper" @@ -98,7 +116,7 @@ if((loc == usr && usr.stat == CONSCIOUS)) name = "paper[(n_name ? text("- '[n_name]'") : null)]" add_fingerprint(usr) - + ui.render_all() /obj/item/paper/suicide_act(mob/user) user.visible_message("[user] scratches a grid on [user.p_their()] wrist with the paper! It looks like [user.p_theyre()] trying to commit sudoku...") @@ -108,7 +126,7 @@ spam_flag = FALSE /obj/item/paper/attack_self(mob/user) - user.examinate(src) + show_content(user) if(rigged && (SSevents.holidays && SSevents.holidays[APRIL_FOOLS])) if(!spam_flag) spam_flag = TRUE @@ -123,11 +141,9 @@ else //cyborg or AI not seeing through a camera dist = get_dist(src, user) if(dist < 2) - usr << browse("[name][info]
[stamps]", "window=[name]") - onclose(usr, "[name]") + show_content(user) else - usr << browse("[name][stars(info)]
[stamps]", "window=[name]") - onclose(usr, "[name]") + to_chat(user, "You can't quite see it.") /obj/item/paper/proc/addtofield(id, text, links = 0) @@ -173,6 +189,7 @@ for(var/i in 1 to min(fields, 15)) addtofield(i, "write", 1) info_links = info_links + "write" + ui.render_all() /obj/item/paper/proc/clearpaper() @@ -274,7 +291,7 @@ else info += t // Oh, he wants to edit to the end of the file, let him. updateinfolinks() - usr << browse("[name][info_links]
[stamps]", "window=[name]") // Update the window + show_content(usr) update_icon() @@ -289,7 +306,7 @@ if(istype(P, /obj/item/pen) || istype(P, /obj/item/toy/crayon)) if(user.is_literate()) - user << browse("[name][info_links]
[stamps]", "window=[name]") + show_content(user) return else to_chat(user, "You don't know how to read or write.") @@ -312,6 +329,7 @@ add_overlay(stampoverlay) to_chat(user, "You stamp the paper with your rubber stamp.") + ui.render_all() if(P.is_hot()) if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(10)) diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm index a5900aa196..5bcb7a60df 100644 --- a/code/modules/paperwork/pen.dm +++ b/code/modules/paperwork/pen.dm @@ -164,7 +164,7 @@ /obj/item/pen/sleepy/Initialize() . = ..() create_reagents(45, OPENCONTAINER) - reagents.add_reagent("chloralhydratedelayed", 20) + reagents.add_reagent("chloralhydrate", 20) reagents.add_reagent("mutetoxin", 15) reagents.add_reagent("tirizene", 10) diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index 7c377ffa22..5fc29cb813 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -267,7 +267,7 @@ to_chat(user, "There is an integration cog installed!") to_chat(user, "Alt-Click the APC to [ locked ? "unlock" : "lock"] the interface.") - + if(issilicon(user)) to_chat(user, "Ctrl-Click the APC to switch the breaker [ operating ? "off" : "on"].") @@ -747,7 +747,7 @@ if(damage_flag == "melee" && damage_amount < damage_deflection) return 0 . = ..() - + /obj/machinery/power/apc/deconstruct(disassembled = TRUE) if(!(flags_1 & NODECONSTRUCT_1)) if(!(stat & BROKEN)) @@ -759,21 +759,23 @@ update_icon() /obj/machinery/power/apc/emag_act(mob/user) - if(!(obj_flags & EMAGGED) && !malfhack) - if(opened) - to_chat(user, "You must close the cover to swipe an ID card!") - else if(panel_open) - to_chat(user, "You must close the panel first!") - else if(stat & (BROKEN|MAINT)) - to_chat(user, "Nothing happens!") - else - flick("apc-spark", src) - playsound(src, "sparks", 75, 1) - obj_flags |= EMAGGED - locked = FALSE - to_chat(user, "You emag the APC interface.") - update_icon() - + . = ..() + if(obj_flags & EMAGGED || malfhack) + return + if(opened) + to_chat(user, "You must close the cover to swipe an ID card!") + else if(panel_open) + to_chat(user, "You must close the panel first!") + else if(stat & (BROKEN|MAINT)) + to_chat(user, "Nothing happens!") + else + flick("apc-spark", src) + playsound(src, "sparks", 75, 1) + obj_flags |= EMAGGED + locked = FALSE + to_chat(user, "You emag the APC interface.") + update_icon() + return TRUE // attack with hand - remove cell (if cover open) or interact with the APC @@ -800,8 +802,6 @@ if(!ui) ui = new(user, src, ui_key, "apc", name, 535, 515, master_ui, state) ui.open() - if(ui) - ui.set_autoupdate(state = (failure_timer ? 1 : 0)) /obj/machinery/power/apc/ui_data(mob/user) var/list/data = list( diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm index 3e93d9f42b..1759f31344 100644 --- a/code/modules/power/cell.dm +++ b/code/modules/power/cell.dm @@ -191,7 +191,7 @@ /obj/item/stock_parts/cell/secborg name = "security borg rechargeable D battery" - maxcharge = 1750 //35/17/8 disabler/laser/taser shots. + maxcharge = 1250 //25/12/6 disabler/laser/taser shots. materials = list(MAT_GLASS=40) /obj/item/stock_parts/cell/secborg/empty/Initialize() diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm index f82f0ee8e6..8d99cbb485 100644 --- a/code/modules/power/lighting.dm +++ b/code/modules/power/lighting.dm @@ -323,6 +323,8 @@ var/BR = brightness var/PO = bulb_power var/CO = bulb_colour + if(color) + CO = color var/area/A = get_area(src) if (A && A.fire) CO = bulb_emergency_colour @@ -360,6 +362,9 @@ else removeStaticPower(static_power_used, STATIC_LIGHT) +/obj/machinery/light/update_atom_colour() + . = ..() + update() /obj/machinery/light/process() if (!cell) diff --git a/code/modules/power/port_gen.dm b/code/modules/power/port_gen.dm index 7a6e313cd0..7375a3e17a 100644 --- a/code/modules/power/port_gen.dm +++ b/code/modules/power/port_gen.dm @@ -194,10 +194,12 @@ return ..() /obj/machinery/power/port_gen/pacman/emag_act(mob/user) + . = ..() if(obj_flags & EMAGGED) return obj_flags |= EMAGGED emp_act(EMP_HEAVY) + return TRUE /obj/machinery/power/port_gen/pacman/attack_ai(mob/user) interact(user) diff --git a/code/modules/power/singularity/collector.dm b/code/modules/power/singularity/collector.dm index 4159d9898a..974b210648 100644 --- a/code/modules/power/singularity/collector.dm +++ b/code/modules/power/singularity/collector.dm @@ -19,6 +19,7 @@ circuit = /obj/item/circuitboard/machine/rad_collector var/obj/item/tank/internals/plasma/loaded_tank = null var/stored_power = 0 + var/last_push var/active = 0 var/locked = FALSE var/drainratio = 1 @@ -61,9 +62,9 @@ loaded_tank.air_contents.gases[/datum/gas/oxygen] -= gasdrained loaded_tank.air_contents.gases[/datum/gas/carbon_dioxide] += gasdrained*2 GAS_GARBAGE_COLLECT(loaded_tank.air_contents.gases) - var/bitcoins_mined = RAD_COLLECTOR_OUTPUT - SSresearch.science_tech.add_point_type(TECHWEB_POINT_TYPE_DEFAULT, bitcoins_mined*RAD_COLLECTOR_MINING_CONVERSION_RATE) - stored_power-=bitcoins_mined + SSresearch.science_tech.add_point_type(TECHWEB_POINT_TYPE_DEFAULT, stored_power*RAD_COLLECTOR_MINING_CONVERSION_RATE) + last_push = stored_power + stored_power = 0 /obj/machinery/power/rad_collector/interact(mob/user) if(anchored) @@ -170,9 +171,9 @@ . = ..() if(active) if(!bitcoinmining) - to_chat(user, "[src]'s display states that it has stored [DisplayPower(stored_power)], and processing [DisplayPower(RAD_COLLECTOR_OUTPUT)].") + to_chat(user, "[src]'s display states that it has stored [DisplayPower(stored_power)], and is processing [DisplayPower((RAD_COLLECTOR_OUTPUT)*((60 SECONDS)/SSmachines.wait))] per minute.
The plasma within it's tank is being irradiated into tritium.
") else - to_chat(user, "[src]'s display states that it has stored a total of [stored_power*RAD_COLLECTOR_MINING_CONVERSION_RATE], and producing [RAD_COLLECTOR_OUTPUT*RAD_COLLECTOR_MINING_CONVERSION_RATE] research points per minute.") + to_chat(user, "[src]'s display states that it's producing a total of [(last_push*RAD_COLLECTOR_MINING_CONVERSION_RATE)*((60 SECONDS)/SSmachines.wait)] research points per minute.
The tritium and oxygen within it's tank is being combusted into carbon dioxide.
") else if(!bitcoinmining) to_chat(user,"[src]'s display displays the words: \"Power production mode. Please insert Plasma. Use a multitool to change production modes.\"") diff --git a/code/modules/power/singularity/emitter.dm b/code/modules/power/singularity/emitter.dm index d805713fa6..4d6ede69d1 100644 --- a/code/modules/power/singularity/emitter.dm +++ b/code/modules/power/singularity/emitter.dm @@ -339,12 +339,13 @@ projectile_sound = initial(projectile_sound) /obj/machinery/power/emitter/emag_act(mob/user) + . = ..() if(obj_flags & EMAGGED) return locked = FALSE obj_flags |= EMAGGED - if(user) - user.visible_message("[user.name] emags [src].","You short out the lock.") + user?.visible_message("[user.name] emags [src].","You short out the lock.") + return TRUE /obj/machinery/power/emitter/prototype diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm index bc05e784a4..35710f8d61 100644 --- a/code/modules/power/singularity/singularity.dm +++ b/code/modules/power/singularity/singularity.dm @@ -84,16 +84,18 @@ /obj/singularity/attack_tk(mob/user) if(iscarbon(user)) var/mob/living/carbon/C = user + log_game("[key_name(C)] has been disintegrated by attempting to telekenetically grab a singularity.
") C.visible_message("[C]'s head begins to collapse in on itself!", "Your head feels like it's collapsing in on itself! This was really not a good idea!", "You hear something crack and explode in gore.") var/turf/T = get_turf(C) for(var/i in 1 to 3) C.apply_damage(30, BRUTE, BODY_ZONE_HEAD) new /obj/effect/gibspawner/generic(T) sleep(1) - C.ghostize() var/obj/item/bodypart/head/rip_u = C.get_bodypart(BODY_ZONE_HEAD) rip_u.dismember(BURN) //nice try jedi qdel(rip_u) + return + return ..() /obj/singularity/ex_act(severity, target) switch(severity) diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm index 026c39c6cf..8d2162a0ff 100644 --- a/code/modules/power/supermatter/supermatter.dm +++ b/code/modules/power/supermatter/supermatter.dm @@ -5,12 +5,21 @@ #define PLASMA_HEAT_PENALTY 15 // Higher == Bigger heat and waste penalty from having the crystal surrounded by this gas. Negative numbers reduce penalty. #define OXYGEN_HEAT_PENALTY 1 #define CO2_HEAT_PENALTY 0.1 -#define NITROGEN_HEAT_MODIFIER -1.5 +#define PLUOXIUM_HEAT_PENALTY -1 +#define TRITIUM_HEAT_PENALTY 10 +#define NITROGEN_HEAT_PENALTY -1.5 +#define BZ_HEAT_PENALTY 5 #define OXYGEN_TRANSMIT_MODIFIER 1.5 //Higher == Bigger bonus to power generation. #define PLASMA_TRANSMIT_MODIFIER 4 +#define BZ_TRANSMIT_MODIFIER -2 + +#define TRITIUM_RADIOACTIVITY_MODIFIER 3 //Higher == Crystal spews out more radiation +#define BZ_RADIOACTIVITY_MODIFIER 5 +#define PLUOXIUM_RADIOACTIVITY_MODIFIER -2 #define N2O_HEAT_RESISTANCE 6 //Higher == Gas makes the crystal more resistant against heat damage. +#define PLUOXIUM_HEAT_RESISTANCE 3 #define POWERLOSS_INHIBITION_GAS_THRESHOLD 0.20 //Higher == Higher percentage of inhibitor gas needed before the charge inertia chain reaction effect starts. #define POWERLOSS_INHIBITION_MOLE_THRESHOLD 20 //Higher == More moles of the gas are needed before the charge inertia chain reaction effect starts. //Scales powerloss inhibition down until this amount of moles is reached @@ -53,6 +62,7 @@ #define SUPERMATTER_EMERGENCY_PERCENT 25 #define SUPERMATTER_DANGER_PERCENT 50 #define SUPERMATTER_WARNING_PERCENT 100 +#define CRITICAL_TEMPERATURE 10000 #define SUPERMATTER_COUNTDOWN_TIME 30 SECONDS @@ -102,6 +112,11 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) var/o2comp = 0 var/co2comp = 0 var/n2ocomp = 0 + var/pluoxiumcomp = 0 + var/tritiumcomp = 0 + var/bzcomp = 0 + + var/pluoxiumbonus = 0 var/combined_gas = 0 var/gasmix_power_ratio = 0 @@ -184,8 +199,6 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) to_chat(H, "You get headaches just from looking at it.") return -#define CRITICAL_TEMPERATURE 10000 - /obj/machinery/power/supermatter_crystal/proc/get_status() var/turf/T = get_turf(src) if(!T) @@ -316,6 +329,12 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) if(power) soundloop.volume = min(40, (round(power/100)/50)+1) // 5 +1 volume per 20 power. 2500 power is max + if(isclosedturf(T)) + var/turf/did_it_melt = T.Melt() + if(!isclosedturf(did_it_melt)) //In case some joker finds way to place these on indestructible walls + visible_message("[src] melts through [T]!") + return + //Ok, get the air from the turf var/datum/gas_mixture/env = T.return_air() @@ -354,16 +373,24 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) plasmacomp = max(removed.gases[/datum/gas/plasma]/combined_gas, 0) o2comp = max(removed.gases[/datum/gas/oxygen]/combined_gas, 0) co2comp = max(removed.gases[/datum/gas/carbon_dioxide]/combined_gas, 0) + pluoxiumcomp = max(removed.gases[/datum/gas/pluoxium]/combined_gas, 0) + tritiumcomp = max(removed.gases[/datum/gas/tritium]/combined_gas, 0) + bzcomp = max(removed.gases[/datum/gas/bz]/combined_gas, 0) n2ocomp = max(removed.gases[/datum/gas/nitrous_oxide]/combined_gas, 0) n2comp = max(removed.gases[/datum/gas/nitrogen]/combined_gas, 0) - gasmix_power_ratio = min(max(plasmacomp + o2comp + co2comp - n2comp, 0), 1) + if(pluoxiumcomp >= 0.15) + pluoxiumbonus = 1 //makes pluoxium only work at 15%+ + else + pluoxiumbonus = 0 - dynamic_heat_modifier = max((plasmacomp * PLASMA_HEAT_PENALTY)+(o2comp * OXYGEN_HEAT_PENALTY)+(co2comp * CO2_HEAT_PENALTY)+(n2comp * NITROGEN_HEAT_MODIFIER), 0.5) - dynamic_heat_resistance = max(n2ocomp * N2O_HEAT_RESISTANCE, 1) + gasmix_power_ratio = min(max(plasmacomp + o2comp + co2comp + tritiumcomp + bzcomp - pluoxiumcomp - n2comp, 0), 1) - power_transmission_bonus = max((plasmacomp * PLASMA_TRANSMIT_MODIFIER) + (o2comp * OXYGEN_TRANSMIT_MODIFIER), 0) + dynamic_heat_modifier = max((plasmacomp * PLASMA_HEAT_PENALTY) + (o2comp * OXYGEN_HEAT_PENALTY) + (co2comp * CO2_HEAT_PENALTY) + (tritiumcomp * TRITIUM_HEAT_PENALTY) + ((pluoxiumcomp * PLUOXIUM_HEAT_PENALTY) * pluoxiumbonus) + (n2comp * NITROGEN_HEAT_PENALTY) + (bzcomp * BZ_HEAT_PENALTY), 0.5) + dynamic_heat_resistance = max((n2ocomp * N2O_HEAT_RESISTANCE) + ((pluoxiumcomp * PLUOXIUM_HEAT_RESISTANCE) * pluoxiumbonus), 1) + + power_transmission_bonus = max((plasmacomp * PLASMA_TRANSMIT_MODIFIER) + (o2comp * OXYGEN_TRANSMIT_MODIFIER) + (bzcomp * BZ_TRANSMIT_MODIFIER), 0) //more moles of gases are harder to heat than fewer, so let's scale heat damage around them mole_heat_penalty = max(combined_gas / MOLE_HEAT_PENALTY, 0.25) @@ -392,7 +419,9 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) power = max( (removed.temperature * temp_factor / T0C) * gasmix_power_ratio + power, 0) //Total laser power plus an overload if(prob(50)) - radiation_pulse(src, power * (1 + power_transmission_bonus/10)) + radiation_pulse(src, power * (1 + (tritiumcomp * TRITIUM_RADIOACTIVITY_MODIFIER) + ((pluoxiumcomp * PLUOXIUM_RADIOACTIVITY_MODIFIER) * pluoxiumbonus) * (power_transmission_bonus/(10-(bzcomp * BZ_RADIOACTIVITY_MODIFIER))))) // Rad Modifiers BZ(500%), Tritium(300%), and Pluoxium(-200%) + if(bzcomp >= 0.4 && prob(30 * bzcomp)) + fire_nuclear_particle() // Start to emit radballs at a maximum of 30% chance per tick var/device_energy = power * REACTION_POWER_MODIFIER @@ -527,11 +556,14 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) /obj/machinery/power/supermatter_crystal/attack_tk(mob/user) if(iscarbon(user)) var/mob/living/carbon/C = user + log_game("[key_name(C)] has been disintegrated by a telekenetic grab on a supermatter crystal.
") to_chat(C, "That was a really dense idea.") - C.ghostize() + C.visible_message("A bright flare of radiation is seen from [C]'s head, shortly before you hear a sickening sizzling!") var/obj/item/organ/brain/rip_u = locate(/obj/item/organ/brain) in C.internal_organs rip_u.Remove(C) qdel(rip_u) + return + return ..() /obj/machinery/power/supermatter_crystal/attack_paw(mob/user) dust_mob(user, cause = "monkey attack") diff --git a/code/modules/power/tesla/energy_ball.dm b/code/modules/power/tesla/energy_ball.dm index bbad3e08b0..9a5486dfe2 100644 --- a/code/modules/power/tesla/energy_ball.dm +++ b/code/modules/power/tesla/energy_ball.dm @@ -132,11 +132,14 @@ /obj/singularity/energy_ball/attack_tk(mob/user) if(iscarbon(user)) var/mob/living/carbon/C = user + log_game("[key_name(C)] has been disintegrated by a telekenetic grab on a tesla ball.
") to_chat(C, "That was a shockingly dumb idea.") + C.visible_message("A bright flare of lightning is seen from [C]'s head, shortly before you hear a sickening sizzling!") var/obj/item/organ/brain/rip_u = locate(/obj/item/organ/brain) in C.internal_organs - C.ghostize(0) + rip_u.Remove(C) qdel(rip_u) - C.death() + return + return ..() /obj/singularity/energy_ball/orbit(obj/singularity/energy_ball/target) if (istype(target)) diff --git a/code/modules/projectiles/ammunition/energy/laser.dm b/code/modules/projectiles/ammunition/energy/laser.dm index 089c79effd..0940144721 100644 --- a/code/modules/projectiles/ammunition/energy/laser.dm +++ b/code/modules/projectiles/ammunition/energy/laser.dm @@ -59,6 +59,9 @@ /obj/item/ammo_casing/energy/laser/redtag/hitscan projectile_type = /obj/item/projectile/beam/lasertag/redtag/hitscan +/obj/item/ammo_casing/energy/laser/redtag/hitscan/holy + projectile_type = /obj/item/projectile/beam/lasertag/redtag/hitscan/holy + /obj/item/ammo_casing/energy/xray projectile_type = /obj/item/projectile/beam/xray e_cost = 50 diff --git a/code/modules/projectiles/ammunition/energy/stun.dm b/code/modules/projectiles/ammunition/energy/stun.dm index c9e60ddc1d..36d6e16496 100644 --- a/code/modules/projectiles/ammunition/energy/stun.dm +++ b/code/modules/projectiles/ammunition/energy/stun.dm @@ -25,3 +25,6 @@ fire_sound = 'sound/weapons/taser2.ogg' harmful = FALSE click_cooldown_override = 3.5 + +/obj/item/ammo_casing/energy/disabler/secborg + e_cost = 50 \ No newline at end of file diff --git a/code/modules/projectiles/guns/ballistic/launchers.dm b/code/modules/projectiles/guns/ballistic/launchers.dm index f6356dce99..12006440d2 100644 --- a/code/modules/projectiles/guns/ballistic/launchers.dm +++ b/code/modules/projectiles/guns/ballistic/launchers.dm @@ -127,15 +127,14 @@ /obj/item/gun/ballistic/rocketlauncher/attackby(obj/item/A, mob/user, params) if(magazine && istype(A, /obj/item/ammo_casing)) - if(user.temporarilyRemoveItemFromInventory(A)) - if(!chambered) - to_chat(user, "You load a new [A] into \the [src].") - playsound(src, "gun_insert_full_magazine", 70, 1) - chamber_round() - update_icon() - return TRUE - else - to_chat(user, "You cannot seem to get \the [A] out of your hands!") + if(chambered) + to_chat(user, "[src] already has a [magazine_wording] chambered.") + return + if(magazine.attackby(A, user, silent = TRUE)) + to_chat(user, "You load a new [A] into \the [src].") + playsound(src, "gun_insert_full_magazine", 70, 1) + chamber_round() + update_icon() /obj/item/gun/ballistic/rocketlauncher/update_icon() icon_state = "[initial(icon_state)]-[chambered ? "1" : "0"]" diff --git a/code/modules/projectiles/guns/ballistic/revolver.dm b/code/modules/projectiles/guns/ballistic/revolver.dm index f455e0f138..a5fb8a85aa 100644 --- a/code/modules/projectiles/guns/ballistic/revolver.dm +++ b/code/modules/projectiles/guns/ballistic/revolver.dm @@ -277,12 +277,12 @@ ..() if(istype(A, /obj/item/ammo_box) || istype(A, /obj/item/ammo_casing)) chamber_round() + if(A.tool_behaviour == TOOL_SAW || istype(A, /obj/item/gun/energy/plasmacutter)) + sawoff(user) if(istype(A, /obj/item/melee/transforming/energy)) var/obj/item/melee/transforming/energy/W = A if(W.active) sawoff(user) - if(istype(A, /obj/item/circular_saw) || istype(A, /obj/item/gun/energy/plasmacutter)) - sawoff(user) /obj/item/gun/ballistic/revolver/doublebarrel/attack_self(mob/living/user) var/num_unloaded = 0 diff --git a/code/modules/projectiles/guns/ballistic/shotgun.dm b/code/modules/projectiles/guns/ballistic/shotgun.dm index 856dfed78b..47ccb6076f 100644 --- a/code/modules/projectiles/guns/ballistic/shotgun.dm +++ b/code/modules/projectiles/guns/ballistic/shotgun.dm @@ -40,7 +40,7 @@ if(istype(user) && user.getStaminaLoss() >= STAMINA_SOFTCRIT)//CIT CHANGE - makes pumping shotguns impossible in stamina softcrit to_chat(user, "You're too exhausted for that.")//CIT CHANGE - ditto return//CIT CHANGE - ditto - pump(user) + pump(user, TRUE) recentpump = world.time + 10 if(istype(user))//CIT CHANGE - makes pumping shotguns cost a lil bit of stamina. user.adjustStaminaLossBuffered(2) //CIT CHANGE - DITTO. make this scale inversely to the strength stat when stats/skills are added @@ -52,7 +52,9 @@ process_fire(user, user, FALSE) . = 1 -/obj/item/gun/ballistic/shotgun/proc/pump(mob/M) +/obj/item/gun/ballistic/shotgun/proc/pump(mob/M, visible = TRUE) + if(visible) + M.visible_message("[M] racks [src].", "You rack [src].") playsound(M, 'sound/weapons/shotgunpump.ogg', 60, 1) pump_unload(M) pump_reload(M) @@ -93,7 +95,7 @@ /obj/item/gun/ballistic/shotgun/riot/attackby(obj/item/A, mob/user, params) ..() - if(istype(A, /obj/item/circular_saw) || istype(A, /obj/item/gun/energy/plasmacutter)) + if(A.tool_behaviour == TOOL_SAW || istype(A, /obj/item/gun/energy/plasmacutter)) sawoff(user) if(istype(A, /obj/item/melee/transforming/energy)) var/obj/item/melee/transforming/energy/W = A @@ -205,6 +207,7 @@ name = "combat shotgun" desc = "A semi automatic shotgun with tactical furniture and a six-shell capacity underneath." icon_state = "cshotgun" + fire_delay = 3 mag_type = /obj/item/ammo_box/magazine/internal/shot/com w_class = WEIGHT_CLASS_HUGE unique_reskin = list("Tatical" = "cshotgun", diff --git a/code/modules/projectiles/guns/energy/energy_gun.dm b/code/modules/projectiles/guns/energy/energy_gun.dm index 54cb9fe5d0..de738c9047 100644 --- a/code/modules/projectiles/guns/energy/energy_gun.dm +++ b/code/modules/projectiles/guns/energy/energy_gun.dm @@ -118,11 +118,11 @@ switch(fail_tick) if(0 to 200) fail_tick += (2*(fail_chance)) - M.rad_act(40) + M.rad_act(400) to_chat(M, "Your [name] feels warmer.") if(201 to INFINITY) SSobj.processing.Remove(src) - M.rad_act(80) + M.rad_act(800) crit_fail = 1 to_chat(M, "Your [name]'s reactor overloads!") diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm index cd0dd53d48..bb97f9cf99 100644 --- a/code/modules/projectiles/guns/energy/laser.dm +++ b/code/modules/projectiles/guns/energy/laser.dm @@ -159,3 +159,65 @@ /obj/item/gun/energy/laser/redtag/hitscan ammo_type = list(/obj/item/ammo_casing/energy/laser/redtag/hitscan) + +/obj/item/gun/energy/laser/redtag/hitscan/chaplain + name = "\improper holy lasrifle" + desc = "A lasrifle from the old Imperium. This one seems to be blessed by techpriests." + icon_state = "LaserAK" + item_state = null + force = 14 + pin = /obj/item/firing_pin/holy + icon = 'modular_citadel/icons/obj/guns/VGguns.dmi' + ammo_x_offset = 4 + ammo_type = list(/obj/item/ammo_casing/energy/laser/redtag/hitscan/holy) + lefthand_file = 'modular_citadel/icons/mob/citadel/guns_lefthand.dmi' + righthand_file = 'modular_citadel/icons/mob/citadel/guns_righthand.dmi' + var/chaplain_spawnable = TRUE + total_mass = TOTAL_MASS_MEDIEVAL_WEAPON + throw_speed = 3 + throw_range = 4 + throwforce = 10 + obj_flags = UNIQUE_RENAME + +/obj/item/gun/energy/laser/redtag/hitscan/chaplain/Initialize() + . = ..() + AddComponent(/datum/component/anti_magic, TRUE, TRUE) + +/obj/item/gun/energy/laser/redtag/hitscan/chaplain/handle_suicide(mob/living/carbon/human/user, mob/living/carbon/human/target, params, bypass_timer) + if(!ishuman(user) || !ishuman(target)) + return + + if(semicd) + return + + if(user == target) + target.visible_message("[user] sticks [src] in [user.p_their()] mouth, ready to pull the trigger...", \ + "You stick [src] in your mouth, ready to pull the trigger...") + else + target.visible_message("[user] points [src] at [target]'s head, ready to pull the trigger...", \ + "[user] points [src] at your head, ready to pull the trigger...") + + semicd = TRUE + + if(!bypass_timer && (!do_mob(user, target, 120) || user.zone_selected != BODY_ZONE_PRECISE_MOUTH)) + if(user) + if(user == target) + user.visible_message("[user] decided not to shoot.") + else if(target && target.Adjacent(user)) + target.visible_message("[user] has decided to spare [target]", "[user] has decided to spare your life!") + semicd = FALSE + return + + semicd = FALSE + + target.visible_message("[user] pulls the trigger!", "[user] pulls the trigger!") + + playsound('sound/weapons/dink.ogg', 30, 1) + + if((iscultist(target)) || (is_servant_of_ratvar(target))) + chambered.BB.damage *= 1500 + + else if(chambered && chambered.BB) + chambered.BB.damage *= 5 + + process_fire(target, user, TRUE, params) diff --git a/code/modules/projectiles/guns/energy/stun.dm b/code/modules/projectiles/guns/energy/stun.dm index 3733dad9a3..c5d4c36813 100644 --- a/code/modules/projectiles/guns/energy/stun.dm +++ b/code/modules/projectiles/guns/energy/stun.dm @@ -20,7 +20,7 @@ name = "hybrid taser" desc = "A dual-mode taser designed to fire both short-range high-power electrodes and long-range disabler beams." icon_state = "advtaser" - ammo_type = list(/obj/item/ammo_casing/energy/electrode, /obj/item/ammo_casing/energy/disabler) + ammo_type = list(/obj/item/ammo_casing/energy/disabler, /obj/item/ammo_casing/energy/electrode) ammo_x_offset = 2 /obj/item/gun/energy/e_gun/advtaser/cyborg @@ -49,6 +49,7 @@ name = "cyborg disabler" desc = "An integrated disabler that draws from a cyborg's power cell. This one contains a limiter to prevent the cyborg's power cell from overheating." can_charge = FALSE + ammo_type = list(/obj/item/ammo_casing/energy/disabler/secborg) selfcharge = EGUN_SELFCHARGE_BORG cell_type = /obj/item/stock_parts/cell/secborg charge_delay = 5 diff --git a/code/modules/projectiles/guns/misc/syringe_gun.dm b/code/modules/projectiles/guns/misc/syringe_gun.dm index 26e66b1987..342ceecbc2 100644 --- a/code/modules/projectiles/guns/misc/syringe_gun.dm +++ b/code/modules/projectiles/guns/misc/syringe_gun.dm @@ -122,3 +122,32 @@ else to_chat(user, "You can't put the [A] into \the [src]!") return FALSE + +/obj/item/gun/syringe/dart/rapiddart + name = "Repeating dart gun" + icon_state = "rapiddartgun" + item_state = "rapiddartgun" + +/obj/item/gun/syringe/dart/rapiddart/CheckParts(list/parts_list) + var/obj/item/reagent_containers/glass/beaker/B = locate(/obj/item/reagent_containers/glass/beaker) in parts_list + + if(istype(B, /obj/item/reagent_containers/glass/beaker/large)) + desc = "[initial(desc)] A modification of the dart gun's pressure chamber has been perfomed using a [B], extending it's holding size to [max_syringes]." + max_syringes = 2 + return + else if(istype(B, /obj/item/reagent_containers/glass/beaker/plastic)) + desc = "[initial(desc)] A modification of the dart gun's pressure chamber has been perfomed using a [B], extending it's holding size to [max_syringes]." + max_syringes = 3 + return + else if(istype(B, /obj/item/reagent_containers/glass/beaker/meta)) + desc = "[initial(desc)] A modification of the dart gun's pressure chamber has been perfomed using a [B], extending it's holding size to [max_syringes]." + max_syringes = 4 + return + else if(istype(B, /obj/item/reagent_containers/glass/beaker/bluespace)) + desc = "[initial(desc)] A modification of the dart gun's pressure chamber has been perfomed using a [B], extending it's holding size to [max_syringes]." + max_syringes = 6 + return + else + max_syringes = 1 + desc = "[initial(desc)] It has a [B] strapped to it, but it doesn't seem to be doing anything." + ..() diff --git a/code/modules/projectiles/pins.dm b/code/modules/projectiles/pins.dm index 05d6367306..9103340790 100644 --- a/code/modules/projectiles/pins.dm +++ b/code/modules/projectiles/pins.dm @@ -37,10 +37,12 @@ to_chat(user, "This firearm already has a firing pin installed.") /obj/item/firing_pin/emag_act(mob/user) + . = ..() if(obj_flags & EMAGGED) return obj_flags |= EMAGGED to_chat(user, "You override the authentication mechanism.") + return TRUE /obj/item/firing_pin/proc/gun_insert(mob/living/user, obj/item/gun/G) gun = G @@ -186,6 +188,15 @@ desc = "This is a DNA-locked firing pin which only authorizes one user. Attempt to fire once to DNA-link. It has a small explosive charge on it." selfdestruct = TRUE +/obj/item/firing_pin/holy + name = "blessed pin" + desc = "A firing pin that only responds to those who are holier than thou." + +/obj/item/firing_pin/holy/pin_auth(mob/living/user) + if(user.mind.isholy) + return TRUE + return FALSE + // Laser tag pins /obj/item/firing_pin/tag name = "laser tag firing pin" diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index efae090707..dace31c2f7 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -88,6 +88,8 @@ //Effects var/stun = 0 var/knockdown = 0 + var/knockdown_stamoverride + var/knockdown_stam_max var/unconscious = 0 var/irradiate = 0 var/stutter = 0 @@ -202,7 +204,7 @@ else L.log_message("has been shot by [firer] with [src]", LOG_ATTACK, color="orange") - return L.apply_effects(stun, knockdown, unconscious, irradiate, slur, stutter, eyeblur, drowsy, blocked, stamina, jitter) + return L.apply_effects(stun, knockdown, unconscious, irradiate, slur, stutter, eyeblur, drowsy, blocked, stamina, jitter, knockdown_stamoverride, knockdown_stam_max) /obj/item/projectile/proc/vol_by_damage() if(src.damage) diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm index cbd0348743..e43eb5a3bc 100644 --- a/code/modules/projectiles/projectile/beams.dm +++ b/code/modules/projectiles/projectile/beams.dm @@ -151,6 +151,11 @@ /obj/item/projectile/beam/lasertag/redtag/hitscan hitscan = TRUE +/obj/item/projectile/beam/lasertag/redtag/hitscan/holy + name = "lasrifle beam" + damage = 0.1 + damage_type = BURN + /obj/item/projectile/beam/lasertag/bluetag icon_state = "bluelaser" suit_types = list(/obj/item/clothing/suit/redtag) diff --git a/code/modules/projectiles/projectile/bullets/shotgun.dm b/code/modules/projectiles/projectile/bullets/shotgun.dm index f9aa47c6a3..4a1c954b1b 100644 --- a/code/modules/projectiles/projectile/bullets/shotgun.dm +++ b/code/modules/projectiles/projectile/bullets/shotgun.dm @@ -5,7 +5,7 @@ /obj/item/projectile/bullet/shotgun_beanbag name = "beanbag slug" damage = 5 - stamina = 80 + stamina = 70 /obj/item/projectile/bullet/incendiary/shotgun name = "incendiary slug" @@ -61,12 +61,12 @@ /obj/item/projectile/bullet/pellet/shotgun_buckshot name = "buckshot pellet" - damage = 12.5 + damage = 10 /obj/item/projectile/bullet/pellet/shotgun_rubbershot name = "rubbershot pellet" - damage = 3 - stamina = 25 + damage = 2 + stamina = 15 /obj/item/projectile/bullet/pellet/Range() ..() diff --git a/code/modules/projectiles/projectile/energy/nuclear_particle.dm b/code/modules/projectiles/projectile/energy/nuclear_particle.dm index 1753587ad3..e08f806fe5 100644 --- a/code/modules/projectiles/projectile/energy/nuclear_particle.dm +++ b/code/modules/projectiles/projectile/energy/nuclear_particle.dm @@ -3,10 +3,9 @@ name = "nuclear particle" icon_state = "nuclear_particle" pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE - damage = 20 - damage_type = TOX - irradiate = 2500 //enough to knockdown and induce vomiting - speed = 0.4 + flag = "rad" + irradiate = 5000 + speed = 0.4 hitsound = 'sound/weapons/emitter2.ogg' impact_type = /obj/effect/projectile/impact/xray var/static/list/particle_colors = list( @@ -25,22 +24,6 @@ add_atom_colour(particle_colors[our_color], FIXED_COLOUR_PRIORITY) set_light(4, 3, particle_colors[our_color]) //Range of 4, brightness of 3 - Same range as a flashlight -/atom/proc/fire_nuclear_particles(power_ratio) //used by fusion to fire random # of nuclear particles - power ratio determines about how many are fired - var/random_particles = rand(3,6) - var/particles_to_fire - var/particles_fired - switch(power_ratio) //multiply random_particles * factor for whatever tier - if(0 to FUSION_MID_TIER_THRESHOLD) - particles_to_fire = random_particles * FUSION_PARTICLE_FACTOR_LOW - if(FUSION_MID_TIER_THRESHOLD to FUSION_HIGH_TIER_THRESHOLD) - particles_to_fire = random_particles * FUSION_PARTICLE_FACTOR_MID - if(FUSION_HIGH_TIER_THRESHOLD to FUSION_SUPER_TIER_THRESHOLD) - particles_to_fire = random_particles * FUSION_PARTICLE_FACTOR_HIGH - if(FUSION_SUPER_TIER_THRESHOLD to INFINITY) - particles_to_fire = random_particles * FUSION_PARTICLE_FACTOR_SUPER - while(particles_to_fire) - particles_fired++ - var/angle = rand(0,360) - var/obj/item/projectile/energy/nuclear_particle/P = new /obj/item/projectile/energy/nuclear_particle(src) - addtimer(CALLBACK(P, /obj/item/projectile.proc/fire, angle), particles_fired) //multiply particles fired * delay so the particles end up stagnated (once every decisecond) - particles_to_fire-- \ No newline at end of file +/atom/proc/fire_nuclear_particle(angle = rand(0,360)) //used by fusion to fire random nuclear particles. Fires one particle in a random direction. + var/obj/item/projectile/energy/nuclear_particle/P = new /obj/item/projectile/energy/nuclear_particle(src) + P.fire(angle) diff --git a/code/modules/projectiles/projectile/energy/stun.dm b/code/modules/projectiles/projectile/energy/stun.dm index 895a165f49..d7c8b8b082 100644 --- a/code/modules/projectiles/projectile/energy/stun.dm +++ b/code/modules/projectiles/projectile/energy/stun.dm @@ -3,7 +3,9 @@ icon_state = "spark" color = "#FFFF00" nodamage = 1 - knockdown = 100 + knockdown = 60 + knockdown_stamoverride = 36 + knockdown_stam_max = 50 stutter = 5 jitter = 20 hitsound = 'sound/weapons/taserhit.ogg' @@ -11,6 +13,7 @@ tracer_type = /obj/effect/projectile/tracer/stun muzzle_type = /obj/effect/projectile/muzzle/stun impact_type = /obj/effect/projectile/impact/stun + var/tase_duration = 50 /obj/item/projectile/energy/electrode/on_hit(atom/target, blocked = FALSE) . = ..() @@ -23,6 +26,7 @@ if(C.dna && C.dna.check_mutation(HULK)) C.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" ), forced = "hulk") else if((C.status_flags & CANKNOCKDOWN) && !HAS_TRAIT(C, TRAIT_STUNIMMUNE)) + C.apply_status_effect(STATUS_EFFECT_TASED, tase_duration) addtimer(CALLBACK(C, /mob/living/carbon.proc/do_jitter_animation, jitter), 5) /obj/item/projectile/energy/electrode/on_range() //to ensure the bolt sparks when it reaches the end of its range if it didn't hit a target yet diff --git a/code/modules/projectiles/projectile/special/mindflayer.dm b/code/modules/projectiles/projectile/special/mindflayer.dm index d717bed39e..ac4488cae0 100644 --- a/code/modules/projectiles/projectile/special/mindflayer.dm +++ b/code/modules/projectiles/projectile/special/mindflayer.dm @@ -5,5 +5,5 @@ . = ..() if(ishuman(target)) var/mob/living/carbon/human/M = target - M.adjustBrainLoss(20) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 20) M.hallucination += 30 diff --git a/code/modules/reagents/chem_wiki_render.dm b/code/modules/reagents/chem_wiki_render.dm new file mode 100644 index 0000000000..efb6bdecfd --- /dev/null +++ b/code/modules/reagents/chem_wiki_render.dm @@ -0,0 +1,387 @@ +//Generates a markdown txt file for use with the wiki + +/proc/find_reagent(input) + . = FALSE + if(GLOB.chemical_reagents_list[input]) //prefer IDs! + var/datum/reagent/R = GLOB.chemical_reagents_list[input] + return R + else + for(var/X in GLOB.chemical_reagents_list) + var/datum/reagent/R = GLOB.chemical_reagents_list[X] + if(input == replacetext(lowertext(R.name), " ", "")) + return R + if(input == replacetext(lowertext(R.id), " ", "")) + return R + + + + +/client/proc/generate_wikichem_list() + set name = "Generate Wikichems" + set category = "Debug" + set desc = "Generate a huge loglist of all the chems. Do not click unless you want lag." + + + + var/prefix = "|Name | Reagents | Reaction vars | Description | Chem properties |\n|---|---|---|-----------|---|\n" + var/input_reagent = replacetext(lowertext(input("Input the name/id of a reagent to get it's description on it's own, or leave blank to parse every chem.", "Input") as text), " ", "") //95% of the time, the reagent id is a lowercase/no spaces version of the name + if(input_reagent) + var/input_reagent2 = find_reagent(input_reagent) + if(!input_reagent2) + to_chat(usr, "Unable to find reagent, stopping proc.") + var/single_parse = generate_chemwiki_line(input_reagent2, input_reagent, FALSE) + text2file(single_parse, "[GLOB.log_directory]/chem_parse.md") + to_chat(usr, "[single_parse].") + + single_parse = generate_chemwiki_line(input_reagent2, input_reagent, FALSE) + text2file(single_parse, "[GLOB.log_directory]/chem_parse.md") + to_chat(usr, "[single_parse].") + to_chat(usr, "Saved line to (wherever your root folder is, i.e. where the DME is)/[GLOB.log_directory]/chem_parse.md OR use the Get Current Logs verb under the Admin tab. (if you click Open, and it does nothing, that's because you've not set a .md default program! Try downloading it instead, and use that file to set a default program! Also have a cute day.)") + //Do things here + return + to_chat(usr, "Generating big list") + message_admins("Someone pressed the lag button. (Generate Wikichems)") + ///datum/reagent/medicine, /datum/reagent/toxin, /datum/reagent/consumable, /datum/reagent/plantnutriment, /datum/reagent/uranium, + ///datum/reagent/colorful_reagent, /datum/reagent/mutationtoxin, /datum/reagent/fermi, /datum/reagent/drug, /datum/reagent/impure + + //Probably not the most eligant of solutions. + to_chat(usr, "Attempting reagent scan. Length of list [LAZYLEN(GLOB.chemical_reagents_list)*2]") + var/datum/reagent/R + var/tally = 0 + var/processCR = TRUE //Process reactions first + var/medicine = "" + var/toxin = "" + var/consumable = "" + var/plant = "" + var/uranium = "" + var/colours = "" + var/muta = "" + var/fermi = "" + var/remainder = "" + var/drug = "" + var/basic = "" + var/upgraded = "" + var/drinks = "" + var/alco = "" + var/grinded = "" + var/blob = "" + var/impure = "" + + //Chem_dispencer + var/list/dispensable_reagents = list( + "hydrogen", + "lithium", + "carbon", + "nitrogen", + "oxygen", + "fluorine", + "sodium", + "aluminium", + "silicon", + "phosphorus", + "sulfur", + "chlorine", + "potassium", + "iron", + "copper", + "mercury", + "radium", + "water", + "ethanol", + "sugar", + "sacid", + "welding_fuel", + "silver", + "iodine", + "bromine", + "stable_plasma" + ) + var/list/components = list( + "oil", + "ammonia", + "ash", + "acetone", + "phenol", + "diethylamine", + "saltpetre", + "sodiumchloride", + "lye" + ) + + var/list/grind = list( + "bluespace", + "gold", + "plasma", + "uranium" + ) + + //Bartender + var/dispence_drinks = list( + "water", + "ice", + "coffee", + "cream", + "tea", + "icetea", + "cola", + "spacemountainwind", + "dr_gibb", + "space_up", + "tonic", + "sodawater", + "lemon_lime", + "pwr_game", + "shamblers", + "sugar", + "orangejuice", + "grenadine", + "limejuice", + "tomatojuice", + "lemonjuice", + "menthol" + ) + var/dispence_alco = list( + "beer", + "kahlua", + "whiskey", + "wine", + "vodka", + "gin", + "rum", + "tequila", + "vermouth", + "cognac", + "ale", + "absinthe", + "hcider", + "creme_de_menthe", + "creme_de_cacao", + "triple_sec", + "sake", + "applejack" + ) + + var/breakout = FALSE + for(var/i = 1, i <= 2, i+=1) + for(var/X in GLOB.chemical_reagents_list) + R = GLOB.chemical_reagents_list[X] + if(!R.description) //No description? It's not worth my time. + continue + + for(var/Y in dispensable_reagents) //Why do you have to do this + if(R.id == Y) + basic += generate_chemwiki_line(R, X, processCR) + breakout = TRUE + continue + + for(var/Y in components) + if(R.id == Y) + upgraded += generate_chemwiki_line(R, X, processCR) + breakout = TRUE + continue + + for(var/Y in dispence_drinks) + if(R.id == Y) + drinks += generate_chemwiki_line(R, X, processCR) + breakout = TRUE + continue + + for(var/Y in dispence_alco) + if(R.id == Y) + alco += generate_chemwiki_line(R, X, processCR) + breakout = TRUE + continue + + for(var/Y in grind) + if(R.id == Y) + grinded += generate_chemwiki_line(R, X, processCR) + breakout = TRUE + continue + + if(breakout) + breakout = FALSE + continue + + if(istype(R, /datum/reagent/medicine)) + medicine += generate_chemwiki_line(R, X, processCR) + + else if(istype(R, /datum/reagent/toxin)) + toxin += generate_chemwiki_line(R, X, processCR) + + else if(istype(R, /datum/reagent/consumable)) + consumable += generate_chemwiki_line(R, X, processCR) + + else if(istype(R, /datum/reagent/plantnutriment)) + plant += generate_chemwiki_line(R, X, processCR) + + else if(istype(R, /datum/reagent/uranium)) + uranium += generate_chemwiki_line(R, X, processCR) + + else if(istype(R, /datum/reagent/colorful_reagent)) + colours += generate_chemwiki_line(R, X, processCR) + + else if(istype(R, /datum/reagent/mutationtoxin)) + muta += generate_chemwiki_line(R, X, processCR) + + else if(istype(R, /datum/reagent/fermi)) + fermi += generate_chemwiki_line(R, X, processCR) + + else if(istype(R, /datum/reagent/drug)) + drug += generate_chemwiki_line(R, X, processCR) + + else if(istype(R, /datum/reagent/blob)) + blob += generate_chemwiki_line(R, X, processCR) + + else if(istype(R, /datum/reagent/impure)) + impure += generate_chemwiki_line(R, X, processCR) + + else + remainder += generate_chemwiki_line(R, X, processCR) + + tally++ + if((tally%50)==0) + to_chat(usr, "[tally] of [LAZYLEN(GLOB.chemical_reagents_list)*2] done.") + + processCR = FALSE + + to_chat(usr, "finished chems") + + var/wholeString = ("\n# DISPENCEABLE REAGENTS\n\n[prefix][basic]\n\n# COMPONENT REAGENTS\n\n[prefix][upgraded]\n\n# GROUND REAGENTS\n\n[prefix][grinded]\n") + wholeString += ("\n# MEDICINE:\n\n[prefix][medicine]\n\n# TOXIN:\n\n[prefix][toxin]\n\n# DRUGS\n\n[prefix][drug]\n\n# FERMI\n\nThese chems lie on the cutting edge of chemical technology, and as such are not recommended for beginners!\n\n[prefix][fermi]\n\n# IMPURE REAGENTS\n\n[prefix][impure]\n\n# GENERAL REAGENTS\n\n[prefix][remainder]\n\n# DISPENCEABLE SOFT DRINKS\n\n[prefix][drinks]\n\n# DISPENCEABLE HARD DRINKS\n\n[prefix][alco]\n\n# CONSUMABLE\n\n[prefix][consumable]\n\n# PLANTS\n\n[prefix][plant]\n\n# URANIUM\n\n[prefix][uranium]\n\n# COLOURS\n\n[prefix][colours]\n\n# RACE MUTATIONS\n\n[prefix][muta]\n\n\n# BLOB REAGENTS\n\n[prefix][blob]\n") + + prefix = "|Name | Reagents | Reaction vars | Description |\n|---|---|---|----------|\n" + var/CRparse = "" + to_chat(usr, "starting reactions") + + //generate the reactions that we missed from before + for(var/reagent in GLOB.chemical_reactions_list) + for(var/datum/chemical_reaction/CR in GLOB.chemical_reactions_list[reagent]) + CRparse += generate_chemreactwiki_line(CR) + + wholeString += ("\n# CHEMICAL REACTIONS\n\n[prefix][CRparse]\n") + text2file(wholeString, "[GLOB.log_directory]/chem_parse.md") + to_chat(usr, "finished reactions") + to_chat(usr, "Saved file to (wherever your root folder is, i.e. where the DME is)/[GLOB.log_directory]/chem_parse.md OR use the Get Current Logs verb under the Admin tab. (if you click Open, and it does nothing, that's because you've not set a .md default program! Try downloading it instead, and use that file to set a default program! Also have a cute day.)") + + + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + + +//Generate the big list of reagent based reactions. +/proc/generate_chemwiki_line(datum/reagent/R, X, processCR) + //name | Reagent pH | reagents | reaction temp | explosion temp | pH range | Kinetics | description | OD level | Addiction level | Metabolism rate | impure chem | inverse chem + + var/datum/chemical_reaction/CR = get_chemical_reaction(R.id) + if((!CR && processCR) || (CR && !processCR)) // Do reactions first. + return "" + + + var/outstring = "|
!\[[R.color]\](https://placehold.it/15/[copytext(R.color, 2, 8)]/000000?text=+)[R.name]
pH: [R.pH] | " + var/datum/reagent/R3 + if(CR) + outstring += "
    " + for(var/R2 in CR.required_reagents) + R3 = GLOB.chemical_reagents_list[R2]//What a convoluted mess + outstring += "
  • [R3.name]: [CR.required_reagents[R3.id]]u
  • " + if(CR.required_catalysts) + for(var/R2 in CR.required_catalysts) + R3 = GLOB.chemical_reagents_list[R2] + outstring += "
  • Catalyst: [R3.name]: [CR.required_catalysts[R3.id]]u
  • " + outstring += "
| " + else + outstring += "N/A | " + + + //Temp, Explosions and pH + if(CR) + outstring += "
    [(CR.FermiChem?"
  • Min react temp: [CR.OptimalTempMin]K
  • ":"[(CR.required_temp?"
  • Min react temp: [CR.required_temp]K
  • ":"")]")] [(CR.FermiChem?"
  • Explosion_temp: [CR.ExplodeTemp]K
  • ":"")] [(CR.FermiChem?"
  • pH range: [max((CR.OptimalpHMin - CR.ReactpHLim), 0)] to [min((CR.OptimalpHMax + CR.ReactpHLim), 14)]
  • ":"")] " + if(CR.FermiChem) + outstring += "[(CR.PurityMin?"
  • Min explosive purity: [CR.PurityMin]
  • ":"")] [(CR.FermiExplode?"
  • Special explosion: Yes
  • ":"")]" + else + outstring += "" + + //Kinetics + if(CR) + if(CR.FermiChem) + switch(CR.ThermicConstant) + if(-INFINITY to -9.9) + outstring += "
  • Extremely endothermic
  • " + if(-9.9 to -4.9) + outstring += "
  • Very endothermic
  • " + if(-4.9 to -0.1) + outstring += "
  • Endothermic
  • " + if(-0.1 to 0.1) + outstring += "
  • Neutral
  • " + if(0.1 to 4.9) + outstring += "
  • Exothermic
  • " + if(4.9 to 9.9) + outstring += "
  • Very exothermic
  • " + if(9.9 to 19.9) + outstring += "
  • Extremely exothermic
  • " + if(19.9 to INFINITY ) + outstring += "
  • **Dangerously exothermic**
  • " + //if("cheesey") + //outstring += "
  • Dangerously Cheesey
  • " + + outstring += "
| " + else + outstring += " | " + + //Description, OD, Addict, Meta + outstring += "[R.description] |
  • Metabolism rate: [R.metabolization_rate/2]u/s
  • [(R.overdose_threshold?"
  • Overdose: [R.overdose_threshold]u
  • ":"")] [(R.addiction_threshold?"
  • Addiction: [R.addiction_threshold]u
  • ":"")] " + + if(R.impure_chem && R.impure_chem != "fermiTox") + R3 = GLOB.chemical_reagents_list[R.impure_chem] + outstring += "
  • Impure chem:[R3.name]
  • " + + if(R.inverse_chem && R.impure_chem != "fermiTox") + R3 = GLOB.chemical_reagents_list[R.inverse_chem] + outstring += "
  • Inverse chem:[R3.name]
  • [(R3.inverse_chem_val?"
  • Inverse purity: [R3.inverse_chem_val]
  • ":"")] " + + if(CR) + if(CR.required_container) + /*var/obj/item/I + I = istype(I, CR.required_container) if you can work out how to get this to work, by all means. + outstring += "
  • Required container: [I.name]
  • "*/ + outstring += "
  • Required container: [CR.required_container]
  • " + + outstring += "
|\n" + return outstring + +//Generate the big list of reaction based reactions. +//|Name | Reagents | Reaction vars | Description | Chem properties +/proc/generate_chemreactwiki_line(datum/chemical_reaction/CR) + if(CR.results.len) //Handled prior + return + var/outstring = "|[CR.name] |
    " + + //reagents + var/datum/reagent/R3 + for(var/R2 in CR.required_reagents) + R3 = GLOB.chemical_reagents_list[R2] + outstring += "
  • [R3.name]: [CR.required_reagents[R3.id]]u
  • " + if(CR.required_catalysts) + for(var/R2 in CR.required_catalysts) + R3 = GLOB.chemical_reagents_list[R2] + outstring += "
  • Catalyst: [R3.name]: [CR.required_catalysts[R3.id]]u
  • " + outstring += "
|
    " + + //Reaction vars + if(CR.required_temp) + outstring += "
  • Min react temp: [CR.required_temp]K
  • " + if(CR.FermiChem) + outstring += "[(CR.FermiChem?"
  • Min react temp: [CR.OptimalTempMin]K
  • ":"[(CR.required_temp?"
  • Min react temp: [CR.required_temp]K
  • ":"")]")] [(CR.FermiChem?"
  • Explosion temp: [CR.ExplodeTemp]K
  • ":"")] [(CR.FermiChem?"
  • pH range: [max((CR.OptimalpHMin - CR.ReactpHLim), 0)] to [min((CR.OptimalpHMax + CR.ReactpHLim), 14)]
  • ":"")]
  • Minimum purity: [CR.PurityMin] [(CR.FermiExplode?"
  • Special explosion: Yes
  • ":"")]" + if(CR.is_cold_recipe) + outstring += "
  • Cold: Yes
  • " + if(CR.required_container) + outstring += "
  • Required container: [CR.required_container]
  • " + if(CR.mob_react) + outstring += "
  • Can react in mob: Yes
  • " + + //description + outstring += "
| fill in manually " + + outstring += "
    |\n" + return outstring diff --git a/code/modules/reagents/chemistry/fermi/readme.md b/code/modules/reagents/chemistry/fermi/readme.md new file mode 100644 index 0000000000..4b897b6c4b --- /dev/null +++ b/code/modules/reagents/chemistry/fermi/readme.md @@ -0,0 +1,23 @@ +How to code fermichem reactions: +First off, probably read though the readme for standard reagent mechanisms, this builds on top of that. + +#bitflags +for `datum/reagent/` you have the following options with `var/chemical_flags`: + +``` +REAGENT_DEAD_PROCESS calls on_mob_dead() if present in a dead body +REAGENT_DONOTSPLIT Do not split the chem at all during processing +REAGENT_ONLYINVERSE Only invert chem, no splitting +REAGENT_ONMOBMERGE Call on_mob_life proc when reagents are merging. +REAGENT_INVISIBLE Doesn't appear on handheld health analyzers. +REAGENT_FORCEONNEW Forces a on_new() call without a data overhead +REAGENT_SNEAKYNAME When inverted, the inverted chem uses the name of the original chem +REAGENT_SPLITRETAINVOL Retains initial volume of chem when splitting +``` + +for `datum/chemical_reaction/` under `var/clear_conversion` + +``` +REACTION_CLEAR_IMPURE Convert into impure/pure on reaction completion +REACTION_CLEAR_INVERSE Convert into inverse on reaction completion when purity is low enough +``` diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm index dc86ab4e6c..fb064b6146 100644 --- a/code/modules/reagents/chemistry/holder.dm +++ b/code/modules/reagents/chemistry/holder.dm @@ -1,3 +1,4 @@ +#define CHEMICAL_QUANTISATION_LEVEL 0.001 /proc/build_chemical_reagent_list() //Chemical Reagents - Initialises all /datum/reagent into a list indexed by reagent id @@ -53,10 +54,16 @@ var/maximum_volume = 100 var/atom/my_atom = null var/chem_temp = 150 + var/pH = REAGENT_NORMAL_PH//Potential of hydrogen. Edited on adding new reagents, deleting reagents, and during fermi reactions. + var/overallPurity = 1 var/last_tick = 1 var/addiction_tick = 1 var/list/datum/reagent/addiction_list = new/list() var/reagents_holder_flags + var/targetVol = 0 //the target volume, i.e. the total amount that can be created during a fermichem reaction. + var/reactedVol = 0 //how much of the reagent is reacted during a fermireaction + var/fermiIsReacting = FALSE //that prevents multiple reactions from occurring (i.e. add_reagent calls to process_reactions(), this stops any extra reactions.) + var/fermiReactID //ID of the chem being made during a fermireaction, kept here so it's cache isn't lost between loops/procs. /datum/reagents/New(maximum=100, new_flags) maximum_volume = maximum @@ -89,7 +96,7 @@ var/list/data = list() for(var/r in reagent_list) //no reagents will be left behind var/datum/reagent/R = r - data += "[R.id] ([round(R.volume, 0.1)]u)" + data += "[R.id] ([round(R.volume, CHEMICAL_QUANTISATION_LEVEL)]u)" //Using IDs because SOME chemicals (I'm looking at you, chlorhydrate-beer) have the same names as other chemicals. return english_list(data) @@ -125,8 +132,8 @@ var/part = amount / total_volume for(var/reagent in cached_reagents) var/datum/reagent/R = reagent - remove_reagent(R.id, R.volume * part) - + remove_reagent(R.id, R.volume * part, ignore_pH = TRUE) + pH = REAGENT_NORMAL_PH update_total() handle_reactions() return amount @@ -189,8 +196,11 @@ var/transfer_amount = T.volume * part if(preserve_data) trans_data = copy_data(T) - R.add_reagent(T.id, transfer_amount * multiplier, trans_data, chem_temp, no_react = 1) //we only handle reaction after every reagent has been transfered. - remove_reagent(T.id, transfer_amount) + + + R.add_reagent(T.id, transfer_amount * multiplier, trans_data, chem_temp, T.purity, pH, no_react = TRUE, ignore_pH = TRUE) //we only handle reaction after every reagent has been transfered. + + remove_reagent(T.id, transfer_amount, ignore_pH = TRUE) update_total() R.update_total() @@ -249,7 +259,8 @@ if(current_reagent.id == reagent) if(preserve_data) trans_data = current_reagent.data - R.add_reagent(current_reagent.id, amount, trans_data, src.chem_temp) + R.add_reagent(current_reagent.id, amount, trans_data, chem_temp, current_reagent.purity, pH, no_react = TRUE) + remove_reagent(current_reagent.id, amount, 1) break @@ -350,14 +361,21 @@ R.on_update (A) update_total() -/datum/reagents/proc/handle_reactions() + +/datum/reagents/proc/handle_reactions()//HERE EDIT HERE THE MAIN REACTION + if(fermiIsReacting) //This ARRESTS other reactions. If you don't want this, then remove it. + return + if(reagents_holder_flags & NO_REACT) return //Yup, no reactions here. No siree. + var/list/cached_reagents = reagent_list var/list/cached_reactions = GLOB.chemical_reactions_list var/datum/cached_my_atom = my_atom - var/reaction_occurred = 0 + var/reaction_occurred = 0 // checks if reaction, binary variable + var/continue_reacting = FALSE //Helps keep track what kind of reaction is occuring; standard or fermi. + do var/list/possible_reactions = list() reaction_occurred = 0 @@ -382,8 +400,9 @@ var/has_special_react = C.special_react var/can_special_react = 0 + for(var/B in cached_required_reagents) - if(!has_reagent(B, cached_required_reagents[B])) + if(!has_reagent(B, cached_required_reagents[B]))//Allows vols at less than 1 to react. break total_matching_reagents++ for(var/B in cached_required_catalysts) @@ -402,7 +421,7 @@ if(!C.required_other) matching_other = 1 - else if(istype(cached_my_atom, /obj/item/slime_extract)) + else if(istype(cached_my_atom, /obj/item/slime_extract))//if the object is a slime_extract. var/obj/item/slime_extract/M = cached_my_atom if(M.Uses > 0) // added a limit to slime cores -- Muskets requested this @@ -413,7 +432,7 @@ if(!C.required_other) matching_other = 1 - if(required_temp == 0 || (is_cold_recipe && chem_temp <= required_temp) || (!is_cold_recipe && chem_temp >= required_temp)) + if(required_temp == 0 || (is_cold_recipe && chem_temp <= required_temp) || (!is_cold_recipe && chem_temp >= required_temp))//Temperature check!! meets_temp_requirement = 1 if(!has_special_react || C.check_special_react(src)) @@ -427,53 +446,291 @@ //select the reaction with the most extreme temperature requirements for(var/V in possible_reactions) var/datum/chemical_reaction/competitor = V - if(selected_reaction.is_cold_recipe) //if there are no recipe conflicts, everything in possible_reactions will have this same value for is_cold_reaction. warranty void if assumption not met. + if(selected_reaction.is_cold_recipe) if(competitor.required_temp <= selected_reaction.required_temp) selected_reaction = competitor else - if(competitor.required_temp >= selected_reaction.required_temp) + if(competitor.required_temp >= selected_reaction.required_temp) //will return with the hotter reacting first. selected_reaction = competitor - var/list/cached_required_reagents = selected_reaction.required_reagents - var/list/cached_results = selected_reaction.results + var/list/cached_required_reagents = selected_reaction.required_reagents//update reagents list + var/list/cached_results = selected_reaction.results//resultant chemical list var/special_react_result = selected_reaction.check_special_react(src) var/list/multiplier = INFINITY - for(var/B in cached_required_reagents) - multiplier = min(multiplier, round(get_reagent_amount(B) / cached_required_reagents[B])) - for(var/B in cached_required_reagents) - remove_reagent(B, (multiplier * cached_required_reagents[B]), safety = 1) + //Splits reactions into two types; FermiChem is advanced reaction mechanics, Other is default reaction. + //FermiChem relies on two additional properties; pH and impurity + //Temperature plays into a larger role too. + var/datum/chemical_reaction/C = selected_reaction - for(var/P in selected_reaction.results) - multiplier = max(multiplier, 1) //this shouldnt happen ... - SSblackbox.record_feedback("tally", "chemical_reaction", cached_results[P]*multiplier, P) - add_reagent(P, cached_results[P]*multiplier, null, chem_temp) + if (C.FermiChem && !continue_reacting) + if (chem_temp > C.ExplodeTemp) //This is first to ensure explosions. + var/datum/chemical_reaction/Ferm = selected_reaction + fermiIsReacting = FALSE + SSblackbox.record_feedback("tally", "fermi_chem", 1, ("[Ferm] explosion")) + Ferm.FermiExplode(src, my_atom, volume = total_volume, temp = chem_temp, pH = pH) + return 0 - var/list/seen = viewers(4, get_turf(my_atom)) - var/iconhtml = icon2html(cached_my_atom, seen) - if(cached_my_atom) - if(!ismob(cached_my_atom)) // No bubbling mobs - if(selected_reaction.mix_sound) - playsound(get_turf(cached_my_atom), selected_reaction.mix_sound, 80, 1) + //This is just to calc the on_reaction multiplier, and is a candidate for removal. + for(var/B in cached_required_reagents) + multiplier = min(multiplier, round((get_reagent_amount(B) / cached_required_reagents[B]), 0.0001)) + for(var/P in selected_reaction.results) + targetVol = cached_results[P]*multiplier - for(var/mob/M in seen) - to_chat(M, "[iconhtml] [selected_reaction.mix_message]") + if(!((chem_temp <= C.ExplodeTemp) && (chem_temp >= C.OptimalTempMin))) + return 0 //Not hot enough + if(! ((pH >= (C.OptimalpHMin - C.ReactpHLim)) && (pH <= (C.OptimalpHMax + C.ReactpHLim)) ))//To prevent pointless reactions + return 0 + if (fermiIsReacting) + return 0 + else + START_PROCESSING(SSprocessing, src) + selected_reaction.on_reaction(src, my_atom, multiplier) + fermiIsReacting = TRUE + fermiReactID = selected_reaction + reaction_occurred = 1 + + //Standard reaction mechanics: + else + if (C.FermiChem)//Just to make sure, should only proc when grenades are combining. + if (chem_temp > C.ExplodeTemp) //To allow fermigrenades + var/datum/chemical_reaction/fermi/Ferm = selected_reaction + fermiIsReacting = FALSE + SSblackbox.record_feedback("tally", "fermi_chem", 1, ("[Ferm] explosion")) + Ferm.FermiExplode(src, my_atom, volume = total_volume, temp = chem_temp, pH = pH) + return 0 + + for(var/B in cached_required_reagents) // + multiplier = min(multiplier, round((get_reagent_amount(B) / cached_required_reagents[B]), CHEMICAL_QUANTISATION_LEVEL)) + + + for(var/B in cached_required_reagents) + remove_reagent(B, (multiplier * cached_required_reagents[B]), safety = 1, ignore_pH = TRUE) + + for(var/P in selected_reaction.results) + multiplier = max(multiplier, 1) //this shouldnt happen ... + SSblackbox.record_feedback("tally", "chemical_reaction", cached_results[P]*multiplier, P)//log + add_reagent(P, cached_results[P]*multiplier, null, chem_temp) + + + var/list/seen = viewers(4, get_turf(my_atom))//Sound and sight checkers + var/iconhtml = icon2html(cached_my_atom, seen) + if(cached_my_atom) + if(!ismob(cached_my_atom)) // No bubbling mobs + if(selected_reaction.mix_sound) + playsound(get_turf(cached_my_atom), selected_reaction.mix_sound, 80, 1) - if(istype(cached_my_atom, /obj/item/slime_extract)) - var/obj/item/slime_extract/ME2 = my_atom - ME2.Uses-- - if(ME2.Uses <= 0) // give the notification that the slime core is dead for(var/mob/M in seen) - to_chat(M, "[iconhtml] \The [my_atom]'s power is consumed in the reaction.") - ME2.name = "used slime extract" - ME2.desc = "This extract has been used up." + to_chat(M, "[iconhtml] [selected_reaction.mix_message]") - selected_reaction.on_reaction(src, multiplier, special_react_result) - reaction_occurred = 1 + if(istype(cached_my_atom, /obj/item/slime_extract))//if there's an extract and it's used up. + var/obj/item/slime_extract/ME2 = my_atom + ME2.Uses-- + if(ME2.Uses <= 0) // give the notification that the slime core is dead + for(var/mob/M in seen) + to_chat(M, "[iconhtml] \The [my_atom]'s power is consumed in the reaction.") + ME2.name = "used slime extract" + ME2.desc = "This extract has been used up." + + selected_reaction.on_reaction(src, multiplier, special_react_result) + reaction_occurred = 1 + continue_reacting = TRUE while(reaction_occurred) update_total() return 0 +/datum/reagents/process() + var/datum/chemical_reaction/C = fermiReactID + + var/list/cached_required_reagents = C.required_reagents//update reagents list + var/list/cached_results = C.results//resultant chemical list + var/multiplier = INFINITY + for(var/B in cached_required_reagents) // + multiplier = min(multiplier, round((get_reagent_amount(B) / cached_required_reagents[B]), 0.0001)) + if (multiplier <= 0)//clarity + fermiEnd() + return + + if(C.required_catalysts) + for(var/P in C.required_catalysts) + if(!has_reagent(P)) + fermiEnd() + return + + if (!fermiIsReacting) + CRASH("Fermi has refused to stop reacting even though we asked her nicely.") + + if (!(chem_temp >= C.OptimalTempMin))//To prevent pointless reactions + fermiEnd() + return + + if (!( (pH >= (C.OptimalpHMin - C.ReactpHLim)) && (pH <= (C.OptimalpHMax + C.ReactpHLim)) )) //if pH is too far out, (could possibly allow reactions at this point, after the reaction has started, but make purity = 0) + fermiEnd() + return + + reactedVol = fermiReact(fermiReactID, chem_temp, pH, reactedVol, targetVol, cached_required_reagents, cached_results, multiplier) + if(round(reactedVol, CHEMICAL_QUANTISATION_LEVEL) == round(targetVol, CHEMICAL_QUANTISATION_LEVEL)) + fermiEnd() + if(!reactedVol)//Maybe unnessicary. + fermiEnd() + return + +/datum/reagents/proc/fermiEnd() + var/datum/chemical_reaction/C = fermiReactID + STOP_PROCESSING(SSprocessing, src) + fermiIsReacting = FALSE + reactedVol = 0 + targetVol = 0 + //Cap off values + for(var/datum/reagent/R in reagent_list) + R.volume = round(R.volume, CHEMICAL_QUANTISATION_LEVEL)//To prevent runaways. + //pH check, handled at the end to reduce calls. + if(istype(my_atom, /obj/item/reagent_containers)) + var/obj/item/reagent_containers/RC = my_atom + RC.pH_check() + C.FermiFinish(src, my_atom, reactedVol) + reactedVol = 0 + targetVol = 0 + handle_reactions() + update_total() + //Reaction sounds and words + var/list/seen = viewers(5, get_turf(my_atom)) + var/iconhtml = icon2html(my_atom, seen) + for(var/mob/M in seen) + to_chat(M, "[iconhtml] [C.mix_message]") + +/datum/reagents/proc/fermiReact(selected_reaction, cached_temp, cached_pH, reactedVol, targetVol, cached_required_reagents, cached_results, multiplier) + var/datum/chemical_reaction/C = selected_reaction + var/deltaT = 0 + var/deltapH = 0 + var/stepChemAmmount = 0 + + //get purity from combined beaker reactant purities HERE. + var/purity = 1 + + //Begin checks + //For now, purity is handled elsewhere (on add) + //Calculate DeltapH (Deviation of pH from optimal) + //Lower range + if (cached_pH < C.OptimalpHMin) + if (cached_pH < (C.OptimalpHMin - C.ReactpHLim)) + deltapH = 0 + return//If outside pH range, no reaction + else + deltapH = (((cached_pH - (C.OptimalpHMin - C.ReactpHLim))**C.CurveSharppH)/((C.ReactpHLim**C.CurveSharppH))) + //Upper range + else if (cached_pH > C.OptimalpHMax) + if (cached_pH > (C.OptimalpHMax + C.ReactpHLim)) + deltapH = 0 + return //If outside pH range, no reaction + else + deltapH = (((- cached_pH + (C.OptimalpHMax + C.ReactpHLim))**C.CurveSharppH)/(C.ReactpHLim**C.CurveSharppH))//Reverse - to + to prevent math operation failures. + //Within mid range + else if (cached_pH >= C.OptimalpHMin && cached_pH <= C.OptimalpHMax) + deltapH = 1 + //This should never proc: + else + WARNING("[my_atom] attempted to determine FermiChem pH for '[C.id]' which broke for some reason! ([usr])") + + //Calculate DeltaT (Deviation of T from optimal) + if (cached_temp < C.OptimalTempMax && cached_temp >= C.OptimalTempMin) + deltaT = (((cached_temp - C.OptimalTempMin)**C.CurveSharpT)/((C.OptimalTempMax - C.OptimalTempMin)**C.CurveSharpT)) + else if (cached_temp >= C.OptimalTempMax) + deltaT = 1 + else + deltaT = 0 + + purity = (deltapH)//set purity equal to pH offset + + //Then adjust purity of result with reagent purity. + purity *= reactant_purity(C) + + var/removeChemAmmount //remove factor + var/addChemAmmount //add factor + //ONLY WORKS FOR ONE PRODUCT AT THE MOMENT + //Calculate how much product to make and how much reactant to remove factors.. + for(var/P in cached_results) + stepChemAmmount = (multiplier*cached_results[P]) + if (stepChemAmmount > C.RateUpLim) + stepChemAmmount = C.RateUpLim + addChemAmmount = deltaT * stepChemAmmount + if (addChemAmmount >= (targetVol - reactedVol)) + addChemAmmount = (targetVol - reactedVol) + if (addChemAmmount < CHEMICAL_QUANTISATION_LEVEL) + addChemAmmount = CHEMICAL_QUANTISATION_LEVEL + removeChemAmmount = (addChemAmmount/cached_results[P]) + //keep limited. + addChemAmmount = round(addChemAmmount, CHEMICAL_QUANTISATION_LEVEL) + removeChemAmmount = round(removeChemAmmount, CHEMICAL_QUANTISATION_LEVEL) + //This is kept for future bugtesters. + //message_admins("Reaction vars: PreReacted: [reactedVol] of [targetVol]. deltaT [deltaT], multiplier [multiplier], Step [stepChemAmmount], uncapped Step [deltaT*(multiplier*cached_results[P])], addChemAmmount [addChemAmmount], removeFactor [removeChemAmmount] Pfactor [cached_results[P]], adding [addChemAmmount]") + + //remove reactants + for(var/B in cached_required_reagents) + remove_reagent(B, (removeChemAmmount * cached_required_reagents[B]), safety = 1, ignore_pH = TRUE) + + //add product + var/TotalStep = 0 + for(var/P in cached_results) + SSblackbox.record_feedback("tally", "chemical_reaction", addChemAmmount, P)//log + SSblackbox.record_feedback("tally", "fermi_chem", addChemAmmount, P) + add_reagent(P, (addChemAmmount), null, cached_temp, purity) + TotalStep += addChemAmmount//for multiple products + //Above should reduce yeild based on holder purity. + //Purity Check + for(var/datum/reagent/R in my_atom.reagents.reagent_list) + if(P == R.id) + if (R.purity < C.PurityMin)//If purity is below the min, blow it up. + fermiIsReacting = FALSE + SSblackbox.record_feedback("tally", "fermi_chem", 1, ("[P] explosion")) + C.FermiExplode(src, my_atom, (total_volume), cached_temp, pH) + STOP_PROCESSING(SSprocessing, src) + return + + C.FermiCreate(src, addChemAmmount, purity)//proc that calls when step is done + + //Apply pH changes and thermal output of reaction to beaker + chem_temp = round(cached_temp + (C.ThermicConstant * addChemAmmount)) + pH += (C.HIonRelease * addChemAmmount) + //keep track of the current reacted amount + reactedVol = reactedVol + addChemAmmount + + //Check extremes + if (chem_temp > C.ExplodeTemp) + //go to explode proc + fermiIsReacting = FALSE + SSblackbox.record_feedback("tally", "fermi_chem", 1, ("[C] explosions")) + C.FermiExplode(src, my_atom, (total_volume), chem_temp, pH) + STOP_PROCESSING(SSprocessing, src) + return + + //Make sure things are limited, but superacids/bases can push forward the reaction + pH = CLAMP(pH, 0, 14) + + //return said amount to compare for next step. + return (reactedVol) + +//Currently calculates it irrespective of required reagents at the start +/datum/reagents/proc/reactant_purity(var/datum/chemical_reaction/C, holder) + var/list/cached_reagents = reagent_list + var/i = 0 + var/cachedPurity + for(var/datum/reagent/R in my_atom.reagents.reagent_list) + if (R in cached_reagents) + cachedPurity += R.purity + i++ + if(!i)//I've never seen it get here with 0, but in case + CRASH("No reactants found mid reaction for [fermiReactID]/[C], how it got here is beyond me. Beaker: [holder]") + return cachedPurity/i + +/datum/reagents/proc/uncache_purity(id) + var/datum/reagent/R = has_reagent("[id]") + if(!R) + return + if(R.cached_purity == 1) + return + R.purity = R.cached_purity + /datum/reagents/proc/isolate_reagent(reagent) var/list/cached_reagents = reagent_list for(var/_reagent in cached_reagents) @@ -505,11 +762,14 @@ total_volume = 0 for(var/reagent in cached_reagents) var/datum/reagent/R = reagent - if(R.volume < 0.1) + if(R.volume <= 0)//For clarity + del_reagent(R.id) + if((R.volume < 0.01) && !fermiIsReacting) del_reagent(R.id) else total_volume += R.volume - + if(!reagent_list || !total_volume) + pH = REAGENT_NORMAL_PH return 0 /datum/reagents/proc/clear_reagents() @@ -517,6 +777,7 @@ for(var/reagent in cached_reagents) var/datum/reagent/R = reagent del_reagent(R.id) + pH = REAGENT_NORMAL_PH return 0 /datum/reagents/proc/reaction(atom/A, method = TOUCH, volume_modifier = 1, show_message = 1) @@ -563,13 +824,17 @@ /datum/reagents/proc/adjust_thermal_energy(J, min_temp = 2.7, max_temp = 1000) var/S = specific_heat() - chem_temp = CLAMP(chem_temp + (J / (S * total_volume)), 2.7, 1000) + chem_temp = CLAMP(chem_temp + (J / (S * total_volume)), min_temp, max_temp) + if(istype(my_atom, /obj/item/reagent_containers)) + var/obj/item/reagent_containers/RC = my_atom + RC.temp_check() + +/datum/reagents/proc/add_reagent(reagent, amount, list/data=null, reagtemp = 300, other_purity = 1, other_pH, no_react = 0, ignore_pH = FALSE) -/datum/reagents/proc/add_reagent(reagent, amount, list/data=null, reagtemp = 300, no_react = 0) if(!isnum(amount) || !amount) return FALSE - if(amount <= 0) + if(amount < CHEMICAL_QUANTISATION_LEVEL)//To prevent small ammount problems. return FALSE var/datum/reagent/D = GLOB.chemical_reagents_list[reagent] @@ -577,6 +842,23 @@ WARNING("[my_atom] attempted to add a reagent called '[reagent]' which doesn't exist. ([usr])") return FALSE + if (D.id == "water" && !no_react && !istype(my_atom, /obj/item/reagent_containers/food)) //Do like an otter, add acid to water, but also don't blow up botany. + if (pH <= 2) + SSblackbox.record_feedback("tally", "fermi_chem", 1, "water-acid explosions") + var/datum/effect_system/smoke_spread/chem/s = new + var/turf/T = get_turf(my_atom) + var/datum/reagents/R = new/datum/reagents(3000) + R.add_reagent("fermiAcid", amount) + for (var/datum/reagent/reagentgas in reagent_list) + R.add_reagent(reagentgas, amount/5) + remove_reagent(reagentgas, amount/5) + s.set_up(R, CLAMP(amount/10, 0, 2), T) + s.start() + return FALSE + + if(!pH) + other_pH = D.pH + update_total() var/cached_total = total_volume if(cached_total + amount > maximum_volume) @@ -586,6 +868,9 @@ var/new_total = cached_total + amount var/cached_temp = chem_temp var/list/cached_reagents = reagent_list + var/cached_pH = pH + + //Equalize temperature - Not using specific_heat() because the new chemical isn't in yet. var/specific_heat = 0 @@ -597,32 +882,53 @@ specific_heat += D.specific_heat * (amount / new_total) thermal_energy += D.specific_heat * amount * reagtemp chem_temp = thermal_energy / (specific_heat * new_total) - //// + + //cacluate reagent based pH shift. + if(ignore_pH) + pH = ((cached_pH * cached_total)+(other_pH * amount))/(cached_total + amount)//should be right + else + pH = ((cached_pH * cached_total)+(D.pH * amount))/(cached_total + amount)//should be right + if(istype(my_atom, /obj/item/reagent_containers/)) + var/obj/item/reagent_containers/RC = my_atom + RC.pH_check()//checks beaker resilience //add the reagent to the existing if it exists for(var/A in cached_reagents) var/datum/reagent/R = A - if (R.id == reagent) - R.volume += amount + if (R.id == reagent) //IF MERGING + //Add amount and equalize purity + R.volume += round(amount, CHEMICAL_QUANTISATION_LEVEL) + R.purity = ((R.purity * R.volume) + (other_purity * amount)) /((R.volume + amount)) //This should add the purity to the product + update_total() if(my_atom) my_atom.on_reagent_change(ADD_REAGENT) - R.on_merge(data, amount) + if(isliving(my_atom)) + if(R.chemical_flags & REAGENT_ONMOBMERGE)//Forces on_mob_add proc when a chem is merged + R.on_mob_add(my_atom, amount) + R.on_merge(data, amount, my_atom, other_purity) if(!no_react) handle_reactions() + return TRUE + //otherwise make a new one var/datum/reagent/R = new D.type(data) cached_reagents += R R.holder = src - R.volume = amount + R.volume = round(amount, CHEMICAL_QUANTISATION_LEVEL) + R.purity = other_purity + R.loc = get_turf(my_atom) if(data) R.data = data R.on_new(data) + if(R.chemical_flags & REAGENT_FORCEONNEW)//Allows on new without data overhead. + R.on_new(pH) //Add more as desired. + if(isliving(my_atom)) - R.on_mob_add(my_atom) //Must occur befor it could posibly run on_mob_delete + R.on_mob_add(my_atom, amount) update_total() if(my_atom) my_atom.on_reagent_change(ADD_REAGENT) @@ -630,12 +936,13 @@ handle_reactions() return TRUE + /datum/reagents/proc/add_reagent_list(list/list_reagents, list/data=null) // Like add_reagent but you can enter a list. Format it like this: list("toxin" = 10, "beer" = 15) for(var/r_id in list_reagents) var/amt = list_reagents[r_id] add_reagent(r_id, amt, data) -/datum/reagents/proc/remove_reagent(reagent, amount, safety)//Added a safety check for the trans_id_to +/datum/reagents/proc/remove_reagent(reagent, amount, safety, ignore_pH = FALSE)//Added a safety check for the trans_id_to if(isnull(amount)) amount = 0 @@ -653,6 +960,15 @@ for(var/A in cached_reagents) var/datum/reagent/R = A if (R.id == reagent) + if((total_volume - amount) <= 0)//Because this can result in 0, I don't want it to crash. + pH = REAGENT_NORMAL_PH + //In practice this is really confusing and players feel like it randomly melts their beakers, but I'm not sure how else to handle it. We'll see how it goes and I can remove this if it confuses people. + else if (!ignore_pH) + //if (((pH > R.pH) && (pH <= 7)) || ((pH < R.pH) && (pH >= 7))) + pH = (((pH - R.pH) / total_volume) * amount) + pH + if(istype(my_atom, /obj/item/reagent_containers/)) + var/obj/item/reagent_containers/RC = my_atom + RC.pH_check()//checks beaker resilience) //clamp the removal amount to be between current reagent amount //and zero, to prevent removing more than the holder has stored amount = CLAMP(amount, 0, R.volume) @@ -674,7 +990,7 @@ if(!amount) return R else - if(R.volume >= amount) + if(round(R.volume, CHEMICAL_QUANTISATION_LEVEL) >= amount) return R else return 0 @@ -686,7 +1002,7 @@ for(var/_reagent in cached_reagents) var/datum/reagent/R = _reagent if (R.id == reagent) - return R.volume + return round(R.volume, CHEMICAL_QUANTISATION_LEVEL) return 0 diff --git a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm index fa9d60a219..9a228b28e3 100644 --- a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm +++ b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm @@ -139,12 +139,14 @@ /obj/machinery/chem_dispenser/emag_act(mob/user) + . = ..() if(obj_flags & EMAGGED) to_chat(user, "[src] has no functional safeties to emag.") return to_chat(user, "You short out [src]'s safeties.") dispensable_reagents |= emagged_reagents//add the emagged reagents to the dispensable ones obj_flags |= EMAGGED + return TRUE /obj/machinery/chem_dispenser/ex_act(severity, target) if(severity < 3) @@ -189,10 +191,16 @@ data["beakerCurrentVolume"] = beakerCurrentVolume data["beakerMaxVolume"] = beaker.volume data["beakerTransferAmounts"] = beaker.possible_transfer_amounts + data["beakerCurrentpH"] = beaker.reagents.pH + //pH accuracy + for(var/obj/item/stock_parts/capacitor/C in component_parts) + data["partRating"]= 10**(C.rating-1) + else data["beakerCurrentVolume"] = null data["beakerMaxVolume"] = null data["beakerTransferAmounts"] = null + data["beakerCurrentpH"] = null var/chemicals[0] var/recipes[0] diff --git a/code/modules/reagents/chemistry/machinery/chem_heater.dm b/code/modules/reagents/chemistry/machinery/chem_heater.dm index a17b1e8190..eeb452dbb5 100644 --- a/code/modules/reagents/chemistry/machinery/chem_heater.dm +++ b/code/modules/reagents/chemistry/machinery/chem_heater.dm @@ -77,6 +77,16 @@ updateUsrDialog() update_icon() return + + if(beaker) + if(istype(I, /obj/item/reagent_containers/dropper)) + var/obj/item/reagent_containers/dropper/D = I + D.afterattack(beaker, user, 1) + + if(istype(I, /obj/item/reagent_containers/syringe)) + var/obj/item/reagent_containers/syringe/S = I + S.afterattack(beaker, user, 1) + return ..() /obj/machinery/chem_heater/on_deconstruction() @@ -97,13 +107,21 @@ data["isBeakerLoaded"] = beaker ? 1 : 0 data["currentTemp"] = beaker ? beaker.reagents.chem_temp : null + data["currentpH"] = beaker ? beaker.reagents.pH : null data["beakerCurrentVolume"] = beaker ? beaker.reagents.total_volume : null data["beakerMaxVolume"] = beaker ? beaker.volume : null + //purity and pH accuracy + for(var/obj/item/stock_parts/micro_laser/M in component_parts) + data["partRating"]= 10**(M.rating-1) + if(M.rating == 4) + data["showPurity"] = 1 + else + data["showPurity"] = 0 var beakerContents[0] if(beaker) for(var/datum/reagent/R in beaker.reagents.reagent_list) - beakerContents.Add(list(list("name" = R.name, "volume" = R.volume))) // list in a list because Byond merges the first list... + beakerContents.Add(list(list("name" = R.name, "volume" = R.volume, "purity" = R.purity))) // list in a list because Byond merges the first list... data["beakerContents"] = beakerContents return data diff --git a/code/modules/reagents/chemistry/machinery/chem_master.dm b/code/modules/reagents/chemistry/machinery/chem_master.dm index 1d13b44c7a..711fe11d5d 100644 --- a/code/modules/reagents/chemistry/machinery/chem_master.dm +++ b/code/modules/reagents/chemistry/machinery/chem_master.dm @@ -21,6 +21,7 @@ var/analyzeVars[0] var/useramount = 30 // Last used amount var/list/pillStyles + var/fermianalyze //Give more detail on fermireactions on analysis /obj/machinery/chem_master/Initialize() create_reagents(100) @@ -170,6 +171,7 @@ data["condi"] = condi data["screen"] = screen data["analyzeVars"] = analyzeVars + data["fermianalyze"] = fermianalyze data["chosenPillStyle"] = chosenPillStyle data["isPillBottleLoaded"] = bottle ? 1 : 0 if(bottle) @@ -211,11 +213,13 @@ var/id = params["id"] var/amount = text2num(params["amount"]) if (amount > 0) + end_fermi_reaction() beaker.reagents.trans_id_to(src, id, amount) . = TRUE else if (amount == -1) // -1 means custom amount useramount = input("Enter the Amount you want to transfer:", name, useramount) as num|null if (useramount > 0) + end_fermi_reaction() beaker.reagents.trans_id_to(src, id, useramount) . = TRUE @@ -229,6 +233,12 @@ else reagents.remove_reagent(id, amount) . = TRUE + else if (amount == -1) // -1 means custom amount + useramount = input("Enter the Amount you want to transfer:", name, useramount) as num|null + if (useramount > 0) + end_fermi_reaction() + reagents.trans_id_to(beaker, id, useramount) + . = TRUE if("toggleMode") mode = !mode @@ -328,7 +338,7 @@ var/vol_part = min(reagents.total_volume, 30) if(text2num(many)) amount_full = round(reagents.total_volume / 30) - vol_part = reagents.total_volume % 30 + vol_part = ((reagents.total_volume*1000) % 30000) / 1000 //% operator doesn't support decimals. var/name = stripped_input(usr, "Name:","Name your bottle!", (reagents.total_volume ? reagents.get_master_reagent_name() : " "), MAX_NAME_LEN) if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr))) return @@ -374,8 +384,40 @@ adjust_item_drop_location(P) reagents.trans_to(P, vol_part) . = TRUE + + if("createDart") + for(var/datum/reagent/R in reagents.reagent_list) + if(!(istype(R, /datum/reagent/medicine))) + visible_message("The [src] beeps, \"SmartDarts are insoluble with non-medicinal compounds.\"") + return + + var/many = params["many"] + if(reagents.total_volume == 0) + return + var/amount = 1 + var/vol_each = min(reagents.total_volume, 20) + if(text2num(many)) + amount = CLAMP(round(input(usr, "Max 10. Buffer content will be split evenly.", "How many darts?", amount) as num|null), 0, 10) + if(!amount) + return + vol_each = min(reagents.total_volume / amount, 20) + + var/name = stripped_input(usr,"Name:","Name your SmartDart!", "[reagents.get_master_reagent_name()] ([vol_each]u)", MAX_NAME_LEN) + if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr))) + return + + var/obj/item/reagent_containers/syringe/dart/D + for(var/i = 0; i < amount; i++) + D = new /obj/item/reagent_containers/syringe/dart(drop_location()) + D.name = trim("[name] SmartDart") + adjust_item_drop_location(D) + reagents.trans_to(D, vol_each) + D.mode=!mode + D.update_icon() + . = TRUE + //END CITADEL ADDITIONS - if("analyze") + if("analyzeBeak") var/datum/reagent/R = GLOB.chemical_reagents_list[params["id"]] if(R) var/state = "Unknown" @@ -387,7 +429,45 @@ state = "Gas" var/const/P = 3 //The number of seconds between life ticks var/T = initial(R.metabolization_rate) * (60 / P) - analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold)) + var/datum/chemical_reaction/Rcr = get_chemical_reaction(R.id) + if(Rcr && Rcr.FermiChem) + fermianalyze = TRUE + var/pHpeakCache = (Rcr.OptimalpHMin + Rcr.OptimalpHMax)/2 + var/datum/reagent/targetReagent = beaker.reagents.has_reagent("[R.id]") + + if(!targetReagent) + CRASH("Tried to find a reagent that doesn't exist in the chem_master!") + analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold), "purityF" = targetReagent.purity, "inverseRatioF" = initial(R.inverse_chem_val), "purityE" = initial(Rcr.PurityMin), "minTemp" = initial(Rcr.OptimalTempMin), "maxTemp" = initial(Rcr.OptimalTempMax), "eTemp" = initial(Rcr.ExplodeTemp), "pHpeak" = pHpeakCache) + else + fermianalyze = FALSE + analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold)) + screen = "analyze" + return + + if("analyzeBuff") + var/datum/reagent/R = GLOB.chemical_reagents_list[params["id"]] + if(R) + var/state = "Unknown" + if(initial(R.reagent_state) == 1) + state = "Solid" + else if(initial(R.reagent_state) == 2) + state = "Liquid" + else if(initial(R.reagent_state) == 3) + state = "Gas" + var/const/P = 3 //The number of seconds between life ticks + var/T = initial(R.metabolization_rate) * (60 / P) + if(istype(R, /datum/reagent/fermi)) + fermianalyze = TRUE + var/datum/chemical_reaction/Rcr = get_chemical_reaction(R.id) + var/pHpeakCache = (Rcr.OptimalpHMin + Rcr.OptimalpHMax)/2 + var/datum/reagent/targetReagent = reagents.has_reagent("[R.id]") + + if(!targetReagent) + CRASH("Tried to find a reagent that doesn't exist in the chem_master!") + analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold), "purityF" = targetReagent.purity, "inverseRatioF" = initial(R.inverse_chem_val), "purityE" = initial(Rcr.PurityMin), "minTemp" = initial(Rcr.OptimalTempMin), "maxTemp" = initial(Rcr.OptimalTempMax), "eTemp" = initial(Rcr.ExplodeTemp), "pHpeak" = pHpeakCache) + else + fermianalyze = FALSE + analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold)) screen = "analyze" return @@ -397,6 +477,9 @@ +/obj/machinery/chem_master/proc/end_fermi_reaction()//Ends any reactions upon moving. + if(beaker.reagents.fermiIsReacting) + beaker.reagents.fermiEnd() /obj/machinery/chem_master/proc/isgoodnumber(num) if(isnum(num)) diff --git a/code/modules/reagents/chemistry/machinery/pandemic.dm b/code/modules/reagents/chemistry/machinery/pandemic.dm index 0e482f8cec..6efa4276b6 100644 --- a/code/modules/reagents/chemistry/machinery/pandemic.dm +++ b/code/modules/reagents/chemistry/machinery/pandemic.dm @@ -125,12 +125,6 @@ else cut_overlays() -/obj/machinery/computer/pandemic/proc/eject_beaker() - if(beaker) - beaker.forceMove(drop_location()) - beaker = null - update_icon() - /obj/machinery/computer/pandemic/ui_interact(mob/user, ui_key = "main", datum/tgui/ui, force_open = FALSE, datum/tgui/master_ui, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) @@ -165,7 +159,7 @@ return switch(action) if("eject_beaker") - eject_beaker() + replace_beaker(usr) . = TRUE if("empty_beaker") if(beaker) @@ -174,7 +168,7 @@ if("empty_eject_beaker") if(beaker) beaker.reagents.clear_reagents() - eject_beaker() + replace_beaker(usr) . = TRUE if("rename_disease") var/id = get_virus_id_by_index(text2num(params["index"])) @@ -201,6 +195,8 @@ B.reagents.add_reagent("blood", 20, data) wait = TRUE update_icon() + var/turf/source_turf = get_turf(src) + log_virus("A culture bottle was printed for the virus [A.admin_details()] at [loc_name(source_turf)] by [key_name(usr)]") addtimer(CALLBACK(src, .proc/reset_replicator_cooldown), 50) . = TRUE if("create_vaccine_bottle") @@ -232,18 +228,32 @@ . = TRUE //no afterattack if(stat & (NOPOWER|BROKEN)) return - if(beaker) - to_chat(user, "A container is already loaded into [src]!") + var/obj/item/reagent_containers/B = I + if(!user.transferItemToLoc(B, src)) return - if(!user.transferItemToLoc(I, src)) - return - - beaker = I + replace_beaker(user, B) to_chat(user, "You insert [I] into [src].") - update_icon() else return ..() +/obj/machinery/computer/pandemic/AltClick(mob/living/user) + if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK)) + return + replace_beaker(user) + return + +/obj/machinery/computer/pandemic/proc/replace_beaker(mob/living/user, obj/item/reagent_containers/new_beaker) + if(beaker) + if(user && Adjacent(user) && !issiliconoradminghost(user)) + if(!user.put_in_hands(beaker)) + beaker.forceMove(drop_location()) + if(new_beaker) + beaker = new_beaker + else + beaker = null + update_icon() + return TRUE + /obj/machinery/computer/pandemic/on_deconstruction() - eject_beaker() + replace_beaker(usr) . = ..() diff --git a/code/modules/reagents/chemistry/reagents.dm b/code/modules/reagents/chemistry/reagents.dm index 0e5c2b39a5..52d3ba7822 100644 --- a/code/modules/reagents/chemistry/reagents.dm +++ b/code/modules/reagents/chemistry/reagents.dm @@ -32,9 +32,19 @@ var/addiction_stage3_end = 30 var/addiction_stage4_end = 40 var/overdosed = 0 // You fucked up and this is now triggering its overdose effects, purge that shit quick. - var/self_consuming = FALSE + var/self_consuming = FALSE //I think this uhhh, makes weird stuff happen when metabolising, but... doesn't seem to do what I think, so I'm gonna leave it. + //Fermichem vars: + var/purity = 1 //How pure a chemical is from 0 - 1. + var/cached_purity = 1 + var/turf/loc = null //Should be the creation location! + var/pH = 7 //pH of the specific reagent, used for calculating the sum pH of a holder. + //var/SplitChem = FALSE //If the chem splits on metabolism + var/impure_chem // What chemical is metabolised with an inpure reaction + var/inverse_chem_val = 0 // If the impurity is below 0.5, replace ALL of the chem with inverse_chemupon metabolising + var/inverse_chem // What chem is metabolised when purity is below inverse_chem_val, this shouldn't be made, but if it does, well, I guess I'll know about it. var/metabolizing = FALSE - var/invisible = FALSE //Set to true if it doesn't appear on handheld health analyzers. + var/chemical_flags // See fermi/readme.dm REAGENT_DEAD_PROCESS, REAGENT_DONOTSPLIT, REAGENT_ONLYINVERSE, REAGENT_ONMOBMERGE, REAGENT_INVISIBLE, REAGENT_FORCEONNEW, REAGENT_SNEAKYNAME + /datum/reagent/Destroy() // This should only be called by the holder, so it's already handled clearing its references . = ..() @@ -59,11 +69,51 @@ /datum/reagent/proc/on_mob_life(mob/living/carbon/M) current_cycle++ - holder.remove_reagent(src.id, metabolization_rate * M.metabolism_efficiency) //By default it slowly disappears. + if(holder) + holder.remove_reagent(src.id, metabolization_rate * M.metabolism_efficiency) //By default it slowly disappears. + return + +//called when a mob processes chems when dead. +/datum/reagent/proc/on_mob_dead(mob/living/carbon/M) + if(!(chemical_flags & REAGENT_DEAD_PROCESS)) //justincase + return + current_cycle++ + if(holder) + holder.remove_reagent(src.id, metabolization_rate * M.metabolism_efficiency) //By default it slowly disappears. return // Called when this reagent is first added to a mob -/datum/reagent/proc/on_mob_add(mob/living/L) +/datum/reagent/proc/on_mob_add(mob/living/L, amount) + if(!iscarbon(L)) + return + var/mob/living/carbon/M = L + if (purity == 1) + log_game("CHEM: [L] ckey: [L.key] has ingested [volume]u of [id]") + return + if(cached_purity == 1) + cached_purity = purity + else if(purity < 0) + CRASH("Purity below 0 for chem: [id], Please let Fermis Know!") + if(chemical_flags & REAGENT_DONOTSPLIT) + return + + if ((inverse_chem_val > purity) && (inverse_chem))//Turns all of a added reagent into the inverse chem + M.reagents.remove_reagent(id, amount, FALSE) + M.reagents.add_reagent(inverse_chem, amount, FALSE, other_purity = 1-cached_purity) + var/datum/reagent/R = M.reagents.has_reagent("[inverse_chem]") + if(R.chemical_flags & REAGENT_SNEAKYNAME) + R.name = name//Negative effects are hidden + if(R.chemical_flags & REAGENT_INVISIBLE) + R.chemical_flags |= (REAGENT_INVISIBLE) + log_game("FERMICHEM: [M] ckey: [M.key] has ingested [volume]u of [inverse_chem]") + return + else if (impure_chem) + var/impureVol = amount * (1 - purity) //turns impure ratio into impure chem + if(!(chemical_flags & REAGENT_SPLITRETAINVOL)) + M.reagents.remove_reagent(id, (impureVol), FALSE) + M.reagents.add_reagent(impure_chem, impureVol, FALSE, other_purity = 1-cached_purity) + log_game("FERMICHEM: [M] ckey: [M.key] has ingested [volume - impureVol]u of [id]") + log_game("FERMICHEM: [M] ckey: [M.key] has ingested [volume]u of [impure_chem]") return // Called when this reagent is removed while inside a mob @@ -86,7 +136,35 @@ return // Called when two reagents of the same are mixing. -/datum/reagent/proc/on_merge(data) +/datum/reagent/proc/on_merge(data, amount, mob/living/carbon/M, purity) + if(!iscarbon(M)) + return + if (purity == 1) + log_game("FERMICHEM: [M] ckey: [M.key] has ingested [volume]u of [id]") + return + cached_purity = purity //purity SHOULD be precalculated from the add_reagent, update cache. + if (purity < 0) + CRASH("Purity below 0 for chem: [id], Please let Fermis Know!") + if(chemical_flags & REAGENT_DONOTSPLIT) + return + + if ((inverse_chem_val > purity) && (inverse_chem)) //INVERT + M.reagents.remove_reagent(id, amount, FALSE) + M.reagents.add_reagent(inverse_chem, amount, FALSE, other_purity = 1-cached_purity) + var/datum/reagent/R = M.reagents.has_reagent("[inverse_chem]") + if(R.chemical_flags & REAGENT_SNEAKYNAME) + R.name = name//Negative effects are hidden + if(R.chemical_flags & REAGENT_INVISIBLE) + R.chemical_flags |= (REAGENT_INVISIBLE) + log_game("FERMICHEM: [M] ckey: [M.key] has merged [volume]u of [inverse_chem]") + return + else if (impure_chem) //SPLIT + var/impureVol = amount * (1 - purity) + if(!(chemical_flags & REAGENT_SPLITRETAINVOL)) + M.reagents.remove_reagent(id, impureVol, FALSE) + M.reagents.add_reagent(impure_chem, impureVol, FALSE, other_purity = 1-cached_purity) + log_game("FERMICHEM: [M] ckey: [M.key] has merged [volume - impureVol]u of [id]") + log_game("FERMICHEM: [M] ckey: [M.key] has merged [volume]u of [impure_chem]") return /datum/reagent/proc/on_update(atom/A) diff --git a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm index a46a4d61e4..94aca411be 100644 --- a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm @@ -14,6 +14,7 @@ nutriment_factor = 0 taste_description = "alcohol" var/boozepwr = 65 //Higher numbers equal higher hardness, higher hardness equals more intense alcohol poisoning + pH = 7.33 /* Boozepwr Chart @@ -86,6 +87,8 @@ All effects don't start immediately, but rather get worse over time; the rate is taste_description = "piss water" glass_name = "glass of beer" glass_desc = "A freezing pint of beer." + pH = 4 + /datum/reagent/consumable/ethanol/beer/light name = "Light Beer" @@ -95,6 +98,7 @@ All effects don't start immediately, but rather get worse over time; the rate is taste_description = "dish water" glass_name = "glass of light beer" glass_desc = "A freezing pint of watery light beer." + pH = 5 /datum/reagent/consumable/ethanol/beer/green name = "Green Beer" @@ -105,6 +109,7 @@ All effects don't start immediately, but rather get worse over time; the rate is glass_icon_state = "greenbeerglass" glass_name = "glass of green beer" glass_desc = "A freezing pint of green beer. Festive." + pH = 6 /datum/reagent/consumable/ethanol/beer/green/on_mob_life(mob/living/carbon/M) if(M.color != color) @@ -124,6 +129,8 @@ All effects don't start immediately, but rather get worse over time; the rate is glass_name = "glass of RR coffee liquor" glass_desc = "DAMN, THIS THING LOOKS ROBUST!" shot_glass_icon_state = "shotglasscream" + pH = 6 + /datum/reagent/consumable/ethanol/kahlua/on_mob_life(mob/living/carbon/M) M.dizziness = max(0,M.dizziness-5) @@ -145,6 +152,7 @@ All effects don't start immediately, but rather get worse over time; the rate is glass_name = "glass of whiskey" glass_desc = "The silky, smokey whiskey goodness inside the glass makes the drink look very classy." shot_glass_icon_state = "shotglassbrown" + pH = 4.5 /datum/reagent/consumable/ethanol/thirteenloko name = "Thirteen Loko" @@ -161,6 +169,7 @@ All effects don't start immediately, but rather get worse over time; the rate is glass_name = "glass of Thirteen Loko" glass_desc = "This is a glass of Thirteen Loko, it appears to be of the highest quality. The drink, not the glass." + /datum/reagent/consumable/ethanol/thirteenloko/on_mob_life(mob/living/carbon/M) M.drowsyness = max(0,M.drowsyness-7) M.AdjustSleeping(-40) @@ -221,6 +230,7 @@ All effects don't start immediately, but rather get worse over time; the rate is glass_name = "glass of vodka" glass_desc = "The glass contain wodka. Xynta." shot_glass_icon_state = "shotglassclear" + pH = 8.1 /datum/reagent/consumable/ethanol/vodka/on_mob_life(mob/living/carbon/M) M.radiation = max(M.radiation-2,0) @@ -255,6 +265,7 @@ All effects don't start immediately, but rather get worse over time; the rate is glass_icon_state = "threemileislandglass" glass_name = "Three Mile Island Ice Tea" glass_desc = "A glass of this is sure to prevent a meltdown." + pH = 3.5 /datum/reagent/consumable/ethanol/threemileisland/on_mob_life(mob/living/carbon/M) M.set_drugginess(50) @@ -270,6 +281,7 @@ All effects don't start immediately, but rather get worse over time; the rate is glass_icon_state = "ginvodkaglass" glass_name = "glass of gin" glass_desc = "A crystal clear glass of Griffeater gin." + pH = 6.9 /datum/reagent/consumable/ethanol/rum name = "Rum" @@ -282,6 +294,7 @@ All effects don't start immediately, but rather get worse over time; the rate is glass_name = "glass of rum" glass_desc = "Now you want to Pray for a pirate suit, don't you?" shot_glass_icon_state = "shotglassbrown" + pH = 6.5 /datum/reagent/consumable/ethanol/tequila name = "Tequila" @@ -294,6 +307,7 @@ All effects don't start immediately, but rather get worse over time; the rate is glass_name = "glass of tequila" glass_desc = "Now all that's missing is the weird colored shades!" shot_glass_icon_state = "shotglassgold" + pH = 4 /datum/reagent/consumable/ethanol/vermouth name = "Vermouth" @@ -306,6 +320,7 @@ All effects don't start immediately, but rather get worse over time; the rate is glass_name = "glass of vermouth" glass_desc = "You wonder why you're even drinking this straight." shot_glass_icon_state = "shotglassclear" + pH = 3.25 /datum/reagent/consumable/ethanol/wine name = "Wine" @@ -318,6 +333,7 @@ All effects don't start immediately, but rather get worse over time; the rate is glass_name = "glass of wine" glass_desc = "A very classy looking drink." shot_glass_icon_state = "shotglassred" + pH = 3.45 /datum/reagent/consumable/ethanol/lizardwine name = "Lizard wine" @@ -327,6 +343,7 @@ All effects don't start immediately, but rather get worse over time; the rate is boozepwr = 45 quality = DRINK_FANTASTIC taste_description = "scaley sweetness" + pH = 3 /datum/reagent/consumable/ethanol/grappa name = "Grappa" @@ -338,6 +355,7 @@ All effects don't start immediately, but rather get worse over time; the rate is glass_icon_state = "grappa" glass_name = "glass of grappa" glass_desc = "A fine drink originally made to prevent waste by using the leftovers from winemaking." + pH = 3.5 /datum/reagent/consumable/ethanol/cognac name = "Cognac" @@ -350,6 +368,7 @@ All effects don't start immediately, but rather get worse over time; the rate is glass_name = "glass of cognac" glass_desc = "Damn, you feel like some kind of French aristocrat just by holding this." shot_glass_icon_state = "shotglassbrown" + pH = 3.5 /datum/reagent/consumable/ethanol/absinthe name = "Absinthe" @@ -395,6 +414,7 @@ All effects don't start immediately, but rather get worse over time; the rate is glass_icon_state = "aleglass" glass_name = "glass of ale" glass_desc = "A freezing pint of delicious Ale." + pH = 4.5 /datum/reagent/consumable/ethanol/goldschlager name = "Goldschlager" @@ -421,6 +441,7 @@ All effects don't start immediately, but rather get worse over time; the rate is glass_name = "glass of patron" glass_desc = "Drinking patron in the bar, with all the subpar ladies." shot_glass_icon_state = "shotglassclear" + pH = 4.5 /datum/reagent/consumable/ethanol/gintonic name = "Gin and Tonic" @@ -433,6 +454,7 @@ All effects don't start immediately, but rather get worse over time; the rate is glass_icon_state = "gintonicglass" glass_name = "Gin and Tonic" glass_desc = "A mild but still great cocktail. Drink up, like a true Englishman." + pH = 3 /datum/reagent/consumable/ethanol/rum_coke name = "Rum and Coke" @@ -445,6 +467,7 @@ All effects don't start immediately, but rather get worse over time; the rate is glass_icon_state = "whiskeycolaglass" glass_name = "Rum and Coke" glass_desc = "The classic go-to of space-fratboys." + pH = 4 /datum/reagent/consumable/ethanol/cuba_libre name = "Cuba Libre" @@ -458,6 +481,7 @@ All effects don't start immediately, but rather get worse over time; the rate is glass_name = "Cuba Libre" glass_desc = "A classic mix of rum, cola, and lime. A favorite of revolutionaries everywhere!" + /datum/reagent/consumable/ethanol/cuba_libre/on_mob_life(mob/living/carbon/M) if(M.mind && M.mind.has_antag_datum(/datum/antagonist/rev)) //Cuba Libre, the traditional drink of revolutions! Heals revolutionaries. M.adjustBruteLoss(-1, 0) @@ -504,6 +528,7 @@ All effects don't start immediately, but rather get worse over time; the rate is glass_name = "Vodka martini" glass_desc ="A bastardisation of the classic martini. Still great." + /datum/reagent/consumable/ethanol/white_russian name = "White Russian" id = "whiterussian" @@ -557,8 +582,8 @@ All effects don't start immediately, but rather get worse over time; the rate is glass_desc = "Tomato juice, mixed with Vodka and a lil' bit of lime. Tastes like liquid murder." /datum/reagent/consumable/ethanol/bloody_mary/on_mob_life(mob/living/carbon/C) - if(C.blood_volume < BLOOD_VOLUME_NORMAL) - C.blood_volume = min(BLOOD_VOLUME_NORMAL, C.blood_volume + 3) //Bloody Mary quickly restores blood loss. + if(C.blood_volume < (BLOOD_VOLUME_NORMAL*C.blood_ratio)) + C.blood_volume = min((BLOOD_VOLUME_NORMAL*C.blood_ratio), C.blood_volume + 3) //Bloody Mary quickly restores blood loss. ..() /datum/reagent/consumable/ethanol/brave_bull @@ -643,6 +668,7 @@ All effects don't start immediately, but rather get worse over time; the rate is glass_icon_state = "beepskysmashglass" glass_name = "Beepsky Smash" glass_desc = "Heavy, hot and strong. Just like the Iron fist of the LAW." + pH = 2 overdose_threshold = 40 var/datum/brain_trauma/special/beepsky/B @@ -1347,6 +1373,7 @@ All effects don't start immediately, but rather get worse over time; the rate is /datum/reagent/consumable/ethanol/neurotoxin name = "Neurotoxin" + id = "neurotoxin" description = "A strong neurotoxin that puts the subject into a death-like state." color = "#2E2E61" // rgb: 46, 46, 97 boozepwr = 50 @@ -1356,6 +1383,10 @@ All effects don't start immediately, but rather get worse over time; the rate is glass_icon_state = "neurotoxinglass" glass_name = "Neurotoxin" glass_desc = "A drink that is guaranteed to knock you silly." + //SplitChem = TRUE + impure_chem = "neuroweak" + inverse_chem_val = 0.5 //Clear conversion + inverse_chem = "neuroweak" /datum/reagent/consumable/ethanol/neurotoxin/proc/pickt() return (pick(TRAIT_PARALYSIS_L_ARM,TRAIT_PARALYSIS_R_ARM,TRAIT_PARALYSIS_R_LEG,TRAIT_PARALYSIS_L_LEG)) @@ -1363,18 +1394,18 @@ All effects don't start immediately, but rather get worse over time; the rate is /datum/reagent/consumable/ethanol/neurotoxin/on_mob_life(mob/living/carbon/M) M.set_drugginess(50) M.dizziness +=2 - M.adjustBrainLoss(1*REM, 150) - if(prob(20)) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 1*REM, 150) + if(prob(20) && !holder.has_reagent("neuroweak")) M.adjustStaminaLoss(10) M.drop_all_held_items() to_chat(M, "You cant feel your hands!") if(current_cycle > 5) - if(prob(20)) + if(prob(20) && !holder.has_reagent("neuroweak")) var/t = pickt() ADD_TRAIT(M, t, type) M.adjustStaminaLoss(10) if(current_cycle > 30) - M.adjustBrainLoss(2*REM) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 2*REM) if(current_cycle > 50 && prob(15)) if(!M.undergoing_cardiac_arrest() && M.can_heartattack()) M.set_heartattack(TRUE) @@ -1391,6 +1422,25 @@ All effects don't start immediately, but rather get worse over time; the rate is M.adjustStaminaLoss(10) ..() +/datum/reagent/consumable/ethanol/neuroweak + name = "Neuro-Smash" + id = "neuroweak" + description = "A mostly safe alcoholic drink for the true daredevils. Counteracts Neurotoxins." + boozepwr = 60 + pH = 8 + +/datum/reagent/consumable/ethanol/neuroweak/on_mob_life(mob/living/carbon/M) + if(holder.has_reagent("neurotoxin")) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, -1*REM, 150) + M.reagents.remove_reagent("neurotoxin", 1.5 * REAGENTS_METABOLISM, FALSE) + if(holder.has_reagent("fentanyl")) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, -1*REM, 150) + M.reagents.remove_reagent("fentanyl", 0.75 * REAGENTS_METABOLISM, FALSE) + else + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, -0.5*REM, 150) + M.dizziness +=2 + ..() + /datum/reagent/consumable/ethanol/hippies_delight name = "Hippie's Delight" id = "hippiesdelight" @@ -1578,6 +1628,7 @@ All effects don't start immediately, but rather get worse over time; the rate is glass_name = "Bastion Bourbon" glass_desc = "If you're feeling low, count on the buttery flavor of our own bastion bourbon." shot_glass_icon_state = "shotglassgreen" + pH = 4 /datum/reagent/consumable/ethanol/bastion_bourbon/on_mob_metabolize(mob/living/L) var/heal_points = 10 @@ -2095,6 +2146,29 @@ All effects don't start immediately, but rather get worse over time; the rate is glass_name = "Planet Cracker" glass_desc = "Although historians believe the drink was originally created to commemorate the end of an important conflict in man's past, its origins have largely been forgotten and it is today seen more as a general symbol of human supremacy." +/datum/reagent/consumable/ethanol/commander_and_chief + name = "Commander and Chief" + id = "commander_and_chief" + description = "A cocktail for the captain on the go." + color = "#ffffc9" + boozepwr = 50 + quality = DRINK_FANTASTIC + taste_description = "Tastes like...duty and responsibility?" + glass_icon_state = "commander_and_chief" + glass_name = "Commander and Chief" + glass_desc = "The gems of this majestic chalice represent the departments and their Heads." + +/datum/reagent/consumable/ethanol/commander_and_chief/on_mob_life(mob/living/carbon/M) + if(M.mind && HAS_TRAIT(M.mind, TRAIT_CAPTAIN_METABOLISM)) + M.heal_bodypart_damage(2,2,2) + M.adjustBruteLoss(-3.5,0) + M.adjustOxyLoss(-3.5,0) + M.adjustFireLoss(-3.5,0) + M.adjustToxLoss(-3.5,0) + M.radiation = max(M.radiation - 25, 0) + . = 1 + return ..() + /datum/reagent/consumable/ethanol/fruit_wine name = "Fruit Wine" id = "fruit_wine" @@ -2106,6 +2180,7 @@ All effects don't start immediately, but rather get worse over time; the rate is can_synth = FALSE var/list/names = list("null fruit" = 1) //Names of the fruits used. Associative list where name is key, value is the percentage of that fruit. var/list/tastes = list("bad coding" = 1) //List of tastes. See above. + pH = 4 /datum/reagent/consumable/ethanol/fruit_wine/on_new(list/data) names = data["names"] diff --git a/code/modules/reagents/chemistry/reagents/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drink_reagents.dm index 8aa555944a..dd51ce2bc7 100644 --- a/code/modules/reagents/chemistry/reagents/drink_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drink_reagents.dm @@ -13,6 +13,7 @@ glass_icon_state = "glass_orange" glass_name = "glass of orange juice" glass_desc = "Vitamins! Yay!" + pH = 3.3 /datum/reagent/consumable/orangejuice/on_mob_life(mob/living/carbon/M) if(M.getOxyLoss() && prob(30)) @@ -45,6 +46,7 @@ glass_icon_state = "glass_green" glass_name = "glass of lime juice" glass_desc = "A glass of sweet-sour lime juice." + pH = 2.2 /datum/reagent/consumable/limejuice/on_mob_life(mob/living/carbon/M) if(M.getToxLoss() && prob(20)) @@ -125,6 +127,7 @@ glass_icon_state = "lemonglass" glass_name = "glass of lemon juice" glass_desc = "Sour..." + pH = 2 /datum/reagent/consumable/banana name = "Banana Juice" @@ -168,6 +171,7 @@ /datum/reagent/consumable/laughter/on_mob_life(mob/living/carbon/M) M.emote("laugh") + SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "chemical_laughter", /datum/mood_event/chemical_laughter) ..() /datum/reagent/consumable/superlaughter @@ -182,6 +186,7 @@ if(prob(30)) M.visible_message("[M] bursts out into a fit of uncontrollable laughter!", "You burst out in a fit of uncontrollable laughter!") M.Stun(5) + SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "chemical_laughter", /datum/mood_event/chemical_superlaughter) ..() /datum/reagent/consumable/potato_juice @@ -881,3 +886,23 @@ to_chat(M, "[pick("Diamond skies where white deer fly.","Sipping strawberry tea.","Silver raindrops drift through timeless, Neverending June.","Crystal ... pearls free, with love!","Beaming love into me.")]") ..() . = 1 + +/datum/reagent/consumable/catnip_tea + name = "Catnip Tea" + id = "catnip_tea" + description = "A sleepy and tasty catnip tea!" + color = "#101000" // rgb: 16, 16, 0 + nutriment_factor = 0 + taste_description = "sugar and catnip" + glass_icon_state = "teaglass" + glass_name = "glass of catnip tea" + glass_desc = "A purrfect drink for a cat." + +/datum/reagent/consumable/catnip_tea/on_mob_life(mob/living/carbon/M) + M.adjustStaminaLoss(min(50 - M.getStaminaLoss(), 3)) + if(prob(20)) + M.emote("nya") + if(prob(20)) + to_chat(M, "[pick("Headpats feel nice.", "Backrubs would be nice.", "Mew")]") + M.adjustArousalLoss(5) + ..() diff --git a/code/modules/reagents/chemistry/reagents/drug_reagents.dm b/code/modules/reagents/chemistry/reagents/drug_reagents.dm index a4586dd997..f3df72cd4d 100644 --- a/code/modules/reagents/chemistry/reagents/drug_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drug_reagents.dm @@ -15,6 +15,7 @@ description = "An illegal chemical compound used as drug." color = "#60A584" // rgb: 96, 165, 132 overdose_threshold = 30 + pH = 9 /datum/reagent/drug/space_drugs/on_mob_life(mob/living/carbon/M) M.set_drugginess(15) @@ -44,6 +45,7 @@ addiction_threshold = 30 taste_description = "smoke" trippy = FALSE + pH = 8 /datum/reagent/drug/nicotine/on_mob_life(mob/living/carbon/M) if(prob(1)) @@ -65,6 +67,7 @@ color = "#FA00C8" overdose_threshold = 20 addiction_threshold = 10 + pH = 10 /datum/reagent/drug/crank/on_mob_life(mob/living/carbon/M) if(prob(5)) @@ -77,14 +80,14 @@ . = 1 /datum/reagent/drug/crank/overdose_process(mob/living/M) - M.adjustBrainLoss(2*REM) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 2*REM) M.adjustToxLoss(2*REM, 0) M.adjustBruteLoss(2*REM, 0) ..() . = 1 /datum/reagent/drug/crank/addiction_act_stage1(mob/living/M) - M.adjustBrainLoss(5*REM) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 5*REM) ..() /datum/reagent/drug/crank/addiction_act_stage2(mob/living/M) @@ -98,7 +101,7 @@ . = 1 /datum/reagent/drug/crank/addiction_act_stage4(mob/living/M) - M.adjustBrainLoss(3*REM) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 3*REM) M.adjustToxLoss(5*REM, 0) M.adjustBruteLoss(5*REM, 0) ..() @@ -112,6 +115,7 @@ color = "#0064B4" overdose_threshold = 20 addiction_threshold = 15 + pH = 9 /datum/reagent/drug/krokodil/on_mob_life(mob/living/carbon/M) @@ -121,13 +125,13 @@ ..() /datum/reagent/drug/krokodil/overdose_process(mob/living/M) - M.adjustBrainLoss(0.25*REM) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 0.25*REM) M.adjustToxLoss(0.25*REM, 0) ..() . = 1 /datum/reagent/drug/krokodil/addiction_act_stage1(mob/living/M) - M.adjustBrainLoss(2*REM) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 2*REM) M.adjustToxLoss(2*REM, 0) ..() . = 1 @@ -167,6 +171,7 @@ var/brain_damage = TRUE var/jitter = TRUE var/confusion = TRUE + pH = 5 /datum/reagent/drug/methamphetamine/on_mob_metabolize(mob/living/L) ..() @@ -187,7 +192,7 @@ if(jitter) M.Jitter(2) if(brain_damage) - M.adjustBrainLoss(rand(1,4)) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, rand(1,4)) M.heal_overall_damage(2, 2) if(prob(5)) M.emote(pick("twitch", "shiver")) @@ -205,7 +210,7 @@ M.drop_all_held_items() ..() M.adjustToxLoss(1, 0) - M.adjustBrainLoss(pick(0.5, 0.6, 0.7, 0.8, 0.9, 1)) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, pick(0.5, 0.6, 0.7, 0.8, 0.9, 1)) . = 1 /datum/reagent/drug/methamphetamine/addiction_act_stage1(mob/living/M) @@ -261,6 +266,7 @@ addiction_threshold = 10 taste_description = "salt" // because they're bathsalts? var/datum/brain_trauma/special/psychotic_brawling/bath_salts/rage + pH = 8.2 /datum/reagent/drug/bath_salts/on_mob_metabolize(mob/living/L) ..() @@ -283,7 +289,7 @@ if(prob(5)) to_chat(M, "[high_message]") M.adjustStaminaLoss(-5, 0) - M.adjustBrainLoss(4) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 4) M.hallucination += 5 if(M.canmove && !ismovableatom(M.loc)) step(M, pick(GLOB.cardinals)) @@ -308,7 +314,7 @@ for(var/i = 0, i < 8, i++) step(M, pick(GLOB.cardinals)) M.Jitter(5) - M.adjustBrainLoss(10) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 10) if(prob(20)) M.emote(pick("twitch","drool","moan")) ..() @@ -320,7 +326,7 @@ step(M, pick(GLOB.cardinals)) M.Jitter(10) M.Dizzy(10) - M.adjustBrainLoss(10) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 10) if(prob(30)) M.emote(pick("twitch","drool","moan")) ..() @@ -332,7 +338,7 @@ step(M, pick(GLOB.cardinals)) M.Jitter(15) M.Dizzy(15) - M.adjustBrainLoss(10) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 10) if(prob(40)) M.emote(pick("twitch","drool","moan")) ..() @@ -345,7 +351,7 @@ M.Jitter(50) M.Dizzy(50) M.adjustToxLoss(5, 0) - M.adjustBrainLoss(10) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 10) if(prob(50)) M.emote(pick("twitch","drool","moan")) ..() @@ -357,6 +363,7 @@ description = "Amps you up and gets you going, fixes all stamina damage you might have but can cause toxin and oxygen damage." reagent_state = LIQUID color = "#78FFF0" + pH = 9.2 /datum/reagent/drug/aranesp/on_mob_life(mob/living/carbon/M) var/high_message = pick("You feel amped up.", "You feel ready.", "You feel like you can push it to the limit.") @@ -370,6 +377,84 @@ ..() . = 1 +/datum/reagent/drug/happiness + name = "Happiness" + id = "happiness" + description = "Fills you with ecstasic numbness and causes minor brain damage. Highly addictive. If overdosed causes sudden mood swings." + reagent_state = LIQUID + color = "#FFF378" + addiction_threshold = 10 + overdose_threshold = 20 + pH = 10.5 + +/datum/reagent/drug/happiness/on_mob_add(mob/living/L) + ..() + ADD_TRAIT(L, TRAIT_FEARLESS, id) + SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "happiness_drug", /datum/mood_event/happiness_drug) + +/datum/reagent/drug/happiness/on_mob_delete(mob/living/L) + REMOVE_TRAIT(L, TRAIT_FEARLESS, id) + SEND_SIGNAL(L, COMSIG_CLEAR_MOOD_EVENT, "happiness_drug") + ..() + +/datum/reagent/drug/happiness/on_mob_life(mob/living/carbon/M) + M.jitteriness = 0 + M.confused = 0 + M.disgust = 0 + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 0.2) + ..() + . = 1 + +/datum/reagent/drug/happiness/overdose_process(mob/living/M) + if(prob(30)) + var/reaction = rand(1,3) + switch(reaction) + if(1) + M.emote("laugh") + SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "happiness_drug", /datum/mood_event/happiness_drug_good_od) + if(2) + M.emote("sway") + M.Dizzy(25) + if(3) + M.emote("frown") + SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "happiness_drug", /datum/mood_event/happiness_drug_bad_od) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 0.5) + ..() + . = 1 + +/datum/reagent/drug/happiness/addiction_act_stage1(mob/living/M)// all work and no play makes jack a dull boy + GET_COMPONENT_FROM(mood, /datum/component/mood, M) + mood.setSanity(min(mood.sanity, SANITY_DISTURBED)) + M.Jitter(5) + if(prob(20)) + M.emote(pick("twitch","laugh","frown")) + ..() + +/datum/reagent/drug/happiness/addiction_act_stage2(mob/living/M) + GET_COMPONENT_FROM(mood, /datum/component/mood, M) + mood.setSanity(min(mood.sanity, SANITY_UNSTABLE)) + M.Jitter(10) + if(prob(30)) + M.emote(pick("twitch","laugh","frown")) + ..() + +/datum/reagent/drug/happiness/addiction_act_stage3(mob/living/M) + GET_COMPONENT_FROM(mood, /datum/component/mood, M) + mood.setSanity(min(mood.sanity, SANITY_CRAZY)) + M.Jitter(15) + if(prob(40)) + M.emote(pick("twitch","laugh","frown")) + ..() + +/datum/reagent/drug/happiness/addiction_act_stage4(mob/living/carbon/human/M) + GET_COMPONENT_FROM(mood, /datum/component/mood, M) + mood.setSanity(SANITY_INSANE) + M.Jitter(20) + if(prob(50)) + M.emote(pick("twitch","laugh","frown")) + ..() + . = 1 + /datum/reagent/drug/skooma name = "Skooma" id = "skooma" @@ -380,6 +465,7 @@ addiction_threshold = 1 addiction_stage3_end = 40 addiction_stage4_end = 240 + pH = 12.5 /datum/reagent/drug/skooma/on_mob_metabolize(mob/living/L) . = ..() @@ -404,7 +490,7 @@ H.dna.species.punchdamagehigh *= 0.2 /datum/reagent/drug/skooma/on_mob_life(mob/living/carbon/M) - M.adjustBrainLoss(1*REM) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 1*REM) M.adjustToxLoss(1*REM) if(prob(10)) M.adjust_blurriness(2) @@ -436,8 +522,7 @@ M.Dizzy(50) M.adjust_blurriness(10) if(prob(50)) //This proc will be called about 200 times and the adjustbrainloss() below only has to be called 40 times to kill. This will make surviving skooma addiction pretty rare without mannitol usage. - M.adjustBrainLoss(5) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 5) if(prob(40)) M.emote(pick("twitch","drool","moan")) ..() - diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm index 4a835d0839..056c5b1901 100644 --- a/code/modules/reagents/chemistry/reagents/food_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm @@ -191,6 +191,13 @@ color = "#731008" // rgb: 115, 16, 8 taste_description = "ketchup" +/datum/reagent/consumable/mustard + name = "Mustard" + id = "mustard" + description = "Mustard, mostly used on hotdogs, corndogs and burgers." + nutriment_factor = 5 * REAGENTS_METABOLISM + color = "#DDED26" // rgb: 221, 237, 38 + taste_description = "mustard" /datum/reagent/consumable/capsaicin name = "Capsaicin Oil" @@ -230,6 +237,7 @@ description = "A special oil that noticably chills the body. Extracted from Icepeppers and slimes." color = "#8BA6E9" // rgb: 139, 166, 233 taste_description = "mint" + pH = 13 //HMM! I wonder /datum/reagent/consumable/frostoil/on_mob_life(mob/living/carbon/M) var/cooling = 0 @@ -275,6 +283,7 @@ description = "A chemical agent used for self-defense and in police work." color = "#B31008" // rgb: 179, 16, 8 taste_description = "scorching agony" + pH = 7.4 /datum/reagent/consumable/condensedcapsaicin/reaction_mob(mob/living/M, method=TOUCH, reac_volume) if(!ishuman(M) && !ismonkey(M)) @@ -402,6 +411,7 @@ color = "#E700E7" // rgb: 231, 0, 231 metabolization_rate = 0.2 * REAGENTS_METABOLISM taste_description = "mushroom" + pH = 11 /datum/reagent/drug/mushroomhallucinogen/on_mob_life(mob/living/carbon/M) M.slurring = max(M.slurring,50) @@ -618,6 +628,7 @@ description = "A blinding substance extracted from certain onions." color = "#c0c9a0" taste_description = "bitterness" + pH = 5 /datum/reagent/consumable/tearjuice/reaction_mob(mob/living/M, method=TOUCH, reac_volume) if(!istype(M)) @@ -672,6 +683,7 @@ description = "An ichor, derived from a certain mushroom, makes for a bad time." color = "#1d043d" taste_description = "bitter mushroom" + pH = 12 /datum/reagent/consumable/entpoly/on_mob_life(mob/living/carbon/M) if(current_cycle >= 10) @@ -679,7 +691,7 @@ . = 1 if(prob(20)) M.losebreath += 4 - M.adjustBrainLoss(2*REM, 150) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 2*REM, 150) M.adjustToxLoss(3*REM,0) M.adjustStaminaLoss(10*REM,0) M.blur_eyes(5) @@ -692,6 +704,7 @@ description = "A stimulating ichor which causes luminescent fungi to grow on the skin. " color = "#b5a213" taste_description = "tingling mushroom" + pH = 11.2 /datum/reagent/consumable/tinlux/reaction_mob(mob/living/M) M.set_light(2) @@ -706,6 +719,7 @@ color = "#d3a308" nutriment_factor = 3 * REAGENTS_METABOLISM taste_description = "fruity mushroom" + pH = 10.4 /datum/reagent/consumable/vitfro/on_mob_life(mob/living/carbon/M) if(prob(80)) @@ -721,6 +735,7 @@ nutriment_factor = 5 * REAGENTS_METABOLISM color = "#eef442" // rgb: 238, 244, 66 taste_description = "mournful honking" + pH = 9.2 /datum/reagent/consumable/astrotame name = "Astrotame" @@ -750,3 +765,4 @@ quality = FOOD_AMAZING taste_mult = 100 can_synth = FALSE + pH = 6.1 diff --git a/code/modules/reagents/chemistry/reagents/impure_reagents.dm b/code/modules/reagents/chemistry/reagents/impure_reagents.dm new file mode 100644 index 0000000000..c96347cda2 --- /dev/null +++ b/code/modules/reagents/chemistry/reagents/impure_reagents.dm @@ -0,0 +1,26 @@ +//Reagents produced by metabolising/reacting fermichems inoptimally, i.e. inverse_chems or impure_chems +//Inverse = Splitting +//Invert = Whole conversion + +/datum/reagent/impure + chemical_flags = REAGENT_INVISIBLE | REAGENT_SNEAKYNAME //by default, it will stay hidden on splitting, but take the name of the source on inverting + + +/datum/reagent/impure/fermiTox + name = "Chemical Isomers" + id = "fermiTox" + description = "Toxic chemical isomers made from impure reactions. At low volumes will cause light toxin damage, but as the volume increases, it deals larger amounts, damages the liver, then eventually the heart. This is default impure chem for all chems, and changes only if stated." + data = "merge" + color = "FFFFFF" + can_synth = FALSE + var/potency = 1 //potency multiplies the volume when added. + + +//I'm concerned this is too weak, but I also don't want deathmixes. +//TODO: liver damage, 100+ heart +/datum/reagent/impure/fermiTox/on_mob_life(mob/living/carbon/C, method) + if(C.dna && istype(C.dna.species, /datum/species/jelly)) + C.adjustToxLoss(-2) + else + C.adjustToxLoss(2) + ..() diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm index fe70db250d..775308589f 100644 --- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm @@ -18,6 +18,7 @@ name = "Leporazine" id = "leporazine" description = "Leporazine will effectively regulate a patient's body temperature, ensuring it never leaves safe levels." + pH = 8.4 color = "#82b8aa" /datum/reagent/medicine/leporazine/on_mob_life(mob/living/carbon/M) @@ -43,7 +44,7 @@ M.heal_bodypart_damage(5,5) M.adjustToxLoss(-5, 0, TRUE) M.hallucination = 0 - M.setBrainLoss(0) + M.setOrganLoss(ORGAN_SLOT_BRAIN, 0) REMOVE_TRAITS_NOT_IN(M, list(SPECIES_TRAIT, ROUNDSTART_TRAIT, ORGAN_TRAIT)) M.set_blurriness(0) M.set_blindness(0) @@ -60,6 +61,13 @@ M.SetSleeping(0, 0) M.jitteriness = 0 M.cure_all_traumas(TRAUMA_RESILIENCE_MAGIC) + if(M.blood_volume < (BLOOD_VOLUME_NORMAL*M.blood_ratio)) + M.blood_volume = (BLOOD_VOLUME_NORMAL*M.blood_ratio) + + for(var/organ in M.internal_organs) + var/obj/item/organ/O = organ + O.setOrganDamage(0) + for(var/thing in M.diseases) var/datum/disease/D = thing if(D.severity == DISEASE_SEVERITY_POSITIVE) @@ -79,6 +87,7 @@ id = "synaptizine" description = "Increases resistance to stuns as well as reducing drowsiness and hallucinations." color = "#FF00FF" + pH = 4 /datum/reagent/medicine/synaptizine/on_mob_life(mob/living/carbon/M) M.drowsyness = max(M.drowsyness-5, 0) @@ -98,6 +107,7 @@ id = "synaphydramine" description = "Reduces drowsiness, hallucinations, and Histamine from body." color = "#EC536D" // rgb: 236, 83, 109 + pH = 5.2 /datum/reagent/medicine/synaphydramine/on_mob_life(mob/living/carbon/M) M.drowsyness = max(M.drowsyness-5, 0) @@ -116,6 +126,7 @@ id = "inacusiate" description = "Instantly restores all hearing to the patient, but does not cure deafness." color = "#6600FF" // rgb: 100, 165, 255 + pH = 2 /datum/reagent/medicine/inacusiate/on_mob_life(mob/living/carbon/M) M.restoreEars() @@ -127,6 +138,7 @@ description = "A chemical mixture with almost magical healing powers. Its main limitation is that the patient's body temperature must be under 270K for it to metabolise correctly." color = "#0000C8" taste_description = "sludge" + pH = 11 /datum/reagent/medicine/cryoxadone/on_mob_life(mob/living/carbon/M) var/power = -0.00003 * (M.bodytemperature ** 2) + 3 @@ -148,6 +160,7 @@ color = "#0000C8" taste_description = "muscle" metabolization_rate = 1.5 * REAGENTS_METABOLISM + pH = 13 /datum/reagent/medicine/clonexadone/on_mob_life(mob/living/carbon/M) if(M.bodytemperature < T0C) @@ -163,6 +176,7 @@ description = "A mixture of cryoxadone and slime jelly, that apparently inverses the requirement for its activation." color = "#f7832a" taste_description = "spicy jelly" + pH = 12 /datum/reagent/medicine/pyroxadone/on_mob_life(mob/living/carbon/M) if(M.bodytemperature > BODYTEMP_HEAT_DAMAGE_LIMIT) @@ -194,6 +208,7 @@ color = "#669900" // rgb: 102, 153, 0 overdose_threshold = 30 taste_description = "fish" + pH = 12.2 /datum/reagent/medicine/rezadone/on_mob_life(mob/living/carbon/M) M.setCloneLoss(0) //Rezadone is almost never used in favor of cryoxadone. Hopefully this will change that. @@ -215,14 +230,18 @@ description = "Spaceacillin will prevent a patient from conventionally spreading any diseases they are currently infected with." color = "#f2f2f2" metabolization_rate = 0.1 * REAGENTS_METABOLISM + pH = 8.1 //Goon Chems. Ported mainly from Goonstation. Easily mixable (or not so easily) and provide a variety of effects. /datum/reagent/medicine/silver_sulfadiazine name = "Silver Sulfadiazine" id = "silver_sulfadiazine" - description = "If used in touch-based applications, immediately restores burn wounds as well as restoring more over time. If ingested through other means, deals minor toxin damage." + description = "If used in touch-based applications, immediately restores burn wounds as well as restoring more over time. It is mildly poisonous taken orally or by injection. If overdosed, deals brute and minor liver damage." reagent_state = LIQUID + pH = 7.2 color = "#ffeac9" + metabolization_rate = 5 * REAGENTS_METABOLISM + overdose_threshold = 50 /datum/reagent/medicine/silver_sulfadiazine/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message = 1) if(iscarbon(M) && M.stat != DEAD) @@ -235,6 +254,7 @@ if(show_message) to_chat(M, "You feel your burns healing! It stings like hell!") M.emote("scream") + SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "painful_medicine", /datum/mood_event/painful_medicine) ..() /datum/reagent/medicine/silver_sulfadiazine/on_mob_life(mob/living/carbon/M) @@ -242,6 +262,15 @@ ..() . = 1 +/datum/reagent/medicine/silver_sulfadiazine/overdose_start(mob/living/M) + metabolization_rate = 15 * REAGENTS_METABOLISM + M.adjustBruteLoss(2*REM, 0) + if(iscarbon(M)) + var/mob/living/carbon/C = M + C.applyLiverDamage(1) + ..() + . = 1 + /datum/reagent/medicine/oxandrolone name = "Oxandrolone" id = "oxandrolone" @@ -250,9 +279,10 @@ color = "#f7ffa5" metabolization_rate = 0.5 * REAGENTS_METABOLISM overdose_threshold = 25 + pH = 10.7 /datum/reagent/medicine/oxandrolone/on_mob_life(mob/living/carbon/M) - if(M.getFireLoss() > 50) + if(M.getFireLoss() > 25) M.adjustFireLoss(-4*REM, 0) //Twice as effective as silver sulfadiazine for severe burns else M.adjustFireLoss(-0.5*REM, 0) //But only a quarter as effective for more minor ones @@ -268,9 +298,12 @@ /datum/reagent/medicine/styptic_powder name = "Styptic Powder" id = "styptic_powder" - description = "If used in touch-based applications, immediately restores bruising as well as restoring more over time. If ingested through other means, deals minor toxin damage." + description = "If used in touch-based applications, immediately restores bruising as well as restoring more over time. It is poisonous if taken orally or by injection. If overdosed, deals brute and minor liver damage." reagent_state = LIQUID color = "#FF9696" + pH = 6.7 + metabolization_rate = 5 * REAGENTS_METABOLISM + overdose_threshold = 50 /datum/reagent/medicine/styptic_powder/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message = 1) if(iscarbon(M) && M.stat != DEAD) @@ -283,6 +316,7 @@ if(show_message) to_chat(M, "You feel your bruises healing! It stings like hell!") M.emote("scream") + SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "painful_medicine", /datum/mood_event/painful_medicine) ..() @@ -291,6 +325,15 @@ ..() . = 1 +datum/reagent/medicine/styptic_powder/overdose_start(mob/living/M) + metabolization_rate = 15 * REAGENTS_METABOLISM + M.adjustBruteLoss(2*REM, 0) + if(iscarbon(M)) + var/mob/living/carbon/C = M + C.applyLiverDamage(1) + ..() + . = 1 + /datum/reagent/medicine/salglu_solution name = "Saline-Glucose Solution" id = "salglu_solution" @@ -302,6 +345,7 @@ taste_description = "sweetness and salt" var/last_added = 0 var/maximum_reachable = BLOOD_VOLUME_NORMAL - 10 //So that normal blood regeneration can continue with salglu active + pH = 5.5 /datum/reagent/medicine/salglu_solution/on_mob_life(mob/living/carbon/M) if(last_added) @@ -340,6 +384,7 @@ reagent_state = LIQUID color = "#6D6374" metabolization_rate = 0.4 * REAGENTS_METABOLISM + pH = 2.6 /datum/reagent/medicine/mine_salve/on_mob_life(mob/living/carbon/C) C.hal_screwyhud = SCREWYHUD_HEALTHY @@ -375,21 +420,35 @@ /datum/reagent/medicine/synthflesh name = "Synthflesh" id = "synthflesh" - description = "Has a 100% chance of instantly healing brute and burn damage. One unit of the chemical will heal one point of damage. Touch application only." + description = "Has a 100% chance of healing large amounts of brute and burn damage very quickly. One unit of the chemical will heal one point of damage. Touch application only." reagent_state = LIQUID color = "#FFEBEB" + pH = 11.5 + metabolization_rate = 5 * REAGENTS_METABOLISM + overdose_threshold = 40 /datum/reagent/medicine/synthflesh/reaction_mob(mob/living/M, method=TOUCH, reac_volume,show_message = 1) if(iscarbon(M)) if (M.stat == DEAD) show_message = 0 - if(method in list(PATCH, TOUCH)) - M.adjustBruteLoss(-1.25 * reac_volume) - M.adjustFireLoss(-1.25 * reac_volume) + if(method in list(INGEST, VAPOR)) + var/mob/living/carbon/C = M + C.losebreath++ + C.emote("cough") + to_chat(M, "You feel your throat closing up!") + else if(method == INJECT) + return + else if(method in list(PATCH, TOUCH)) + M.adjustBruteLoss(-1 * reac_volume) + M.adjustFireLoss(-1 * reac_volume) if(show_message) to_chat(M, "You feel your burns and bruises healing! It stings like hell!") + SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "painful_medicine", /datum/mood_event/painful_medicine) ..() +/datum/reagent/medicine/synthflesh/overdose_start(mob/living/M) + metabolization_rate = 15 * REAGENTS_METABOLISM + /datum/reagent/medicine/charcoal name = "Charcoal" id = "charcoal" @@ -398,6 +457,7 @@ color = "#000000" metabolization_rate = 0.5 * REAGENTS_METABOLISM taste_description = "ash" + pH = 5 /datum/reagent/medicine/charcoal/on_mob_life(mob/living/carbon/M) M.adjustToxLoss(-2*REM, 0) @@ -415,6 +475,7 @@ color = "#DCDCDC" metabolization_rate = 0.25 * REAGENTS_METABOLISM overdose_threshold = 30 + pH = 2 /datum/reagent/medicine/omnizine/on_mob_life(mob/living/carbon/M) M.adjustToxLoss(-0.5*REM, 0) @@ -440,6 +501,7 @@ color = "#19C832" metabolization_rate = 0.5 * REAGENTS_METABOLISM taste_description = "acid" + pH = 1.5 /datum/reagent/medicine/calomel/on_mob_life(mob/living/carbon/M) for(var/datum/reagent/R in M.reagents.reagent_list) @@ -457,6 +519,7 @@ reagent_state = LIQUID color = "#14FF3C" metabolization_rate = 2 * REAGENTS_METABOLISM + pH = 12 //It's a reducing agent /datum/reagent/medicine/potass_iodide/on_mob_life(mob/living/carbon/M) if(M.radiation > 0) @@ -470,6 +533,7 @@ reagent_state = LIQUID color = "#003153" // RGB 0, 49, 83 metabolization_rate = 0.5 * REAGENTS_METABOLISM + pH = 8.9 /datum/reagent/medicine/prussian_blue/on_mob_life(mob/living/carbon/M) if(M.radiation > 0) @@ -483,6 +547,7 @@ reagent_state = LIQUID color = "#E6FFF0" metabolization_rate = 0.5 * REAGENTS_METABOLISM + pH = 1 //One of the best buffers, NEVERMIND! var/healtoxinlover = FALSE /datum/reagent/medicine/pen_acid/on_mob_life(mob/living/carbon/M) @@ -500,6 +565,7 @@ description = "Reduces massive amounts of radiation and toxin damage while purging other chemicals from the body. Slimepeople friendly!" color = "#91D865" healtoxinlover = TRUE + pH = 12//invert /datum/reagent/medicine/sal_acid name = "Salicyclic Acid" @@ -509,10 +575,11 @@ color = "#D2D2D2" metabolization_rate = 0.5 * REAGENTS_METABOLISM overdose_threshold = 25 + pH = 2.1 /datum/reagent/medicine/sal_acid/on_mob_life(mob/living/carbon/M) - if(M.getBruteLoss() > 50) + if(M.getBruteLoss() > 25) M.adjustBruteLoss(-4*REM, 0) //Twice as effective as styptic powder for severe bruising else M.adjustBruteLoss(-0.5*REM, 0) //But only a quarter as effective for more minor ones @@ -532,6 +599,7 @@ reagent_state = LIQUID color = "#00FFFF" metabolization_rate = 0.25 * REAGENTS_METABOLISM + pH = 2 /datum/reagent/medicine/salbutamol/on_mob_life(mob/living/carbon/M) M.adjustOxyLoss(-3*REM, 0) @@ -547,6 +615,7 @@ reagent_state = LIQUID color = "#FF6464" metabolization_rate = 0.25 * REAGENTS_METABOLISM + pH = 11 /datum/reagent/medicine/perfluorodecalin/on_mob_life(mob/living/carbon/human/M) M.adjustOxyLoss(-12*REM, 0) @@ -566,6 +635,7 @@ metabolization_rate = 0.5 * REAGENTS_METABOLISM overdose_threshold = 45 addiction_threshold = 30 + pH = 12 /datum/reagent/medicine/ephedrine/on_mob_life(mob/living/carbon/M) M.AdjustStun(-20, 0) @@ -620,6 +690,7 @@ reagent_state = LIQUID color = "#64FFE6" metabolization_rate = 0.5 * REAGENTS_METABOLISM + pH = 11.5 /datum/reagent/medicine/diphenhydramine/on_mob_life(mob/living/carbon/M) if(prob(10)) @@ -637,6 +708,7 @@ metabolization_rate = 0.5 * REAGENTS_METABOLISM overdose_threshold = 30 addiction_threshold = 25 + pH = 8.96 /datum/reagent/medicine/morphine/on_mob_metabolize(mob/living/L) ..() @@ -705,6 +777,7 @@ color = "#FFFFFF" metabolization_rate = 0.25 * REAGENTS_METABOLISM taste_description = "dull toxin" + pH = 10 /datum/reagent/medicine/oculine/on_mob_life(mob/living/carbon/M) var/obj/item/organ/eyes/eyes = M.getorganslot(ORGAN_SLOT_EYES) @@ -736,6 +809,7 @@ color = "#000000" metabolization_rate = 0.25 * REAGENTS_METABOLISM overdose_threshold = 35 + pH = 12 /datum/reagent/medicine/atropine/on_mob_life(mob/living/carbon/M) if(M.health < 0) @@ -765,6 +839,7 @@ color = "#D2FFFA" metabolization_rate = 0.25 * REAGENTS_METABOLISM overdose_threshold = 30 + pH = 10.2 /datum/reagent/medicine/epinephrine/on_mob_life(mob/living/carbon/M) if(M.health < 0) @@ -801,6 +876,7 @@ color = "#A0E85E" metabolization_rate = 0.5 * REAGENTS_METABOLISM taste_description = "magnets" + pH = 0 /datum/reagent/medicine/strange_reagent/reaction_mob(mob/living/carbon/human/M, method=TOUCH, reac_volume) if(M.stat == DEAD) @@ -814,10 +890,16 @@ if(M.notify_ghost_cloning(source = M)) spawn (100) //so the ghost has time to re-enter return + else M.adjustOxyLoss(-20, 0) M.adjustToxLoss(-20, 0) + var/mob/living/carbon/H = M + for(var/organ in H.internal_organs) + var/obj/item/organ/O = organ + O.setOrganDamage(0) M.updatehealth() + if(M.revive()) M.emote("gasp") log_combat(M, M, "revived", src) @@ -834,19 +916,34 @@ id = "mannitol" description = "Efficiently restores brain damage." color = "#DCDCFF" + pH = 10.4 /datum/reagent/medicine/mannitol/on_mob_life(mob/living/carbon/C) - C.adjustBrainLoss(-2*REM) + C.adjustOrganLoss(ORGAN_SLOT_BRAIN, -2*REM) if(prob(10)) C.cure_trauma_type(resilience = TRAUMA_RESILIENCE_BASIC) ..() +/datum/reagent/medicine/neurine + name = "Neurine" + id = "neurine" + description = "Reacts with neural tissue, helping reform damaged connections. Can cure minor traumas." + color = "#EEFF8F" + +/datum/reagent/medicine/neurine/on_mob_life(mob/living/carbon/C) + if(holder.has_reagent("neurotoxin")) + holder.remove_reagent("neurotoxin", 5) + if(prob(15)) + C.cure_trauma_type(resilience = TRAUMA_RESILIENCE_BASIC) + ..() + /datum/reagent/medicine/mutadone name = "Mutadone" id = "mutadone" description = "Removes jitteriness and restores genetic defects." color = "#5096C8" taste_description = "acid" + pH = 2 /datum/reagent/medicine/mutadone/on_mob_life(mob/living/carbon/M) M.jitteriness = 0 @@ -861,6 +958,7 @@ description = "Purges alcoholic substance from the patient's body and eliminates its side effects." color = "#00B4C8" taste_description = "raw egg" + pH = 4 /datum/reagent/medicine/antihol/on_mob_life(mob/living/carbon/M) M.dizziness = 0 @@ -882,6 +980,7 @@ color = "#78008C" metabolization_rate = 0.5 * REAGENTS_METABOLISM overdose_threshold = 60 + pH = 8.7 /datum/reagent/medicine/stimulants/on_mob_metabolize(mob/living/L) ..() @@ -919,6 +1018,7 @@ reagent_state = LIQUID color = "#FFFFF0" metabolization_rate = 0.5 * REAGENTS_METABOLISM + pH = 6.7 /datum/reagent/medicine/insulin/on_mob_life(mob/living/carbon/M) if(M.AdjustSleeping(-20, FALSE)) @@ -934,6 +1034,7 @@ reagent_state = LIQUID color = "#fc2626" overdose_threshold = 30 + pH = 5 /datum/reagent/medicine/bicaridine/on_mob_life(mob/living/carbon/M) M.adjustBruteLoss(-2*REM, 0) @@ -952,6 +1053,7 @@ reagent_state = LIQUID color = "#13d2f0" overdose_threshold = 30 + pH = 9.7 /datum/reagent/medicine/dexalin/on_mob_life(mob/living/carbon/M) M.adjustOxyLoss(-2*REM, 0) @@ -970,6 +1072,7 @@ reagent_state = LIQUID color = "#ffc400" overdose_threshold = 30 + pH = 9 /datum/reagent/medicine/kelotane/on_mob_life(mob/living/carbon/M) M.adjustFireLoss(-2*REM, 0) @@ -989,6 +1092,7 @@ color = "#6aff00" overdose_threshold = 30 taste_description = "a roll of gauze" + pH = 10 /datum/reagent/medicine/antitoxin/on_mob_life(mob/living/carbon/M) M.adjustToxLoss(-2*REM, 0) @@ -1007,6 +1111,7 @@ id = "inaprovaline" description = "Stabilizes the breathing of patients. Good for those in critical condition." reagent_state = LIQUID + pH = 8.5 color = "#5dc1f0" /datum/reagent/medicine/inaprovaline/on_mob_life(mob/living/carbon/M) @@ -1062,27 +1167,29 @@ description = "Miniature medical robots that swiftly restore bodily damage." reagent_state = SOLID color = "#555555" + pH = 11 /datum/reagent/medicine/syndicate_nanites/on_mob_life(mob/living/carbon/M) M.adjustBruteLoss(-5*REM, 0) //A ton of healing - this is a 50 telecrystal investment. M.adjustFireLoss(-5*REM, 0) M.adjustOxyLoss(-15, 0) M.adjustToxLoss(-5*REM, 0) - M.adjustBrainLoss(-15*REM) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, -15*REM) M.adjustCloneLoss(-3*REM, 0) M.adjustStaminaLoss(-20*REM,0) ..() . = 1 /datum/reagent/medicine/neo_jelly - name = "Neo Jelly" - id = "neo_jelly" - description = "Gradually regenerates all types of damage, without harming slime anatomy.Can OD" - reagent_state = LIQUID - metabolization_rate = 1 * REAGENTS_METABOLISM - color = "#91D865" - overdose_threshold = 30 - taste_description = "jelly" + name = "Neo Jelly" + id = "neo_jelly" + description = "Gradually regenerates all types of damage, without harming slime anatomy.Can OD" + reagent_state = LIQUID + metabolization_rate = 1 * REAGENTS_METABOLISM + color = "#91D865" + overdose_threshold = 30 + taste_description = "jelly" + pH = 11.8 /datum/reagent/medicine/neo_jelly/on_mob_life(mob/living/carbon/M) M.adjustBruteLoss(-1.5*REM, 0) @@ -1105,15 +1212,16 @@ description = "Ichor from an extremely powerful plant. Great for restoring wounds, but it's a little heavy on the brain." color = rgb(255, 175, 0) overdose_threshold = 25 + pH = 11 /datum/reagent/medicine/earthsblood/on_mob_life(mob/living/carbon/M) M.adjustBruteLoss(-3 * REM, 0) M.adjustFireLoss(-3 * REM, 0) M.adjustOxyLoss(-15 * REM, 0) M.adjustToxLoss(-3 * REM, 0, TRUE) //Heals TOXINLOVERS - M.adjustBrainLoss(2 * REM, 150) //This does, after all, come from ambrosia, and the most powerful ambrosia in existence, at that! + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 2 * REM, 150) //This does, after all, come from ambrosia, and the most powerful ambrosia in existence, at that! M.adjustCloneLoss(-1 * REM, 0) - M.adjustStaminaLoss(-30 * REM, 0) + M.adjustStaminaLoss(-13 * REM, 0) M.jitteriness = min(max(0, M.jitteriness + 3), 30) M.druggy = min(max(0, M.druggy + 10), 15) //See above ..() @@ -1132,6 +1240,7 @@ reagent_state = LIQUID color = "#27870a" metabolization_rate = 0.4 * REAGENTS_METABOLISM + pH = 4.3 /datum/reagent/medicine/haloperidol/on_mob_life(mob/living/carbon/M) for(var/datum/reagent/drug/R in M.reagents.reagent_list) @@ -1142,7 +1251,7 @@ if (M.hallucination >= 5) M.hallucination -= 5 if(prob(20)) - M.adjustBrainLoss(1*REM, 50) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 1*REM, 50) M.adjustStaminaLoss(2.5*REM, 0) ..() return TRUE @@ -1154,6 +1263,7 @@ color = "#a1a1a1" overdose_threshold = 3 //To prevent people stacking massive amounts of a very strong healing reagent can_synth = FALSE + pH = 14 /datum/reagent/medicine/lavaland_extract/on_mob_life(mob/living/carbon/M) M.heal_bodypart_damage(5,5) @@ -1217,13 +1327,16 @@ description = "A medication used to treat pain, fever, and inflammation, along with heart attacks." color = "#F5F5F5" self_consuming = TRUE + pH = 12.5 /datum/reagent/medicine/corazone/on_mob_metabolize(mob/living/M) ..() - ADD_TRAIT(M, TRAIT_STABLEHEART, id) + ADD_TRAIT(M, TRAIT_STABLEHEART, type) + ADD_TRAIT(M, TRAIT_STABLELIVER, type) /datum/reagent/medicine/corazone/on_mob_end_metabolize(mob/living/M) - REMOVE_TRAIT(M, TRAIT_STABLEHEART, id) + REMOVE_TRAIT(M, TRAIT_STABLEHEART, type) + REMOVE_TRAIT(M, TRAIT_STABLELIVER, type) ..() /datum/reagent/medicine/muscle_stimulant @@ -1249,6 +1362,7 @@ overdose_threshold = 20 // with the random effects this might be awesome or might kill you at less than 10u (extensively tested) taste_description = "salt" // it actually does taste salty var/overdose_progress = 0 // to track overdose progress + pH = 7.89 /datum/reagent/medicine/modafinil/on_mob_metabolize(mob/living/M) ADD_TRAIT(M, TRAIT_SLEEPIMMUNE, id) @@ -1305,3 +1419,38 @@ M.adjustStaminaLoss(1.5*REM, 0) ..() return TRUE + +/datum/reagent/medicine/psicodine + name = "Psicodine" + id = "psicodine" + description = "Suppresses anxiety and other various forms of mental distress. Overdose causes hallucinations and minor toxin damage." + reagent_state = LIQUID + color = "#07E79E" + metabolization_rate = 0.25 * REAGENTS_METABOLISM + overdose_threshold = 30 + pH = 9.12 + +/datum/reagent/medicine/psicodine/on_mob_add(mob/living/L) + ..() + ADD_TRAIT(L, TRAIT_FEARLESS, id) + +/datum/reagent/medicine/psicodine/on_mob_delete(mob/living/L) + REMOVE_TRAIT(L, TRAIT_FEARLESS, id) + ..() + +/datum/reagent/medicine/psicodine/on_mob_life(mob/living/carbon/M) + M.jitteriness = max(0, M.jitteriness-6) + M.dizziness = max(0, M.dizziness-6) + M.confused = max(0, M.confused-6) + M.disgust = max(0, M.disgust-6) + GET_COMPONENT_FROM(mood, /datum/component/mood, M) + if(mood.sanity <= SANITY_NEUTRAL) // only take effect if in negative sanity and then... + mood.setSanity(min(mood.sanity+5, SANITY_NEUTRAL)) // set minimum to prevent unwanted spiking over neutral + ..() + . = 1 + +/datum/reagent/medicine/psicodine/overdose_process(mob/living/M) + M.hallucination = min(max(0, M.hallucination + 5), 60) + M.adjustToxLoss(1, 0) + ..() + . = 1 diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index db927411c0..95b4a33c0d 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -3,6 +3,7 @@ name = "Blood" id = "blood" color = "#C80000" // rgb: 200, 0, 0 + description = "Blood from a human, or otherwise." metabolization_rate = 5 //fast rate so it disappears fast. taste_description = "iron" taste_mult = 1.3 @@ -10,6 +11,7 @@ glass_name = "glass of tomato juice" glass_desc = "Are you sure this is tomato juice?" shot_glass_icon_state = "shotglassred" + pH = 7.4 /datum/reagent/blood/reaction_mob(mob/living/L, method=TOUCH, reac_volume) if(data && data["viruses"]) @@ -95,6 +97,7 @@ description = "You don't even want to think about what's in here." taste_description = "gross iron" shot_glass_icon_state = "shotglassred" + pH = 7.45 /datum/reagent/vaccine //data must contain virus type @@ -195,24 +198,23 @@ glass_icon_state = "glass_clear" glass_name = "glass of holy water" glass_desc = "A glass of holy water." + pH = 7.5 //God is alkaline /datum/reagent/water/holywater/on_mob_metabolize(mob/living/L) - ..() + . = ..() ADD_TRAIT(L, TRAIT_HOLY, id) + if(is_servant_of_ratvar(L)) + to_chat(L, "A fog spreads through your mind, purging the Justiciar's influence!") + else if(iscultist(L)) + to_chat(L, "A fog spreads through your mind, weakening your connection to the veil and purging Nar-sie's influence") + /datum/reagent/water/holywater/on_mob_end_metabolize(mob/living/L) REMOVE_TRAIT(L, TRAIT_HOLY, id) - ..() - -/datum/reagent/water/holywater/reaction_mob(mob/living/M, method=TOUCH, reac_volume) - if(is_servant_of_ratvar(M)) - to_chat(M, "A fog spreads through your mind, purging the Justiciar's influence!") - ..() - -/datum/reagent/water/holywater/reaction_mob(mob/living/M, method=TOUCH, reac_volume) - if(iscultist(M)) - to_chat(M, "A fog spreads through your mind, weakening your connection to the veil and purging Nar-sie's influence") - ..() + if(iscultist(L)) + for(var/datum/action/innate/cult/blood_magic/BM in L.actions) + BM.holy_dispel = FALSE + return ..() /datum/reagent/water/holywater/on_mob_life(mob/living/carbon/M) if(!data) @@ -221,9 +223,11 @@ M.jitteriness = min(M.jitteriness+4,10) if(iscultist(M)) for(var/datum/action/innate/cult/blood_magic/BM in M.actions) - to_chat(M, "Your blood rites falter as holy water scours your body!") - for(var/datum/action/innate/cult/blood_spell/BS in BM.spells) - qdel(BS) + if(!BM.holy_dispel) + BM.holy_dispel = TRUE + to_chat(M, "Your blood rites falter as holy water scours your body!") + for(var/datum/action/innate/cult/blood_spell/BS in BM.spells) + qdel(BS) if(data >= 25) // 10 units, 45 seconds @ metabolism 0.4 units & tick rate 1.8 sec if(!M.stuttering) M.stuttering = 1 @@ -271,6 +275,7 @@ id = "unholywater" description = "Something that shouldn't exist on this plane of existence." taste_description = "suffering" + pH = 6.5 /datum/reagent/fuel/unholywater/reaction_mob(mob/living/M, method=TOUCH, reac_volume) if(method == TOUCH || method == VAPOR) @@ -289,10 +294,10 @@ M.adjustOxyLoss(-2, 0) M.adjustBruteLoss(-2, 0) M.adjustFireLoss(-2, 0) - if(ishuman(M) && M.blood_volume < BLOOD_VOLUME_NORMAL) + if(ishuman(M) && M.blood_volume < (BLOOD_VOLUME_NORMAL*M.blood_ratio)) M.blood_volume += 3 else // Will deal about 90 damage when 50 units are thrown - M.adjustBrainLoss(3, 150) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 3, 150) M.adjustToxLoss(2, 0) M.adjustFireLoss(2, 0) M.adjustOxyLoss(2, 0) @@ -311,8 +316,9 @@ M.IgniteMob() //Only problem with igniting people is currently the commonly availible fire suits make you immune to being on fire M.adjustToxLoss(1, 0) M.adjustFireLoss(1, 0) //Hence the other damages... ain't I a bastard? - M.adjustBrainLoss(5, 150) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 5, 150) holder.remove_reagent(id, 1) + pH = 0.1 /datum/reagent/fuel/holyoil //Its oil name = "Zelus Oil" @@ -380,6 +386,7 @@ metabolization_rate = 10 * REAGENTS_METABOLISM // very fast, so it can be applied rapidly. But this changes on an overdose overdose_threshold = 11 //Slightly more than one un-nozzled spraybottle. taste_description = "sour oranges" + pH = 5 /datum/reagent/spraytan/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message = 1) if(ishuman(M)) @@ -530,12 +537,12 @@ race = /datum/species/fly mutationtext = "The pain subsides. You feel... buzzy." -/datum/reagent/mutationtoxin/moth - name = "Moth Mutation Toxin" +/datum/reagent/mutationtoxin/insect + name = "Insect Mutation Toxin" id = "mothmutationtoxin" description = "A glowing toxin." color = "#5EFF3B" //RGB: 94, 255, 59 - race = /datum/species/moth + race = /datum/species/insect mutationtext = "The pain subsides. You feel... attracted to light." /datum/reagent/mutationtoxin/pod @@ -704,6 +711,7 @@ color = "#202040" // rgb: 20, 20, 40 metabolization_rate = 0.25 * REAGENTS_METABOLISM taste_description = "bitterness" + pH = 10 /datum/reagent/serotrotium/on_mob_life(mob/living/carbon/M) if(ishuman(M)) @@ -718,6 +726,7 @@ reagent_state = GAS color = "#808080" // rgb: 128, 128, 128 taste_mult = 0 // oderless and tasteless + pH = 9.2//It's acutally a huge range and very dependant on the chemistry but pH is basically a made up var in it's implementation anyways /datum/reagent/oxygen/reaction_obj(obj/O, reac_volume) if((!O) || (!reac_volume)) @@ -738,6 +747,7 @@ reagent_state = SOLID color = "#6E3B08" // rgb: 110, 59, 8 taste_description = "metal" + pH = 5.5 /datum/reagent/copper/reaction_obj(obj/O, reac_volume) if(istype(O, /obj/item/stack/sheet/metal)) @@ -754,6 +764,7 @@ color = "#808080" // rgb: 128, 128, 128 taste_mult = 0 + /datum/reagent/nitrogen/reaction_obj(obj/O, reac_volume) if((!O) || (!reac_volume)) return 0 @@ -773,6 +784,7 @@ reagent_state = GAS color = "#808080" // rgb: 128, 128, 128 taste_mult = 0 + pH = 0.1//Now I'm stuck in a trap of my own design. Maybe I should make -ve pHes? (not 0 so I don't get div/0 errors) /datum/reagent/potassium name = "Potassium" @@ -794,7 +806,7 @@ step(M, pick(GLOB.cardinals)) if(prob(5)) M.emote(pick("twitch","drool","moan")) - M.adjustBrainLoss(1) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 1) ..() /datum/reagent/sulfur @@ -804,6 +816,7 @@ reagent_state = SOLID color = "#BF8C00" // rgb: 191, 140, 0 taste_description = "rotten eggs" + pH = 4.5 /datum/reagent/carbon name = "Carbon" @@ -812,6 +825,7 @@ reagent_state = SOLID color = "#1C1300" // rgb: 30, 20, 0 taste_description = "sour chalk" + pH = 5 /datum/reagent/carbon/reaction_turf(turf/T, reac_volume) if(!isspaceturf(T)) @@ -826,6 +840,7 @@ reagent_state = GAS color = "#808080" // rgb: 128, 128, 128 taste_description = "chlorine" + pH = 7.4 /datum/reagent/chlorine/on_mob_life(mob/living/carbon/M) M.take_bodypart_damage(1*REM, 0, 0, 0) @@ -839,6 +854,7 @@ reagent_state = GAS color = "#808080" // rgb: 128, 128, 128 taste_description = "acid" + pH = 2 /datum/reagent/fluorine/on_mob_life(mob/living/carbon/M) M.adjustToxLoss(1*REM, 0) @@ -852,6 +868,7 @@ reagent_state = SOLID color = "#808080" // rgb: 128, 128, 128 taste_description = "salty metal" + pH = 11.6 /datum/reagent/phosphorus name = "Phosphorus" @@ -860,6 +877,7 @@ reagent_state = SOLID color = "#832828" // rgb: 131, 40, 40 taste_description = "vinegar" + pH = 6.5 /datum/reagent/lithium name = "Lithium" @@ -868,6 +886,7 @@ reagent_state = SOLID color = "#808080" // rgb: 128, 128, 128 taste_description = "metal" + pH = 11.3 /datum/reagent/lithium/on_mob_life(mob/living/carbon/M) if(M.canmove && !isspaceturf(M.loc)) @@ -882,6 +901,7 @@ description = "Glycerol is a simple polyol compound. Glycerol is sweet-tasting and of low toxicity." color = "#808080" // rgb: 128, 128, 128 taste_description = "sweetness" + pH = 9 /datum/reagent/radium name = "Radium" @@ -890,6 +910,7 @@ reagent_state = SOLID color = "#C7C7C7" // rgb: 199,199,199 taste_description = "the colour blue and regret" + pH = 10 /datum/reagent/radium/on_mob_life(mob/living/carbon/M) M.apply_effect(2*REM/M.metabolism_efficiency,EFFECT_IRRADIATE,0) @@ -909,6 +930,7 @@ description = "Sterilizes wounds in preparation for surgery." color = "#e6f1f5" // rgb: 200, 165, 220 taste_description = "bitterness" + pH = 10.5 /datum/reagent/space_cleaner/sterilizine/reaction_mob(mob/living/carbon/C, method=TOUCH, reac_volume) if(method in list(TOUCH, VAPOR, PATCH)) @@ -924,11 +946,12 @@ description = "Pure iron is a metal." reagent_state = SOLID taste_description = "iron" + pH = 6 color = "#c2391d" /datum/reagent/iron/on_mob_life(mob/living/carbon/C) - if(C.blood_volume < BLOOD_VOLUME_NORMAL) + if(C.blood_volume < (BLOOD_VOLUME_NORMAL*C.blood_ratio)) C.blood_volume += 0.5 ..() @@ -966,6 +989,7 @@ reagent_state = SOLID color = "#B8B8C0" // rgb: 184, 184, 192 taste_description = "the inside of a reactor" + pH = 4 /datum/reagent/uranium/on_mob_life(mob/living/carbon/M) M.apply_effect(1/M.metabolism_efficiency,EFFECT_IRRADIATE,0) @@ -986,6 +1010,7 @@ reagent_state = SOLID color = "#0000CC" taste_description = "fizzling blue" + pH = 12 /datum/reagent/bluespace/reaction_mob(mob/living/M, method=TOUCH, reac_volume) if(method == TOUCH || method == VAPOR) @@ -1018,6 +1043,7 @@ reagent_state = SOLID color = "#A8A8A8" // rgb: 168, 168, 168 taste_mult = 0 + pH = 10 /datum/reagent/fuel name = "Welding fuel" @@ -1028,6 +1054,8 @@ glass_icon_state = "dr_gibb_glass" glass_name = "glass of welder fuel" glass_desc = "Unless you're an industrial tool, this is probably not safe for consumption." + pH = 4 + /datum/reagent/fuel/reaction_mob(mob/living/M, method=TOUCH, reac_volume)//Splashing people with welding fuel to make them easy to ignite! if(method == TOUCH || method == VAPOR) @@ -1046,6 +1074,7 @@ description = "A compound used to clean things. Now with 50% more sodium hypochlorite!" color = "#A5F0EE" // rgb: 165, 240, 238 taste_description = "sourness" + pH = 5.5 /datum/reagent/space_cleaner/reaction_obj(obj/O, reac_volume) if(istype(O, /obj/effect/decal/cleanable)) @@ -1103,6 +1132,7 @@ description = "A powerful, acidic cleaner sold by Waffle Co. Affects organic matter while leaving other objects unaffected." metabolization_rate = 1.5 * REAGENTS_METABOLISM taste_description = "acid" + pH = 2 /datum/reagent/space_cleaner/ez_clean/on_mob_life(mob/living/carbon/M) M.adjustBruteLoss(3.33) @@ -1123,6 +1153,7 @@ color = "#7529b3" // rgb: 200, 165, 220 metabolization_rate = 1.5 * REAGENTS_METABOLISM taste_description = "sourness" + pH = 11.9 /datum/reagent/cryptobiolin/on_mob_life(mob/living/carbon/M) M.Dizzy(1) @@ -1137,11 +1168,12 @@ description = "Impedrezene is a narcotic that impedes one's ability by slowing down the higher brain cell functions." color = "#587a31" // rgb: 200, 165, 220A taste_description = "numbness" + pH = 9.1 /datum/reagent/impedrezene/on_mob_life(mob/living/carbon/M) M.jitteriness = max(M.jitteriness-5,0) if(prob(80)) - M.adjustBrainLoss(2*REM) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 2*REM) if(prob(50)) M.drowsyness = max(M.drowsyness, 3) if(prob(10)) @@ -1179,6 +1211,7 @@ color = "#92D17D" // rgb: 146, 209, 125 can_synth = FALSE taste_description = "slime" + pH = 11 /datum/reagent/fungalspores/reaction_mob(mob/living/L, method=TOUCH, reac_volume, show_message = 1, touch_protection = 0) if(method==PATCH || method==INGEST || method==INJECT || (method == VAPOR && prob(min(reac_volume,100)*(1 - touch_protection)))) @@ -1190,6 +1223,7 @@ description = "A perfluoronated sulfonic acid that forms a foam when mixed with water." color = "#9E6B38" // rgb: 158, 107, 56 taste_description = "metal" + pH = 11 /datum/reagent/foaming_agent// Metal foaming agent. This is lithium hydride. Add other recipes (e.g. LiH + H2O -> LiOH + H2) eventually. name = "Foaming agent" @@ -1198,6 +1232,7 @@ reagent_state = SOLID color = "#664B63" // rgb: 102, 75, 99 taste_description = "metal" + pH = 11.5 /datum/reagent/smart_foaming_agent //Smart foaming agent. Functions similarly to metal foam, but conforms to walls. name = "Smart foaming agent" @@ -1206,6 +1241,7 @@ reagent_state = SOLID color = "#664B63" // rgb: 102, 75, 99 taste_description = "metal" + pH = 11.8 /datum/reagent/ammonia name = "Ammonia" @@ -1214,6 +1250,7 @@ reagent_state = GAS color = "#404030" // rgb: 64, 64, 48 taste_description = "mordant" + pH = 11.6 /datum/reagent/diethylamine name = "Diethylamine" @@ -1221,6 +1258,7 @@ description = "A secondary amine, mildly corrosive." color = "#604030" // rgb: 96, 64, 48 taste_description = "iron" + pH = 12 /datum/reagent/carbondioxide name = "Carbon Dioxide" @@ -1229,6 +1267,7 @@ description = "A gas commonly produced by burning carbon fuels. You're constantly producing this in your lungs." color = "#B0B0B0" // rgb : 192, 192, 192 taste_description = "something unknowable" + pH = 6 /datum/reagent/carbondioxide/reaction_obj(obj/O, reac_volume) if((!O) || (!reac_volume)) @@ -1250,6 +1289,7 @@ metabolization_rate = 1.5 * REAGENTS_METABOLISM color = "#808080" taste_description = "sweetness" + pH = 5.8 /datum/reagent/nitrous_oxide/reaction_obj(obj/O, reac_volume) if((!O) || (!reac_volume)) @@ -1309,6 +1349,7 @@ metabolization_rate = REAGENTS_METABOLISM color = "90560B" taste_description = "burning" + pH = 2 /datum/reagent/nitryl/on_mob_metabolize(mob/living/L) ..() @@ -1342,6 +1383,7 @@ colorname = "red" color = "#DA0000" // red random_color_list = list("#DA0000") + pH = 0.5 /datum/reagent/colorful_reagent/crayonpowder/orange name = "Orange Crayon Powder" @@ -1349,6 +1391,7 @@ colorname = "orange" color = "#FF9300" // orange random_color_list = list("#FF9300") + pH = 2 /datum/reagent/colorful_reagent/crayonpowder/yellow name = "Yellow Crayon Powder" @@ -1356,6 +1399,7 @@ colorname = "yellow" color = "#FFF200" // yellow random_color_list = list("#FFF200") + pH = 5 /datum/reagent/colorful_reagent/crayonpowder/green name = "Green Crayon Powder" @@ -1364,12 +1408,14 @@ color = "#A8E61D" // green random_color_list = list("#A8E61D") + /datum/reagent/colorful_reagent/crayonpowder/blue name = "Blue Crayon Powder" id = "bluecrayonpowder" colorname = "blue" color = "#00B7EF" // blue random_color_list = list("#00B7EF") + pH = 10 /datum/reagent/colorful_reagent/crayonpowder/purple name = "Purple Crayon Powder" @@ -1377,6 +1423,7 @@ colorname = "purple" color = "#DA00FF" // purple random_color_list = list("#DA00FF") + pH = 13 /datum/reagent/colorful_reagent/crayonpowder/invisible name = "Invisible Crayon Powder" @@ -1399,9 +1446,6 @@ color = "#FFFFFF" // white random_color_list = list("#FFFFFF") //doesn't actually change appearance at all - - - //////////////////////////////////Hydroponics stuff/////////////////////////////// /datum/reagent/plantnutriment @@ -1411,6 +1455,7 @@ color = "#000000" // RBG: 0, 0, 0 var/tox_prob = 0 taste_description = "plant food" + pH = 3 /datum/reagent/plantnutriment/on_mob_life(mob/living/carbon/M) if(prob(tox_prob)) @@ -1424,6 +1469,7 @@ description = "Cheap and extremely common type of plant nutriment." color = "#376400" // RBG: 50, 100, 0 tox_prob = 10 + pH = 2 /datum/reagent/plantnutriment/left4zednutriment name = "Left 4 Zed" @@ -1431,6 +1477,7 @@ description = "Unstable nutriment that makes plants mutate more often than usual." color = "#1A1E4D" // RBG: 26, 30, 77 tox_prob = 25 + pH = 1.5 /datum/reagent/plantnutriment/robustharvestnutriment name = "Robust Harvest" @@ -1438,17 +1485,10 @@ description = "Very potent nutriment that prevents plants from mutating." color = "#9D9D00" // RBG: 157, 157, 0 tox_prob = 15 - - - - - - + pH = 1 // GOON OTHERS - - /datum/reagent/oil name = "Oil" id = "oil" @@ -1465,6 +1505,7 @@ color = "#6b008f" taste_description = "bitterness" taste_mult = 1.5 + pH = 1.5 /datum/reagent/stable_plasma/on_mob_life(mob/living/carbon/C) C.adjustPlasma(10) @@ -1477,20 +1518,7 @@ reagent_state = LIQUID color = "#694600" taste_description = "metal" - -/datum/reagent/carpet - name = "Carpet" - id = "carpet" - description = "For those that need a more creative way to roll out a red carpet." - reagent_state = LIQUID - color = "#b51d05" - taste_description = "carpet" // Your tounge feels furry. - -/datum/reagent/carpet/reaction_turf(turf/T, reac_volume) - if(isplatingturf(T) || istype(T, /turf/open/floor/plasteel)) - var/turf/open/floor/F = T - F.PlaceOnTop(/turf/open/floor/carpet) - ..() + pH = 4.5 /datum/reagent/bromine name = "Bromine" @@ -1499,14 +1527,16 @@ reagent_state = LIQUID color = "#b37740" taste_description = "chemicals" + pH = 7.8 /datum/reagent/phenol name = "Phenol" id = "phenol" description = "An aromatic ring of carbon with a hydroxyl group. A useful precursor to some medicines, but has no healing properties on its own." reagent_state = LIQUID + taste_description = "sweet and tarry" //Again, not a strong acid. + pH = 5.5 color = "#e6e8ff" - taste_description = "acid" /datum/reagent/ash name = "Ash" @@ -1515,14 +1545,15 @@ reagent_state = LIQUID color = "#665c56" taste_description = "ash" + pH = 6.5 /datum/reagent/acetone name = "Acetone" id = "acetone" description = "A slick, slightly carcinogenic liquid. Has a multitude of mundane uses in everyday life." reagent_state = LIQUID + taste_description = "solvent"//It's neutral though..? color = "#e6e6e6" - taste_description = "acid" /datum/reagent/colorful_reagent name = "Colorful Reagent" @@ -1612,6 +1643,7 @@ reagent_state = LIQUID color = "#60A584" // rgb: 96, 165, 132 taste_description = "cool salt" + pH = 11.2 /datum/reagent/lye name = "Lye" @@ -1619,7 +1651,8 @@ description = "Also known as sodium hydroxide. As a profession making this is somewhat underwhelming." reagent_state = LIQUID color = "#FFFFD6" // very very light yellow - taste_description = "acid" + taste_description = "alkali" //who put ACID for NaOH ???? + pH = 11.9 /datum/reagent/drying_agent name = "Drying agent" @@ -1628,6 +1661,7 @@ reagent_state = LIQUID color = "#A70FFF" taste_description = "dryness" + pH = 10.7 /datum/reagent/drying_agent/reaction_turf(turf/open/T, reac_volume) if(istype(T)) @@ -1639,6 +1673,143 @@ qdel(O) new /obj/item/clothing/shoes/galoshes/dry(t_loc) +// Liquid Carpets +/datum/reagent/carpet + name = "Liquid Carpet" + id = "carpet" + description = "For those that need a more creative way to roll out a carpet." + reagent_state = LIQUID + color = "#b51d05" + taste_description = "carpet" // Your tounge feels furry. + +/datum/reagent/carpet/reaction_turf(turf/T, reac_volume) + if(isplatingturf(T) || istype(T, /turf/open/floor/plasteel)) + var/turf/open/floor/F = T + F.PlaceOnTop(/turf/open/floor/carpet) + ..() + +/datum/reagent/carpet/black + name = "Liquid Black Carpet" + id = "blackcarpet" + color = "#363636" + +/datum/reagent/carpet/black/reaction_turf(turf/T, reac_volume) + if(isplatingturf(T) || istype(T, /turf/open/floor/plasteel)) + var/turf/open/floor/F = T + F.PlaceOnTop(/turf/open/floor/carpet/black) + ..() + +/datum/reagent/carpet/blackred + name = "Liquid Red Black Carpet" + id = "blackredcarpet" + color = "#342125" + +/datum/reagent/carpet/blackred/reaction_turf(turf/T, reac_volume) + if(isplatingturf(T) || istype(T, /turf/open/floor/plasteel)) + var/turf/open/floor/F = T + F.PlaceOnTop(/turf/open/floor/carpet/blackred) + ..() + +/datum/reagent/carpet/monochrome + name = "Liquid Monochrome Carpet" + id = "monochromecarpet" + color = "#b4b4b4" + +/datum/reagent/carpet/monochrome/reaction_turf(turf/T, reac_volume) + if(isplatingturf(T) || istype(T, /turf/open/floor/plasteel)) + var/turf/open/floor/F = T + F.PlaceOnTop(/turf/open/floor/carpet/monochrome) + ..() + +/datum/reagent/carpet/blue + name = "Liquid Blue Carpet" + id = "bluecarpet" + color = "#1256ff" + +/datum/reagent/carpet/blue/reaction_turf(turf/T, reac_volume) + if(isplatingturf(T) || istype(T, /turf/open/floor/plasteel)) + var/turf/open/floor/F = T + F.PlaceOnTop(/turf/open/floor/carpet/blue) + ..() + +/datum/reagent/carpet/cyan + name = "Liquid Cyan Carpet" + id = "cyancarpet" + color = "#3acfb9" + +/datum/reagent/carpet/cyan/reaction_turf(turf/T, reac_volume) + if(isplatingturf(T) || istype(T, /turf/open/floor/plasteel)) + var/turf/open/floor/F = T + F.PlaceOnTop(/turf/open/floor/carpet/cyan) + ..() + +/datum/reagent/carpet/green + name = "Liquid Green Carpet" + id = "greencarpet" + color = "#619b62" + +/datum/reagent/carpet/green/reaction_turf(turf/T, reac_volume) + if(isplatingturf(T) || istype(T, /turf/open/floor/plasteel)) + var/turf/open/floor/F = T + F.PlaceOnTop(/turf/open/floor/carpet/green) + ..() + +/datum/reagent/carpet/orange + name = "Liquid Orange Carpet" + id = "orangecarpet" + color = "#cc7900" + +/datum/reagent/carpet/orange/reaction_turf(turf/T, reac_volume) + if(isplatingturf(T) || istype(T, /turf/open/floor/plasteel)) + var/turf/open/floor/F = T + F.PlaceOnTop(/turf/open/floor/carpet/orange) + ..() + +/datum/reagent/carpet/purple + name = "Liquid Purple Carpet" + id = "purplecarpet" + color = "#6d3392" + +/datum/reagent/carpet/purple/reaction_turf(turf/T, reac_volume) + if(isplatingturf(T) || istype(T, /turf/open/floor/plasteel)) + var/turf/open/floor/F = T + F.PlaceOnTop(/turf/open/floor/carpet/purple) + ..() + +/datum/reagent/carpet/red + name = "Liquid Red Carpet" + id = "redcarpet" + color = "#871515" + +/datum/reagent/carpet/red/reaction_turf(turf/T, reac_volume) + if(isplatingturf(T) || istype(T, /turf/open/floor/plasteel)) + var/turf/open/floor/F = T + F.PlaceOnTop(/turf/open/floor/carpet/red) + ..() + +/datum/reagent/carpet/royalblack + name = "Liquid Royal Black Carpet" + id = "royalblackcarpet" + color = "#483d05" + +/datum/reagent/carpet/royalblack/reaction_turf(turf/T, reac_volume) + if(isplatingturf(T) || istype(T, /turf/open/floor/plasteel)) + var/turf/open/floor/F = T + F.PlaceOnTop(/turf/open/floor/carpet/royalblack) + ..() + +/datum/reagent/carpet/royalblue + name = "Liquid Royal Blue Carpet" + id = "royalbluecarpet" + color = "#24227e" + +/datum/reagent/carpet/royalblue/reaction_turf(turf/T, reac_volume) + if(isplatingturf(T) || istype(T, /turf/open/floor/plasteel)) + var/turf/open/floor/F = T + F.PlaceOnTop(/turf/open/floor/carpet/royalblue) + ..() + + // Virology virus food chems. /datum/reagent/toxin/mutagen/mutagenvirusfood @@ -1699,6 +1870,7 @@ description = "Royal Bee Jelly, if injected into a Queen Space Bee said bee will split into two bees." color = "#00ff80" taste_description = "strange honey" + pH = 3 /datum/reagent/royal_bee_jelly/on_mob_life(mob/living/carbon/M) if(prob(2)) @@ -1720,6 +1892,7 @@ metabolization_rate = INFINITY can_synth = FALSE taste_description = "brains" + pH = 0.5 /datum/reagent/romerol/reaction_mob(mob/living/carbon/human/H, method=TOUCH, reac_volume) // Silently add the zombie infection organ to be activated upon death @@ -1778,6 +1951,7 @@ description = "the petroleum based components of plastic." color = "#f7eded" taste_description = "plastic" + pH = 6 /datum/reagent/glitter name = "generic glitter" @@ -1820,6 +1994,7 @@ color = "#AAAAAA55" taste_description = "water" metabolization_rate = 0.25 * REAGENTS_METABOLISM + pH = 15 /datum/reagent/pax/on_mob_metabolize(mob/living/L) ..() @@ -1908,6 +2083,13 @@ color = "#FAEAFF" taste_description = "synthetic catnip" +/datum/reagent/moonsugar/on_mob_life(mob/living/carbon/M) + if(prob(20)) + to_chat(M, "You find yourself unable to supress the desire to meow!") + M.emote("nya") + ..() + +//Kept for legacy, I think it will break everything if you enable it. /datum/reagent/penis_enlargement name = "Penis Enlargement" id = "penis_enlargement" @@ -1934,7 +2116,7 @@ can_synth = FALSE var/datum/dna/original_dna var/reagent_ticks = 0 - invisible = TRUE + chemical_flags = REAGENT_INVISIBLE /datum/reagent/changeling_string/on_mob_metabolize(mob/living/carbon/C) if(C && C.dna && data["desired_dna"]) @@ -1962,3 +2144,25 @@ /datum/reagent/changeling_string/Destroy() qdel(original_dna) return ..() + +/datum/reagent/mustardgrind + name = "Mustardgrind" + id = "mustardgrind" + description = "A powerd that is mixed with water and enzymes to make mustard." + color = "#BCC740" //RGB: 188, 199, 64 + taste_description = "plant dust" + +/datum/reagent/pax/catnip + name = "catnip" + id = "catnip" + taste_description = "grass" + description = "A colorless liquid that makes people more peaceful and felines more happy." + metabolization_rate = 1.75 * REAGENTS_METABOLISM + +/datum/reagent/pax/catnip/on_mob_life(mob/living/carbon/M) + if(prob(20)) + M.emote("nya") + if(prob(20)) + to_chat(M, "[pick("Headpats feel nice.", "The feeling of a hairball...", "Backrubs would be nice.", "Whats behind those doors?")]") + M.adjustArousalLoss(2) + ..() diff --git a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm index 6bd165f23e..2b50ecc0f1 100644 --- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm @@ -23,6 +23,7 @@ color = "#792300" // rgb: 121, 35, 0 toxpwr = 2.5 taste_description = "mushroom" + pH = 13 /datum/reagent/toxin/mutagen name = "Unstable mutagen" @@ -32,6 +33,7 @@ toxpwr = 0 taste_description = "slime" taste_mult = 0.9 + pH = 2 /datum/reagent/toxin/mutagen/reaction_mob(mob/living/carbon/M, method=TOUCH, reac_volume) if(!..()) @@ -61,6 +63,7 @@ taste_mult = 1.5 color = "#8228A0" toxpwr = 3 + pH = 4 /datum/reagent/toxin/plasma/on_mob_life(mob/living/carbon/C) if(holder.has_reagent("epinephrine")) @@ -93,6 +96,7 @@ color = "#7DC3A0" toxpwr = 0 taste_description = "acid" + pH = 1.2 /datum/reagent/toxin/lexorin/on_mob_life(mob/living/carbon/C) . = TRUE @@ -115,6 +119,7 @@ toxpwr = 0 taste_description = "slime" taste_mult = 1.3 + pH = 10 /datum/reagent/toxin/slimejelly/on_mob_life(mob/living/carbon/M) if(prob(10)) @@ -133,6 +138,7 @@ color = "#CF3600" // rgb: 207, 54, 0 toxpwr = 0 taste_description = "mint" + pH = 8 /datum/reagent/toxin/minttoxin/on_mob_life(mob/living/carbon/M) if(HAS_TRAIT(M, TRAIT_FAT)) @@ -146,6 +152,7 @@ color = "#003333" // rgb: 0, 51, 51 toxpwr = 2 taste_description = "fish" + pH = 12 /datum/reagent/toxin/zombiepowder name = "Zombie Powder" @@ -155,6 +162,7 @@ color = "#669900" // rgb: 102, 153, 0 toxpwr = 0.5 taste_description = "death" + pH = 13 /datum/reagent/toxin/zombiepowder/on_mob_metabolize(mob/living/L) ..() @@ -177,6 +185,7 @@ color = "#664700" // rgb: 102, 71, 0 toxpwr = 0.8 taste_description = "death" + pH = 14.5 /datum/reagent/toxin/ghoulpowder/on_mob_metabolize(mob/living/L) ..() @@ -198,6 +207,7 @@ color = "#B31008" // rgb: 139, 166, 233 toxpwr = 0 taste_description = "sourness" + pH = 11 /datum/reagent/toxin/mindbreaker/on_mob_life(mob/living/carbon/M) M.hallucination += 5 @@ -210,6 +220,7 @@ color = "#49002E" // rgb: 73, 0, 46 toxpwr = 1 taste_mult = 1 + pH = 2 /datum/reagent/toxin/plantbgone/reaction_obj(obj/O, reac_volume) if(istype(O, /obj/structure/alien/weeds)) @@ -234,6 +245,7 @@ id = "weedkiller" description = "A harmful toxic mixture to kill weeds. Do not ingest!" color = "#4B004B" // rgb: 75, 0, 75 + pH = 3 /datum/reagent/toxin/pestkiller name = "Pest Killer" @@ -241,6 +253,7 @@ description = "A harmful toxic mixture to kill pests. Do not ingest!" color = "#4B004B" // rgb: 75, 0, 75 toxpwr = 1 + pH = 3.2 /datum/reagent/toxin/pestkiller/reaction_mob(mob/living/M, method=TOUCH, reac_volume) ..() @@ -254,6 +267,7 @@ description = "A natural toxin produced by blob spores that inhibits vision when ingested." color = "#9ACD32" toxpwr = 1 + pH = 11 /datum/reagent/toxin/spore/on_mob_life(mob/living/carbon/C) C.damageoverlaytemp = 60 @@ -268,6 +282,7 @@ color = "#9ACD32" toxpwr = 0.5 taste_description = "burning" + pH = 13 /datum/reagent/toxin/spore_burning/on_mob_life(mob/living/carbon/M) M.adjust_fire_stacks(2) @@ -282,6 +297,7 @@ color = "#000067" // rgb: 0, 0, 103 toxpwr = 0 metabolization_rate = 1.5 * REAGENTS_METABOLISM + pH = 11 /datum/reagent/toxin/chloralhydrate/on_mob_life(mob/living/carbon/M) switch(current_cycle) @@ -297,25 +313,6 @@ . = 1 ..() -/datum/reagent/toxin/chloralhydratedelayed //sedates half as quickly and does not cause toxloss. same name/desc so it doesn't give away sleepypens - name = "Chloral Hydrate" - id = "chloralhydratedelayed" - description = "A powerful sedative that induces confusion and drowsiness before putting its target to sleep." - reagent_state = SOLID - color = "#000067" // rgb: 0, 0, 103 - toxpwr = 0 - metabolization_rate = 1 * REAGENTS_METABOLISM - -/datum/reagent/toxin/chloralhydratedelayed/on_mob_life(mob/living/carbon/M) - switch(current_cycle) - if(10 to 20) - M.confused += 1 - M.drowsyness += 1 - M.adjustStaminaLoss(7.5) - if(20 to INFINITY) - M.Sleeping(40, 0) - ..() - /datum/reagent/toxin/fakebeer //disguised as normal beer for use by emagged brobots name = "Beer" id = "fakebeer" @@ -326,6 +323,7 @@ glass_icon_state = "beerglass" glass_name = "glass of beer" glass_desc = "A freezing pint of beer." + pH = 2 /datum/reagent/toxin/fakebeer/on_mob_life(mob/living/carbon/M) switch(current_cycle) @@ -343,6 +341,7 @@ reagent_state = SOLID color = "#5B2E0D" // rgb: 91, 46, 13 toxpwr = 0.5 + pH = 4.2 /datum/reagent/toxin/teapowder name = "Ground Tea Leaves" @@ -351,6 +350,7 @@ reagent_state = SOLID color = "#7F8400" // rgb: 127, 132, 0 toxpwr = 0.5 + pH = 4.9 /datum/reagent/toxin/mutetoxin //the new zombie powder. name = "Mute Toxin" @@ -359,6 +359,7 @@ color = "#F0F8FF" // rgb: 240, 248, 255 toxpwr = 0 taste_description = "silence" + pH = 12.2 /datum/reagent/toxin/mutetoxin/on_mob_life(mob/living/carbon/M) M.silent = max(M.silent, 3) @@ -369,12 +370,12 @@ id = "tirizene" description = "A nonlethal poison that causes extreme fatigue and weakness in its victim." color = "#6E2828" - data = 13 + data = 15 toxpwr = 0 /datum/reagent/toxin/staminatoxin/on_mob_life(mob/living/carbon/M) M.adjustStaminaLoss(REM * data, 0) - data = max(data - 1, 3) + data = max(data - 1, 5) ..() . = 1 @@ -470,7 +471,7 @@ toxpwr = 0 /datum/reagent/toxin/fentanyl/on_mob_life(mob/living/carbon/M) - M.adjustBrainLoss(3*REM, 150) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 3*REM, 150) if(M.toxloss <= 60) M.adjustToxLoss(1*REM, 0) if(current_cycle >= 18) @@ -816,6 +817,7 @@ var/acidpwr = 10 //the amount of protection removed from the armour taste_description = "acid" self_consuming = TRUE + pH = 2.75 /datum/reagent/toxin/acid/reaction_mob(mob/living/carbon/C, method=TOUCH, reac_volume) if(!istype(C)) @@ -948,3 +950,20 @@ to_chat(M, "Your missing arm aches from wherever you left it.") M.emote("sigh") return ..() + +/datum/reagent/toxin/brainhurtingjuice //oof ouch + name = "Brain Hurting Juice" + id = "brainhurtingjuice" + color = "#AAAAAA77" //RGBA: 170, 170, 170, 77 + toxpwr = 0 + taste_description = "brain hurting" + metabolization_rate = 5 + +/datum/reagent/toxin/brainhurtingjuice/on_mob_life(mob/living/carbon/M) + if(prob(50)) + M.gain_trauma_type(BRAIN_TRAUMA_MILD) + else if(prob(50)) + M.gain_trauma_type(BRAIN_TRAUMA_SEVERE) + else + M.gain_trauma_type(BRAIN_TRAUMA_SPECIAL) + ..() diff --git a/code/modules/reagents/chemistry/recipes.dm b/code/modules/reagents/chemistry/recipes.dm index 50006eef62..a915087428 100644 --- a/code/modules/reagents/chemistry/recipes.dm +++ b/code/modules/reagents/chemistry/recipes.dm @@ -17,6 +17,25 @@ var/mix_message = "The solution begins to bubble." //The message shown to nearby people upon mixing, if applicable var/mix_sound = 'sound/effects/bubbles.ogg' //The sound played upon mixing, if applicable + //FermiChem! + var/OptimalTempMin = 200 // Lower area of bell curve for determining heat based rate reactions + var/OptimalTempMax = 800 // Upper end for above + var/ExplodeTemp = 900 // Temperature at which reaction explodes - If any reaction is this hot, it explodes! + var/OptimalpHMin = 5 // Lowest value of pH determining pH a 1 value for pH based rate reactions (Plateu phase) + var/OptimalpHMax = 10 // Higest value for above + var/ReactpHLim = 3 // How far out pH wil react, giving impurity place (Exponential phase) + var/CatalystFact = 0 // How much the catalyst affects the reaction (0 = no catalyst)//Not implemented yet + var/CurveSharpT = 2 // How sharp the temperature exponential curve is (to the power of value) + var/CurveSharppH = 2 // How sharp the pH exponential curve is (to the power of value) + var/ThermicConstant = 1 // Temperature change per 1u produced + var/HIonRelease = 0.1 // pH change per 1u reaction + var/RateUpLim = 10 // Optimal/max rate possible if all conditions are perfect + var/FermiChem = FALSE // If the chemical uses the Fermichem reaction mechanics//If the chemical uses the Fermichem reaction mechanics + var/FermiExplode = FALSE // If the chemical explodes in a special way + var/clear_conversion //bitflags for clear conversions; REACTION_CLEAR_IMPURE or REACTION_CLEAR_INVERSE + var/PurityMin = 0.15 //If purity is below 0.15, it explodes too. Set to 0 to disable this. + + /datum/chemical_reaction/proc/on_reaction(datum/reagents/holder, created_volume, specialreact) return //I recommend you set the result amount to the total volume of all components. diff --git a/code/modules/reagents/chemistry/recipes/drugs.dm b/code/modules/reagents/chemistry/recipes/drugs.dm index d91e2af7e9..27b1fe12ee 100644 --- a/code/modules/reagents/chemistry/recipes/drugs.dm +++ b/code/modules/reagents/chemistry/recipes/drugs.dm @@ -41,6 +41,13 @@ results = list("aranesp" = 3) required_reagents = list("epinephrine" = 1, "atropine" = 1, "morphine" = 1) +/datum/chemical_reaction/happiness + name = "Happiness" + id = "happiness" + results = list("happiness" = 4) + required_reagents = list("nitrous_oxide" = 2, "epinephrine" = 1, "ethanol" = 1) + required_catalysts = list("plasma" = 5) + /datum/chemical_reaction/skooma name = "skooma" id = "skooma" diff --git a/code/modules/reagents/chemistry/recipes/medicine.dm b/code/modules/reagents/chemistry/recipes/medicine.dm index 727048a12c..2ed9a31107 100644 --- a/code/modules/reagents/chemistry/recipes/medicine.dm +++ b/code/modules/reagents/chemistry/recipes/medicine.dm @@ -68,6 +68,44 @@ results = list("synthflesh" = 3) required_reagents = list("blood" = 1, "carbon" = 1, "styptic_powder" = 1) +/datum/chemical_reaction/synthtissue + name = "Synthtissue" + id = "synthtissue" + results = list("synthtissue" = 5) + required_reagents = list("synthflesh" = 1) + required_catalysts = list("nutriment" = 0.1) + //FermiChem vars: + OptimalTempMin = 305 // Lower area of bell curve for determining heat based rate reactions + OptimalTempMax = 315 // Upper end for above + ExplodeTemp = 1050 // Temperature at which reaction explodes + OptimalpHMin = 8.5 // Lowest value of pH determining pH a 1 value for pH based rate reactions (Plateu phase) + OptimalpHMax = 9.5 // Higest value for above + ReactpHLim = 2 // How far out pH wil react, giving impurity place (Exponential phase) + CatalystFact = 0 // How much the catalyst affects the reaction (0 = no catalyst) + CurveSharpT = 1 // How sharp the temperature exponential curve is (to the power of value) + CurveSharppH = 2.5 // How sharp the pH exponential curve is (to the power of value) + ThermicConstant = 0.01 // Temperature change per 1u produced + HIonRelease = 0.015 // pH change per 1u reaction (inverse for some reason) + RateUpLim = 0.05 // Optimal/max rate possible if all conditions are perfect + FermiChem = TRUE // If the chemical uses the Fermichem reaction mechanics + PurityMin = 0 + +/datum/chemical_reaction/synthtissue/FermiCreate(datum/reagents/holder, added_volume, added_purity) + var/datum/reagent/synthtissue/St = holder.has_reagent("synthtissue") + var/datum/reagent/N = holder.has_reagent("nutriment") + if(!St) + return + if(holder.chem_temp > 320) + var/temp_ratio = 1-(330 - holder.chem_temp)/10 + holder.remove_reagent(src.id, added_volume*temp_ratio) + if(St.purity < 1) + St.volume *= St.purity + St.purity = 1 + var/amount = CLAMP(0.002, 0, N.volume) + N.volume -= amount + St.data["grown_volume"] = St.data["grown_volume"] + added_volume + St.name = "[initial(St.name)] [round(St.data["grown_volume"], 0.1)]u colony" + /datum/chemical_reaction/styptic_powder name = "Styptic Powder" id = "styptic_powder" @@ -178,6 +216,12 @@ results = list("mutadone" = 3) required_reagents = list("mutagen" = 1, "acetone" = 1, "bromine" = 1) +/datum/chemical_reaction/neurine + name = "Neurine" + id = "neurine" + results = list("neurine" = 3) + required_reagents = list("mannitol" = 1, "acetone" = 1, "oxygen" = 1) + /datum/chemical_reaction/antihol name = "antihol" id = "antihol" @@ -258,3 +302,9 @@ results = list("modafinil" = 5) required_reagents = list("diethylamine" = 1, "ammonia" = 1, "phenol" = 1, "acetone" = 1, "sacid" = 1) required_catalysts = list("bromine" = 1) // as close to the real world synthesis as possible + +/datum/chemical_reaction/psicodine + name = "Psicodine" + id = "psicodine" + results = list("psicodine" = 5) + required_reagents = list( "mannitol" = 2, "water" = 2, "impedrezene" = 1) diff --git a/code/modules/reagents/chemistry/recipes/others.dm b/code/modules/reagents/chemistry/recipes/others.dm index bcd08b1853..eaae548d68 100644 --- a/code/modules/reagents/chemistry/recipes/others.dm +++ b/code/modules/reagents/chemistry/recipes/others.dm @@ -82,6 +82,12 @@ required_temp = 374 mob_react = FALSE +/datum/chemical_reaction/mustard + name = "Mustard" + id = "mustard" + results = list("mustard" = 5) + required_reagents = list("mustardgrind" = 1, "water" = 10, "enzyme"= 1) + /datum/chemical_reaction/soapification/on_reaction(datum/reagents/holder, created_volume) var/location = get_turf(holder.my_atom) for(var/i = 1, i <= created_volume, i++) @@ -488,12 +494,6 @@ results = list("acetone" = 3) required_reagents = list("oil" = 1, "welding_fuel" = 1, "oxygen" = 1) -/datum/chemical_reaction/carpet - name = "carpet" - id = "carpet" - results = list("carpet" = 2) - required_reagents = list("space_drugs" = 1, "blood" = 1) - /datum/chemical_reaction/oil name = "Oil" id = "oil" @@ -528,6 +528,16 @@ /datum/chemical_reaction/life/on_reaction(datum/reagents/holder, created_volume) chemical_mob_spawn(holder, rand(1, round(created_volume, 1)), "Life") // Lol. +//This is missing, I'm adding it back (see tgwiki). Not sure why we don't have it. +/datum/chemical_reaction/life_friendly + name = "Life (Friendly)" + id = "life_friendly" + required_reagents = list("strange_reagent" = 1, "synthflesh" = 1, "sugar" = 1) + required_temp = 374 + +/datum/chemical_reaction/life_friendly/on_reaction(datum/reagents/holder, created_volume) + chemical_mob_spawn(holder, rand(1, round(created_volume, 1)), "Life (friendly)", FRIENDLY_SPAWN) //Pray for cute cats + /datum/chemical_reaction/corgium name = "corgium" id = "corgium" @@ -613,7 +623,7 @@ required_temp = 450 /datum/chemical_reaction/moff - name = "moth mutation toxic" + name = "insect mutation toxic" id = "moffs" results = list("mothmutationtoxin" = 1) required_reagents = list("liquid_dark_matter" = 2, "ammonia" = 5, "lithium" = 1, "stablemutationtoxin" = 1) @@ -625,3 +635,77 @@ results = list("shadowmutationtoxin" = 1) required_reagents = list("liquid_dark_matter" = 5, "synaptizine" = 10, "oculine" = 10, "stablemutationtoxin" = 1) required_temp = 600 + +// Liquid Carpets + +/datum/chemical_reaction/carpet + name = "carpet" + id = "carpet" + results = list("carpet" = 2) + required_reagents = list("space_drugs" = 1, "blood" = 1) + +/datum/chemical_reaction/carpet/black + name = "liquid black carpet" + id = "blackcarpet" + results = list("blackcarpet" = 2) + required_reagents = list("carpet" = 1, "carbon" = 1) + +/datum/chemical_reaction/carpet/blackred + name = "liquid red black carpet" + id = "blackredcarpet" + results = list("blackredcarpet" = 2) + required_reagents = list("carpet" = 1, "charcoal" = 1) + +/datum/chemical_reaction/carpet/monochrome + name = "liquid monochrome carpet" + id = "monochromecarpet" + results = list("monochromecarpet" = 2) + required_reagents = list("carpet" = 1, "oil" = 1) + +/datum/chemical_reaction/carpet/blue + name = "liquid blue carpet" + id = "bluecarpet" + results = list("bluecarpet" = 2) + required_reagents = list("carpet" = 1, "tonic" = 1) + +/datum/chemical_reaction/carpet/cyan + name = "liquid cyan carpet" + id = "cyancarpet" + results = list("cyancarpet" = 2) + required_reagents = list("carpet" = 1, "ice" = 1) + +/datum/chemical_reaction/carpet/green + name = "liquid green carpet" + id = "greencarpet" + results = list("greencarpet" = 2) + required_reagents = list("carpet" = 1, "sacid" = 1) + +/datum/chemical_reaction/carpet/orange + name = "liquid orange carpet" + id = "orangecarpet" + results = list("orangecarpet" = 2) + required_reagents = list("carpet" = 1, "orangejuice" = 1) + +/datum/chemical_reaction/carpet/purple + name = "liquid purple carpet" + id = "purplecarpet" + results = list("purplecarpet" = 2) + required_reagents = list("carpet" = 1, "stable_plasma" = 1) + +/datum/chemical_reaction/carpet/red + name = "liquid red carpet" + id = "redcarpet" + results = list("redcarpet" = 2) + required_reagents = list("carpet" = 1, "welding_fuel" = 1) + +/datum/chemical_reaction/carpet/royalblack + name = "liquid royal black carpet" + id = "royalblackcarpet" + results = list("royalblackcarpet" = 2) + required_reagents = list("carpet" = 1, "blackpepper" = 1) + +/datum/chemical_reaction/carpet/royalblue + name = "liquid royal blue carpet" + id = "royalbluecarpet" + results = list("royalbluecarpet" = 2) + required_reagents = list("carpet" = 1, "clonexadone" = 1) diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm index 13e809f7cb..b3f9591f64 100644 --- a/code/modules/reagents/reagent_containers.dm +++ b/code/modules/reagents/reagent_containers.dm @@ -1,3 +1,6 @@ +#define PH_WEAK (1 << 0) +#define TEMP_WEAK (1 << 1) + /obj/item/reagent_containers name = "Container" desc = "..." @@ -12,6 +15,9 @@ var/spawned_disease = null var/disease_amount = 20 var/spillable = FALSE + var/beaker_weakness_bitflag = NONE//Bitflag! + var/container_HP = 2 + var/cached_icon /obj/item/reagent_containers/Initialize(mapload, vol) . = ..() @@ -123,9 +129,91 @@ reagents.clear_reagents() +//melts plastic beakers /obj/item/reagent_containers/microwave_act(obj/machinery/microwave/M) reagents.expose_temperature(1000) + if(beaker_weakness_bitflag & TEMP_WEAK) + var/list/seen = viewers(5, get_turf(src)) + var/iconhtml = icon2html(src, seen) + for(var/mob/H in seen) + to_chat(H, "[iconhtml] \The [src]'s melts from the temperature!") + playsound(get_turf(src), 'sound/FermiChem/heatmelt.ogg', 80, 1) + qdel(src) ..() +//melts plastic beakers /obj/item/reagent_containers/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) - reagents.expose_temperature(exposed_temperature) \ No newline at end of file + reagents.expose_temperature(exposed_temperature) + temp_check() + +/obj/item/reagent_containers/proc/temp_check() + if(beaker_weakness_bitflag & TEMP_WEAK) + if(reagents.chem_temp >= 444)//assuming polypropylene + START_PROCESSING(SSobj, src) + +//melts glass beakers +/obj/item/reagent_containers/proc/pH_check() + if(beaker_weakness_bitflag & PH_WEAK) + if((reagents.pH < 1.5) || (reagents.pH > 12.5)) + START_PROCESSING(SSobj, src) + + +/obj/item/reagent_containers/process() + if(!cached_icon) + cached_icon = icon_state + var/damage + var/cause + if(beaker_weakness_bitflag & PH_WEAK) + if(reagents.pH < 2) + damage = (2 - reagents.pH)/20 + cause = "from the extreme pH" + playsound(get_turf(src), 'sound/FermiChem/bufferadd.ogg', 50, 1) + + if(reagents.pH > 12) + damage = (reagents.pH - 12)/20 + cause = "from the extreme pH" + playsound(get_turf(src), 'sound/FermiChem/bufferadd.ogg', 50, 1) + + if(beaker_weakness_bitflag & TEMP_WEAK) + if(reagents.chem_temp >= 444) + if(damage) + damage += (reagents.chem_temp/444)/5 + else + damage = (reagents.chem_temp/444)/5 + if(cause) + cause += " and " + cause += "from the high temperature" + playsound(get_turf(src), 'sound/FermiChem/heatdam.ogg', 50, 1) + + if(!damage || damage <= 0) + STOP_PROCESSING(SSobj, src) + + container_HP -= damage + + var/list/seen = viewers(5, get_turf(src)) + var/iconhtml = icon2html(src, seen) + + var/damage_percent = ((container_HP / initial(container_HP)*100)) + switch(damage_percent) + if(-INFINITY to 0) + for(var/mob/M in seen) + to_chat(M, "[iconhtml] \The [src]'s melts [cause]!") + playsound(get_turf(src), 'sound/FermiChem/acidmelt.ogg', 80, 1) + SSblackbox.record_feedback("tally", "fermi_chem", 1, "Times beakers have melted") + STOP_PROCESSING(SSobj, src) + qdel(src) + return + if(0 to 35) + icon_state = "[cached_icon]_m3" + desc = "[initial(desc)] It is severely deformed." + if(35 to 70) + icon_state = "[cached_icon]_m2" + desc = "[initial(desc)] It is deformed." + if(70 to 85) + desc = "[initial(desc)] It is mildly deformed." + icon_state = "[cached_icon]_m1" + + update_icon() + if(prob(25)) + for(var/mob/M in seen) + to_chat(M, "[iconhtml] \The [src]'s is damaged by [cause] and begins to deform!") diff --git a/code/modules/reagents/reagent_containers/blood_pack.dm b/code/modules/reagents/reagent_containers/blood_pack.dm index 31e893aa3a..3e555f385f 100644 --- a/code/modules/reagents/reagent_containers/blood_pack.dm +++ b/code/modules/reagents/reagent_containers/blood_pack.dm @@ -90,3 +90,9 @@ update_pack_name() else return ..() + +/obj/item/reagent_containers/blood/bluespace + name = "bluespace blood pack" + desc = "Contains blood used for transfusion, this one has been made with bluespace technology to hold much more blood. Must be attached to an IV drip." + icon_state = "bsbloodpack" + volume = 600 //its a blood bath! \ No newline at end of file diff --git a/code/modules/reagents/reagent_containers/bottle.dm b/code/modules/reagents/reagent_containers/bottle.dm index 66befb1bb6..afe48ab3fb 100644 --- a/code/modules/reagents/reagent_containers/bottle.dm +++ b/code/modules/reagents/reagent_containers/bottle.dm @@ -240,7 +240,7 @@ name = "Rhinovirus culture bottle" desc = "A small bottle. Contains XY-rhinovirus culture in synthblood medium." spawned_disease = /datum/disease/advance/cold - + /obj/item/reagent_containers/glass/bottle/flu_virion name = "Flu virion culture bottle" desc = "A small bottle. Contains H13N1 flu virion culture in synthblood medium." @@ -404,3 +404,25 @@ /obj/item/reagent_containers/glass/bottle/bromine name = "bromine bottle" list_reagents = list("bromine" = 30) + +//Lewd Stuff + +/obj/item/reagent_containers/glass/bottle/crocin + name = "Crocin bottle" + desc = "A bottle of mild aphrodisiac. Increases libido." + list_reagents = list("aphro" = 30) + +/obj/item/reagent_containers/glass/bottle/hexacrocin + name = "Hexacrocin bottle" + desc = "A bottle of strong aphrodisiac. Increases libido." + list_reagents = list("aphro+" = 30) + +/obj/item/reagent_containers/glass/bottle/camphor + name = "Camphor bottle" + desc = "A bottle of mild anaphrodisiac. Reduces libido." + list_reagents = list("anaphro" = 30) + +/obj/item/reagent_containers/glass/bottle/hexacamphor + name = "Hexacamphor bottle" + desc = "A bottle of strong anaphrodisiac. Reduces libido." + list_reagents = list("anaphro+" = 30) \ No newline at end of file diff --git a/code/modules/reagents/reagent_containers/glass.dm b/code/modules/reagents/reagent_containers/glass.dm index 9bc6bef8a5..257106aaa7 100644 --- a/code/modules/reagents/reagent_containers/glass.dm +++ b/code/modules/reagents/reagent_containers/glass.dm @@ -6,6 +6,7 @@ reagent_flags = OPENCONTAINER spillable = TRUE resistance_flags = ACID_PROOF + container_HP = 2 /obj/item/reagent_containers/glass/attack(mob/M, mob/user, obj/target) @@ -108,11 +109,12 @@ /obj/item/reagent_containers/glass/beaker name = "beaker" - desc = "A beaker. It can hold up to 50 units." + desc = "A beaker. It can hold up to 50 units. Unable to withstand extreme pHes" icon = 'icons/obj/chemical.dmi' icon_state = "beaker" item_state = "beaker" materials = list(MAT_GLASS=500) + beaker_weakness_bitflag = PH_WEAK /obj/item/reagent_containers/glass/beaker/Initialize() . = ..() @@ -125,54 +127,62 @@ update_icon() /obj/item/reagent_containers/glass/beaker/update_icon() + if(!cached_icon) + cached_icon = icon_state cut_overlays() if(reagents.total_volume) - var/mutable_appearance/filling = mutable_appearance('icons/obj/reagentfillings.dmi', "[icon_state]10") + var/mutable_appearance/filling = mutable_appearance('icons/obj/reagentfillings.dmi', "[cached_icon]10") var/percent = round((reagents.total_volume / volume) * 100) switch(percent) if(0 to 9) - filling.icon_state = "[icon_state]-10" + filling.icon_state = "[cached_icon]-10" if(10 to 24) - filling.icon_state = "[icon_state]10" + filling.icon_state = "[cached_icon]10" if(25 to 49) - filling.icon_state = "[icon_state]25" + filling.icon_state = "[cached_icon]25" if(50 to 74) - filling.icon_state = "[icon_state]50" + filling.icon_state = "[cached_icon]50" if(75 to 79) - filling.icon_state = "[icon_state]75" + filling.icon_state = "[cached_icon]75" if(80 to 90) - filling.icon_state = "[icon_state]80" + filling.icon_state = "[cached_icon]80" if(91 to INFINITY) - filling.icon_state = "[icon_state]100" + filling.icon_state = "[cached_icon]100" filling.color = mix_color_from_reagents(reagents.reagent_list) add_overlay(filling) /obj/item/reagent_containers/glass/beaker/jar name = "honey jar" - desc = "A jar for honey. It can hold up to 50 units of sweet delight." + desc = "A jar for honey. It can hold up to 50 units of sweet delight. Unable to withstand reagents of an extreme pH." icon = 'icons/obj/chemical.dmi' icon_state = "vapour" /obj/item/reagent_containers/glass/beaker/large name = "large beaker" - desc = "A large beaker. Can hold up to 100 units." + desc = "A large beaker. Can hold up to 100 units. Unable to withstand reagents of an extreme pH." icon_state = "beakerlarge" materials = list(MAT_GLASS=2500) volume = 100 amount_per_transfer_from_this = 10 possible_transfer_amounts = list(5,10,15,20,25,30,50,100) + container_HP = 3 /obj/item/reagent_containers/glass/beaker/plastic name = "x-large beaker" - desc = "An extra-large beaker. Can hold up to 120 units." + desc = "An extra-large beaker. Can hold up to 150 units. Is able to resist acid and alkaline solutions, but melts at 444K" icon_state = "beakerwhite" materials = list(MAT_GLASS=2500, MAT_PLASTIC=3000) - volume = 120 + volume = 150 amount_per_transfer_from_this = 10 - possible_transfer_amounts = list(5,10,15,20,25,30,60,120) + possible_transfer_amounts = list(5,10,15,20,25,30,50,100,150) + +/obj/item/reagent_containers/glass/beaker/plastic/Initialize() + beaker_weakness_bitflag &= ~PH_WEAK + beaker_weakness_bitflag |= TEMP_WEAK + . = ..() /obj/item/reagent_containers/glass/beaker/plastic/update_icon() icon_state = "beakerlarge" // hack to lets us reuse the large beaker reagent fill states @@ -181,12 +191,16 @@ /obj/item/reagent_containers/glass/beaker/meta name = "metamaterial beaker" - desc = "A large beaker. Can hold up to 180 units." + desc = "A large beaker. Can hold up to 200 units. Is able to withstand all chemical situations." icon_state = "beakergold" materials = list(MAT_GLASS=2500, MAT_PLASTIC=3000, MAT_GOLD=1000, MAT_TITANIUM=1000) - volume = 180 + volume = 200 amount_per_transfer_from_this = 10 - possible_transfer_amounts = list(5,10,15,20,25,30,60,120,180) + possible_transfer_amounts = list(5,10,15,20,25,30,50,100,200) + +/obj/item/reagent_containers/glass/beaker/meta/Initialize() + beaker_weakness_bitflag &= ~PH_WEAK + . = ..() /obj/item/reagent_containers/glass/beaker/noreact name = "cryostasis beaker" @@ -197,17 +211,24 @@ reagent_flags = OPENCONTAINER | NO_REACT volume = 50 amount_per_transfer_from_this = 10 + container_HP = 10//shouldn't be needed + +/obj/item/reagent_containers/glass/beaker/noreact/Initialize() + beaker_weakness_bitflag &= ~PH_WEAK + . = ..() + //reagents.set_reacting(FALSE) was this removed in a recent pr? /obj/item/reagent_containers/glass/beaker/bluespace name = "bluespace beaker" desc = "A bluespace beaker, powered by experimental bluespace technology \ and Element Cuban combined with the Compound Pete. Can hold up to \ - 300 units." + 300 units. Unable to withstand reagents of an extreme pH." icon_state = "beakerbluespace" materials = list(MAT_GLASS=3000) volume = 300 amount_per_transfer_from_this = 10 possible_transfer_amounts = list(5,10,15,20,25,30,50,100,300) + container_HP = 4 /obj/item/reagent_containers/glass/beaker/cryoxadone list_reagents = list("cryoxadone" = 30) @@ -264,6 +285,11 @@ SLOT_L_STORE, SLOT_R_STORE,\ SLOT_GENERC_DEXTROUS_STORAGE ) + container_HP = 1 + +/obj/item/reagent_containers/glass/bucket/Initialize() + beaker_weakness_bitflag |= TEMP_WEAK + . = ..() /obj/item/reagent_containers/glass/bucket/attackby(obj/O, mob/user, params) if(istype(O, /obj/item/mop)) @@ -313,6 +339,11 @@ materials = list(MAT_GLASS=0) volume = 50 amount_per_transfer_from_this = 10 + container_HP = 1 + +/obj/item/reagent_containers/glass/beaker/waterbottle/Initialize() + beaker_weakness_bitflag |= TEMP_WEAK + . = ..() /obj/item/reagent_containers/glass/beaker/waterbottle/empty list_reagents = list() @@ -324,6 +355,7 @@ list_reagents = list("water" = 100) volume = 100 amount_per_transfer_from_this = 20 + container_HP = 1 /obj/item/reagent_containers/glass/beaker/waterbottle/large/empty list_reagents = list() diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm index 82d95cea40..a96ba006c9 100644 --- a/code/modules/reagents/reagent_containers/hypospray.dm +++ b/code/modules/reagents/reagent_containers/hypospray.dm @@ -127,6 +127,21 @@ else to_chat(usr, "It is spent.") +/obj/item/reagent_containers/hypospray/medipen/stimulants + name = "illegal stimpack medipen" + desc = "A highly illegal medipen due to its load and small injections, allow for five uses before being drained" + volume = 50 + amount_per_transfer_from_this = 10 + list_reagents = list("stimulants" = 50) + +/obj/item/reagent_containers/hypospray/medipen/stimulants/baseball + name = "the reason the syndicate major league team wins." + desc = "They say drugs never win, but look where you are now, then where they are." + icon_state = "baseballstim" + volume = 50 + amount_per_transfer_from_this = 50 + list_reagents = list("stimulants" = 50) + /obj/item/reagent_containers/hypospray/medipen/stimpack //goliath kiting name = "stimpack medipen" desc = "A rapid way to stimulate your body's adrenaline, allowing for freer movement in restrictive armor." diff --git a/code/modules/reagents/reagent_containers/medspray.dm b/code/modules/reagents/reagent_containers/medspray.dm index 54a38eef86..df7c7af225 100644 --- a/code/modules/reagents/reagent_containers/medspray.dm +++ b/code/modules/reagents/reagent_containers/medspray.dm @@ -19,8 +19,8 @@ var/can_fill_from_container = TRUE var/apply_type = PATCH var/apply_method = "spray" - var/self_delay = 30 - var/squirt_mode = 0 + var/self_delay = 3 SECONDS + var/squirt_mode = FALSE var/squirt_amount = 5 /obj/item/reagent_containers/medspray/attack_self(mob/user) @@ -31,40 +31,51 @@ amount_per_transfer_from_this = initial(amount_per_transfer_from_this) to_chat(user, "You will now apply the medspray's contents in [squirt_mode ? "short bursts":"extended sprays"]. You'll now use [amount_per_transfer_from_this] units per use.") -/obj/item/reagent_containers/medspray/attack(mob/M, mob/user, def_zone) +/obj/item/reagent_containers/medspray/attack(mob/living/L, mob/user, def_zone) if(!reagents || !reagents.total_volume) to_chat(user, "[src] is empty!") return - if(M == user) - M.visible_message("[user] attempts to [apply_method] [src] on [user.p_them()]self.") + if(ishuman(L)) + var/obj/item/bodypart/affecting = L.get_bodypart(check_zone(user.zone_selected)) + if(!affecting) + to_chat(user, "The limb is missing!") + return + if(!L.can_inject(user, TRUE, user.zone_selected, FALSE, TRUE)) //stopped by clothing, like patches + return + if(affecting.status != BODYPART_ORGANIC) + to_chat(user, "Medicine won't work on a robotic limb!") + return + + if(L == user) + L.visible_message("[user] attempts to [apply_method] [src] on [user.p_them()]self.") if(self_delay) - if(!do_mob(user, M, self_delay)) + if(!do_mob(user, L, self_delay)) return if(!reagents || !reagents.total_volume) return - to_chat(M, "You [apply_method] yourself with [src].") + to_chat(L, "You [apply_method] yourself with [src].") else - log_combat(user, M, "attempted to apply", src, reagents.log_list()) - M.visible_message("[user] attempts to [apply_method] [src] on [M].", \ - "[user] attempts to [apply_method] [src] on [M].") - if(!do_mob(user, M)) + log_combat(user, L, "attempted to apply", src, reagents.log_list()) + L.visible_message("[user] attempts to [apply_method] [src] on [L].", \ + "[user] attempts to [apply_method] [src] on [L].") + if(!do_mob(user, L)) return if(!reagents || !reagents.total_volume) return - M.visible_message("[user] [apply_method]s [M] down with [src].", \ - "[user] [apply_method]s [M] down with [src].") + L.visible_message("[user] [apply_method]s [L] down with [src].", \ + "[user] [apply_method]s [L] down with [src].") if(!reagents || !reagents.total_volume) return else - log_combat(user, M, "applied", src, reagents.log_list()) + log_combat(user, L, "applied", src, reagents.log_list()) playsound(src, 'sound/effects/spray2.ogg', 50, 1, -6) var/fraction = min(amount_per_transfer_from_this/reagents.total_volume, 1) - reagents.reaction(M, apply_type, fraction) - reagents.trans_to(M, amount_per_transfer_from_this) + reagents.reaction(L, apply_type, fraction) + reagents.trans_to(L, amount_per_transfer_from_this) return /obj/item/reagent_containers/medspray/styptic diff --git a/code/modules/reagents/reagent_containers/pill.dm b/code/modules/reagents/reagent_containers/pill.dm index 280337e686..38880f669f 100644 --- a/code/modules/reagents/reagent_containers/pill.dm +++ b/code/modules/reagents/reagent_containers/pill.dm @@ -1,242 +1,259 @@ -/obj/item/reagent_containers/pill - name = "pill" - desc = "A tablet or capsule." - icon = 'icons/obj/chemical.dmi' - icon_state = "pill" - item_state = "pill" - lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' - possible_transfer_amounts = list() - volume = 50 - grind_results = list() - var/apply_type = INGEST - var/apply_method = "swallow" - var/roundstart = 0 - var/self_delay = 0 //pills are instant, this is because patches inheret their aplication from pills - var/dissolvable = TRUE - -/obj/item/reagent_containers/pill/Initialize() - . = ..() - if(!icon_state) - icon_state = "pill[rand(1,20)]" - if(reagents.total_volume && roundstart) - name += " ([reagents.total_volume]u)" - - -/obj/item/reagent_containers/pill/attack_self(mob/user) - return - - -/obj/item/reagent_containers/pill/attack(mob/M, mob/user, def_zone) - if(!canconsume(M, user)) - return 0 - - if(M == user) - M.visible_message("[user] attempts to [apply_method] [src].") - if(self_delay) - if(!do_mob(user, M, self_delay)) - return 0 - to_chat(M, "You [apply_method] [src].") - - else - M.visible_message("[user] attempts to force [M] to [apply_method] [src].", \ - "[user] attempts to force [M] to [apply_method] [src].") - if(!do_mob(user, M)) - return 0 - M.visible_message("[user] forces [M] to [apply_method] [src].", \ - "[user] forces [M] to [apply_method] [src].") - - var/makes_me_think = pick(strings("redpill.json", "redpill_questions")) - if(icon_state == "pill4" && prob(5)) //you take the red pill - you stay in Wonderland, and I show you how deep the rabbit hole goes - addtimer(CALLBACK(GLOBAL_PROC, /proc/to_chat, M, "[makes_me_think]"), 50) - - log_combat(user, M, "fed", reagents.log_list()) - if(reagents.total_volume) - reagents.reaction(M, apply_type) - reagents.trans_to(M, reagents.total_volume) - qdel(src) - return 1 - - -/obj/item/reagent_containers/pill/afterattack(obj/target, mob/user , proximity) - . = ..() - if(!proximity) - return - if(!dissolvable || !target.is_refillable()) - return - if(target.is_drainable() && !target.reagents.total_volume) - to_chat(user, "[target] is empty! There's nothing to dissolve [src] in.") - return - - if(target.reagents.holder_full()) - to_chat(user, "[target] is full.") - return - - to_chat(user, "You dissolve [src] in [target].") - for(var/mob/O in viewers(2, user)) //viewers is necessary here because of the small radius - to_chat(O, "[user] slips something into [target]!") - reagents.trans_to(target, reagents.total_volume) - qdel(src) - -/obj/item/reagent_containers/pill/tox - name = "toxins pill" - desc = "Highly toxic." - icon_state = "pill5" - list_reagents = list("toxin" = 50) - roundstart = 1 - -/obj/item/reagent_containers/pill/cyanide - name = "cyanide pill" - desc = "Don't swallow this." - icon_state = "pill5" - list_reagents = list("cyanide" = 50) - roundstart = 1 - -/obj/item/reagent_containers/pill/adminordrazine - name = "adminordrazine pill" - desc = "It's magic. We don't have to explain it." - icon_state = "pill16" - list_reagents = list("adminordrazine" = 50) - roundstart = 1 - -/obj/item/reagent_containers/pill/morphine - name = "morphine pill" - desc = "Commonly used to treat insomnia." - icon_state = "pill8" - list_reagents = list("morphine" = 30) - roundstart = 1 - -/obj/item/reagent_containers/pill/stimulant - name = "stimulant pill" - desc = "Often taken by overworked employees, athletes, and the inebriated. You'll snap to attention immediately!" - icon_state = "pill19" - list_reagents = list("ephedrine" = 10, "antihol" = 10, "coffee" = 30) - roundstart = 1 - -/obj/item/reagent_containers/pill/salbutamol - name = "salbutamol pill" - desc = "Used to treat oxygen deprivation." - icon_state = "pill16" - list_reagents = list("salbutamol" = 30) - roundstart = 1 - -/obj/item/reagent_containers/pill/charcoal - name = "charcoal pill" - desc = "Neutralizes many common toxins." - icon_state = "pill17" - list_reagents = list("charcoal" = 10) - roundstart = 1 - -/obj/item/reagent_containers/pill/epinephrine - name = "epinephrine pill" - desc = "Used to stabilize patients." - icon_state = "pill5" - list_reagents = list("epinephrine" = 15) - roundstart = 1 - -/obj/item/reagent_containers/pill/mannitol - name = "mannitol pill" - desc = "Used to treat brain damage." - icon_state = "pill17" - list_reagents = list("mannitol" = 50) - roundstart = 1 - -/obj/item/reagent_containers/pill/mutadone - name = "mutadone pill" - desc = "Used to treat genetic damage." - icon_state = "pill20" - list_reagents = list("mutadone" = 50) - roundstart = 1 - -/obj/item/reagent_containers/pill/salicyclic - name = "salicylic acid pill" - desc = "Used to dull pain." - icon_state = "pill9" - list_reagents = list("sal_acid" = 24) - roundstart = 1 - -/obj/item/reagent_containers/pill/oxandrolone - name = "oxandrolone pill" - desc = "Used to stimulate burn healing." - icon_state = "pill11" - list_reagents = list("oxandrolone" = 24) - roundstart = 1 - -/obj/item/reagent_containers/pill/insulin - name = "insulin pill" - desc = "Handles hyperglycaemic coma." - icon_state = "pill18" - list_reagents = list("insulin" = 50) - roundstart = 1 - -/obj/item/reagent_containers/pill/antirad - name = "potassium iodide pill" - desc = "Used to treat radition used to counter radiation poisoning." - icon_state = "pill18" - list_reagents = list("potass_iodide" = 50) - roundstart = 1 - -/obj/item/reagent_containers/pill/antirad_plus - name = "prussian blue pill" - desc = "Used to treat heavy radition poisoning." - icon = 'modular_citadel/icons/obj/modularpills.dmi' - icon_state = "prussian_blue" - list_reagents = list("prussian_blue" = 25, "water" = 10) - roundstart = 1 - -/obj/item/reagent_containers/pill/mutarad - name = "radiation treatment deluxe pill" - desc = "Used to treat heavy radition poisoning and genetic defects." - icon = 'modular_citadel/icons/obj/modularpills.dmi' - icon_state = "anit_rad_fixgene" - list_reagents = list("prussian_blue" = 15, "potass_iodide" = 15, "mutadone" = 15, "water" = 5) - roundstart = 1 - -///////////////////////////////////////// this pill is used only in a legion mob drop -/obj/item/reagent_containers/pill/shadowtoxin - name = "black pill" - desc = "I wouldn't eat this if I were you." - icon_state = "pill9" - color = "#454545" - list_reagents = list("shadowmutationtoxin" = 1) -//////////////////////////////////////// drugs -/obj/item/reagent_containers/pill/zoom - name = "zoom pill" - list_reagents = list("synaptizine" = 10, "nicotine" = 10, "methamphetamine" = 1) - - -/obj/item/reagent_containers/pill/happy - name = "happy pill" - list_reagents = list("sugar" = 10, "space_drugs" = 10) - - -/obj/item/reagent_containers/pill/lsd - name = "hallucinogen pill" - list_reagents = list("mushroomhallucinogen" = 15, "mindbreaker" = 15) - - -/obj/item/reagent_containers/pill/aranesp - name = "speedy pill" - list_reagents = list("aranesp" = 10) - -/obj/item/reagent_containers/pill/floorpill - name = "floorpill" - desc = "A strange pill found in the depths of maintenance" - icon_state = "pill21" - var/static/list/names = list("maintenance pill","floorpill","mystery pill","suspicious pill","strange pill") - var/static/list/descs = list("Your feeling is telling you no, but...","Drugs are expensive, you can't afford not to eat any pills that you find."\ - , "Surely, there's no way this could go bad.") - -/obj/item/reagent_containers/pill/floorpill/Initialize() - list_reagents = list(get_random_reagent_id() = rand(10,50)) - . = ..() - name = pick(names) - if(prob(20)) - desc = pick(descs) - -/obj/item/reagent_containers/pill/get_belt_overlay() - return mutable_appearance('icons/obj/clothing/belt_overlays.dmi', "pouch") - -/obj/item/reagent_containers/pill/penis_enlargement - name = "penis enlargement pill" - list_reagents = list("penis_enlargement" = 30) +/obj/item/reagent_containers/pill + name = "pill" + desc = "A tablet or capsule." + icon = 'icons/obj/chemical.dmi' + icon_state = "pill" + item_state = "pill" + lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' + possible_transfer_amounts = list() + volume = 50 + grind_results = list() + var/apply_type = INGEST + var/apply_method = "swallow" + var/roundstart = 0 + var/self_delay = 0 //pills are instant, this is because patches inheret their aplication from pills + var/dissolvable = TRUE + +/obj/item/reagent_containers/pill/Initialize() + . = ..() + if(!icon_state) + icon_state = "pill[rand(1,20)]" + if(reagents.total_volume && roundstart) + name += " ([reagents.total_volume]u)" + + +/obj/item/reagent_containers/pill/attack_self(mob/user) + return + + +/obj/item/reagent_containers/pill/attack(mob/M, mob/user, def_zone) + if(!canconsume(M, user)) + return 0 + + if(M == user) + M.visible_message("[user] attempts to [apply_method] [src].") + if(self_delay) + if(!do_mob(user, M, self_delay)) + return 0 + to_chat(M, "You [apply_method] [src].") + + else + M.visible_message("[user] attempts to force [M] to [apply_method] [src].", \ + "[user] attempts to force [M] to [apply_method] [src].") + if(!do_mob(user, M)) + return 0 + M.visible_message("[user] forces [M] to [apply_method] [src].", \ + "[user] forces [M] to [apply_method] [src].") + + var/makes_me_think = pick(strings("redpill.json", "redpill_questions")) + if(icon_state == "pill4" && prob(5)) //you take the red pill - you stay in Wonderland, and I show you how deep the rabbit hole goes + addtimer(CALLBACK(GLOBAL_PROC, /proc/to_chat, M, "[makes_me_think]"), 50) + + log_combat(user, M, "fed", reagents.log_list()) + if(reagents.total_volume) + reagents.reaction(M, apply_type) + reagents.trans_to(M, reagents.total_volume) + qdel(src) + return 1 + + +/obj/item/reagent_containers/pill/afterattack(obj/target, mob/user , proximity) + . = ..() + if(!proximity) + return + if(!dissolvable || !target.is_refillable()) + return + if(target.is_drainable() && !target.reagents.total_volume) + to_chat(user, "[target] is empty! There's nothing to dissolve [src] in.") + return + + if(target.reagents.holder_full()) + to_chat(user, "[target] is full.") + return + + to_chat(user, "You dissolve [src] in [target].") + for(var/mob/O in viewers(2, user)) //viewers is necessary here because of the small radius + to_chat(O, "[user] slips something into [target]!") + reagents.trans_to(target, reagents.total_volume) + qdel(src) + +/obj/item/reagent_containers/pill/tox + name = "toxins pill" + desc = "Highly toxic." + icon_state = "pill5" + list_reagents = list("toxin" = 50) + roundstart = 1 + +/obj/item/reagent_containers/pill/cyanide + name = "cyanide pill" + desc = "Don't swallow this." + icon_state = "pill5" + list_reagents = list("cyanide" = 50) + roundstart = 1 + +/obj/item/reagent_containers/pill/adminordrazine + name = "adminordrazine pill" + desc = "It's magic. We don't have to explain it." + icon_state = "pill16" + list_reagents = list("adminordrazine" = 50) + roundstart = 1 + +/obj/item/reagent_containers/pill/morphine + name = "morphine pill" + desc = "Commonly used to treat insomnia." + icon_state = "pill8" + list_reagents = list("morphine" = 30) + roundstart = 1 + +/obj/item/reagent_containers/pill/stimulant + name = "stimulant pill" + desc = "Often taken by overworked employees, athletes, and the inebriated. You'll snap to attention immediately!" + icon_state = "pill19" + list_reagents = list("ephedrine" = 10, "antihol" = 10, "coffee" = 30) + roundstart = 1 + +/obj/item/reagent_containers/pill/salbutamol + name = "salbutamol pill" + desc = "Used to treat oxygen deprivation." + icon_state = "pill16" + list_reagents = list("salbutamol" = 30) + roundstart = 1 + +/obj/item/reagent_containers/pill/charcoal + name = "charcoal pill" + desc = "Neutralizes many common toxins." + icon_state = "pill17" + list_reagents = list("charcoal" = 10) + roundstart = 1 + +/obj/item/reagent_containers/pill/epinephrine + name = "epinephrine pill" + desc = "Used to stabilize patients." + icon_state = "pill5" + list_reagents = list("epinephrine" = 15) + roundstart = 1 + +/obj/item/reagent_containers/pill/mannitol + name = "mannitol pill" + desc = "Used to treat brain damage." + icon_state = "pill17" + list_reagents = list("mannitol" = 50) + roundstart = 1 + +/obj/item/reagent_containers/pill/mutadone + name = "mutadone pill" + desc = "Used to treat genetic damage." + icon_state = "pill20" + list_reagents = list("mutadone" = 50) + roundstart = 1 + +/obj/item/reagent_containers/pill/salicyclic + name = "salicylic acid pill" + desc = "Used to dull pain." + icon_state = "pill9" + list_reagents = list("sal_acid" = 24) + roundstart = 1 + +/obj/item/reagent_containers/pill/oxandrolone + name = "oxandrolone pill" + desc = "Used to stimulate burn healing." + icon_state = "pill11" + list_reagents = list("oxandrolone" = 24) + roundstart = 1 + +/obj/item/reagent_containers/pill/insulin + name = "insulin pill" + desc = "Handles hyperglycaemic coma." + icon_state = "pill18" + list_reagents = list("insulin" = 50) + roundstart = 1 + +/obj/item/reagent_containers/pill/psicodine + name = "psicodine pill" + desc = "Used to treat mental instability and traumas." + list_reagents = list("psicodine" = 10) + icon_state = "pill22" + roundstart = 1 + +/obj/item/reagent_containers/pill/antirad + name = "potassium iodide pill" + desc = "Used to treat radition used to counter radiation poisoning." + icon_state = "pill18" + list_reagents = list("potass_iodide" = 50) + roundstart = 1 + +/obj/item/reagent_containers/pill/antirad_plus + name = "prussian blue pill" + desc = "Used to treat heavy radition poisoning." + icon = 'modular_citadel/icons/obj/modularpills.dmi' + icon_state = "prussian_blue" + list_reagents = list("prussian_blue" = 25, "water" = 10) + roundstart = 1 + +/obj/item/reagent_containers/pill/mutarad + name = "radiation treatment deluxe pill" + desc = "Used to treat heavy radition poisoning and genetic defects." + icon = 'modular_citadel/icons/obj/modularpills.dmi' + icon_state = "anit_rad_fixgene" + list_reagents = list("prussian_blue" = 15, "potass_iodide" = 15, "mutadone" = 15, "water" = 5) + roundstart = 1 + +///////////////////////////////////////// this pill is used only in a legion mob drop +/obj/item/reagent_containers/pill/shadowtoxin + name = "black pill" + desc = "I wouldn't eat this if I were you." + icon_state = "pill9" + color = "#454545" + list_reagents = list("shadowmutationtoxin" = 1) +//////////////////////////////////////// drugs +/obj/item/reagent_containers/pill/zoom + name = "zoom pill" + list_reagents = list("synaptizine" = 10, "nicotine" = 10, "methamphetamine" = 1) + + +/obj/item/reagent_containers/pill/happy + name = "happy pill" + list_reagents = list("sugar" = 10, "space_drugs" = 10) + + +/obj/item/reagent_containers/pill/lsd + name = "hallucinogen pill" + list_reagents = list("mushroomhallucinogen" = 15, "mindbreaker" = 15) + + +/obj/item/reagent_containers/pill/aranesp + name = "speedy pill" + list_reagents = list("aranesp" = 10) + +/obj/item/reagent_containers/pill/happiness + name = "happiness pill" + desc = "It has a creepy smiling face on it." + icon_state = "pill_happy" + list_reagents = list("happiness" = 10) + +/obj/item/reagent_containers/pill/floorpill + name = "floorpill" + desc = "A strange pill found in the depths of maintenance" + icon_state = "pill21" + var/static/list/names = list("maintenance pill","floorpill","mystery pill","suspicious pill","strange pill") + var/static/list/descs = list("Your feeling is telling you no, but...","Drugs are expensive, you can't afford not to eat any pills that you find."\ + , "Surely, there's no way this could go bad.") + +/obj/item/reagent_containers/pill/floorpill/Initialize() + list_reagents = list(get_random_reagent_id() = rand(10,50)) + . = ..() + name = pick(names) + if(prob(20)) + desc = pick(descs) + +/obj/item/reagent_containers/pill/get_belt_overlay() + return mutable_appearance('icons/obj/clothing/belt_overlays.dmi', "pouch") + +/obj/item/reagent_containers/pill/penis_enlargement + name = "penis enlargement pill" + list_reagents = list("penis_enlarger" = 10) + +/obj/item/reagent_containers/pill/breast_enlargement + name = "breast enlargement pill" + list_reagents = list("breast_enlarger" = 10) diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm index cc83eb28f6..6bdae6225a 100644 --- a/code/modules/reagents/reagent_containers/syringes.dm +++ b/code/modules/reagents/reagent_containers/syringes.dm @@ -104,7 +104,7 @@ var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this) // transfer from, transfer to - who cares? to_chat(user, "You fill [src] with [trans] units of the solution. It now contains [reagents.total_volume] units.") - if (reagents.total_volume >= reagents.maximum_volume) + if (round(reagents.total_volume, 0.1) >= reagents.maximum_volume) mode=!mode update_icon() @@ -307,7 +307,7 @@ var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this) to_chat(user, "You soak the [src] with [trans] units of the solution. It now contains [reagents.total_volume] units.") - if (reagents.total_volume >= reagents.maximum_volume) + if (round(reagents.total_volume,1) >= reagents.maximum_volume) mode=!mode update_icon() @@ -323,8 +323,9 @@ rounded_vol = "empty" if(reagents && reagents.total_volume) - if(volume/reagents.total_volume == 1) + if(volume/round(reagents.total_volume, 1) == 1) rounded_vol="full" + mode = SYRINGE_INJECT icon_state = "[rounded_vol]" item_state = "syringe_[rounded_vol]" diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm index 19afab2e6e..216ecd9654 100644 --- a/code/modules/reagents/reagent_dispenser.dm +++ b/code/modules/reagents/reagent_dispenser.dm @@ -39,6 +39,10 @@ else qdel(src) +/////////////// +//Water Tanks// +/////////////// + /obj/structure/reagent_dispensers/watertank name = "water tank" desc = "A water tank." @@ -57,12 +61,52 @@ reagent_id = "firefighting_foam" tank_volume = 500 +/obj/structure/reagent_dispensers/water_cooler + name = "liquid cooler" + desc = "A machine that dispenses liquid to drink." + icon = 'icons/obj/vending.dmi' + icon_state = "water_cooler" + anchored = TRUE + tank_volume = 500 + var/paper_cups = 25 //Paper cups left from the cooler + +/obj/structure/reagent_dispensers/water_cooler/examine(mob/user) + ..() + if (paper_cups > 1) + to_chat(user, "There are [paper_cups] paper cups left.") + else if (paper_cups == 1) + to_chat(user, "There is one paper cup left.") + else + to_chat(user, "There are no paper cups left.") + +/obj/structure/reagent_dispensers/water_cooler/attack_hand(mob/living/user) + . = ..() + if(.) + return + if(!paper_cups) + to_chat(user, "There aren't any cups left!") + return + user.visible_message("[user] takes a cup from [src].", "You take a paper cup from [src].") + var/obj/item/reagent_containers/food/drinks/sillycup/S = new(get_turf(src)) + user.put_in_hands(S) + paper_cups-- + +////////////// +//Fuel Tanks// +////////////// + /obj/structure/reagent_dispensers/fueltank name = "fuel tank" desc = "A tank full of industrial welding fuel. Do not consume." icon_state = "fuel" reagent_id = "welding_fuel" +/obj/structure/reagent_dispensers/fueltank/high //Unused - Good for ghost roles + name = "high-capacity fuel tank" + desc = "A now illegal tank, full of highly pressurized industrial welding fuel. Do not consume or have a open flame close to this tank." + icon_state = "fuel_high" + tank_volume = 3000 + /obj/structure/reagent_dispensers/fueltank/boom() explosion(get_turf(src), 0, 1, 5, flame_range = 5) qdel(src) @@ -117,6 +161,9 @@ return return ..() +/////////////////// +//Misc Dispenders// +/////////////////// /obj/structure/reagent_dispensers/peppertank name = "pepper spray refiller" @@ -131,36 +178,24 @@ if(prob(1)) desc = "IT'S PEPPER TIME, BITCH!" - -/obj/structure/reagent_dispensers/water_cooler - name = "liquid cooler" - desc = "A machine that dispenses liquid to drink." - icon = 'icons/obj/vending.dmi' - icon_state = "water_cooler" +/obj/structure/reagent_dispensers/virusfood + name = "virus food dispenser" + desc = "A dispenser of low-potency virus mutagenic." + icon_state = "virus_food" anchored = TRUE - tank_volume = 500 - var/paper_cups = 25 //Paper cups left from the cooler + density = FALSE + reagent_id = "virusfood" -/obj/structure/reagent_dispensers/water_cooler/examine(mob/user) - ..() - if (paper_cups > 1) - to_chat(user, "There are [paper_cups] paper cups left.") - else if (paper_cups == 1) - to_chat(user, "There is one paper cup left.") - else - to_chat(user, "There are no paper cups left.") +/obj/structure/reagent_dispensers/cooking_oil + name = "vat of cooking oil" + desc = "A huge metal vat with a tap on the front. Filled with cooking oil for use in frying food." + icon_state = "vat" + anchored = TRUE + reagent_id = "cooking_oil" -/obj/structure/reagent_dispensers/water_cooler/attack_hand(mob/living/user) - . = ..() - if(.) - return - if(!paper_cups) - to_chat(user, "There aren't any cups left!") - return - user.visible_message("[user] takes a cup from [src].", "You take a paper cup from [src].") - var/obj/item/reagent_containers/food/drinks/sillycup/S = new(get_turf(src)) - user.put_in_hands(S) - paper_cups-- +//////// +//Kegs// +//////// /obj/structure/reagent_dispensers/beerkeg name = "beer keg" @@ -173,19 +208,44 @@ if(!QDELETED(src)) qdel(src) +/obj/structure/reagent_dispensers/keg + name = "keg" + desc = "A keg." + icon = 'modular_citadel/icons/obj/objects.dmi' + icon_state = "keg" + reagent_id = "water" -/obj/structure/reagent_dispensers/virusfood - name = "virus food dispenser" - desc = "A dispenser of low-potency virus mutagenic." - icon_state = "virus_food" - anchored = TRUE - density = FALSE - reagent_id = "virusfood" +/obj/structure/reagent_dispensers/keg/mead + name = "keg of mead" + desc = "A keg of mead." + icon_state = "orangekeg" + reagent_id = "mead" +/obj/structure/reagent_dispensers/keg/aphro + name = "keg of aphrodisiac" + desc = "A keg of aphrodisiac." + icon_state = "pinkkeg" + reagent_id = "aphro" -/obj/structure/reagent_dispensers/cooking_oil - name = "vat of cooking oil" - desc = "A huge metal vat with a tap on the front. Filled with cooking oil for use in frying food." - icon_state = "vat" - anchored = TRUE - reagent_id = "cooking_oil" +/obj/structure/reagent_dispensers/keg/aphro/strong + name = "keg of strong aphrodisiac" + desc = "A keg of strong and addictive aphrodisiac." + reagent_id = "aphro+" + +/obj/structure/reagent_dispensers/keg/milk + name = "keg of milk" + desc = "It's not quite what you were hoping for." + icon_state = "whitekeg" + reagent_id = "milk" + +/obj/structure/reagent_dispensers/keg/semen + name = "keg of semen" + desc = "Dear lord, where did this even come from?" + icon_state = "whitekeg" + reagent_id = "semen" + +/obj/structure/reagent_dispensers/keg/gargle + name = "keg of pan galactic gargleblaster" + desc = "A keg of... wow that's a long name." + icon_state = "bluekeg" + reagent_id = "gargleblaster" \ No newline at end of file diff --git a/code/modules/recycling/disposal/bin.dm b/code/modules/recycling/disposal/bin.dm index 871fd32b16..a4a6a7d473 100644 --- a/code/modules/recycling/disposal/bin.dm +++ b/code/modules/recycling/disposal/bin.dm @@ -111,14 +111,7 @@ stuff_mob_in(target, user) /obj/machinery/disposal/proc/stuff_mob_in(mob/living/target, mob/living/user) - if(!iscarbon(user) && !user.ventcrawler) //only carbon and ventcrawlers can climb into disposal by themselves. - return - if(!isturf(user.loc)) //No magically doing it from inside closets - return - if(target.buckled || target.has_buckled_mobs()) - return - if(target.mob_size > MOB_SIZE_HUMAN) - to_chat(user, "[target] doesn't fit inside [src]!") + if(!can_stuff_mob_in(target, user)) return add_fingerprint(user) if(user == target) @@ -137,6 +130,19 @@ target.LAssailant = user update_icon() +/obj/machinery/disposal/proc/can_stuff_mob_in(mob/living/target, mob/living/user, pushing = FALSE) + if(!pushing && !iscarbon(user) && !user.ventcrawler) //only carbon and ventcrawlers can climb into disposal by themselves. + return FALSE + if(!isturf(user.loc)) //No magically doing it from inside closets + return FALSE + if(target.buckled || target.has_buckled_mobs()) + return FALSE + if(target.mob_size > MOB_SIZE_HUMAN) + if(!pushing) + to_chat(user, "[target] doesn't fit inside [src]!") + return FALSE + return TRUE + /obj/machinery/disposal/relaymove(mob/user) attempt_escape(user) @@ -264,6 +270,14 @@ name = "disposal unit" desc = "A pneumatic waste disposal unit." icon_state = "disposal" + var/datum/oracle_ui/themed/nano/ui + obj_flags = CAN_BE_HIT | USES_TGUI | SHOVABLE_ONTO + +/obj/machinery/disposal/bin/Initialize(mapload, obj/structure/disposalconstruct/make_from) + . = ..() + ui = new /datum/oracle_ui/themed/nano(src, 330, 190, "disposal_bin") + ui.auto_refresh = TRUE + ui.can_resize = FALSE // attack by item places it in to disposal /obj/machinery/disposal/bin/attackby(obj/item/I, mob/user, params) @@ -275,32 +289,43 @@ STR.remove_from_storage(O,src) T.update_icon() update_icon() + ui.soft_update_fields() else + ui.soft_update_fields() return ..() // handle machine interaction -/obj/machinery/disposal/bin/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state) +/obj/machinery/disposal/bin/ui_interact(mob/user, state) if(stat & BROKEN) return - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) - if(!ui) - ui = new(user, src, ui_key, "disposal_unit", name, 300, 200, master_ui, state) - ui.open() + if(user.loc == src) + to_chat(user, "You cannot reach the controls from inside!") + return + ui.render(user) -/obj/machinery/disposal/bin/ui_data(mob/user) +/obj/machinery/disposal/bin/oui_canview(mob/user) + if(user.loc == src) + return FALSE + if(stat & BROKEN) + return FALSE + if(Adjacent(user)) + return TRUE + return ..() + + +/obj/machinery/disposal/bin/oui_data(mob/user) var/list/data = list() - data["flush"] = flush - data["full_pressure"] = full_pressure - data["pressure_charging"] = pressure_charging - data["panel_open"] = panel_open - var/per = CLAMP(100* air_contents.return_pressure() / (SEND_PRESSURE), 0, 100) - data["per"] = round(per, 1) + data["flush"] = flush ? ui.act("Disengage", user, "handle-0", class="active") : ui.act("Engage", user, "handle-1") + data["full_pressure"] = full_pressure ? "Ready" : (pressure_charging ? "Pressurizing" : "Off") + data["pressure_charging"] = pressure_charging ? ui.act("Turn Off", user, "pump-0", class="active", disabled=full_pressure) : ui.act("Turn On", user, "pump-1", disabled=full_pressure) + var/per = full_pressure ? 100 : CLAMP(100* air_contents.return_pressure() / (SEND_PRESSURE), 0, 99) + data["per"] = "[round(per, 1)]%" + data["contents"] = ui.act("Eject Contents", user, "eject", disabled=contents.len < 1) data["isai"] = isAI(user) return data -/obj/machinery/disposal/bin/ui_act(action, params) +/obj/machinery/disposal/bin/oui_act(mob/user, action, list/params) if(..()) return @@ -327,6 +352,7 @@ if("eject") eject() . = TRUE + ui.soft_update_fields() /obj/machinery/disposal/bin/hitby(atom/movable/AM) @@ -341,11 +367,23 @@ else return ..() +/obj/machinery/disposal/bin/shove_act(mob/living/target, mob/living/user) + if(!can_stuff_mob_in(target, user, TRUE)) + return FALSE + target.Knockdown(SHOVE_KNOCKDOWN_SOLID) + target.forceMove(src) + user.visible_message("[user.name] shoves [target.name] into \the [src]!", + "You shove [target.name] into \the [src]!", null, COMBAT_MESSAGE_RANGE) + log_combat(user, target, "shoved", "into [src] (disposal bin)") + return TRUE + + /obj/machinery/disposal/bin/flush() ..() full_pressure = FALSE pressure_charging = TRUE update_icon() + ui.soft_update_fields() /obj/machinery/disposal/bin/update_icon() cut_overlays() @@ -389,7 +427,7 @@ do_flush() flush_count = 0 - updateDialog() + ui.soft_update_fields() if(flush && air_contents.return_pressure() >= SEND_PRESSURE) // flush can happen even without power do_flush() diff --git a/code/modules/research/designs/comp_board_designs/comp_board_designs_cargo .dm b/code/modules/research/designs/comp_board_designs/comp_board_designs_cargo .dm index fd548adc76..b11a5ee258 100644 --- a/code/modules/research/designs/comp_board_designs/comp_board_designs_cargo .dm +++ b/code/modules/research/designs/comp_board_designs/comp_board_designs_cargo .dm @@ -32,4 +32,12 @@ id = "mining" build_path = /obj/item/circuitboard/computer/mining category = list("Computer Boards") - departmental_flags = DEPARTMENTAL_FLAG_CARGO | DEPARTMENTAL_FLAG_SECURITY \ No newline at end of file + departmental_flags = DEPARTMENTAL_FLAG_CARGO | DEPARTMENTAL_FLAG_SECURITY + +/datum/design/board/miningshuttle + name = "Computer Design (Mining Shuttle Console)" + desc = "Allows for the construction of circuit boards used to build a Mining Shuttle Console." + id = "miningshuttle" + build_path = /obj/item/circuitboard/computer/mining_shuttle + category = list("Computer Boards") + departmental_flags = DEPARTMENTAL_FLAG_CARGO \ No newline at end of file diff --git a/code/modules/research/designs/limbgrower_designs.dm b/code/modules/research/designs/limbgrower_designs.dm index 71f7234e34..dae59408c8 100644 --- a/code/modules/research/designs/limbgrower_designs.dm +++ b/code/modules/research/designs/limbgrower_designs.dm @@ -8,7 +8,7 @@ build_type = LIMBGROWER reagents_list = list("synthflesh" = 25) build_path = /obj/item/bodypart/l_arm - category = list("initial","human","lizard","fly","moth","plasmaman") + category = list("initial","human","lizard","fly","insect","plasmaman","mammal","xeno") /datum/design/rightarm name = "Right Arm" @@ -16,7 +16,7 @@ build_type = LIMBGROWER reagents_list = list("synthflesh" = 25) build_path = /obj/item/bodypart/r_arm - category = list("initial","human","lizard","fly","moth","plasmaman") + category = list("initial","human","lizard","fly","insect","plasmaman","mammal","xeno") /datum/design/leftleg name = "Left Leg" @@ -24,7 +24,7 @@ build_type = LIMBGROWER reagents_list = list("synthflesh" = 25) build_path = /obj/item/bodypart/l_leg - category = list("initial","human","lizard","fly","moth","plasmaman") + category = list("initial","human","lizard","fly","insect","plasmaman","mammal","xeno") /datum/design/rightleg name = "Right Leg" @@ -32,7 +32,7 @@ build_type = LIMBGROWER reagents_list = list("synthflesh" = 25) build_path = /obj/item/bodypart/r_leg - category = list("initial","human","lizard","fly","moth","plasmaman") + category = list("initial","human","lizard","fly","insect","plasmaman","mammal","xeno") /datum/design/armblade name = "Arm Blade" diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm index 3a7ef68903..e70362553c 100644 --- a/code/modules/research/designs/medical_designs.dm +++ b/code/modules/research/designs/medical_designs.dm @@ -192,6 +192,16 @@ category = list("Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL +/datum/design/bsblood_bag + name = "Blue Space Empty Blood Bag" + desc = "A large sterilized plastic bag for blood." + id = "bsblood_bag" + build_path = /obj/item/reagent_containers/blood/bluespace + build_type = PROTOLATHE + materials = list(MAT_GLASS = 2500, MAT_PLASTIC = 4500, MAT_BLUESPACE = 250) + category = list("Medical Designs") + departmental_flags = DEPARTMENTAL_FLAG_MEDICAL + /datum/design/cloning_disk name = "Cloning Data Disk" desc = "Produce additional disks for storing genetic data." @@ -524,6 +534,17 @@ category = list("Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL +/datum/design/cybernetic_heart_u + name = "Upgraded Cybernetic Heart" + desc = "An upgraded cybernetic heart" + id = "cybernetic_heart_u" + build_type = PROTOLATHE | MECHFAB + construction_time = 50 + materials = list(MAT_METAL = 500, MAT_GLASS = 500, MAT_SILVER = 500) + build_path = /obj/item/organ/heart/cybernetic/upgraded + category = list("Misc", "Medical Designs") + departmental_flags = DEPARTMENTAL_FLAG_MEDICAL + /datum/design/cybernetic_liver_u name = "Upgraded Cybernetic Liver" desc = "An upgraded cybernetic liver" @@ -554,6 +575,16 @@ category = list("Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL +/datum/design/cybernetic_tongue + name = "Cybernetic tongue" + desc = "A fancy cybernetic tongue." + id = "cybernetic_tongue" + build_type = PROTOLATHE + materials = list(MAT_METAL = 500, MAT_GLASS = 500) + build_path = /obj/item/organ/tongue/cybernetic + category = list("Medical Designs") + departmental_flags = DEPARTMENTAL_FLAG_MEDICAL + ///////////////////// //Adv Surgery Tools// ///////////////////// @@ -570,63 +601,34 @@ /datum/design/retractor_adv name = "Advanced Retractor" - desc = "A high-class, premium retractor, featuring precision crafted, silver-plated hook-ends and an electrum handle." + desc = "An almagation of rods and gears, able to function as both a surgical clamp and retractor. " id = "retractor_adv" build_type = PROTOLATHE materials = list(MAT_METAL = 500, MAT_GLASS = 500, MAT_SILVER = 1500, MAT_GOLD = 1000) - build_path = /obj/item/retractor/adv - category = list("Medical Designs") - departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE - -/datum/design/hemostat_adv - name = "Advanced Hemostat" - desc = "An exceptionally fine pair of arterial forceps. These appear to be plated in electrum and feel soft to the touch." - id = "hemostat_adv" - build_type = PROTOLATHE - materials = list(MAT_METAL = 500, MAT_GLASS = 500, MAT_SILVER = 1000, MAT_GOLD = 1500) - build_path = /obj/item/hemostat/adv - category = list("Medical Designs") - departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE - -/datum/design/cautery_adv - name = "Electrocautery" //This is based on real-life science. - desc = "A high-tech unipolar Electrocauter. This tiny device contains an extremely powerful microbattery that uses arcs of electricity to painlessly sear wounds shut. It seems to recharge with the user's body-heat. Wow!" - id = "cautery_adv" - build_type = PROTOLATHE - materials = list(MAT_METAL = 500, MAT_GLASS = 500, MAT_SILVER = 1000, MAT_GOLD = 1500) - build_path = /obj/item/cautery/adv + build_path = /obj/item/retractor/advanced category = list("Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE /datum/design/surgicaldrill_adv - name = "Surgical Autodrill" - desc = "With a diamond tip and built-in depth and safety sensors, this drill alerts the user before overpenetrating a patient's skull or tooth. There also appears to be a disable switch." + name = "Surgical Laser Drill" + desc = "It projects a high power laser used for medical applications." id = "surgicaldrill_adv" build_type = PROTOLATHE materials = list(MAT_METAL = 2500, MAT_GLASS = 2500, MAT_SILVER = 6000, MAT_GOLD = 5500, MAT_DIAMOND = 3500) - build_path = /obj/item/surgicaldrill/adv + build_path = /obj/item/surgicaldrill/advanced category = list("Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE /datum/design/scalpel_adv - name = "Precision Scalpel" - desc = "A perfectly balanced electrum scalpel with a silicon-coated edge to eliminate wear and tear." + name = "Laser Scalpel" + desc = "An advanced scalpel which uses laser technology to cut." id = "scalpel_adv" build_type = PROTOLATHE materials = list(MAT_METAL = 1500, MAT_GLASS = 1500, MAT_SILVER = 4000, MAT_GOLD = 2500) - build_path = /obj/item/scalpel/adv + build_path = /obj/item/scalpel/advanced category = list("Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE -/datum/design/circular_saw_adv - name = "Diamond-Grit Circular Saw" - desc = "For those Assistants with REALLY thick skulls." - id = "circular_saw_adv" - build_type = PROTOLATHE - materials = list(MAT_METAL = 7500, MAT_GLASS = 6000, MAT_SILVER = 6500, MAT_GOLD = 7500, MAT_DIAMOND = 4500) - build_path = /obj/item/circular_saw/adv - category = list("Medical Designs") - departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE ///////////////////////////////////////// //////////Alien Surgery Tools//////////// @@ -692,6 +694,28 @@ category = list("Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL +/datum/design/cybernetic_ears + name = "Cybernetic Ears" + desc = "A pair of cybernetic ears." + id = "cybernetic_ears" + build_type = PROTOLATHE | MECHFAB + construction_time = 30 + materials = list(MAT_METAL = 250, MAT_GLASS = 400) + build_path = /obj/item/organ/ears/cybernetic + category = list("Misc", "Medical Designs") + departmental_flags = DEPARTMENTAL_FLAG_MEDICAL + +/datum/design/cybernetic_ears_u + name = "Upgraded Cybernetic Ears" + desc = "A pair of upgraded cybernetic ears." + id = "cybernetic_ears_u" + build_type = PROTOLATHE | MECHFAB + construction_time = 40 + materials = list(MAT_METAL = 500, MAT_GLASS = 500, MAT_SILVER = 500) + build_path = /obj/item/organ/ears/cybernetic/upgraded + category = list("Misc", "Medical Designs") + departmental_flags = DEPARTMENTAL_FLAG_MEDICAL + ///////////////////// ///Surgery Designs/// ///////////////////// @@ -704,6 +728,23 @@ research_icon_state = "surgery_any" var/surgery +/datum/design/surgery/experimental_dissection + name = "Advanced Dissection" + desc = "A surgical procedure which analyzes the biology of a corpse, and automatically adds new findings to the research database." + id = "surgery_adv_dissection" + surgery = /datum/surgery/advanced/experimental_dissection/adv + research_icon_state = "surgery_chest" + +/datum/design/surgery/experimental_dissection/exp + name = "Experimental Dissection" + id = "surgery_exp_dissection" + surgery = /datum/surgery/advanced/experimental_dissection/exp + +/datum/design/surgery/experimental_dissection/ext + name = "Extraterrestrial Dissection" + id = "surgery_ext_dissection" + surgery = /datum/surgery/advanced/experimental_dissection/alien + /datum/design/surgery/lobotomy name = "Lobotomy" desc = "An invasive surgical procedure which guarantees removal of almost all brain traumas, but might cause another permanent trauma in return." @@ -725,11 +766,54 @@ surgery = /datum/surgery/advanced/viral_bonding research_icon_state = "surgery_chest" -/datum/design/surgery/reconstruction - name = "Reconstruction" - desc = "A surgical procedure that gradually repairs damage done to a body without the assistance of chemicals. Unlike classic medicine, it is effective on corpses." - id = "surgery_reconstruction" - surgery = /datum/surgery/advanced/reconstruction +/datum/design/surgery/healing + name = "Tend Wounds" + desc = "An upgraded version of the original surgery." + id = "surgery_healing_base" //holder because travis cries otherwise. Not used in techweb unlocks. + research_icon_state = "surgery_chest" + +/datum/design/surgery/healing/brute_upgrade + name = "Tend Wounds (Brute) Upgrade" + surgery = /datum/surgery/healing/brute/upgraded + id = "surgery_heal_brute_upgrade" + +/datum/design/surgery/healing/brute_upgrade_2 + name = "Tend Wounds (Brute) Upgrade" + surgery = /datum/surgery/healing/brute/upgraded/femto + id = "surgery_heal_brute_upgrade_femto" + +/datum/design/surgery/healing/burn_upgrade + name = "Tend Wounds (Burn) Upgrade" + surgery = /datum/surgery/healing/burn/upgraded + id = "surgery_heal_burn_upgrade" + +/datum/design/surgery/healing/burn_upgrade_2 + name = "Tend Wounds (Burn) Upgrade" + surgery = /datum/surgery/healing/brute/upgraded/femto + id = "surgery_heal_burn_upgrade_femto" + +/datum/design/surgery/healing/combo + name = "Tend Wounds (Mixture)" + desc = "A surgical procedure that repairs both bruises and burns. Repair efficiency is not as high as the individual surgeries but it is faster." + surgery = /datum/surgery/healing/combo + id = "surgery_heal_combo" + +/datum/design/surgery/healing/combo_upgrade + name = "Tend Wounds (Mixture) Upgrade" + surgery = /datum/surgery/healing/combo/upgraded + id = "surgery_heal_combo_upgrade" + +/datum/design/surgery/healing/combo_upgrade_2 + name = "Tend Wounds (Mixture) Upgrade" + desc = "A surgical procedure that repairs both bruises and burns faster than their individual counterparts. It is more effective than both the individual surgeries." + surgery = /datum/surgery/healing/combo/upgraded/femto + id = "surgery_heal_combo_upgrade_femto" + +/datum/design/surgery/surgery_toxinhealing + name = "Body Rejuvenation" + desc = "A surgical procedure that helps deal with oxygen deprecation, and treat toxic damaged. Works on corpses and alive alike without chemicals." + id = "surgery_toxinhealing" + surgery = /datum/surgery/advanced/toxichealing research_icon_state = "surgery_chest" /datum/design/surgery/revival @@ -767,6 +851,29 @@ surgery = /datum/surgery/advanced/bioware/vein_threading research_icon_state = "surgery_chest" +/datum/design/surgery/muscled_veins + name = "Vein Muscle Membrane" + desc = "A surgical procedure which adds a muscled membrane to blood vessels, allowing them to pump blood without a heart." + id = "surgery_muscled_veins" + surgery = /datum/surgery/advanced/bioware/muscled_veins + research_icon_state = "surgery_chest" + +/datum/design/surgery/ligament_hook + name = "Ligament Hook" + desc = "A surgical procedure which reshapes the connections between torso and limbs, making it so limbs can be attached manually if severed. \ + However this weakens the connection, making them easier to detach as well." + id = "surgery_ligament_hook" + surgery = /datum/surgery/advanced/bioware/ligament_hook + research_icon_state = "surgery_chest" + +/datum/design/surgery/ligament_reinforcement + name = "Ligament Reinforcement" + desc = "A surgical procedure which adds a protective tissue and bone cage around the connections between the torso and limbs, preventing dismemberment. \ + However, the nerve connections as a result are more easily interrupted, making it easier to disable limbs with damage." + id = "surgery_ligament_reinforcement" + surgery = /datum/surgery/advanced/bioware/ligament_reinforcement + research_icon_state = "surgery_chest" + /datum/design/surgery/necrotic_revival name = "Necrotic Revival" desc = "An experimental surgical procedure that stimulates the growth of a Romerol tumor inside the patient's brain. Requires zombie powder or rezadone." diff --git a/code/modules/research/designs/misc_designs.dm b/code/modules/research/designs/misc_designs.dm index d27c876f88..77eebca696 100644 --- a/code/modules/research/designs/misc_designs.dm +++ b/code/modules/research/designs/misc_designs.dm @@ -1,4 +1,3 @@ - ///////////////////////////////////////// /////////////////HUDs//////////////////// ///////////////////////////////////////// @@ -291,6 +290,16 @@ category = list("Equipment") departmental_flags = DEPARTMENTAL_FLAG_SERVICE +/datum/design/light_replacer + name = "Light Replacer" + desc = "A device to automatically replace lights. Refill with working light bulbs." + id = "light_replacer" + build_type = PROTOLATHE + materials = list(MAT_METAL = 1500, MAT_SILVER = 150, MAT_GLASS = 3000) + build_path = /obj/item/lightreplacer + category = list("Equipment") + departmental_flags = DEPARTMENTAL_FLAG_SERVICE + /datum/design/blutrash name = "Trashbag of Holding" desc = "An advanced trash bag with bluespace properties; capable of holding a plethora of garbage." @@ -370,6 +379,16 @@ ////////////Tools////////////// /////////////////////////////// +/datum/design/rcd_upgrade + name = "Advanced RCD designs upgrade" + desc = "Adds the computer frame and machine frame to the RCD." + id = "rcd_upgrade" + build_type = PROTOLATHE + materials = list(MAT_METAL = 5000, MAT_GLASS = 2500, MAT_SILVER = 1500, MAT_TITANIUM = 2000) + build_path = /obj/item/rcd_upgrade + category = list("Equipment") + departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING + /datum/design/exwelder name = "Experimental Welding Tool" desc = "An experimental welder capable of self-fuel generation." @@ -480,6 +499,16 @@ category = list("Equipment") departmental_flags = DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_ENGINEERING +/datum/design/pHmeter + name = "Chemical Analyser" + desc = "A a electrode attached to a small circuit box that will tell you the pH of a solution." + id = "pHmeter" + build_type = PROTOLATHE + materials = list(MAT_METAL = 1000, MAT_SILVER = 100, MAT_DIAMOND = 100) + build_path = /obj/item/fermichem/pHmeter + category = list("Equipment") + departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE + ///////////////////////////////////////// ////////////Armour/////////////////////// ///////////////////////////////////////// diff --git a/code/modules/research/designs/power_designs.dm b/code/modules/research/designs/power_designs.dm index f8122c16e3..1dbd111785 100644 --- a/code/modules/research/designs/power_designs.dm +++ b/code/modules/research/designs/power_designs.dm @@ -57,16 +57,6 @@ category = list("Misc","Power Designs") departmental_flags = DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_ENGINEERING -/datum/design/light_replacer - name = "Light Replacer" - desc = "A device to automatically replace lights. Refill with working light bulbs." - id = "light_replacer" - build_type = PROTOLATHE - materials = list(MAT_METAL = 1500, MAT_SILVER = 150, MAT_GLASS = 3000) - build_path = /obj/item/lightreplacer - category = list("Power Designs") - departmental_flags = DEPARTMENTAL_FLAG_SERVICE - /datum/design/inducer name = "Inducer" desc = "The NT-75 Electromagnetic Power Inducer can wirelessly induce electric charge in an object, allowing you to recharge power cells without having to remove them." diff --git a/code/modules/research/designs/weapon_designs.dm b/code/modules/research/designs/weapon_designs.dm index 214ef36afe..11bc31bedc 100644 --- a/code/modules/research/designs/weapon_designs.dm +++ b/code/modules/research/designs/weapon_designs.dm @@ -47,6 +47,22 @@ build_path = /obj/item/ammo_box/magazine/wt550m9/wtic departmental_flags = DEPARTMENTAL_FLAG_SECURITY +/datum/design/mag_oldsmg/tx_mag + name = "WT-550 Semi-Auto SMG Uranium Magazine (4.6x30mm TX)" + desc = "A 20 round uranium tipped magazine for the out of date security WT-550 Semi-Auto SMG." + id = "mag_oldsmg_tx" + materials = list(MAT_METAL = 6000, MAT_SILVER = 600, MAT_URANIUM = 2000) + build_path = /obj/item/ammo_box/magazine/wt550m9/wttx + departmental_flags = DEPARTMENTAL_FLAG_SECURITY + +/datum/design/mag_oldsmg/rubber_mag + name = "WT-550 Semi-Auto SMG rubberbullets Magazine (4.6x30mm rubber)" + desc = "A 20 round rubber shots magazine for the out of date security WT-550 Semi-Auto SMG" + id = "mag_oldsmg_rubber" + materials = list(MAT_METAL = 6000) + build_path = /obj/item/ammo_box/magazine/wt550m9/wtrubber + departmental_flags = DEPARTMENTAL_FLAG_SECURITY + ////////////// //Ammo Shells/ ////////////// diff --git a/code/modules/research/nanites/nanite_programs/healing.dm b/code/modules/research/nanites/nanite_programs/healing.dm index d3a268047e..1113f11e87 100644 --- a/code/modules/research/nanites/nanite_programs/healing.dm +++ b/code/modules/research/nanites/nanite_programs/healing.dm @@ -48,7 +48,7 @@ /datum/nanite_program/purging name = "Blood Purification" - desc = "The nanites purge toxins and chemicals from the host's bloodstream." + desc = "The nanites purge toxins and chemicals from the host's bloodstream, however it is dangerous to slimepeople biology due to inaccuracy." use_rate = 1 rogue_types = list(/datum/nanite_program/suffocating, /datum/nanite_program/necrotic) @@ -72,14 +72,16 @@ /datum/nanite_program/brain_heal/check_conditions() if(iscarbon(host_mob)) var/mob/living/carbon/C = host_mob - if(length(C.get_traumas())) - return ..() - if(host_mob.getBrainLoss()) + for(var/X in C.get_traumas()) + var/datum/brain_trauma/BT = X + if(BT.resilience <= TRAUMA_RESILIENCE_BASIC) + return ..() + if(host_mob.getOrganLoss(ORGAN_SLOT_BRAIN)) return ..() return FALSE /datum/nanite_program/brain_heal/active_effect() - host_mob.adjustBrainLoss(-1, TRUE) + host_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, -1, TRUE) if(iscarbon(host_mob) && prob(10)) var/mob/living/carbon/C = host_mob C.cure_trauma_type(resilience = TRAUMA_RESILIENCE_BASIC) @@ -93,7 +95,7 @@ /datum/nanite_program/blood_restoring/check_conditions() if(iscarbon(host_mob)) var/mob/living/carbon/C = host_mob - if(C.blood_volume >= BLOOD_VOLUME_SAFE) + if(C.blood_volume >= (BLOOD_VOLUME_SAFE*C.blood_ratio)) return FALSE else return FALSE @@ -143,7 +145,7 @@ /datum/nanite_program/purging_advanced name = "Selective Blood Purification" desc = "The nanites purge toxins and dangerous chemicals from the host's bloodstream, while ignoring beneficial chemicals. \ - The added processing power required to analyze the chemicals severely increases the nanite consumption rate." + The added processing power required to analyze the chemicals severely increases the nanite consumption rate. Due to added complexity, it is safe with slimepeople biology." use_rate = 2 rogue_types = list(/datum/nanite_program/suffocating, /datum/nanite_program/necrotic) @@ -157,7 +159,7 @@ return ..() /datum/nanite_program/purging_advanced/active_effect() - host_mob.adjustToxLoss(-1) + host_mob.adjustToxLoss(-1, forced = TRUE) for(var/datum/reagent/toxin/R in host_mob.reagents.reagent_list) host_mob.reagents.remove_reagent(R.id,1) @@ -193,14 +195,16 @@ /datum/nanite_program/brain_heal_advanced/check_conditions() if(iscarbon(host_mob)) var/mob/living/carbon/C = host_mob - if(length(C.get_traumas())) - return ..() - if(host_mob.getBrainLoss()) + for(var/X in C.get_traumas()) + var/datum/brain_trauma/BT = X + if(BT.resilience <= TRAUMA_RESILIENCE_LOBOTOMY) + return ..() + if(host_mob.getOrganLoss(ORGAN_SLOT_BRAIN)) return ..() return FALSE - + /datum/nanite_program/brain_heal_advanced/active_effect() - host_mob.adjustBrainLoss(-2, TRUE) + host_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, -2, TRUE) if(iscarbon(host_mob) && prob(10)) var/mob/living/carbon/C = host_mob C.cure_trauma_type(resilience = TRAUMA_RESILIENCE_LOBOTOMY) @@ -232,7 +236,7 @@ if(!C.getorgan(/obj/item/organ/heart)) //what are we even shocking return FALSE var/obj/item/organ/brain/BR = C.getorgan(/obj/item/organ/brain) - if(QDELETED(BR) || BR.damaged_brain) + if(QDELETED(BR) || BR.brain_death || (BR.organ_flags & ORGAN_FAILING) || C.suiciding) return FALSE if(C.get_ghost()) return FALSE @@ -252,8 +256,7 @@ SEND_SIGNAL(C, COMSIG_LIVING_MINOR_SHOCK) var/tplus = world.time - C.timeofdeath if(tplus > 600) - C.adjustBrainLoss( max(0, ((1800 - tplus) / 1800 * 150)), 150) + C.adjustOrganLoss(ORGAN_SLOT_BRAIN, max(0, ((1800 - tplus) / 1800 * 150)), 150) log_game("[C] has been successfully defibrillated by nanites.") else playsound(C, 'sound/machines/defib_failed.ogg', 50, 0) - diff --git a/code/modules/research/nanites/nanite_programs/rogue.dm b/code/modules/research/nanites/nanite_programs/rogue.dm index f64c7e8781..287aed36fe 100644 --- a/code/modules/research/nanites/nanite_programs/rogue.dm +++ b/code/modules/research/nanites/nanite_programs/rogue.dm @@ -59,7 +59,7 @@ /datum/nanite_program/brain_decay/active_effect() if(prob(4)) host_mob.hallucination = min(15, host_mob.hallucination) - host_mob.adjustBrainLoss(1) + host_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, 1) //Generic brain-affecting programs can also decay into this /datum/nanite_program/brain_misfire diff --git a/code/modules/research/nanites/nanite_remote.dm b/code/modules/research/nanites/nanite_remote.dm index 60dd78cf94..824d033bf4 100644 --- a/code/modules/research/nanites/nanite_remote.dm +++ b/code/modules/research/nanites/nanite_remote.dm @@ -37,6 +37,7 @@ to_chat(user, "Access denied.") /obj/item/nanite_remote/emag_act(mob/user) + . = ..() if(obj_flags & EMAGGED) return to_chat(user, "You override [src]'s ID lock.") @@ -44,6 +45,7 @@ if(locked) locked = FALSE update_icon() + return TRUE /obj/item/nanite_remote/update_icon() . = ..() diff --git a/code/modules/research/rdconsole.dm b/code/modules/research/rdconsole.dm index cb5062904d..a7d7857a24 100644 --- a/code/modules/research/rdconsole.dm +++ b/code/modules/research/rdconsole.dm @@ -184,12 +184,14 @@ Nothing else in the console has ID requirements. ..() /obj/machinery/computer/rdconsole/emag_act(mob/user) - if(!(obj_flags & EMAGGED)) - to_chat(user, "You disable the security protocols[locked? " and unlock the console":""].") - playsound(src, "sparks", 75, 1) - obj_flags |= EMAGGED - locked = FALSE - return ..() + . = ..() + if(obj_flags & EMAGGED) + return + to_chat(user, "You disable the security protocols[locked? " and unlock the console":""].") + playsound(src, "sparks", 75, 1) + obj_flags |= EMAGGED + locked = FALSE + return TRUE /obj/machinery/computer/rdconsole/multitool_act(mob/user, obj/item/multitool/I) var/lathe = linked_lathe && linked_lathe.multitool_act(user, I) diff --git a/code/modules/research/server.dm b/code/modules/research/server.dm index 20e05782ef..b3e114d2ad 100644 --- a/code/modules/research/server.dm +++ b/code/modules/research/server.dm @@ -155,8 +155,10 @@ src.updateUsrDialog() /obj/machinery/computer/rdservercontrol/emag_act(mob/user) + . = ..() if(obj_flags & EMAGGED) return playsound(src, "sparks", 75, 1) obj_flags |= EMAGGED to_chat(user, "You disable the security protocols.") + return TRUE diff --git a/code/modules/research/stock_parts.dm b/code/modules/research/stock_parts.dm index af004c4701..3cd296f866 100644 --- a/code/modules/research/stock_parts.dm +++ b/code/modules/research/stock_parts.dm @@ -13,6 +13,7 @@ If you create T5+ please take a pass at gene_modder.dm [L40]. Max_values MUST fi var/works_from_distance = FALSE var/pshoom_or_beepboopblorpzingshadashwoosh = 'sound/items/rped.ogg' var/alt_sound = null + rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE //cutting down on exploits /obj/item/storage/part_replacer/pre_attack(obj/machinery/T, mob/living/user, params) if(!istype(T) || !T.component_parts) @@ -67,6 +68,7 @@ If you create T5+ please take a pass at gene_modder.dm [L40]. Max_values MUST fi icon = 'icons/obj/stock_parts.dmi' w_class = WEIGHT_CLASS_SMALL var/rating = 1 + rad_flags = RAD_NO_CONTAMINATE /obj/item/stock_parts/Initialize() . = ..() diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm index 90d446bbc2..5b3a21dd5c 100644 --- a/code/modules/research/techweb/all_nodes.dm +++ b/code/modules/research/techweb/all_nodes.dm @@ -69,7 +69,7 @@ display_name = "Advanced Biotechnology" description = "Advanced Biotechnology" prereq_ids = list("biotech") - design_ids = list("piercesyringe", "crewpinpointer", "smoke_machine", "plasmarefiller", "limbgrower", "defibrillator", "meta_beaker", "healthanalyzer_advanced","harvester","holobarrier_med","smartdartgun","medicinalsmartdart") + design_ids = list("piercesyringe", "crewpinpointer", "smoke_machine", "plasmarefiller", "limbgrower", "defibrillator", "meta_beaker", "healthanalyzer_advanced","harvester","holobarrier_med","smartdartgun","medicinalsmartdart", "pHmeter") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) export_price = 5000 @@ -96,7 +96,7 @@ display_name = "Advanced Surgery Tools" description = "Refined and improved redesigns for the run-of-the-mill medical utensils." prereq_ids = list("adv_biotech", "adv_surgery") - design_ids = list("drapes", "retractor_adv", "hemostat_adv", "cautery_adv", "surgicaldrill_adv", "scalpel_adv", "circular_saw_adv") + design_ids = list("drapes", "retractor_adv", "surgicaldrill_adv", "scalpel_adv") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) export_price = 5000 @@ -110,12 +110,21 @@ export_price = 5000 /////////////////////////Advanced Surgery///////////////////////// +/datum/techweb_node/imp_wt_surgery + id = "imp_wt_surgery" + display_name = "Improved Wound-Tending Surgery" + description = "Who would have known being more gentle with a hemostat decreases patient pain?" + prereq_ids = list("biotech") + design_ids = list("surgery_heal_brute_upgrade","surgery_heal_burn_upgrade") + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1000) + export_price = 1000 + /datum/techweb_node/adv_surgery id = "adv_surgery" display_name = "Advanced Surgery" description = "When simple medicine doesn't cut it." - prereq_ids = list("adv_biotech") - design_ids = list("surgery_lobotomy", "surgery_reconstruction", "organbox") + prereq_ids = list("imp_wt_surgery") + design_ids = list("surgery_revival", "surgery_lobotomy", "surgery_heal_brute_upgrade_femto","surgery_heal_burn_upgrade_femto", "surgery_heal_combo", "surgery_toxinhealing", "organbox", "surgery_adv_dissection") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) export_price = 5000 @@ -124,7 +133,7 @@ display_name = "Experimental Surgery" description = "When evolution isn't fast enough." prereq_ids = list("adv_surgery") - design_ids = list("surgery_revival","surgery_pacify","surgery_vein_thread","surgery_nerve_splice","surgery_nerve_ground","surgery_viral_bond") + design_ids = list("surgery_pacify","surgery_vein_thread","surgery_muscled_veins","surgery_nerve_splice","surgery_nerve_ground","surgery_ligament_hook","surgery_ligament_reinforcement","surgery_viral_bond", "surgery_exp_dissection", "surgery_heal_combo_upgrade") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000) export_price = 5000 @@ -133,7 +142,7 @@ display_name = "Alien Surgery" description = "Abductors did nothing wrong." prereq_ids = list("exp_surgery", "alientech") - design_ids = list("surgery_brainwashing","surgery_zombie") + design_ids = list("surgery_brainwashing","surgery_zombie", "surgery_ext_dissection", "surgery_heal_combo_upgrade_femto") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 10000) export_price = 5000 @@ -172,7 +181,7 @@ display_name = "Advanced Engineering" description = "Pushing the boundaries of physics, one chainsaw-fist at a time." prereq_ids = list("engineering", "emp_basic") - design_ids = list("engine_goggles", "magboots", "forcefield_projector", "weldingmask", "tray_goggles_prescription", "engine_goggles_prescription", "mesons_prescription") + design_ids = list("engine_goggles", "magboots", "forcefield_projector", "weldingmask", "tray_goggles_prescription", "engine_goggles_prescription", "mesons_prescription", "rcd_upgrade") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 4000) export_price = 5000 @@ -221,13 +230,22 @@ //research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1500) //export_price = 5000 +/datum/techweb_node/computer_board_gaming + id = "computer_board_gaming" + display_name = "Games and Toys" + description = "For the slackers on the station." + prereq_ids = list("comptech") + design_ids = list("arcade_battle", "arcade_orion", "slotmachine", "autoylathe") + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1000) + export_price = 5000 + /////////////////////////Bluespace tech///////////////////////// /datum/techweb_node/bluespace_basic //Bluespace-memery id = "bluespace_basic" display_name = "Basic Bluespace Theory" description = "Basic studies into the mysterious alternate dimension known as bluespace." prereq_ids = list("base", "datatheory") - design_ids = list("beacon", "xenobioconsole", "telesci_gps") + design_ids = list("beacon", "xenobioconsole", "telesci_gps", "xenobio_monkeys") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) export_price = 5000 @@ -236,7 +254,7 @@ display_name = "Applied Bluespace Research" description = "Using bluespace to make things faster and better." prereq_ids = list("bluespace_basic", "engineering") - design_ids = list("bs_rped","biobag_holding","minerbag_holding", "bluespacebeaker", "bluespacesyringe", "phasic_scanning", "bluespacesmartdart") + design_ids = list("bs_rped","biobag_holding","minerbag_holding", "bluespacebeaker", "bluespacesyringe", "phasic_scanning", "bluespacesmartdart", "xenobio_slimebasic") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000) export_price = 5000 @@ -245,7 +263,7 @@ display_name = "Advanced Bluespace Research" description = "Deeper understanding of how the Bluespace dimension works" prereq_ids = list("practical_bluespace", "high_efficiency") - design_ids = list("bluespace_matter_bin", "femto_mani", "triphasic_scanning", "bluespace_crystal", "roastingstick") + design_ids = list("bluespace_matter_bin", "femto_mani", "triphasic_scanning", "bluespace_crystal", "xenobio_slimeadv") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 10000) export_price = 5000 @@ -263,7 +281,7 @@ display_name = "Bluespace Pockets" description = "Studies into the mysterious alternate dimension known as bluespace and how to place items in the threads of reality." prereq_ids = list("adv_power", "adv_bluespace", "adv_biotech", "adv_plasma") - design_ids = list( "bluespacebodybag","bag_holding", "bluespace_pod", "borg_upgrade_trashofholding", "blutrash", "satchel_holding") + design_ids = list( "bluespacebodybag","bag_holding", "bluespace_pod", "borg_upgrade_trashofholding", "blutrash", "satchel_holding", "bsblood_bag") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5500) export_price = 5000 @@ -281,7 +299,7 @@ display_name = "Bluespace Travel" description = "Application of Bluespace for static teleportation technology." prereq_ids = list("adv_power", "adv_bluespace") - design_ids = list("tele_station", "tele_hub", "quantumpad", "quantum_keycard", "launchpad", "launchpad_console", "teleconsole") + design_ids = list("tele_station", "tele_hub", "quantumpad", "quantum_keycard", "launchpad", "launchpad_console", "teleconsole", "roastingstick") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) export_price = 5000 @@ -423,7 +441,7 @@ display_name = "Computer Consoles" description = "Computers and how they work." prereq_ids = list("datatheory") - design_ids = list("cargo", "cargorequest", "libraryconsole", "mining", "crewconsole", "rdcamera", "comconsole", "idcardconsole", "seccamera") + design_ids = list("cargo", "cargorequest", "libraryconsole", "mining", "miningshuttle", "crewconsole", "rdcamera", "comconsole", "idcardconsole", "seccamera") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2000) export_price = 5000 @@ -438,15 +456,6 @@ "portadrive_basic", "portadrive_advanced", "portadrive_super", "cardslot", "aislot", "miniprinter", "APClink", "bat_control", "bat_normal", "bat_advanced", "bat_super", "bat_micro", "bat_nano", "cpu_normal", "pcpu_normal", "cpu_small", "pcpu_small") -/datum/techweb_node/computer_board_gaming - id = "computer_board_gaming" - display_name = "Arcade Games" - description = "For the slackers on the station." - prereq_ids = list("comptech") - design_ids = list("arcade_battle", "arcade_orion", "slotmachine") // Magic money - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1500) - export_price = 2000 - /datum/techweb_node/comp_recordkeeping id = "comp_recordkeeping" display_name = "Computerized Recordkeeping" @@ -517,8 +526,17 @@ display_name = "Cybernetic Organs" description = "We have the technology to rebuild him." prereq_ids = list("adv_biotech") - design_ids = list("cybernetic_heart", "cybernetic_liver", "cybernetic_liver_u", "cybernetic_lungs", "cybernetic_lungs_u") - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) + design_ids = list("cybernetic_ears", "cybernetic_heart", "cybernetic_liver", "cybernetic_lungs", "cybernetic_tongue") + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1000) + export_price = 5000 + +/datum/techweb_node/cyber_organs_upgraded + id = "cyber_organs_upgraded" + display_name = "Upgraded Cybernetic Organs" + description = "We have the technology to upgrade him." + prereq_ids = list("cyber_organs") + design_ids = list("cybernetic_ears_u", "cybernetic_heart_u", "cybernetic_liver_u", "cybernetic_lungs_u") + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1500) export_price = 5000 /datum/techweb_node/cyber_implants @@ -672,7 +690,7 @@ display_name = "Ballistic Weaponry" description = "This isn't research.. This is reverse-engineering!" prereq_ids = list("weaponry") - design_ids = list("mag_oldsmg", "mag_oldsmg_ap", "mag_oldsmg_ic") + design_ids = list("mag_oldsmg", "mag_oldsmg_ap", "mag_oldsmg_ic", "mag_oldsmg_rubber", "mag_oldsmg_tx") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2750) export_price = 5000 @@ -998,7 +1016,7 @@ description = "Things used by the greys." prereq_ids = list("biotech","engineering") boost_item_paths = list(/obj/item/gun/energy/alien, /obj/item/scalpel/alien, /obj/item/hemostat/alien, /obj/item/retractor/alien, /obj/item/circular_saw/alien, - /obj/item/cautery/alien, /obj/item/surgicaldrill/alien, /obj/item/screwdriver/abductor, /obj/item/wrench/abductor, /obj/item/crowbar/abductor, /obj/item/multitool/abductor, + /obj/item/cautery/alien, /obj/item/surgicaldrill/alien, /obj/item/screwdriver/abductor, /obj/item/wrench/abductor, /obj/item/crowbar/abductor, /obj/item/multitool/abductor, /obj/item/stock_parts/cell/infinite/abductor, /obj/item/weldingtool/abductor, /obj/item/wirecutters/abductor, /obj/item/circuitboard/machine/abductor, /obj/item/abductor_baton, /obj/item/abductor, /obj/item/stack/sheet/mineral/abductor) research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000) export_price = 20000 @@ -1012,7 +1030,7 @@ prereq_ids = list("alientech", "adv_biotech") design_ids = list("alien_scalpel", "alien_hemostat", "alien_retractor", "alien_saw", "alien_drill", "alien_cautery") boost_item_paths = list(/obj/item/gun/energy/alien, /obj/item/scalpel/alien, /obj/item/hemostat/alien, /obj/item/retractor/alien, /obj/item/circular_saw/alien, - /obj/item/cautery/alien, /obj/item/surgicaldrill/alien, /obj/item/screwdriver/abductor, /obj/item/wrench/abductor, /obj/item/crowbar/abductor, /obj/item/multitool/abductor, + /obj/item/cautery/alien, /obj/item/surgicaldrill/alien, /obj/item/screwdriver/abductor, /obj/item/wrench/abductor, /obj/item/crowbar/abductor, /obj/item/multitool/abductor, /obj/item/stock_parts/cell/infinite/abductor, /obj/item/weldingtool/abductor, /obj/item/wirecutters/abductor, /obj/item/circuitboard/machine/abductor, /obj/item/abductor_baton, /obj/item/abductor) research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) export_price = 20000 @@ -1024,7 +1042,7 @@ description = "Alien engineering tools" prereq_ids = list("alientech", "adv_engi") design_ids = list("alien_wrench", "alien_wirecutters", "alien_screwdriver", "alien_crowbar", "alien_welder", "alien_multitool") - boost_item_paths = list(/obj/item/screwdriver/abductor, /obj/item/wrench/abductor, /obj/item/crowbar/abductor, /obj/item/multitool/abductor, + boost_item_paths = list(/obj/item/screwdriver/abductor, /obj/item/wrench/abductor, /obj/item/crowbar/abductor, /obj/item/multitool/abductor, /obj/item/stock_parts/cell/infinite/abductor, /obj/item/weldingtool/abductor, /obj/item/wirecutters/abductor, /obj/item/circuitboard/machine/abductor, /obj/item/abductor_baton, /obj/item/abductor) research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) export_price = 20000 @@ -1045,10 +1063,19 @@ boost_item_paths = list() for(var/path in GLOB.uplink_items) var/datum/uplink_item/UI = new path - if(!UI.item) + if(!UI.item || !UI.illegal_tech) continue boost_item_paths |= UI.item //allows deconning to unlock. +/datum/techweb_node/advanced_illegl_ballistics + id = "advanced_illegal_ballistics" + display_name = "Advanced Illegal Ballistics" + description = "Advanced Ballistic for Illegal weaponds." + design_ids = list("10mm","10mmap","10mminc","10mmhp","pistolm9mm","m45","bolt_clip") + prereq_ids = list("ballistic_weapons","syndicate_basic","explosive_weapons") + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 25000) //This gives sec lethal mags/clips for guns form traitors or space. + export_price = 7000 + //Helpers for debugging/balancing the techweb in its entirety! /proc/total_techweb_exports() var/list/datum/techweb_node/processing = list() @@ -1079,4 +1106,4 @@ for(var/i in processing) var/datum/techweb_node/TN = i TW.add_point_list(TN.research_costs) - return TW.printout_points() + return TW.printout_points() \ No newline at end of file diff --git a/code/modules/research/xenobiology/crossbreeding/_weapons.dm b/code/modules/research/xenobiology/crossbreeding/_weapons.dm index 53857b214c..1b2f43c518 100644 --- a/code/modules/research/xenobiology/crossbreeding/_weapons.dm +++ b/code/modules/research/xenobiology/crossbreeding/_weapons.dm @@ -15,6 +15,7 @@ recharge_rate = 1 ammo_type = /obj/item/ammo_casing/magic/bloodchill fire_sound = 'sound/effects/attackblob.ogg' + total_mass = TOTAL_MASS_HAND_REPLACEMENT /obj/item/gun/magic/bloodchill/Initialize() . = ..() @@ -26,9 +27,9 @@ return 0 charge_tick = 0 var/mob/living/M = loc - if(istype(M) && M.blood_volume >= 20) + if(istype(M) && M.blood_volume >= 5) charges++ - M.blood_volume -= 20 + M.blood_volume -= 5 if(charges == 1) recharge_newshot() return 1 diff --git a/code/modules/research/xenobiology/crossbreeding/consuming.dm b/code/modules/research/xenobiology/crossbreeding/consuming.dm index 0b2d60da8c..d6536f4fdd 100644 --- a/code/modules/research/xenobiology/crossbreeding/consuming.dm +++ b/code/modules/research/xenobiology/crossbreeding/consuming.dm @@ -119,7 +119,7 @@ Consuming extracts: M.adjustToxLoss(-5, forced=1) //To heal slimepeople. M.adjustOxyLoss(-5) M.adjustCloneLoss(-5) - M.adjustBrainLoss(-5) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, -5) /obj/item/slimecross/consuming/blue colour = "blue" diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm index 7acbaaac1c..2894ce2108 100644 --- a/code/modules/research/xenobiology/xenobiology.dm +++ b/code/modules/research/xenobiology/xenobiology.dm @@ -325,7 +325,7 @@ if(SLIME_ACTIVATE_MAJOR) var/turf/open/T = get_turf(user) if(istype(T)) - T.atmos_spawn_air("nitrogen=40;TEMP=2.7") + T.atmos_spawn_air("n2=40;TEMP=2.7") to_chat(user, "You activate [src], and icy air bursts out of your skin!") return 900 @@ -523,7 +523,8 @@ /obj/item/slime_extract/pyrite/activate(mob/living/carbon/human/user, datum/species/jelly/luminescent/species, activation_type) switch(activation_type) if(SLIME_ACTIVATE_MINOR) - var/chosen = pick(difflist(subtypesof(/obj/item/toy/crayon),typesof(/obj/item/toy/crayon/spraycan))) + var/blacklisted_cans = list(/obj/item/toy/crayon/spraycan/borg, /obj/item/toy/crayon/spraycan/infinite) + var/chosen = pick(subtypesof(/obj/item/toy/crayon/spraycan) - blacklisted_cans) var/obj/item/O = new chosen(null) if(!user.put_in_active_hand(O)) O.forceMove(user.drop_location()) @@ -680,7 +681,7 @@ var/list/candidates = pollCandidatesForMob("Do you want to play as [SM.name]?", ROLE_SENTIENCE, null, ROLE_SENTIENCE, 50, SM, POLL_IGNORE_SENTIENCE_POTION) // see poll_ignore.dm if(LAZYLEN(candidates)) var/mob/dead/observer/C = pick(candidates) - SM.key = C.key + C.transfer_ckey(SM, FALSE) SM.mind.enslave_mind_to_creator(user) SM.sentience_act() to_chat(SM, "All at once it makes sense: you know what you are and who you are! Self awareness is yours!") @@ -704,7 +705,7 @@ desc = "A miraculous chemical mix that grants human like intelligence to living beings. It has been modified with Syndicate technology to also grant an internal radio implant to the target and authenticate with identification systems." /obj/item/slimepotion/slime/sentience/nuclear/after_success(mob/living/user, mob/living/simple_animal/SM) - var/obj/item/implant/radio/syndicate/imp = new(src) + var/obj/item/implant/radio/syndicate/imp = new imp.implant(SM, user) SM.access_card = new /obj/item/card/id/syndicate(SM) @@ -968,7 +969,7 @@ to_chat(user, "You feed the potion to [M].") to_chat(M, "Your mind tingles as you are fed the potion. You can hear radio waves now!") - var/obj/item/implant/radio/slime/imp = new(src) + var/obj/item/implant/radio/slime/imp = new imp.implant(M, user) qdel(src) diff --git a/code/modules/shuttle/computer.dm b/code/modules/shuttle/computer.dm index 0c957919a1..946f0fb9a4 100644 --- a/code/modules/shuttle/computer.dm +++ b/code/modules/shuttle/computer.dm @@ -63,11 +63,13 @@ to_chat(usr, "Unable to comply.") /obj/machinery/computer/shuttle/emag_act(mob/user) + . = ..() if(obj_flags & EMAGGED) return req_access = list() obj_flags |= EMAGGED to_chat(user, "You fried the consoles ID checking system.") + return TRUE /obj/machinery/computer/shuttle/proc/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE) if(port && (shuttleId == initial(shuttleId) || override)) diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm index 020b4b29ab..119023d465 100644 --- a/code/modules/shuttle/emergency.dm +++ b/code/modules/shuttle/emergency.dm @@ -134,6 +134,8 @@ . = TRUE /obj/machinery/computer/emergency_shuttle/emag_act(mob/user) + . = ..() + // How did you even get on the shuttle before it go to the station? if(!IS_DOCKED) return @@ -159,6 +161,7 @@ authorized += ID process() + return TRUE /obj/machinery/computer/emergency_shuttle/Destroy() // Our fake IDs that the emag generated are just there for colour @@ -459,10 +462,12 @@ return /obj/machinery/computer/shuttle/pod/emag_act(mob/user) + . = SEND_SIGNAL(src, COMSIG_ATOM_EMAG_ACT) if(obj_flags & EMAGGED) return obj_flags |= EMAGGED to_chat(user, "You fry the pod's alert level checking system.") + return TRUE /obj/machinery/computer/shuttle/pod/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE) . = ..() diff --git a/code/modules/shuttle/ferry.dm b/code/modules/shuttle/ferry.dm index 06e38bb3eb..39ab087f9c 100644 --- a/code/modules/shuttle/ferry.dm +++ b/code/modules/shuttle/ferry.dm @@ -12,7 +12,7 @@ /obj/machinery/computer/shuttle/ferry/emag_act(mob/user) if(!allow_emag) to_chat(user, "[src]'s security firewall is far too powerful for you to bypass.") - return FALSE + return SEND_SIGNAL(src, COMSIG_ATOM_EMAG_ACT) return ..() /obj/machinery/computer/shuttle/ferry/attack_ai() diff --git a/code/modules/shuttle/on_move.dm b/code/modules/shuttle/on_move.dm index a6904c28cc..dd2d7483e3 100644 --- a/code/modules/shuttle/on_move.dm +++ b/code/modules/shuttle/on_move.dm @@ -179,7 +179,7 @@ All ShuttleMove procs go here for(var/obj/machinery/door/airlock/A in range(1, src)) // includes src A.shuttledocked = FALSE A.air_tight = TRUE - INVOKE_ASYNC(A, /obj/machinery/door/.proc/close) + addtimer(CALLBACK(A, /obj/machinery/door/.proc/close), 0) /obj/machinery/door/airlock/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation) . = ..() diff --git a/code/modules/shuttle/special.dm b/code/modules/shuttle/special.dm index d1435a554c..9bea790957 100644 --- a/code/modules/shuttle/special.dm +++ b/code/modules/shuttle/special.dm @@ -48,7 +48,7 @@ return /obj/machinery/power/emitter/energycannon/magical/emag_act(mob/user) - return + return SEND_SIGNAL(src, COMSIG_ATOM_EMAG_ACT) /obj/structure/table/abductor/wabbajack name = "wabbajack altar" diff --git a/code/modules/shuttle/supply.dm b/code/modules/shuttle/supply.dm index b54fceb3e7..2249f5f10e 100644 --- a/code/modules/shuttle/supply.dm +++ b/code/modules/shuttle/supply.dm @@ -60,6 +60,10 @@ GLOBAL_LIST_INIT(blacklisted_cargo_types, typecacheof(list( for(var/a in T.GetAllContents()) if(is_type_in_typecache(a, GLOB.blacklisted_cargo_types)) return FALSE + if(istype(a, /obj/structure/closet))//Prevents eigenlockers from ending up at CC + var/obj/structure/closet/c = a + if(c.eigen_teleport == TRUE) + return FALSE return TRUE /obj/docking_port/mobile/supply/request(obj/docking_port/stationary/S) diff --git a/code/modules/spells/spell_types/lichdom.dm b/code/modules/spells/spell_types/lichdom.dm index efc80101f6..0cbb3a8272 100644 --- a/code/modules/spells/spell_types/lichdom.dm +++ b/code/modules/spells/spell_types/lichdom.dm @@ -57,7 +57,7 @@ new /obj/item/phylactery(marked_item, M.mind) to_chat(M, "With a hideous feeling of emptiness you watch in horrified fascination as skin sloughs off bone! Blood boils, nerves disintegrate, eyes boil in their sockets! As your organs crumble to dust in your fleshless chest you come to terms with your choice. You're a lich!") - M.set_species(/datum/species/skeleton) + M.set_species(/datum/species/skeleton/space) if(ishuman(M)) var/mob/living/carbon/human/H = M H.dropItemToGround(H.w_uniform) @@ -132,7 +132,7 @@ lich.real_name = mind.name mind.transfer_to(lich) mind.grab_ghost(force=TRUE) - lich.hardset_dna(null,null,lich.real_name,null, new /datum/species/skeleton) + lich.hardset_dna(null,null,lich.real_name,null, new /datum/species/skeleton/space) to_chat(lich, "Your bones clatter and shudder as you are pulled back into this world!") var/turf/body_turf = get_turf(old_body) lich.Knockdown(200 + 200*resurrections) diff --git a/code/modules/spells/spell_types/mind_transfer.dm b/code/modules/spells/spell_types/mind_transfer.dm index ffdd270994..107f303049 100644 --- a/code/modules/spells/spell_types/mind_transfer.dm +++ b/code/modules/spells/spell_types/mind_transfer.dm @@ -70,12 +70,12 @@ Also, you never added distance checking after target is selected. I've went ahea var/mob/living/caster = user//The wizard/whomever doing the body transferring. //MIND TRANSFER BEGIN - var/mob/dead/observer/ghost = victim.ghostize(0) + var/mob/dead/observer/ghost = victim.ghostize(FALSE, TRUE) caster.mind.transfer_to(victim) ghost.mind.transfer_to(caster) if(ghost.key) - caster.key = ghost.key //have to transfer the key since the mind was not active + ghost.transfer_ckey(caster) //have to transfer the key since the mind was not active qdel(ghost) //MIND TRANSFER END diff --git a/code/modules/spells/spell_types/shapeshift.dm b/code/modules/spells/spell_types/shapeshift.dm index 88c6ce175f..1576c55326 100644 --- a/code/modules/spells/spell_types/shapeshift.dm +++ b/code/modules/spells/spell_types/shapeshift.dm @@ -15,7 +15,6 @@ var/die_with_shapeshifted_form = TRUE var/convert_damage = FALSE //If you want to convert the caster's health to the shift, and vice versa. var/convert_damage_type = BRUTE //Since simplemobs don't have advanced damagetypes, what to convert damage back into. - var/shapeshift_type var/list/possible_shapes = list(/mob/living/simple_animal/mouse,\ /mob/living/simple_animal/pet/dog/corgi,\ @@ -167,4 +166,4 @@ /datum/soullink/shapeshift/sharerDies(gibbed, mob/living/sharer) if(source) - source.shapeDeath(gibbed) \ No newline at end of file + source.shapeDeath(gibbed) diff --git a/code/modules/station_goals/shield.dm b/code/modules/station_goals/shield.dm index 98f5534d06..b09dee04c7 100644 --- a/code/modules/station_goals/shield.dm +++ b/code/modules/station_goals/shield.dm @@ -133,6 +133,7 @@ mode = "M-SHIELD" speed_process = TRUE var/kill_range = 14 + density = 0 /obj/machinery/satellite/meteor_shield/sci name = "\improper Meteor Shield Satellite" @@ -197,9 +198,11 @@ change_meteor_chance(0.5) /obj/machinery/satellite/meteor_shield/emag_act(mob/user) + . = ..() if(obj_flags & EMAGGED) return obj_flags |= EMAGGED to_chat(user, "You access the satellite's debug mode, increasing the chance of meteor strikes.") if(active) change_meteor_chance(4) + return TRUE diff --git a/code/modules/surgery/advanced/bioware/bioware_surgery.dm b/code/modules/surgery/advanced/bioware/bioware_surgery.dm index 86817b9b09..eb8f739193 100644 --- a/code/modules/surgery/advanced/bioware/bioware_surgery.dm +++ b/code/modules/surgery/advanced/bioware/bioware_surgery.dm @@ -5,6 +5,8 @@ /datum/surgery/advanced/bioware/can_start(mob/user, mob/living/carbon/human/target) if(!..()) return FALSE + if(!istype(target)) + return FALSE for(var/X in target.bioware) var/datum/bioware/B = X if(B.mod_type == bioware_target) diff --git a/code/modules/surgery/advanced/bioware/ligament_hook.dm b/code/modules/surgery/advanced/bioware/ligament_hook.dm new file mode 100644 index 0000000000..2c154436e6 --- /dev/null +++ b/code/modules/surgery/advanced/bioware/ligament_hook.dm @@ -0,0 +1,45 @@ +/datum/surgery/advanced/bioware/ligament_hook + name = "Ligament Hook" + desc = "A surgical procedure which reshapes the connections between torso and limbs, making it so limbs can be attached manually if severed. \ + However this weakens the connection, making them easier to detach as well." + steps = list(/datum/surgery_step/incise, + /datum/surgery_step/retract_skin, + /datum/surgery_step/clamp_bleeders, + /datum/surgery_step/incise, + /datum/surgery_step/incise, + /datum/surgery_step/reshape_ligaments, + /datum/surgery_step/close) + possible_locs = list(BODY_ZONE_CHEST) + bioware_target = BIOWARE_LIGAMENTS + +/datum/surgery_step/reshape_ligaments + name = "reshape ligaments" + accept_hand = TRUE + time = 125 + +/datum/surgery_step/reshape_ligaments/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You start reshaping [target]'s ligaments into a hook-like shape.", + "[user] starts reshaping [target]'s ligaments into a hook-like shape.", + "[user] starts manipulating [target]'s ligaments.") + +/datum/surgery_step/reshape_ligaments/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You finish reshaping [target]'s ligaments into a connective hook!", + "[user] finishes reshaping [target]'s ligaments into a connective hook!", + "[user] finishes manipulating [target]'s ligaments!") + new /datum/bioware/hooked_ligaments(target) + return TRUE + +/datum/bioware/hooked_ligaments + name = "Hooked Ligaments" + desc = "The ligaments and nerve endings that connect the torso to the limbs are formed into a hook-like shape, so limbs can be attached without requiring surgery, but are easier to sever." + mod_type = BIOWARE_LIGAMENTS + +/datum/bioware/hooked_ligaments/on_gain() + ..() + ADD_TRAIT(owner, TRAIT_LIMBATTACHMENT, "ligament_hook") + ADD_TRAIT(owner, TRAIT_EASYDISMEMBER, "ligament_hook") + +/datum/bioware/hooked_ligaments/on_lose() + ..() + REMOVE_TRAIT(owner, TRAIT_LIMBATTACHMENT, "ligament_hook") + REMOVE_TRAIT(owner, TRAIT_EASYDISMEMBER, "ligament_hook") \ No newline at end of file diff --git a/code/modules/surgery/advanced/bioware/ligament_reinforcement.dm b/code/modules/surgery/advanced/bioware/ligament_reinforcement.dm new file mode 100644 index 0000000000..ac034fcea7 --- /dev/null +++ b/code/modules/surgery/advanced/bioware/ligament_reinforcement.dm @@ -0,0 +1,45 @@ +/datum/surgery/advanced/bioware/ligament_reinforcement + name = "Ligament Reinforcement" + desc = "A surgical procedure which adds a protective tissue and bone cage around the connections between the torso and limbs, preventing dismemberment. \ + However, the nerve connections as a result are more easily interrupted, making it easier to disable limbs with damage." + steps = list(/datum/surgery_step/incise, + /datum/surgery_step/retract_skin, + /datum/surgery_step/clamp_bleeders, + /datum/surgery_step/incise, + /datum/surgery_step/incise, + /datum/surgery_step/reinforce_ligaments, + /datum/surgery_step/close) + possible_locs = list(BODY_ZONE_CHEST) + bioware_target = BIOWARE_LIGAMENTS + +/datum/surgery_step/reinforce_ligaments + name = "reinforce ligaments" + accept_hand = TRUE + time = 125 + +/datum/surgery_step/reinforce_ligaments/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You start reinforcing [target]'s ligaments.", + "[user] starts reinforcing [target]'s ligaments.", + "[user] starts manipulating [target]'s ligaments.") + +/datum/surgery_step/reinforce_ligaments/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You finish reinforcing [target]'s ligaments!", + "[user] finishes reinforcing [target]'s ligaments!", + "[user] finishes manipulating [target]'s ligaments!") + new /datum/bioware/reinforced_ligaments(target) + return TRUE + +/datum/bioware/reinforced_ligaments + name = "Reinforced Ligaments" + desc = "The ligaments and nerve endings that connect the torso to the limbs are protected by a mix of bone and tissues, and are much harder to separate from the body, but are also easier to disable." + mod_type = BIOWARE_LIGAMENTS + +/datum/bioware/reinforced_ligaments/on_gain() + ..() + ADD_TRAIT(owner, TRAIT_NODISMEMBER, "reinforced_ligaments") + ADD_TRAIT(owner, TRAIT_EASYLIMBDISABLE, "reinforced_ligaments") + +/datum/bioware/reinforced_ligaments/on_lose() + ..() + REMOVE_TRAIT(owner, TRAIT_NODISMEMBER, "reinforced_ligaments") + REMOVE_TRAIT(owner, TRAIT_EASYLIMBDISABLE, "reinforced_ligaments") \ No newline at end of file diff --git a/code/modules/surgery/advanced/bioware/muscled_veins.dm b/code/modules/surgery/advanced/bioware/muscled_veins.dm new file mode 100644 index 0000000000..81212019a8 --- /dev/null +++ b/code/modules/surgery/advanced/bioware/muscled_veins.dm @@ -0,0 +1,42 @@ +/datum/surgery/advanced/bioware/muscled_veins + name = "Vein Muscle Membrane" + desc = "A surgical procedure which adds a muscled membrane to blood vessels, allowing them to pump blood without a heart." + steps = list(/datum/surgery_step/incise, + /datum/surgery_step/retract_skin, + /datum/surgery_step/clamp_bleeders, + /datum/surgery_step/incise, + /datum/surgery_step/incise, + /datum/surgery_step/muscled_veins, + /datum/surgery_step/close) + possible_locs = list(BODY_ZONE_CHEST) + bioware_target = BIOWARE_CIRCULATION + +/datum/surgery_step/muscled_veins + name = "shape vein muscles" + accept_hand = TRUE + time = 125 + +/datum/surgery_step/muscled_veins/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You start wrapping muscles around [target]'s circulatory system.", + "[user] starts wrapping muscles around [target]'s circulatory system.", + "[user] starts manipulating [target]'s circulatory system.") + +/datum/surgery_step/muscled_veins/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You reshape [target]'s circulatory system, adding a muscled membrane!", + "[user] reshapes [target]'s circulatory system, adding a muscled membrane!", + "[user] finishes manipulating [target]'s circulatory system.") + new /datum/bioware/muscled_veins(target) + return TRUE + +/datum/bioware/muscled_veins + name = "Threaded Veins" + desc = "The circulatory system is woven into a mesh, severely reducing the amount of blood lost from wounds." + mod_type = BIOWARE_CIRCULATION + +/datum/bioware/muscled_veins/on_gain() + ..() + ADD_TRAIT(owner, TRAIT_STABLEHEART, "muscled_veins") + +/datum/bioware/muscled_veins/on_lose() + ..() + REMOVE_TRAIT(owner, TRAIT_STABLEHEART, "muscled_veins") \ No newline at end of file diff --git a/code/modules/surgery/advanced/bioware/nerve_grounding.dm b/code/modules/surgery/advanced/bioware/nerve_grounding.dm index f4b23c89b1..99902ff6d6 100644 --- a/code/modules/surgery/advanced/bioware/nerve_grounding.dm +++ b/code/modules/surgery/advanced/bioware/nerve_grounding.dm @@ -17,10 +17,14 @@ time = 155 /datum/surgery_step/ground_nerves/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] starts splicing together [target]'s nerves.", "You start splicing together [target]'s nerves.") + display_results(user, target, "You start rerouting [target]'s nerves.", + "[user] starts rerouting [target]'s nerves.", + "[user] starts manipulating [target]'s nervous system.") /datum/surgery_step/ground_nerves/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] successfully splices [target]'s nervous system!", "You successfully splice [target]'s nervous system!") + display_results(user, target, "You successfully reroute [target]'s nervous system!", + "[user] successfully reroutes [target]'s nervous system!", + "[user] finishes manipulating [target]'s nervous system.") new /datum/bioware/grounded_nerves(target) return TRUE @@ -37,4 +41,4 @@ /datum/bioware/grounded_nerves/on_lose() ..() - owner.physiology.siemens_coeff = prev_coeff \ No newline at end of file + owner.physiology.siemens_coeff = prev_coeff diff --git a/code/modules/surgery/advanced/bioware/nerve_splicing.dm b/code/modules/surgery/advanced/bioware/nerve_splicing.dm index 6192786cc4..e6e66e1b6e 100644 --- a/code/modules/surgery/advanced/bioware/nerve_splicing.dm +++ b/code/modules/surgery/advanced/bioware/nerve_splicing.dm @@ -10,17 +10,20 @@ /datum/surgery_step/close) possible_locs = list(BODY_ZONE_CHEST) bioware_target = BIOWARE_NERVES - /datum/surgery_step/splice_nerves name = "splice nerves" accept_hand = TRUE time = 155 /datum/surgery_step/splice_nerves/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] starts splicing together [target]'s nerves.", "You start splicing together [target]'s nerves.") + display_results(user, target, "You start splicing together [target]'s nerves.", + "[user] starts splicing together [target]'s nerves.", + "[user] starts manipulating [target]'s nervous system.") /datum/surgery_step/splice_nerves/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] successfully splices [target]'s nervous system!", "You successfully splice [target]'s nervous system!") + display_results(user, target, "You successfully splice [target]'s nervous system!", + "[user] successfully splices [target]'s nervous system!", + "[user] finishes manipulating [target]'s nervous system.") new /datum/bioware/spliced_nerves(target) return TRUE @@ -28,11 +31,9 @@ name = "Spliced Nerves" desc = "Nerves are connected to each other multiple times, greatly reducing the impact of stunning effects." mod_type = BIOWARE_NERVES - /datum/bioware/spliced_nerves/on_gain() ..() owner.physiology.stun_mod *= 0.5 - /datum/bioware/spliced_nerves/on_lose() ..() - owner.physiology.stun_mod *= 2 \ No newline at end of file + owner.physiology.stun_mod *= 2 diff --git a/code/modules/surgery/advanced/bioware/vein_threading.dm b/code/modules/surgery/advanced/bioware/vein_threading.dm index 7a03833c51..fc0868c116 100644 --- a/code/modules/surgery/advanced/bioware/vein_threading.dm +++ b/code/modules/surgery/advanced/bioware/vein_threading.dm @@ -10,17 +10,20 @@ /datum/surgery_step/close) possible_locs = list(BODY_ZONE_CHEST) bioware_target = BIOWARE_CIRCULATION - /datum/surgery_step/thread_veins name = "thread veins" accept_hand = TRUE time = 125 /datum/surgery_step/thread_veins/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] starts weaving [target]'s circulatory system.", "You start weaving [target]'s circulatory system.") + display_results(user, target, "You start weaving [target]'s circulatory system.", + "[user] starts weaving [target]'s circulatory system.", + "[user] starts manipulating [target]'s circulatory system.") /datum/surgery_step/thread_veins/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] weaves [target]'s circulatory system into a resistant mesh!", "You weave [target]'s circulatory system into a resistant mesh!") + display_results(user, target, "You weave [target]'s circulatory system into a resistant mesh!", + "[user] weaves [target]'s circulatory system into a resistant mesh!", + "[user] finishes manipulating [target]'s circulatory system.") new /datum/bioware/threaded_veins(target) return TRUE @@ -28,11 +31,9 @@ name = "Threaded Veins" desc = "The circulatory system is woven into a mesh, severely reducing the amount of blood lost from wounds." mod_type = BIOWARE_CIRCULATION - /datum/bioware/threaded_veins/on_gain() ..() owner.physiology.bleed_mod *= 0.25 - /datum/bioware/threaded_veins/on_lose() ..() - owner.physiology.bleed_mod *= 4 \ No newline at end of file + owner.physiology.bleed_mod *= 4 diff --git a/code/modules/surgery/advanced/brainwashing.dm b/code/modules/surgery/advanced/brainwashing.dm index 23783f1bf2..b067cce56b 100644 --- a/code/modules/surgery/advanced/brainwashing.dm +++ b/code/modules/surgery/advanced/brainwashing.dm @@ -2,7 +2,6 @@ name = "Brainwashing Surgery Disk" desc = "The disk provides instructions on how to impress an order on a brain, making it the primary objective of the patient." surgeries = list(/datum/surgery/advanced/brainwashing) - /datum/surgery/advanced/brainwashing name = "Brainwashing" desc = "A surgical procedure which directly implants a directive into the patient's brain, making it their absolute priority. It can be cleared using a mindshield implant." @@ -14,7 +13,7 @@ /datum/surgery_step/brainwash, /datum/surgery_step/close) - species = list(/mob/living/carbon/human) + target_mobtypes = list(/mob/living/carbon/human) possible_locs = list(BODY_ZONE_HEAD) /datum/surgery/advanced/brainwashing/can_start(mob/user, mob/living/carbon/target) @@ -24,27 +23,29 @@ if(!B) return FALSE return TRUE - /datum/surgery_step/brainwash name = "brainwash" - implements = list(/obj/item/hemostat = 85, TOOL_WIRECUTTER = 50, /obj/item/stack/packageWrap = 35, /obj/item/stack/cable_coil = 15) + implements = list(TOOL_HEMOSTAT = 85, TOOL_WIRECUTTER = 50, /obj/item/stack/packageWrap = 35, /obj/item/stack/cable_coil = 15) time = 200 var/objective - /datum/surgery_step/brainwash/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) objective = stripped_input(user, "Choose the objective to imprint on your victim's brain.", "Brainwashing", null, MAX_MESSAGE_LEN) if(!objective) return -1 - user.visible_message("[user] begins to tinker with [target]'s brain.", "You begin to brainwash [target]...") + display_results(user, target, "You begin to brainwash [target]...", + "[user] begins to fix [target]'s brain.", + "[user] begins to perform surgery on [target]'s brain.") /datum/surgery_step/brainwash/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) if(!target.mind) - user.visible_message("[target] doesn't respond to the brainwashing, as if [target.p_they()] lacked a mind...") + to_chat(user, "[target] doesn't respond to the brainwashing, as if [target.p_they()] lacked a mind...") return FALSE if(HAS_TRAIT(target, TRAIT_MINDSHIELD)) - user.visible_message("You hear a faint buzzing from a device inside [target]'s brain, and the brainwashing is erased.") + to_chat(user, "You hear a faint buzzing from a device inside [target]'s brain, and the brainwashing is erased.") return FALSE - user.visible_message("[user] successfully brainwashes [target]!", "You succeed in brainwashing [target].") + display_results(user, target, "You succeed in brainwashing [target].", + "[user] successfully fixes [target]'s brain!", + "[user] completes the surgery on [target]'s brain.") to_chat(target, "A new compulsion fills your mind... you feel forced to obey it!") brainwash(target, objective) message_admins("[ADMIN_LOOKUPFLW(user)] surgically brainwashed [ADMIN_LOOKUPFLW(target)] with the objective '[objective]'.") @@ -53,8 +54,10 @@ /datum/surgery_step/brainwash/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) if(target.getorganslot(ORGAN_SLOT_BRAIN)) - user.visible_message("[user] damages some brain tissue!", "You bruise some brain tissue!") - target.adjustBrainLoss(40) + display_results(user, target, "You screw up, bruising the brain tissue!", + "[user] screws up, causing brain damage!", + "[user] completes the surgery on [target]'s brain.") + target.adjustOrganLoss(ORGAN_SLOT_BRAIN, 40) else user.visible_message("[user] suddenly notices that the brain [user.p_they()] [user.p_were()] working on is not there anymore.", "You suddenly notice that the brain you were working on is not there anymore.") - return FALSE \ No newline at end of file + return FALSE diff --git a/code/modules/surgery/advanced/lobotomy.dm b/code/modules/surgery/advanced/lobotomy.dm index f74346b193..5667a2132d 100644 --- a/code/modules/surgery/advanced/lobotomy.dm +++ b/code/modules/surgery/advanced/lobotomy.dm @@ -9,10 +9,9 @@ /datum/surgery_step/lobotomize, /datum/surgery_step/close) - species = list(/mob/living/carbon/human, /mob/living/carbon/monkey) + target_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey) possible_locs = list(BODY_ZONE_HEAD) requires_bodypart_type = 0 - /datum/surgery/advanced/lobotomy/can_start(mob/user, mob/living/carbon/target) if(!..()) return FALSE @@ -20,23 +19,25 @@ if(!B) return FALSE return TRUE - /datum/surgery_step/lobotomize name = "perform lobotomy" - implements = list(/obj/item/scalpel = 85, /obj/item/melee/transforming/energy/sword = 55, /obj/item/kitchen/knife = 35, + implements = list(TOOL_SCALPEL = 85, /obj/item/melee/transforming/energy/sword = 55, /obj/item/kitchen/knife = 35, /obj/item/shard = 25, /obj/item = 20) time = 100 - /datum/surgery_step/lobotomize/tool_check(mob/user, obj/item/tool) if(implement_type == /obj/item && !tool.is_sharp()) return FALSE return TRUE /datum/surgery_step/lobotomize/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] begins to cut a piece of [target]'s brain.", "You begin to cut a piece of [target]'s brain...") + display_results(user, target, "You begin to perform a lobotomy on [target]'s brain...", + "[user] begins to perform a lobotomy on [target]'s brain.", + "[user] begins to perform surgery on [target]'s brain.") /datum/surgery_step/lobotomize/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] successfully lobotomizes [target]!", "You succeed in lobotomizing [target].") + display_results(user, target, "You succeed in lobotomizing [target].", + "[user] successfully lobotomizes [target]!", + "[user] completes the surgery on [target]'s brain.") target.cure_all_traumas(TRAUMA_RESILIENCE_LOBOTOMY) if(target.mind && target.mind.has_antag_datum(/datum/antagonist/brainwashed)) target.mind.remove_antag_datum(/datum/antagonist/brainwashed) @@ -50,9 +51,12 @@ return TRUE /datum/surgery_step/lobotomize/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - if(target.getorganslot(ORGAN_SLOT_BRAIN)) - user.visible_message("[user] removes the wrong part, causing more damage!", "You remove the wrong part, causing more damage!") - target.adjustBrainLoss(80) + var/obj/item/organ/brain/B = target.getorganslot(ORGAN_SLOT_BRAIN) + if(B) + display_results(user, target, "You remove the wrong part, causing more damage!", + "[user] successfully lobotomizes [target]!", + "[user] completes the surgery on [target]'s brain.") + B.applyOrganDamage(80) switch(rand(1,3)) if(1) target.gain_trauma_type(BRAIN_TRAUMA_MILD, TRAUMA_RESILIENCE_MAGIC) @@ -62,4 +66,4 @@ target.gain_trauma_type(BRAIN_TRAUMA_SPECIAL, TRAUMA_RESILIENCE_MAGIC) else user.visible_message("[user] suddenly notices that the brain [user.p_they()] [user.p_were()] working on is not there anymore.", "You suddenly notice that the brain you were working on is not there anymore.") - return FALSE \ No newline at end of file + return FALSE diff --git a/code/modules/surgery/advanced/necrotic_revival.dm b/code/modules/surgery/advanced/necrotic_revival.dm index a88bb51b31..f8fb160a8a 100644 --- a/code/modules/surgery/advanced/necrotic_revival.dm +++ b/code/modules/surgery/advanced/necrotic_revival.dm @@ -7,9 +7,7 @@ /datum/surgery_step/clamp_bleeders, /datum/surgery_step/bionecrosis, /datum/surgery_step/close) - possible_locs = list(BODY_ZONE_HEAD) - /datum/surgery/advanced/necrotic_revival/can_start(mob/user, mob/living/carbon/target) . = ..() var/obj/item/organ/zombie_infection/ZI = target.getorganslot(ORGAN_SLOT_ZOMBIE) @@ -18,17 +16,22 @@ /datum/surgery_step/bionecrosis name = "start bionecrosis" - implements = list(/obj/item/hemostat = 100, TOOL_SCREWDRIVER = 35, /obj/item/pen = 15) + implements = list(TOOL_HEMOSTAT = 100, TOOL_SCREWDRIVER = 35, /obj/item/pen = 15) + implements = list(/obj/item/reagent_containers/syringe = 100, /obj/item/pen = 30) time = 50 chems_needed = list("zombiepowder", "rezadone") require_all_chems = FALSE /datum/surgery_step/bionecrosis/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] begins to stimulate [target]'s brain.", "You begin to stimulate [target]'s brain...") + display_results(user, target, "You begin to grow a romerol tumor on [target]'s brain...", + "[user] begins to tinker with [target]'s brain...", + "[user] begins to perform surgery on [target]'s brain.") /datum/surgery_step/bionecrosis/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] successfully grows a necrotic tumor on [target]'s brain!", "You succeed in growing a necrotic tumor on [target]'s brain.") + display_results(user, target, "You succeed in growing a romerol tumor on [target]'s brain.", + "[user] successfully grows a romerol tumor on [target]'s brain!", + "[user] completes the surgery on [target]'s brain.") if(!target.getorganslot(ORGAN_SLOT_ZOMBIE)) var/obj/item/organ/zombie_infection/ZI = new() ZI.Insert(target) - return TRUE \ No newline at end of file + return TRUE diff --git a/code/modules/surgery/advanced/pacification.dm b/code/modules/surgery/advanced/pacification.dm index 15e34d003c..866c85842b 100644 --- a/code/modules/surgery/advanced/pacification.dm +++ b/code/modules/surgery/advanced/pacification.dm @@ -8,30 +8,34 @@ /datum/surgery_step/pacify, /datum/surgery_step/close) - species = list(/mob/living/carbon/human, /mob/living/carbon/monkey) + target_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey) possible_locs = list(BODY_ZONE_HEAD) requires_bodypart_type = 0 - /datum/surgery/advanced/pacify/can_start(mob/user, mob/living/carbon/target) . = ..() var/obj/item/organ/brain/B = target.getorganslot(ORGAN_SLOT_BRAIN) if(!B) return FALSE - /datum/surgery_step/pacify name = "rewire brain" - implements = list(/obj/item/hemostat = 100, TOOL_SCREWDRIVER = 35, /obj/item/pen = 15) + implements = list(TOOL_HEMOSTAT = 100, TOOL_SCREWDRIVER = 35, /obj/item/pen = 15) time = 40 /datum/surgery_step/pacify/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] begins to reshape [target]'s brain.", "You begin to reshape [target]'s brain...") + display_results(user, target, "You begin to pacify [target]...", + "[user] begins to fix [target]'s brain.", + "[user] begins to perform surgery on [target]'s brain.") /datum/surgery_step/pacify/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] reshapes [target]'s brain!", "You succeed in reshaping [target]'s brain.") + display_results(user, target, "You succeed in neurologically pacifying [target].", + "[user] successfully fixes [target]'s brain!", + "[user] completes the surgery on [target]'s brain.") target.gain_trauma(/datum/brain_trauma/severe/pacifism, TRAUMA_RESILIENCE_LOBOTOMY) return TRUE /datum/surgery_step/pacify/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] reshapes [target]'s brain!", "You screwed up, and rewired [target]'s brain the wrong way around...") + display_results(user, target, "You screw up, rewiring [target]'s brain the wrong way around...", + "[user] screws up, causing brain damage!", + "[user] completes the surgery on [target]'s brain.") target.gain_trauma_type(BRAIN_TRAUMA_SEVERE, TRAUMA_RESILIENCE_LOBOTOMY) - return FALSE \ No newline at end of file + return FALSE diff --git a/code/modules/surgery/advanced/reconstruction.dm b/code/modules/surgery/advanced/reconstruction.dm deleted file mode 100644 index 84d9f5b9f8..0000000000 --- a/code/modules/surgery/advanced/reconstruction.dm +++ /dev/null @@ -1,35 +0,0 @@ -/datum/surgery/advanced/reconstruction - name = "Reconstruction" - desc = "A surgical procedure that gradually repairs damage done to a body without the assistance of chemicals. Unlike classic medicine, it is effective on corpses." - steps = list(/datum/surgery_step/incise, - /datum/surgery_step/incise, - /datum/surgery_step/retract_skin, - /datum/surgery_step/incise, - /datum/surgery_step/clamp_bleeders, - /datum/surgery_step/incise, - /datum/surgery_step/retract_skin, - /datum/surgery_step/reconstruct, - /datum/surgery_step/close) - - species = list(/mob/living/carbon/human, /mob/living/carbon/monkey) - possible_locs = list(BODY_ZONE_CHEST) - requires_bodypart_type = 0 - -/datum/surgery_step/reconstruct - name = "repair body" - implements = list(/obj/item/hemostat = 100, TOOL_SCREWDRIVER = 35, /obj/item/pen = 15) - repeatable = TRUE - time = 25 - -/datum/surgery_step/reconstruct/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] starts knitting some of [target]'s flesh back together.", "You start knitting some of [target]'s flesh back together.") - -/datum/surgery_step/reconstruct/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] fixes some of [target]'s wounds.", "You succeed in fixing some of [target]'s wounds.") - target.heal_bodypart_damage(10,10) - return TRUE - -/datum/surgery_step/reconstruct/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] screws up!", "You screwed up!") - target.take_bodypart_damage(5,0) - return FALSE \ No newline at end of file diff --git a/code/modules/surgery/advanced/revival.dm b/code/modules/surgery/advanced/revival.dm index ebda8a04e2..a2d5345ea4 100644 --- a/code/modules/surgery/advanced/revival.dm +++ b/code/modules/surgery/advanced/revival.dm @@ -9,10 +9,9 @@ /datum/surgery_step/revive, /datum/surgery_step/close) - species = list(/mob/living/carbon/human, /mob/living/carbon/monkey) + target_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey) possible_locs = list(BODY_ZONE_HEAD) requires_bodypart_type = 0 - /datum/surgery/advanced/revival/can_start(mob/user, mob/living/carbon/target) if(!..()) return FALSE @@ -24,12 +23,10 @@ if(!B) return FALSE return TRUE - /datum/surgery_step/revive name = "electrically stimulate brain" implements = list(/obj/item/twohanded/shockpaddles = 100, /obj/item/abductor/gizmo = 100, /obj/item/melee/baton = 75, /obj/item/organ/cyberimp/arm/baton = 75, /obj/item/organ/cyberimp/arm/gun/taser = 60, /obj/item/gun/energy/e_gun/advtaser = 60, /obj/item/gun/energy/taser = 60) time = 120 - /datum/surgery_step/revive/tool_check(mob/user, obj/item/tool) . = TRUE if(istype(tool, /obj/item/twohanded/shockpaddles)) @@ -51,25 +48,33 @@ return FALSE /datum/surgery_step/revive/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] prepares to shock [target]'s brain with [tool].", "You prepare to give [target]'s brain the spark of life with [tool].") + display_results(user, target, "You prepare to give [target]'s brain the spark of life with [tool].", + "[user] prepares to shock [target]'s brain with [tool].", + "[user] prepares to shock [target]'s brain with [tool].") target.notify_ghost_cloning("Someone is trying to zap your brain. Re-enter your corpse if you want to be revived!", source = target) /datum/surgery_step/revive/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] send a powerful shock to [target]'s brain with [tool]...", "You successfully shock [target]'s brain with [tool]...") + display_results(user, target, "You successfully shock [target]'s brain with [tool]...", + "[user] send a powerful shock to [target]'s brain with [tool]...", + "[user] send a powerful shock to [target]'s brain with [tool]...") playsound(get_turf(target), 'sound/magic/lightningbolt.ogg', 50, 1) target.adjustOxyLoss(-50, 0) target.updatehealth() if(target.revive()) user.visible_message("...[target] wakes up, alive and aware!", "IT'S ALIVE!") + target.visible_message("...[target] wakes up, alive and aware!") target.emote("gasp") - target.adjustBrainLoss(50, 199) //MAD SCIENCE + target.adjustOrganLoss(ORGAN_SLOT_BRAIN, 50, 199) //MAD SCIENCE return TRUE else user.visible_message("...[target.p_they()] convulses, then lies still.") + target.visible_message("...[target.p_they()] convulses, then lies still.") return FALSE /datum/surgery_step/revive/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] send a powerful shock to [target]'s brain with [tool], but [target.p_they()] doesn't react.", "You shock [target]'s brain with [tool], but [target.p_they()] doesn't react.") + display_results(user, target, "You shock [target]'s brain with [tool], but [target.p_they()] doesn't react.", + "[user] send a powerful shock to [target]'s brain with [tool], but [target.p_they()] doesn't react.", + "[user] send a powerful shock to [target]'s brain with [tool], but [target.p_they()] doesn't react.") playsound(get_turf(target), 'sound/magic/lightningbolt.ogg', 50, 1) - target.adjustBrainLoss(15, 199) - return FALSE \ No newline at end of file + target.adjustOrganLoss(ORGAN_SLOT_BRAIN, 15, 199) + return FALSE diff --git a/code/modules/surgery/advanced/toxichealing.dm b/code/modules/surgery/advanced/toxichealing.dm new file mode 100644 index 0000000000..bb28a0fb05 --- /dev/null +++ b/code/modules/surgery/advanced/toxichealing.dm @@ -0,0 +1,37 @@ +/datum/surgery/advanced/toxichealing + name = "Body Rejuvenation" + desc = "A surgical procedure that helps deal with oxygen deprivation, and treats parts damaged due to toxic compounds. Works on corpses and alive alike without chemicals." + steps = list(/datum/surgery_step/incise, + /datum/surgery_step/incise, + /datum/surgery_step/retract_skin, + /datum/surgery_step/incise, + /datum/surgery_step/clamp_bleeders, + /datum/surgery_step/incise, + /datum/surgery_step/retract_skin, + /datum/surgery_step/toxichealing, + /datum/surgery_step/close) + + target_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey) + possible_locs = list(BODY_ZONE_CHEST) + requires_bodypart_type = 0 + +/datum/surgery_step/toxichealing + name = "rejuvenate body" + implements = list(TOOL_HEMOSTAT = 100, TOOL_SCREWDRIVER = 35, /obj/item/pen = 15) + repeatable = TRUE + time = 25 + +/datum/surgery_step/toxichealing/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + user.visible_message("[user] starts rejuvenating some of [target]'s flesh back to life.", "You start knitting some of [target]'s flesh back to life.") + +/datum/surgery_step/toxichealing/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + user.visible_message("[user] fixes some of [target]'s wounds.", "You succeed in fixing some of [target]'s wounds.") + target.heal_bodypart_damage(0,0,30) //Heals stam + target.adjustToxLoss(-15, 0, TRUE) + target.adjustOxyLoss(-20, 0) + return TRUE + +/datum/surgery_step/toxichealing/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + user.visible_message("[user] screws up!", "You screwed up!") + target.take_bodypart_damage(25,0) + return FALSE \ No newline at end of file diff --git a/code/modules/surgery/advanced/viral_bonding.dm b/code/modules/surgery/advanced/viral_bonding.dm index 115f8a2eed..e6e24238c1 100644 --- a/code/modules/surgery/advanced/viral_bonding.dm +++ b/code/modules/surgery/advanced/viral_bonding.dm @@ -8,34 +8,35 @@ /datum/surgery_step/viral_bond, /datum/surgery_step/close) - species = list(/mob/living/carbon/human, /mob/living/carbon/monkey) + target_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey) possible_locs = list(BODY_ZONE_CHEST) - /datum/surgery/advanced/viral_bonding/can_start(mob/user, mob/living/carbon/target) if(!..()) return FALSE if(!LAZYLEN(target.diseases)) return FALSE return TRUE - /datum/surgery_step/viral_bond name = "viral bond" - implements = list(/obj/item/cautery = 100, TOOL_WELDER = 50, /obj/item = 30) // 30% success with any hot item. + implements = list(TOOL_CAUTERY = 100, TOOL_WELDER = 50, /obj/item = 30) // 30% success with any hot item. time = 100 chems_needed = list("spaceacillin","virusfood","formaldehyde") /datum/surgery_step/viral_bond/tool_check(mob/user, obj/item/tool) if(implement_type == TOOL_WELDER || implement_type == /obj/item) return tool.is_hot() - return TRUE /datum/surgery_step/viral_bond/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] starts heating [target]'s bone marrow with [tool]...", "You start heating [target]'s bone marrow with [tool]...") + display_results(user, target, "You start heating [target]'s bone marrow with [tool]...", + "[user] starts heating [target]'s bone marrow with [tool]...", + "[user] starts heating something in [target]'s chest with [tool]...") /datum/surgery_step/viral_bond/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[target]'s bone marrow begins pulsing slowly.", "[target]'s bone marrow begins pulsing slowly. The viral bonding is complete.") + display_results(user, target, "[target]'s bone marrow begins pulsing slowly. The viral bonding is complete.", + "[target]'s bone marrow begins pulsing slowly.", + "[user] finishes the operation.") for(var/X in target.diseases) var/datum/disease/D = X D.carrier = TRUE - return TRUE \ No newline at end of file + return TRUE diff --git a/code/modules/surgery/amputation.dm b/code/modules/surgery/amputation.dm index 8465a6d332..5c77532188 100644 --- a/code/modules/surgery/amputation.dm +++ b/code/modules/surgery/amputation.dm @@ -1,25 +1,25 @@ - /datum/surgery/amputation - name = "amputation" + name = "Amputation" steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/saw, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/sever_limb) - species = list(/mob/living/carbon/human, /mob/living/carbon/monkey) + target_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey) possible_locs = list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG, BODY_ZONE_HEAD) requires_bodypart_type = 0 - - /datum/surgery_step/sever_limb name = "sever limb" - implements = list(/obj/item/scalpel = 100, /obj/item/circular_saw = 100, /obj/item/melee/transforming/energy/sword/cyborg/saw = 100, /obj/item/melee/arm_blade = 80, /obj/item/twohanded/required/chainsaw = 80, /obj/item/mounted_chainsaw = 80, /obj/item/twohanded/fireaxe = 50, /obj/item/hatchet = 40, /obj/item/kitchen/knife/butcher = 25) + implements = list(TOOL_SCALPEL = 100, TOOL_SAW = 100, /obj/item/melee/transforming/energy/sword/cyborg/saw = 100, /obj/item/melee/arm_blade = 80, /obj/item/twohanded/required/chainsaw = 80, /obj/item/mounted_chainsaw = 80, /obj/item/twohanded/fireaxe = 50, /obj/item/hatchet = 40, /obj/item/kitchen/knife/butcher = 25) time = 64 /datum/surgery_step/sever_limb/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] begins to sever [target]'s [parse_zone(target_zone)]!", "You begin to sever [target]'s [parse_zone(target_zone)]...") + display_results(user, target, "You begin to sever [target]'s [parse_zone(target_zone)]...", + "[user] begins to sever [target]'s [parse_zone(target_zone)]!", + "[user] begins to sever [target]'s [parse_zone(target_zone)]!") /datum/surgery_step/sever_limb/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) var/mob/living/carbon/human/L = target - user.visible_message("[user] severs [L]'s [parse_zone(target_zone)]!", "You sever [L]'s [parse_zone(target_zone)].") + display_results(user, target, "You sever [L]'s [parse_zone(target_zone)].", + "[user] severs [L]'s [parse_zone(target_zone)]!", + "[user] severs [L]'s [parse_zone(target_zone)]!") if(surgery.operated_bodypart) var/obj/item/bodypart/target_limb = surgery.operated_bodypart target_limb.drop_limb() - - return 1 \ No newline at end of file + return 1 diff --git a/code/modules/surgery/bodyparts/bodyparts.dm b/code/modules/surgery/bodyparts/bodyparts.dm index a97a133685..dffb7bf355 100644 --- a/code/modules/surgery/bodyparts/bodyparts.dm +++ b/code/modules/surgery/bodyparts/bodyparts.dm @@ -40,6 +40,7 @@ var/skin_tone = "" var/body_gender = "" var/species_id = "" + var/should_draw_citadel = FALSE var/should_draw_gender = FALSE var/should_draw_greyscale = FALSE var/species_color = "" @@ -48,8 +49,8 @@ var/body_markings = "" //for bodypart markings var/body_markings_icon = 'modular_citadel/icons/mob/mam_markings.dmi' var/list/markings_color = list() - var/auxmarking = "" - var/list/auxmarking_color = list() + var/aux_marking + var/digitigrade_type var/animal_origin = null //for nonhuman bodypart (e.g. monkey) var/dismemberable = 1 //whether it can be dismembered with a weapon. @@ -230,7 +231,7 @@ return BODYPART_DISABLED_PARALYSIS if(can_dismember() && !HAS_TRAIT(owner, TRAIT_NODISMEMBER)) . = disabled //inertia, to avoid limbs healing 0.1 damage and being re-enabled - if((get_damage(TRUE) >= max_damage)) + if((get_damage(TRUE) >= max_damage) || (HAS_TRAIT(owner, TRAIT_EASYLIMBDISABLE) && (get_damage(TRUE) >= (max_damage * 0.6)))) //Easy limb disable disables the limb at 40% health instead of 0% return BODYPART_DISABLED_DAMAGE if(disabled && (get_damage(TRUE) <= (max_damage * 0.5))) return BODYPART_NOT_DISABLED @@ -309,7 +310,7 @@ should_draw_greyscale = FALSE no_update = TRUE body_markings = "husk" // reeee - auxmarking = "husk" + aux_marking = "husk" if(no_update) return @@ -351,21 +352,29 @@ else species_color = "" + if("legs" in S.default_features) + if(body_zone == BODY_ZONE_L_LEG || body_zone == BODY_ZONE_R_LEG) + if(DIGITIGRADE in S.species_traits) + digitigrade_type = lowertext(H.dna.features.["legs"]) + else + digitigrade_type = null + if("mam_body_markings" in S.default_features) var/datum/sprite_accessory/Smark Smark = GLOB.mam_body_markings_list[H.dna.features["mam_body_markings"]] - body_markings_icon = Smark.icon + if(Smark) + body_markings_icon = Smark.icon if(H.dna.features.["mam_body_markings"] != "None") body_markings = lowertext(H.dna.features.["mam_body_markings"]) - auxmarking = lowertext(H.dna.features.["mam_body_markings"]) + aux_marking = lowertext(H.dna.features.["mam_body_markings"]) else body_markings = "plain" - auxmarking = "plain" + aux_marking = "plain" markings_color = list(colorlist) else body_markings = null - auxmarking = null + aux_marking = null if(!dropping_limb && H.dna.check_mutation(HULK)) mutation_color = "00aa00" @@ -380,7 +389,7 @@ if(status == BODYPART_ROBOTIC) dmg_overlay_type = "robotic" body_markings = null - auxmarking = null + aux_marking = null if(dropping_limb) no_update = TRUE //when attached, the limb won't be affected by the appearance changes of its mob owner. @@ -422,7 +431,7 @@ else . += image(body_markings_icon, "[body_markings]_[body_zone]", -MARKING_LAYER, image_dir) else - . += image(body_markings_icon, "[body_markings]_digitigrade_[use_digitigrade]_[body_zone]", -MARKING_LAYER, image_dir) + . += image(body_markings_icon, "[body_markings]_[digitigrade_type]_[use_digitigrade]_[body_zone]", -MARKING_LAYER, image_dir) var/image/limb = image(layer = -BODYPARTS_LAYER, dir = image_dir) var/image/aux @@ -452,21 +461,25 @@ if(should_draw_gender) limb.icon_state = "[species_id]_[body_zone]_[icon_gender]" else if(use_digitigrade) - limb.icon_state = "digitigrade_[use_digitigrade]_[body_zone]" + limb.icon_state = "[digitigrade_type]_[use_digitigrade]_[body_zone]" else limb.icon_state = "[species_id]_[body_zone]" else limb.icon = 'icons/mob/human_parts.dmi' if(should_draw_gender) limb.icon_state = "[species_id]_[body_zone]_[icon_gender]" + else if(use_digitigrade) + limb.icon_state = "[species_id]_[digitigrade_type]_[use_digitigrade]_[body_zone]" else limb.icon_state = "[species_id]_[body_zone]" // Citadel Start - if(should_draw_citadel && !use_digitigrade) + if(should_draw_citadel) limb.icon = 'modular_citadel/icons/mob/mutant_bodyparts.dmi' if(should_draw_gender) limb.icon_state = "[species_id]_[body_zone]_[icon_gender]" + else if(use_digitigrade) + limb.icon_state = "[species_id]_[digitigrade_type]_[use_digitigrade]_[body_zone]" else limb.icon_state = "[species_id]_[body_zone]" @@ -475,7 +488,7 @@ if(species_id == "husk") marking = image('modular_citadel/icons/mob/markings_notmammals.dmi', "husk_[body_zone]", -MARKING_LAYER, image_dir) else if(species_id == "husk" && use_digitigrade) - marking = image('modular_citadel/icons/mob/markings_notmammals.dmi', "husk_digitigrade_[use_digitigrade]_[body_zone]", -MARKING_LAYER, image_dir) + marking = image('modular_citadel/icons/mob/markings_notmammals.dmi', "husk_[digitigrade_type]_[use_digitigrade]_[body_zone]", -MARKING_LAYER, image_dir) else if(!use_digitigrade) if(body_zone == BODY_ZONE_CHEST) @@ -483,20 +496,21 @@ else marking = image(body_markings_icon, "[body_markings]_[body_zone]", -MARKING_LAYER, image_dir) else - marking = image(body_markings_icon, "[body_markings]_digitigrade_[use_digitigrade]_[body_zone]", -MARKING_LAYER, image_dir) + marking = image(body_markings_icon, "[body_markings]_[digitigrade_type]_[use_digitigrade]_[body_zone]", -MARKING_LAYER, image_dir) + . += marking // Citadel End if(aux_zone) aux = image(limb.icon, "[species_id]_[aux_zone]", -aux_layer, image_dir) - . += aux - if(!isnull(auxmarking)) + if(!isnull(aux_marking)) if(species_id == "husk") auxmarking = image('modular_citadel/icons/mob/markings_notmammals.dmi', "husk_[aux_zone]", -aux_layer, image_dir) else auxmarking = image(body_markings_icon, "[body_markings]_[aux_zone]", -aux_layer, image_dir) - . += auxmarking + . += aux + . += auxmarking else limb.icon = icon @@ -508,7 +522,7 @@ if(aux_zone) aux = image(limb.icon, "[aux_zone]", -aux_layer, image_dir) . += aux - if(!isnull(auxmarking)) + if(!isnull(aux_marking)) if(species_id == "husk") auxmarking = image('modular_citadel/icons/mob/markings_notmammals.dmi', "husk_[aux_zone]", -aux_layer, image_dir) else @@ -527,7 +541,7 @@ else marking = image(body_markings_icon, "[body_markings]_[body_zone]", -MARKING_LAYER, image_dir) else - marking = image(body_markings_icon, "[body_markings]_digitigrade_[use_digitigrade]_[body_zone]", -MARKING_LAYER, image_dir) + marking = image(body_markings_icon, "[body_markings]_[digitigrade_type]_[use_digitigrade]_[body_zone]", -MARKING_LAYER, image_dir) . += marking return @@ -537,8 +551,11 @@ limb.color = "#[draw_color]" if(aux_zone) aux.color = "#[draw_color]" - if(!isnull(auxmarking)) - auxmarking.color = list(markings_color) + if(!isnull(aux_marking)) + if(species_id == "husk") + auxmarking.color = "#141414" + else + auxmarking.color = list(markings_color) if(!isnull(body_markings)) if(species_id == "husk") diff --git a/code/modules/surgery/bodyparts/head.dm b/code/modules/surgery/bodyparts/head.dm index 46ee10a3fd..23d49e98bb 100644 --- a/code/modules/surgery/bodyparts/head.dm +++ b/code/modules/surgery/bodyparts/head.dm @@ -32,6 +32,8 @@ var/lip_style = null var/lip_color = "white" + //If the head is a special sprite + var/custom_head /obj/item/bodypart/head/can_dismember(obj/item/I) if(!((owner.stat == DEAD) || owner.InFullCritical())) @@ -128,6 +130,8 @@ add_overlay(standing) /obj/item/bodypart/head/get_limb_icon(dropped) + if(custom_head) + return cut_overlays() . = ..() if(dropped) //certain overlays only appear when the limb is being detached from its owner. diff --git a/code/modules/surgery/bodyparts/robot_bodyparts.dm b/code/modules/surgery/bodyparts/robot_bodyparts.dm index ab31d64034..a3f8b883b4 100644 --- a/code/modules/surgery/bodyparts/robot_bodyparts.dm +++ b/code/modules/surgery/bodyparts/robot_bodyparts.dm @@ -20,8 +20,8 @@ icon_state = "borg_l_arm" status = BODYPART_ROBOTIC - brute_reduction = 5 - burn_reduction = 4 + brute_reduction = 2 + burn_reduction = 1 light_brute_msg = ROBOTIC_LIGHT_BRUTE_MSG medium_brute_msg = ROBOTIC_MEDIUM_BRUTE_MSG @@ -41,8 +41,8 @@ icon_state = "borg_r_arm" status = BODYPART_ROBOTIC - brute_reduction = 5 - burn_reduction = 4 + brute_reduction = 2 + burn_reduction = 1 light_brute_msg = ROBOTIC_LIGHT_BRUTE_MSG medium_brute_msg = ROBOTIC_MEDIUM_BRUTE_MSG @@ -62,8 +62,8 @@ icon_state = "borg_l_leg" status = BODYPART_ROBOTIC - brute_reduction = 5 - burn_reduction = 4 + brute_reduction = 2 + burn_reduction = 1 light_brute_msg = ROBOTIC_LIGHT_BRUTE_MSG medium_brute_msg = ROBOTIC_MEDIUM_BRUTE_MSG @@ -83,8 +83,8 @@ icon_state = "borg_r_leg" status = BODYPART_ROBOTIC - brute_reduction = 5 - burn_reduction = 4 + brute_reduction = 2 + burn_reduction = 1 light_brute_msg = ROBOTIC_LIGHT_BRUTE_MSG medium_brute_msg = ROBOTIC_MEDIUM_BRUTE_MSG @@ -103,8 +103,8 @@ icon_state = "borg_chest" status = BODYPART_ROBOTIC - brute_reduction = 5 - burn_reduction = 4 + brute_reduction = 2 + burn_reduction = 1 light_brute_msg = ROBOTIC_LIGHT_BRUTE_MSG medium_brute_msg = ROBOTIC_MEDIUM_BRUTE_MSG @@ -268,38 +268,38 @@ burn_reduction = 0 max_damage = 20 -// Upgraded Surplus lims +// Upgraded Surplus lims - Better then robotic lims /obj/item/bodypart/l_arm/robot/surplus_upgraded name = "reinforced surplus prosthetic left arm" - desc = "A skeletal, robotic limb. This one is reinforced to provide better protection." + desc = "A skeletal, robotic limb. This one is reinforced to provide better protection, and is made of stronger parts." icon = 'icons/mob/augmentation/surplus_augments.dmi' - brute_reduction = 1 - burn_reduction = 1 - max_damage = 30 + brute_reduction = 3 + burn_reduction = 2 + max_damage = 55 /obj/item/bodypart/r_arm/robot/surplus_upgraded name = "reinforced surplus prosthetic right arm" - desc = "A skeletal, robotic limb. This one is reinforced to provide better protection." + desc = "A skeletal, robotic limb. This one is reinforced to provide better protection, and is made of stronger parts." icon = 'icons/mob/augmentation/surplus_augments.dmi' - brute_reduction = 1 - burn_reduction = 1 - max_damage = 30 + brute_reduction = 3 + burn_reduction = 2 + max_damage = 55 /obj/item/bodypart/l_leg/robot/surplus_upgraded name = "reinforced surplus prosthetic left leg" - desc = "A skeletal, robotic limb. This one is reinforced to provide better protection." + desc = "A skeletal, robotic limb. This one is reinforced to provide better protection, and is made of stronger parts." icon = 'icons/mob/augmentation/surplus_augments.dmi' - brute_reduction = 1 - burn_reduction = 1 - max_damage = 30 + brute_reduction = 3 + burn_reduction = 2 + max_damage = 55 /obj/item/bodypart/r_leg/robot/surplus_upgraded name = "reinforced surplus prosthetic right leg" - desc = "A skeletal, robotic limb. This one is reinforced to provide better protection." + desc = "A skeletal, robotic limb. This one is reinforced to provide better protection, and is made of stronger parts." icon = 'icons/mob/augmentation/surplus_augments.dmi' - brute_reduction = 1 - burn_reduction = 1 - max_damage = 30 + brute_reduction = 3 + burn_reduction = 2 + max_damage = 55 #undef ROBOTIC_LIGHT_BRUTE_MSG #undef ROBOTIC_MEDIUM_BRUTE_MSG diff --git a/code/modules/surgery/brain_surgery.dm b/code/modules/surgery/brain_surgery.dm index fcd626ad97..d86f5731c7 100644 --- a/code/modules/surgery/brain_surgery.dm +++ b/code/modules/surgery/brain_surgery.dm @@ -1,5 +1,5 @@ /datum/surgery/brain_surgery - name = "brain surgery" + name = "Brain surgery" steps = list( /datum/surgery_step/incise, /datum/surgery_step/retract_skin, @@ -8,15 +8,13 @@ /datum/surgery_step/fix_brain, /datum/surgery_step/close) - species = list(/mob/living/carbon/human, /mob/living/carbon/monkey) + target_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey) possible_locs = list(BODY_ZONE_HEAD) requires_bodypart_type = 0 - /datum/surgery_step/fix_brain name = "fix brain" - implements = list(/obj/item/hemostat = 85, TOOL_SCREWDRIVER = 35, /obj/item/pen = 15) //don't worry, pouring some alcohol on their open brain will get that chance to 100 + implements = list(TOOL_HEMOSTAT = 85, TOOL_SCREWDRIVER = 35, /obj/item/pen = 15) //don't worry, pouring some alcohol on their open brain will get that chance to 100 time = 120 //long and complicated - /datum/surgery/brain_surgery/can_start(mob/user, mob/living/carbon/target) var/obj/item/organ/brain/B = target.getorganslot(ORGAN_SLOT_BRAIN) if(!B) @@ -24,21 +22,27 @@ return TRUE /datum/surgery_step/fix_brain/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] begins to fix [target]'s brain.", "You begin to fix [target]'s brain...") + display_results(user, target, "You begin to fix [target]'s brain...", + "[user] begins to fix [target]'s brain.", + "[user] begins to perform surgery on [target]'s brain.") /datum/surgery_step/fix_brain/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] successfully fixes [target]'s brain!", "You succeed in fixing [target]'s brain.") + display_results(user, target, "You succeed in fixing [target]'s brain.", + "[user] successfully fixes [target]'s brain!", + "[user] completes the surgery on [target]'s brain.") if(target.mind && target.mind.has_antag_datum(/datum/antagonist/brainwashed)) target.mind.remove_antag_datum(/datum/antagonist/brainwashed) - target.adjustBrainLoss(-60) + target.setOrganLoss(ORGAN_SLOT_BRAIN, target.getOrganLoss(ORGAN_SLOT_BRAIN) - 60) //we set damage in this case in order to clear the "failing" flag target.cure_all_traumas(TRAUMA_RESILIENCE_SURGERY) return TRUE /datum/surgery_step/fix_brain/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) if(target.getorganslot(ORGAN_SLOT_BRAIN)) - user.visible_message("[user] screws up, causing more damage!", "You screw up, causing more damage!") - target.adjustBrainLoss(60) + display_results(user, target, "You screw up, causing more damage!", + "[user] screws up, causing brain damage!", + "[user] completes the surgery on [target]'s brain.") + target.adjustOrganLoss(ORGAN_SLOT_BRAIN, 60) target.gain_trauma_type(BRAIN_TRAUMA_SEVERE, TRAUMA_RESILIENCE_LOBOTOMY) else user.visible_message("[user] suddenly notices that the brain [user.p_they()] [user.p_were()] working on is not there anymore.", "You suddenly notice that the brain you were working on is not there anymore.") - return FALSE \ No newline at end of file + return FALSE diff --git a/code/modules/surgery/cavity_implant.dm b/code/modules/surgery/cavity_implant.dm index 72874e0308..e50f8ddcac 100644 --- a/code/modules/surgery/cavity_implant.dm +++ b/code/modules/surgery/cavity_implant.dm @@ -1,30 +1,32 @@ /datum/surgery/cavity_implant - name = "cavity implant" + name = "Cavity implant" steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/incise, /datum/surgery_step/handle_cavity, /datum/surgery_step/close) - species = list(/mob/living/carbon/human, /mob/living/carbon/monkey) + target_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey) possible_locs = list(BODY_ZONE_CHEST) - - //handle cavity /datum/surgery_step/handle_cavity name = "implant item" accept_hand = 1 accept_any_item = 1 + implements = list(/obj/item = 100) + repeatable = TRUE time = 32 var/obj/item/IC = null - +/datum/surgery_step/handle_cavity/tool_check(mob/user, obj/item/tool) + if(istype(tool, /obj/item/cautery) || istype(tool, /obj/item/gun/energy/laser)) + return FALSE + return !tool.is_hot() /datum/surgery_step/handle_cavity/preop(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool, datum/surgery/surgery) var/obj/item/bodypart/chest/CH = target.get_bodypart(BODY_ZONE_CHEST) IC = CH.cavity_item if(tool) - if(istype(tool, /obj/item/surgical_drapes) || istype(tool, /obj/item/bedsheet)) - var/obj/item/inactive = user.get_inactive_held_item() - if(istype(inactive, /obj/item/cautery) || istype(inactive, /obj/item/screwdriver) || iscyborg(user)) - attempt_cancel_surgery(surgery, tool, target, user) - return -1 - user.visible_message("[user] begins to insert [tool] into [target]'s [target_zone].", "You begin to insert [tool] into [target]'s [target_zone]...") + display_results(user, target, "You begin to insert [tool] into [target]'s [target_zone]...", + "[user] begins to insert [tool] into [target]'s [target_zone].", + "[user] begins to insert [tool.w_class > WEIGHT_CLASS_SMALL ? tool : "something"] into [target]'s [target_zone].") else - user.visible_message("[user] checks for items in [target]'s [target_zone].", "You check for items in [target]'s [target_zone]...") + display_results(user, target, "You check for items in [target]'s [target_zone]...", + "[user] checks for items in [target]'s [target_zone].", + "[user] looks for something in [target]'s [target_zone].") /datum/surgery_step/handle_cavity/success(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool, datum/surgery/surgery) var/obj/item/bodypart/chest/CH = target.get_bodypart(BODY_ZONE_CHEST) @@ -32,18 +34,18 @@ if(IC || tool.w_class > WEIGHT_CLASS_NORMAL || HAS_TRAIT(tool, TRAIT_NODROP) || istype(tool, /obj/item/organ)) to_chat(user, "You can't seem to fit [tool] in [target]'s [target_zone]!") return 0 - var/obj/item/electronic_assembly/EA = tool - if(istype(EA) && EA.combat_circuits && tool.w_class > WEIGHT_CLASS_SMALL) - to_chat(user, "[tool] is too dangerous to put in [target]'s [target_zone]! Maybe if it was smaller...") - return 0 else - user.visible_message("[user] stuffs [tool] into [target]'s [target_zone]!", "You stuff [tool] into [target]'s [target_zone].") + display_results(user, target, "You stuff [tool] into [target]'s [target_zone].", + "[user] stuffs [tool] into [target]'s [target_zone]!", + "[user] stuffs [tool.w_class > WEIGHT_CLASS_SMALL ? tool : "something"] into [target]'s [target_zone].") user.transferItemToLoc(tool, target, TRUE) CH.cavity_item = tool return 1 else if(IC) - user.visible_message("[user] pulls [IC] out of [target]'s [target_zone]!", "You pull [IC] out of [target]'s [target_zone].") + display_results(user, target, "You pull [IC] out of [target]'s [target_zone].", + "[user] pulls [IC] out of [target]'s [target_zone]!", + "[user] pulls [IC.w_class > WEIGHT_CLASS_SMALL ? IC : "something"] out of [target]'s [target_zone].") user.put_in_hands(IC) CH.cavity_item = null return 1 diff --git a/code/modules/surgery/core_removal.dm b/code/modules/surgery/core_removal.dm index 7bf888ab40..3f36a8bb8c 100644 --- a/code/modules/surgery/core_removal.dm +++ b/code/modules/surgery/core_removal.dm @@ -1,28 +1,33 @@ /datum/surgery/core_removal - name = "core removal" + name = "Core removal" steps = list(/datum/surgery_step/incise, /datum/surgery_step/extract_core) - species = list(/mob/living/simple_animal/slime) + target_mobtypes = list(/mob/living/simple_animal/slime) possible_locs = list(BODY_ZONE_R_ARM,BODY_ZONE_L_ARM,BODY_ZONE_R_LEG,BODY_ZONE_L_LEG,BODY_ZONE_CHEST,BODY_ZONE_HEAD) + lying_required = FALSE + ignore_clothes = TRUE /datum/surgery/core_removal/can_start(mob/user, mob/living/target) if(target.stat == DEAD) return 1 return 0 - //extract brain /datum/surgery_step/extract_core name = "extract core" - implements = list(/obj/item/hemostat = 100, TOOL_CROWBAR = 100) + implements = list(TOOL_HEMOSTAT = 100, TOOL_CROWBAR = 100) time = 16 /datum/surgery_step/extract_core/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] begins to extract a core from [target].", "You begin to extract a core from [target]...") + display_results(user, target, "You begin to extract a core from [target]...", + "[user] begins to extract a core from [target].", + "[user] begins to extract a core from [target].") /datum/surgery_step/extract_core/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) var/mob/living/simple_animal/slime/slime = target if(slime.cores > 0) slime.cores-- - user.visible_message("[user] successfully extracts a core from [target]!", "You successfully extract a core from [target]. [slime.cores] core\s remaining.") + display_results(user, target, "You successfully extract a core from [target]. [slime.cores] core\s remaining.", + "[user] successfully extracts a core from [target]!", + "[user] successfully extracts a core from [target]!") new slime.coretype(slime.loc) @@ -33,4 +38,4 @@ return 0 else to_chat(user, "There aren't any cores left in [target]!") - return 1 \ No newline at end of file + return 1 diff --git a/code/modules/surgery/coronary_bypass.dm b/code/modules/surgery/coronary_bypass.dm new file mode 100644 index 0000000000..71a48ae68c --- /dev/null +++ b/code/modules/surgery/coronary_bypass.dm @@ -0,0 +1,77 @@ +/datum/surgery/coronary_bypass + name = "Coronary Bypass" + steps = list(/datum/surgery_step/incise, /datum/surgery_step/retract_skin, /datum/surgery_step/saw, /datum/surgery_step/clamp_bleeders, + /datum/surgery_step/incise_heart, /datum/surgery_step/coronary_bypass, /datum/surgery_step/close) + possible_locs = list(BODY_ZONE_CHEST) + +/datum/surgery/coronary_bypass/can_start(mob/user, mob/living/carbon/target) + var/obj/item/organ/heart/H = target.getorganslot(ORGAN_SLOT_HEART) + if(H) + if(H.damage > 60 && !H.operated) + return TRUE + return FALSE + + +//an incision but with greater bleed, and a 90% base success chance +/datum/surgery_step/incise_heart + name = "incise heart" + implements = list(TOOL_SCALPEL = 90, /obj/item/melee/transforming/energy/sword = 45, /obj/item/kitchen/knife = 45, + /obj/item/shard = 25) + time = 16 + +/datum/surgery_step/incise_heart/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You begin to make an incision in [target]'s heart...", + "[user] begins to make an incision in [target]'s heart.", + "[user] begins to make an incision in [target]'s heart.") + +/datum/surgery_step/incise_heart/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + if(ishuman(target)) + var/mob/living/carbon/human/H = target + if (!(NOBLOOD in H.dna.species.species_traits)) + display_results(user, target, "Blood pools around the incision in [H]'s heart.", + "Blood pools around the incision in [H]'s heart.", + "") + H.bleed_rate += 10 + H.adjustBruteLoss(10) + return TRUE + +/datum/surgery_step/incise_heart/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + if(ishuman(target)) + var/mob/living/carbon/human/H = target + display_results(user, target, "You screw up, cutting too deeply into the heart!", + "[user] screws up, causing blood to spurt out of [H]'s chest!", + "[user] screws up, causing blood to spurt out of [H]'s chest!") + H.bleed_rate += 20 + H.adjustOrganLoss(ORGAN_SLOT_HEART, 10) + H.adjustBruteLoss(10) + +//grafts a coronary bypass onto the individual's heart, success chance is 90% base again +/datum/surgery_step/coronary_bypass + name = "graft coronary bypass" + implements = list(TOOL_HEMOSTAT = 90, TOOL_WIRECUTTER = 35, /obj/item/stack/packageWrap = 15, /obj/item/stack/cable_coil = 5) + time = 90 + +/datum/surgery_step/coronary_bypass/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You begin to graft a bypass onto [target]'s heart...", + "[user] begins to graft something onto [target]'s heart!", + "[user] begins to graft something onto [target]'s heart!") + +/datum/surgery_step/coronary_bypass/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + target.setOrganLoss(ORGAN_SLOT_HEART, 60) + var/obj/item/organ/heart/heart = target.getorganslot(ORGAN_SLOT_HEART) + if(heart) //slightly worrying if we lost our heart mid-operation, but that's life + heart.operated = TRUE + display_results(user, target, "You successfully graft a bypass onto [target]'s heart.", + "[user] finishes grafting something onto [target]'s heart.", + "[user] finishes grafting something onto [target]'s heart.") + return TRUE + +/datum/surgery_step/coronary_bypass/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + if(ishuman(target)) + var/mob/living/carbon/human/H = target + display_results(user, target, "You screw up in attaching the graft, and it tears off, tearing part of the heart!", + "[user] screws up, causing blood to spurt out of [H]'s chest profusely!", + "[user] screws up, causing blood to spurt out of [H]'s chest profusely!") + H.adjustOrganLoss(ORGAN_SLOT_HEART, 20) + H.bleed_rate += 30 + return FALSE diff --git a/code/modules/surgery/embalming.dm b/code/modules/surgery/embalming.dm new file mode 100644 index 0000000000..b07c2b3179 --- /dev/null +++ b/code/modules/surgery/embalming.dm @@ -0,0 +1,30 @@ +/datum/surgery/embalming //Fast and easy way to husk bodys + name = "Embalming" + desc = "A surgical procedure that prevents a corpse from producing miasma." + steps = list(/datum/surgery_step/incise, + /datum/surgery_step/embalming, + /datum/surgery_step/close) + + target_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey) + possible_locs = list(BODY_ZONE_CHEST) + requires_bodypart_type = 0 + +/datum/surgery_step/embalming + name = "embalming body" + implements = list(/obj/item/reagent_containers/syringe = 100, /obj/item/pen = 30) + time = 10 + chems_needed = list("drying_agent", "sterilizine") + require_all_chems = FALSE + +/datum/surgery_step/embalming/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + user.visible_message("[user] starts to embalm [target]'s body.", "You start embalming [target]'s body.") + +/datum/surgery_step/embalming/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + user.visible_message("[user] embalms [target]'s body.", "You succeed in embalming [target]'s body.") + ADD_TRAIT(target, TRAIT_HUSK, MAGIC_TRAIT) //Husk's prevent body smell + return FALSE + +/datum/surgery_step/embalming/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + user.visible_message("[user] screws up!", "You screwed up!") + ADD_TRAIT(target, TRAIT_NOCLONE, MAGIC_TRAIT) //That body is ruined, but still gives miasma + return FALSE diff --git a/code/modules/surgery/experimental_dissection.dm b/code/modules/surgery/experimental_dissection.dm new file mode 100644 index 0000000000..3172496146 --- /dev/null +++ b/code/modules/surgery/experimental_dissection.dm @@ -0,0 +1,113 @@ +#define BASE_HUMAN_REWARD 500 + +/datum/surgery/advanced/experimental_dissection + name = "Dissection" + desc = "A surgical procedure which analyzes the biology of a corpse, and automatically adds new findings to the research database." + steps = list(/datum/surgery_step/incise, + /datum/surgery_step/retract_skin, + /datum/surgery_step/clamp_bleeders, + /datum/surgery_step/dissection, + /datum/surgery_step/clamp_bleeders, + /datum/surgery_step/close) + possible_locs = list(BODY_ZONE_CHEST) + target_mobtypes = list(/mob/living) //Feel free to dissect devils but they're magic. + replaced_by = /datum/surgery/advanced/experimental_dissection/adv + requires_tech = FALSE + var/value_multiplier = 1 + +/datum/surgery/advanced/experimental_dissection/can_start(mob/user, mob/living/target) + . = ..() + if(HAS_TRAIT_FROM(target, TRAIT_DISSECTED,"[name]")) + return FALSE + if(target.stat != DEAD) + return FALSE + +/datum/surgery_step/dissection + name = "dissection" + implements = list(/obj/item/scalpel/augment = 75, /obj/item/scalpel/advanced = 60, /obj/item/scalpel = 45, /obj/item/kitchen/knife = 20, /obj/item/shard = 10)// special tools not only cut down time but also improve probability, doesn't use TOOL_SCALPEL because different scalpels have different probs + time = 125 + silicons_obey_prob = TRUE + repeatable = TRUE + +/datum/surgery_step/dissection/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You start dissecting [target].", + "[user] starts dissecting [target].", + "[user] starts dissecting [target].") + +/datum/surgery_step/dissection/proc/check_value(mob/living/target, datum/surgery/advanced/experimental_dissection/ED) + var/cost = BASE_HUMAN_REWARD + var/multi_surgery_adjust = 0 + + //determine bonus applied + if(isalienroyal(target)) + cost = (BASE_HUMAN_REWARD*10) + else if(isalienadult(target)) + cost = (BASE_HUMAN_REWARD*5) + else if(ismonkey(target)) + cost = (BASE_HUMAN_REWARD*0.5) + else if(ishuman(target)) + var/mob/living/carbon/human/H = target + if(H?.dna?.species) + if(isabductor(H)) + cost = (BASE_HUMAN_REWARD*4) + else if(isgolem(H) || iszombie(H)) + cost = (BASE_HUMAN_REWARD*3) + /*else if(isjellyperson(H) || ispodperson(H)) CITADEL CHANGE: jelly and pod being available roundstart shouldn't give additional points + cost = (BASE_HUMAN_REWARD*2)*/ + else + cost = (BASE_HUMAN_REWARD * 0.6) + + + + //now we do math for surgeries already done (no double dipping!). + for(var/i in typesof(/datum/surgery/advanced/experimental_dissection)) + var/datum/surgery/advanced/experimental_dissection/cringe = i + if(HAS_TRAIT_FROM(target,TRAIT_DISSECTED,"[initial(cringe.name)]")) + multi_surgery_adjust = max(multi_surgery_adjust,initial(cringe.value_multiplier)) - 1 + + multi_surgery_adjust *= cost + + //multiply by multiplier in surgery + cost *= ED.value_multiplier + return (cost-multi_surgery_adjust) + +/datum/surgery_step/dissection/success(mob/user, mob/living/target, target_zone, obj/item/tool, datum/surgery/surgery) + var/points_earned = check_value(target, surgery) + display_results(user, target, "You dissect [target], and add your [points_earned] point\s worth of discoveries to the research database!", + "[user] dissects [target], discovering [points_earned] point\s of data!", + "[user] dissects [target]!") + SSresearch.science_tech.add_point_list(list(TECHWEB_POINT_TYPE_GENERIC = points_earned)) + var/obj/item/bodypart/L = target.get_bodypart(BODY_ZONE_CHEST) + target.apply_damage(80, BRUTE, L) + ADD_TRAIT(target, TRAIT_DISSECTED, "[surgery.name]") + repeatable = FALSE + return TRUE + +/datum/surgery_step/dissection/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You dissect [target], but do not find anything particularly interesting.", + "[user] dissects [target], however it seems [user.p_they()] didn't find anything useful.", + "[user] dissects [target], but looks a little dissapointed.") + SSresearch.science_tech.add_point_list(list(TECHWEB_POINT_TYPE_GENERIC = (round(check_value(target, surgery) * 0.01)))) + var/obj/item/bodypart/L = target.get_bodypart(BODY_ZONE_CHEST) + target.apply_damage(80, BRUTE, L) + return TRUE + +/datum/surgery/advanced/experimental_dissection/adv + name = "Thorough Dissection" + value_multiplier = 2 + replaced_by = /datum/surgery/advanced/experimental_dissection/exp + requires_tech = TRUE + +/datum/surgery/advanced/experimental_dissection/exp + name = "Experimental Dissection" + value_multiplier = 5 + replaced_by = /datum/surgery/advanced/experimental_dissection/alien + requires_tech = TRUE + +/datum/surgery/advanced/experimental_dissection/alien + name = "Extraterrestrial Dissection" + value_multiplier = 10 + requires_tech = TRUE + replaced_by = null + +#undef EXPDIS_FAIL_MSG \ No newline at end of file diff --git a/code/modules/surgery/eye_surgery.dm b/code/modules/surgery/eye_surgery.dm index a8cb881326..f7a06af388 100644 --- a/code/modules/surgery/eye_surgery.dm +++ b/code/modules/surgery/eye_surgery.dm @@ -1,16 +1,14 @@ /datum/surgery/eye_surgery - name = "eye surgery" + name = "Eye surgery" steps = list(/datum/surgery_step/incise, /datum/surgery_step/retract_skin, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/fix_eyes, /datum/surgery_step/close) - species = list(/mob/living/carbon/human, /mob/living/carbon/monkey) + target_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey) possible_locs = list(BODY_ZONE_PRECISE_EYES) requires_bodypart_type = 0 - //fix eyes /datum/surgery_step/fix_eyes name = "fix eyes" - implements = list(/obj/item/hemostat = 100, TOOL_SCREWDRIVER = 45, /obj/item/pen = 25) + implements = list(TOOL_HEMOSTAT = 100, TOOL_SCREWDRIVER = 45, /obj/item/pen = 25) time = 64 - /datum/surgery/eye_surgery/can_start(mob/user, mob/living/carbon/target) var/obj/item/organ/eyes/E = target.getorganslot(ORGAN_SLOT_EYES) if(!E) @@ -19,10 +17,14 @@ return TRUE /datum/surgery_step/fix_eyes/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] begins to fix [target]'s eyes.", "You begin to fix [target]'s eyes...") + display_results(user, target, "You begin to fix [target]'s eyes...", + "[user] begins to fix [target]'s eyes.", + "[user] begins to perform surgery on [target]'s eyes.") /datum/surgery_step/fix_eyes/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] successfully fixes [target]'s eyes!", "You succeed in fixing [target]'s eyes.") + display_results(user, target, "You succeed in fixing [target]'s eyes.", + "[user] successfully fixes [target]'s eyes!", + "[user] completes the surgery on [target]'s eyes.") target.cure_blind(list(EYE_DAMAGE)) target.set_blindness(0) target.cure_nearsighted(list(EYE_DAMAGE)) @@ -32,8 +34,12 @@ /datum/surgery_step/fix_eyes/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) if(target.getorgan(/obj/item/organ/brain)) - user.visible_message("[user] accidentally stabs [target] right in the brain!", "You accidentally stab [target] right in the brain!") - target.adjustBrainLoss(70) + display_results(user, target, "You accidentally stab [target] right in the brain!", + "[user] accidentally stabs [target] right in the brain!", + "[user] accidentally stabs [target] right in the brain!") + target.adjustOrganLoss(ORGAN_SLOT_BRAIN, 70) else - user.visible_message("[user] accidentally stabs [target] right in the brain! Or would have, if [target] had a brain.", "You accidentally stab [target] right in the brain! Or would have, if [target] had a brain.") - return FALSE \ No newline at end of file + display_results(user, target, "You accidentally stab [target] right in the brain! Or would have, if [target] had a brain.", + "[user] accidentally stabs [target] right in the brain! Or would have, if [target] had a brain.", + "[user] accidentally stabs [target] right in the brain!") + return FALSE diff --git a/code/modules/surgery/graft_synthtissue.dm b/code/modules/surgery/graft_synthtissue.dm new file mode 100644 index 0000000000..7540b2cd94 --- /dev/null +++ b/code/modules/surgery/graft_synthtissue.dm @@ -0,0 +1,71 @@ +//Organ reconstruction, limited to the chest region as most organs in the head have their own repair method (eyes/brain). We require synthflesh for these +//steps since fixing internal organs aren't as simple as mending exterior flesh, though in the future it would be neat to add more chems to the viable list. +//TBD: Add heart damage, have heart reconstruction seperate from organ reconstruction, and find a better name for this. I can imagine people getting it confused with manipulation. + +/datum/surgery/graft_synthtissue + name = "Graft synthtissue" + target_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey) + possible_locs = list(BODY_ZONE_CHEST, BODY_ZONE_PRECISE_GROIN, BODY_ZONE_PRECISE_EYES) + steps = list( + /datum/surgery_step/incise, + /datum/surgery_step/retract_skin, + /datum/surgery_step/saw, + /datum/surgery_step/clamp_bleeders, + /datum/surgery_step/incise, + /datum/surgery_step/graft_synthtissue, + /datum/surgery_step/close + ) + +//repair organs +/datum/surgery_step/graft_synthtissue + name = "graft synthtissue" + implements = list(TOOL_HEMOSTAT = 100, TOOL_SCREWDRIVER = 35, /obj/item/pen = 15) + repeatable = TRUE + time = 75 + chems_needed = list("synthtissue") + var/obj/item/organ/chosen_organ + var/health_restored = 10 + +/datum/surgery_step/graft_synthtissue/preop(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool, datum/surgery/surgery) + if(implement_type in implements) + var/list/organs = target.getorganszone(target_zone) + if(!organs.len) + to_chat(user, "There are no targetable organs in [target]'s [parse_zone(target_zone)]!") + return -1 + else + for(var/obj/item/organ/O in organs) + O.on_find(user) + organs -= O + organs[O.name] = O + chosen_organ = input("Target which organ?", "Surgery", null, null) as null|anything in organs + chosen_organ = organs[chosen_organ] + if(!chosen_organ) + return -1 + if(!target.reagents.has_reagent("synthtissue")) + to_chat(user, "There's no synthtissue available for use on [chosen_organ]") + return -1 + var/datum/reagent/synthtissue/Sf = locate(/datum/reagent/synthtissue) in target.reagents.reagent_list + if(Sf.volume < 10) + to_chat(user, "There's not enough synthtissue to perform the operation! There needs to be at least 10u.") + return -1 + + if((chosen_organ.organ_flags & ORGAN_FAILING) && !(Sf.data["grown_volume"] >= 115)) + to_chat(user, "[chosen_organ] is too damaged to graft onto!") + return -1 + + if(health_restored != 10) + health_restored = 10 + health_restored += (Sf.data["grown_volume"]/10) + + user.visible_message("[user] begins to graft synthtissue onto [chosen_organ].") + target.reagents.remove_reagent("synthtissue", 10) + +/datum/surgery_step/graft_synthtissue/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + user.visible_message("[user] successfully grafts synthtissue to [chosen_organ].", "You succeed in grafting 10u of the synthflesh to the [chosen_organ].") + chosen_organ.applyOrganDamage(-health_restored) + return TRUE + +/datum/surgery_step/graft_synthtissue/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + user.visible_message("[user] accidentally damages part of [chosen_organ]!", "You damage [chosen_organ]! Apply more synthtissue if it's run out.") + chosen_organ.applyOrganDamage(10) + return FALSE diff --git a/code/modules/surgery/healing.dm b/code/modules/surgery/healing.dm new file mode 100644 index 0000000000..d20d1d822a --- /dev/null +++ b/code/modules/surgery/healing.dm @@ -0,0 +1,215 @@ +/datum/surgery/healing + steps = list(/datum/surgery_step/incise, + /datum/surgery_step/retract_skin, + /datum/surgery_step/incise, + /datum/surgery_step/clamp_bleeders, + /datum/surgery_step/heal, + /datum/surgery_step/close) + + target_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey) + possible_locs = list(BODY_ZONE_CHEST) + requires_bodypart_type = FALSE + replaced_by = /datum/surgery + ignore_clothes = TRUE + var/healing_step_type + var/antispam = FALSE + +/datum/surgery/healing/New(surgery_target, surgery_location, surgery_bodypart) + ..() + if(healing_step_type) + steps = list(/datum/surgery_step/incise/nobleed, + healing_step_type, //hehe cheeky + /datum/surgery_step/close) + +/datum/surgery_step/heal + name = "repair body" + implements = list(TOOL_HEMOSTAT = 100, TOOL_SCREWDRIVER = 65, /obj/item/pen = 55) + repeatable = TRUE + time = 25 + var/brutehealing = 0 + var/burnhealing = 0 + var/missinghpbonus = 0 //heals an extra point of damager per X missing damage of type (burn damage for burn healing, brute for brute). Smaller Number = More Healing! + +/datum/surgery_step/heal/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + var/woundtype + if(brutehealing && burnhealing) + woundtype = "wounds" + else if(brutehealing) + woundtype = "bruises" + else //why are you trying to 0,0...? + woundtype = "burns" + if(istype(surgery,/datum/surgery/healing)) + var/datum/surgery/healing/the_surgery = surgery + if(!the_surgery.antispam) + display_results(user, target, "You attempt to patch some of [target]'s [woundtype].", + "[user] attempts to patch some of [target]'s [woundtype].", + "[user] attempts to patch some of [target]'s [woundtype].") + +/datum/surgery_step/heal/initiate(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, try_to_fail = FALSE) + if(..()) + while((brutehealing && target.getBruteLoss()) || (burnhealing && target.getFireLoss())) + if(!..()) + break + +/datum/surgery_step/heal/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + var/umsg = "You succeed in fixing some of [target]'s wounds" //no period, add initial space to "addons" + var/tmsg = "[user] fixes some of [target]'s wounds" //see above + var/urhealedamt_brute = brutehealing + var/urhealedamt_burn = burnhealing + if(missinghpbonus) + if(target.stat != DEAD) + urhealedamt_brute += round((target.getBruteLoss()/ missinghpbonus),0.1) + urhealedamt_burn += round((target.getFireLoss()/ missinghpbonus),0.1) + else //less healing bonus for the dead since they're expected to have lots of damage to begin with (to make TW into defib not TOO simple) + urhealedamt_brute += round((target.getBruteLoss()/ (missinghpbonus*5)),0.1) + urhealedamt_burn += round((target.getFireLoss()/ (missinghpbonus*5)),0.1) + if(!get_location_accessible(target, target_zone)) + urhealedamt_brute *= 0.55 + urhealedamt_burn *= 0.55 + umsg += " as best as you can while they have clothing on" + tmsg += " as best as they can while [target] has clothing on" + target.heal_bodypart_damage(urhealedamt_brute,urhealedamt_burn) + display_results(user, target, "[umsg].", + "[tmsg].", + "[tmsg].") + if(istype(surgery, /datum/surgery/healing)) + var/datum/surgery/healing/the_surgery = surgery + the_surgery.antispam = TRUE + return TRUE + +/datum/surgery_step/heal/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You screwed up!", + "[user] screws up!", + "[user] fixes some of [target]'s wounds.", TRUE) + var/urdamageamt_burn = brutehealing * 0.8 + var/urdamageamt_brute = burnhealing * 0.8 + if(missinghpbonus) + urdamageamt_brute += round((target.getBruteLoss()/ (missinghpbonus*2)),0.1) + urdamageamt_burn += round((target.getFireLoss()/ (missinghpbonus*2)),0.1) + + target.take_bodypart_damage(urdamageamt_brute, urdamageamt_burn) + return FALSE + +/***************************BRUTE***************************/ +/datum/surgery/healing/brute + name = "Tend Wounds (Bruises)" + +/datum/surgery/healing/brute/basic + name = "Tend Wounds (Bruises, Basic)" + replaced_by = /datum/surgery/healing/brute/upgraded + healing_step_type = /datum/surgery_step/heal/brute/basic + desc = "A surgical procedure that provides basic treatment for a patient's brute traumas. Heals slightly more when the patient is severely injured." + +/datum/surgery/healing/brute/upgraded + name = "Tend Wounds (Bruises, Adv.)" + replaced_by = /datum/surgery/healing/brute/upgraded/femto + requires_tech = TRUE + healing_step_type = /datum/surgery_step/heal/brute/upgraded + desc = "A surgical procedure that provides advanced treatment for a patient's brute traumas. Heals more when the patient is severely injured." + +/datum/surgery/healing/brute/upgraded/femto + name = "Tend Wounds (Bruises, Exp.)" + replaced_by = /datum/surgery/healing/combo/upgraded/femto + requires_tech = TRUE + healing_step_type = /datum/surgery_step/heal/brute/upgraded/femto + desc = "A surgical procedure that provides experimental treatment for a patient's brute traumas. Heals considerably more when the patient is severely injured." + +/********************BRUTE STEPS********************/ +/datum/surgery_step/heal/brute/basic + name = "tend bruises" + brutehealing = 5 + missinghpbonus = 15 + +/datum/surgery_step/heal/brute/upgraded + brutehealing = 5 + missinghpbonus = 10 + +/datum/surgery_step/heal/brute/upgraded/femto + brutehealing = 5 + missinghpbonus = 5 + +/***************************BURN***************************/ +/datum/surgery/healing/burn + name = "Tend Wounds (Burn)" + +/datum/surgery/healing/burn/basic + name = "Tend Wounds (Burn, Basic)" + replaced_by = /datum/surgery/healing/burn/upgraded + healing_step_type = /datum/surgery_step/heal/burn/basic + desc = "A surgical procedure that provides basic treatment for a patient's burns. Heals slightly more when the patient is severely injured." + +/datum/surgery/healing/burn/upgraded + name = "Tend Wounds (Burn, Adv.)" + replaced_by = /datum/surgery/healing/burn/upgraded/femto + requires_tech = TRUE + healing_step_type = /datum/surgery_step/heal/burn/upgraded + desc = "A surgical procedure that provides advanced treatment for a patient's burns. Heals more when the patient is severely injured." + +/datum/surgery/healing/burn/upgraded/femto + name = "Tend Wounds (Burn, Exp.)" + replaced_by = /datum/surgery/healing/combo/upgraded/femto + requires_tech = TRUE + healing_step_type = /datum/surgery_step/heal/burn/upgraded/femto + desc = "A surgical procedure that provides experimental treatment for a patient's burns. Heals considerably more when the patient is severely injured." + +/********************BURN STEPS********************/ +/datum/surgery_step/heal/burn/basic + name = "tend burn wounds" + burnhealing = 5 + missinghpbonus = 15 + +/datum/surgery_step/heal/burn/upgraded + burnhealing = 5 + missinghpbonus = 10 + +/datum/surgery_step/heal/burn/upgraded/femto + burnhealing = 5 + missinghpbonus = 5 + +/***************************COMBO***************************/ +/datum/surgery/healing/combo + + +/datum/surgery/healing/combo + name = "Tend Wounds (Mixture, Basic)" + replaced_by = /datum/surgery/healing/combo/upgraded + requires_tech = TRUE + healing_step_type = /datum/surgery_step/heal/combo + desc = "A surgical procedure that provides basic treatment for a patient's burns and brute traumas. Heals slightly more when the patient is severely injured." + +/datum/surgery/healing/combo/upgraded + name = "Tend Wounds (Mixture, Adv.)" + replaced_by = /datum/surgery/healing/combo/upgraded/femto + healing_step_type = /datum/surgery_step/heal/combo/upgraded + desc = "A surgical procedure that provides advanced treatment for a patient's burns and brute traumas. Heals more when the patient is severely injured." + + +/datum/surgery/healing/combo/upgraded/femto //no real reason to type it like this except consistency, don't worry you're not missing anything + name = "Tend Wounds (Mixture, Exp.)" + replaced_by = null + healing_step_type = /datum/surgery_step/heal/combo/upgraded/femto + desc = "A surgical procedure that provides experimental treatment for a patient's burns and brute traumas. Heals considerably more when the patient is severely injured." + +/********************COMBO STEPS********************/ +/datum/surgery_step/heal/combo + name = "tend physical wounds" + brutehealing = 3 + burnhealing = 3 + missinghpbonus = 15 + time = 10 + +/datum/surgery_step/heal/combo/upgraded + brutehealing = 3 + burnhealing = 3 + missinghpbonus = 10 + +/datum/surgery_step/heal/combo/upgraded/femto + brutehealing = 1 + burnhealing = 1 + missinghpbonus = 2.5 + +/datum/surgery_step/heal/combo/upgraded/femto/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You screwed up!", + "[user] screws up!", + "[user] fixes some of [target]'s wounds.", TRUE) + target.take_bodypart_damage(5,5) \ No newline at end of file diff --git a/code/modules/surgery/helpers.dm b/code/modules/surgery/helpers.dm index 1eca915d70..f52bf97147 100644 --- a/code/modules/surgery/helpers.dm +++ b/code/modules/surgery/helpers.dm @@ -10,9 +10,6 @@ C = M affecting = C.get_bodypart(check_zone(selected_zone)) - if(!M.lying && !isslime(M)) //if they're prone or a slime - return - var/datum/surgery/current_surgery for(var/datum/surgery/S in M.surgeries) @@ -35,13 +32,18 @@ continue else if(C && S.requires_bodypart) //mob with no limb in surgery zone when we need a limb continue + if(S.lying_required && !(M.lying)) + continue if(!S.can_start(user, M)) continue - for(var/path in S.species) + for(var/path in S.target_mobtypes) if(istype(M, path)) available_surgeries[S.name] = S break + if(!available_surgeries.len) + return + var/P = input("Begin which procedure?", "Surgery", null, null) as null|anything in available_surgeries if(P && user && user.Adjacent(M) && (I in user)) var/datum/surgery/S = available_surgeries[P] @@ -60,12 +62,14 @@ return else if(C && S.requires_bodypart) return + if(S.lying_required && !(M.lying)) + return if(!S.can_start(user, M)) return if(S.ignore_clothes || get_location_accessible(M, selected_zone)) var/datum/surgery/procedure = new S.type(M, selected_zone, affecting) - user.visible_message("[user] drapes [I] over [M]'s [parse_zone(selected_zone)] to prepare for \an [procedure.name].", \ + user.visible_message("[user] drapes [I] over [M]'s [parse_zone(selected_zone)] to prepare for surgery.", \ "You drape [I] over [M]'s [parse_zone(selected_zone)] to prepare for \an [procedure.name].") log_combat(user, M, "operated on", null, "(OPERATION TYPE: [procedure.name]) (TARGET AREA: [selected_zone])") @@ -110,15 +114,22 @@ return 0.5 -/proc/get_location_accessible(mob/living/M, location) +/proc/get_location_accessible(mob/M, location) var/covered_locations = 0 //based on body_parts_covered var/face_covered = 0 //based on flags_inv var/eyesmouth_covered = 0 //based on flags_cover - for(var/A in M.get_equipped_items()) - var/obj/item/I = A - covered_locations |= I.body_parts_covered - face_covered |= I.flags_inv - eyesmouth_covered |= I.flags_cover + if(iscarbon(M)) + var/mob/living/carbon/C = M + for(var/obj/item/clothing/I in list(C.back, C.wear_mask, C.head)) + covered_locations |= I.body_parts_covered + face_covered |= I.flags_inv + eyesmouth_covered |= I.flags_cover + if(ishuman(C)) + var/mob/living/carbon/human/H = C + for(var/obj/item/I in list(H.wear_suit, H.w_uniform, H.shoes, H.belt, H.gloves, H.glasses, H.ears)) + covered_locations |= I.body_parts_covered + face_covered |= I.flags_inv + eyesmouth_covered |= I.flags_cover switch(location) if(BODY_ZONE_HEAD) @@ -162,4 +173,3 @@ return 0 return 1 - diff --git a/code/modules/surgery/implant_removal.dm b/code/modules/surgery/implant_removal.dm index 92c5e05246..3eb05c91c7 100644 --- a/code/modules/surgery/implant_removal.dm +++ b/code/modules/surgery/implant_removal.dm @@ -1,29 +1,32 @@ /datum/surgery/implant_removal name = "implant removal" steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/extract_implant, /datum/surgery_step/close) - species = list(/mob/living/carbon/human, /mob/living/carbon/monkey) + target_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey) possible_locs = list(BODY_ZONE_CHEST) - - //extract implant /datum/surgery_step/extract_implant name = "extract implant" - implements = list(/obj/item/hemostat = 100, TOOL_CROWBAR = 65) + implements = list(TOOL_HEMOSTAT = 100, TOOL_CROWBAR = 65) time = 64 var/obj/item/implant/I = null - /datum/surgery_step/extract_implant/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) for(var/obj/item/O in target.implants) I = O break if(I) - user.visible_message("[user] begins to extract [I] from [target]'s [target_zone].", "You begin to extract [I] from [target]'s [target_zone]...") + display_results(user, target, "You begin to extract [I] from [target]'s [target_zone]...", + "[user] begins to extract [I] from [target]'s [target_zone].", + "[user] begins to extract something from [target]'s [target_zone].") else - user.visible_message("[user] looks for an implant in [target]'s [target_zone].", "You look for an implant in [target]'s [target_zone]...") + display_results(user, target, "You look for an implant in [target]'s [target_zone]...", + "[user] looks for an implant in [target]'s [target_zone].", + "[user] looks for something in [target]'s [target_zone].") /datum/surgery_step/extract_implant/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) if(I) - user.visible_message("[user] successfully removes [I] from [target]'s [target_zone]!", "You successfully remove [I] from [target]'s [target_zone].") + display_results(user, target, "You successfully remove [I] from [target]'s [target_zone].", + "[user] successfully removes [I] from [target]'s [target_zone]!", + "[user] successfully removes something from [target]'s [target_zone]!") I.removed(target) var/obj/item/implantcase/case @@ -36,14 +39,15 @@ case.imp = I I.forceMove(case) case.update_icon() - user.visible_message("[user] places [I] into [case]!", "You place [I] into [case].") + display_results(user, target, "You place [I] into [case].", + "[user] places [I] into [case]!", + "[user] places it into [case]!") else qdel(I) else to_chat(user, "You can't find anything in [target]'s [target_zone]!") return 1 - /datum/surgery/implant_removal/mechanic name = "implant removal" requires_bodypart_type = BODYPART_ROBOTIC @@ -53,4 +57,4 @@ /datum/surgery_step/mechanic_unwrench, /datum/surgery_step/extract_implant, /datum/surgery_step/mechanic_wrench, - /datum/surgery_step/mechanic_close) \ No newline at end of file + /datum/surgery_step/mechanic_close) diff --git a/code/modules/surgery/limb_augmentation.dm b/code/modules/surgery/limb_augmentation.dm index 46fe262189..b1d8990b48 100644 --- a/code/modules/surgery/limb_augmentation.dm +++ b/code/modules/surgery/limb_augmentation.dm @@ -1,26 +1,21 @@ - /////AUGMENTATION SURGERIES////// - - //SURGERY STEPS - /datum/surgery_step/replace name = "sever muscles" - implements = list(/obj/item/scalpel = 100, TOOL_WIRECUTTER = 55) + implements = list(TOOL_SCALPEL = 100, TOOL_WIRECUTTER = 55) time = 32 /datum/surgery_step/replace/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] begins to sever the muscles on [target]'s [parse_zone(user.zone_selected)].", "You begin to sever the muscles on [target]'s [parse_zone(user.zone_selected)]...") - + display_results(user, target, "You begin to sever the muscles on [target]'s [parse_zone(user.zone_selected)]...", + "[user] begins to sever the muscles on [target]'s [parse_zone(user.zone_selected)].", + "[user] begins an incision on [target]'s [parse_zone(user.zone_selected)].") /datum/surgery_step/replace_limb name = "replace limb" implements = list(/obj/item/bodypart = 100, /obj/item/organ_storage = 100) time = 32 var/obj/item/bodypart/L = null // L because "limb" - - /datum/surgery_step/replace_limb/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) if(istype(tool, /obj/item/organ_storage) && istype(tool.contents[1], /obj/item/bodypart)) tool = tool.contents[1] @@ -33,22 +28,20 @@ return -1 L = surgery.operated_bodypart if(L) - user.visible_message("[user] begins to augment [target]'s [parse_zone(user.zone_selected)].", "You begin to augment [target]'s [parse_zone(user.zone_selected)]...") + display_results(user, target, "You begin to augment [target]'s [parse_zone(user.zone_selected)]...", + "[user] begins to augment [target]'s [parse_zone(user.zone_selected)] with [aug].", + "[user] begins to augment [target]'s [parse_zone(user.zone_selected)].") else user.visible_message("[user] looks for [target]'s [parse_zone(user.zone_selected)].", "You look for [target]'s [parse_zone(user.zone_selected)]...") - //ACTUAL SURGERIES - /datum/surgery/augmentation - name = "augmentation" + name = "Augmentation" steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/replace, /datum/surgery_step/saw, /datum/surgery_step/replace_limb) - species = list(/mob/living/carbon/human) + target_mobtypes = list(/mob/living/carbon/human) possible_locs = list(BODY_ZONE_R_ARM,BODY_ZONE_L_ARM,BODY_ZONE_R_LEG,BODY_ZONE_L_LEG,BODY_ZONE_CHEST,BODY_ZONE_HEAD) requires_real_bodypart = TRUE - //SURGERY STEP SUCCESSES - /datum/surgery_step/replace_limb/success(mob/user, mob/living/carbon/target, target_zone, obj/item/bodypart/tool, datum/surgery/surgery) if(L) if(istype(tool, /obj/item/organ_storage)) @@ -58,7 +51,9 @@ tool = tool.contents[1] if(istype(tool) && user.temporarilyRemoveItemFromInventory(tool)) tool.replace_limb(target, TRUE) - user.visible_message("[user] successfully augments [target]'s [parse_zone(target_zone)]!", "You successfully augment [target]'s [parse_zone(target_zone)].") + display_results(user, target, "You successfully augment [target]'s [parse_zone(target_zone)].", + "[user] successfully augments [target]'s [parse_zone(target_zone)] with [tool]!", + "[user] successfully augments [target]'s [parse_zone(target_zone)]!") log_combat(user, target, "augmented", addition="by giving him new [parse_zone(target_zone)] INTENT: [uppertext(user.a_intent)]") else to_chat(user, "[target] has no organic [parse_zone(target_zone)] there!") diff --git a/code/modules/surgery/lipoplasty.dm b/code/modules/surgery/lipoplasty.dm index 9967eba663..b28b439f9f 100644 --- a/code/modules/surgery/lipoplasty.dm +++ b/code/modules/surgery/lipoplasty.dm @@ -1,53 +1,56 @@ /datum/surgery/lipoplasty - name = "lipoplasty" + name = "Lipoplasty" steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/cut_fat, /datum/surgery_step/remove_fat, /datum/surgery_step/close) possible_locs = list(BODY_ZONE_CHEST) - /datum/surgery/lipoplasty/can_start(mob/user, mob/living/carbon/target) if(HAS_TRAIT(target, TRAIT_FAT)) return 1 return 0 - - //cut fat /datum/surgery_step/cut_fat name = "cut excess fat" - implements = list(/obj/item/circular_saw = 100, /obj/item/melee/transforming/energy/sword/cyborg/saw = 100, /obj/item/hatchet = 35, /obj/item/kitchen/knife/butcher = 25) + implements = list(TOOL_SAW = 100, /obj/item/hatchet = 35, /obj/item/kitchen/knife/butcher = 25) //why we need a saw to cut adipose tissue is beyond me, shit's soft as fuck time = 64 /datum/surgery_step/cut_fat/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] begins to cut away [target]'s excess fat.", "You begin to cut away [target]'s excess fat...") + display_results(user, target, "You begin to cut away [target]'s excess fat...", + "[user] begins to cut away [target]'s excess fat.", + "[user] begins to cut [target]'s [target_zone] with [tool].") /datum/surgery_step/cut_fat/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] cuts [target]'s excess fat loose!", "You cut [target]'s excess fat loose.") + display_results(user, target, "You cut [target]'s excess fat loose.", + "[user] cuts [target]'s excess fat loose!", + "[user] finishes the cut on [target]'s [target_zone].") return 1 //remove fat /datum/surgery_step/remove_fat name = "remove loose fat" - implements = list(/obj/item/retractor = 100, TOOL_SCREWDRIVER = 45, TOOL_WIRECUTTER = 35) + implements = list(TOOL_RETRACTOR = 100, TOOL_SCREWDRIVER = 45, TOOL_WIRECUTTER = 35) time = 32 /datum/surgery_step/remove_fat/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] begins to extract [target]'s loose fat!", "You begin to extract [target]'s loose fat...") + display_results(user, target, "You begin to extract [target]'s loose fat...", + "[user] begins to extract [target]'s loose fat!", + "[user] begins to extract something from [target]'s [target_zone].") /datum/surgery_step/remove_fat/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] extracts [target]'s fat!", "You extract [target]'s fat.") + display_results(user, target, "You extract [target]'s fat.", + "[user] extracts [target]'s fat!", + "[user] extracts [target]'s fat!") target.overeatduration = 0 //patient is unfatted var/removednutriment = target.nutrition target.nutrition = NUTRITION_LEVEL_WELL_FED removednutriment -= 450 //whatever was removed goes into the meat var/mob/living/carbon/human/H = target var/typeofmeat = /obj/item/reagent_containers/food/snacks/meat/slab/human - if(H.dna && H.dna.species) typeofmeat = H.dna.species.meat - var/obj/item/reagent_containers/food/snacks/meat/slab/human/newmeat = new typeofmeat newmeat.name = "fatty meat" newmeat.desc = "Extremely fatty tissue taken from a patient." newmeat.subjectname = H.real_name newmeat.subjectjob = H.job - newmeat.reagents.add_reagent ("nutriment", (removednutriment / 15)) //To balance with nutriment_factor of nutriment + newmeat.reagents.add_reagent (/datum/reagent/consumable/nutriment, (removednutriment / 15)) //To balance with nutriment_factor of nutriment newmeat.forceMove(target.loc) - return 1 \ No newline at end of file + return 1 diff --git a/code/modules/surgery/lobectomy.dm b/code/modules/surgery/lobectomy.dm new file mode 100644 index 0000000000..297be175a0 --- /dev/null +++ b/code/modules/surgery/lobectomy.dm @@ -0,0 +1,46 @@ +/datum/surgery/lobectomy + name = "Lobectomy" //not to be confused with lobotomy + steps = list(/datum/surgery_step/incise, /datum/surgery_step/retract_skin, /datum/surgery_step/saw, /datum/surgery_step/clamp_bleeders, + /datum/surgery_step/lobectomy, /datum/surgery_step/close) + possible_locs = list(BODY_ZONE_CHEST) + +/datum/surgery/lobectomy/can_start(mob/user, mob/living/carbon/target) + var/obj/item/organ/lungs/L = target.getorganslot(ORGAN_SLOT_LUNGS) + if(L) + if(L.damage > 60 && !L.operated) + return TRUE + return FALSE + + +//lobectomy, removes the most damaged lung lobe with a 95% base success chance +/datum/surgery_step/lobectomy + name = "excise damaged lung node" + implements = list(TOOL_SCALPEL = 95, /obj/item/melee/transforming/energy/sword = 65, /obj/item/kitchen/knife = 45, + /obj/item/shard = 35) + time = 42 + +/datum/surgery_step/lobectomy/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You begin to make an incision in [target]'s lungs...", + "[user] begins to make an incision in [target].", + "[user] begins to make an incision in [target].") + +/datum/surgery_step/lobectomy/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + if(ishuman(target)) + var/mob/living/carbon/human/H = target + var/obj/item/organ/lungs/L = H.getorganslot(ORGAN_SLOT_LUNGS) + L.operated = TRUE + H.setOrganLoss(ORGAN_SLOT_LUNGS, 60) + display_results(user, target, "You successfully excise [H]'s most damaged lobe.", + "Successfully removes a piece of [H]'s lungs.", + "") + return TRUE + +/datum/surgery_step/lobectomy/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + if(ishuman(target)) + var/mob/living/carbon/human/H = target + display_results(user, target, "You screw up, failing to excise [H]'s damaged lobe!", + "[user] screws up!", + "[user] screws up!") + H.losebreath += 4 + H.adjustOrganLoss(ORGAN_SLOT_LUNGS, 10) + return FALSE \ No newline at end of file diff --git a/code/modules/surgery/mechanic_steps.dm b/code/modules/surgery/mechanic_steps.dm index 6431770fa9..23f9c167a0 100644 --- a/code/modules/surgery/mechanic_steps.dm +++ b/code/modules/surgery/mechanic_steps.dm @@ -3,76 +3,77 @@ name = "unscrew shell" implements = list( TOOL_SCREWDRIVER = 100, - /obj/item/scalpel = 75, // med borgs could try to unskrew shell with scalpel + TOOL_SCALPEL = 75, // med borgs could try to unskrew shell with scalpel /obj/item/kitchen/knife = 50, /obj/item = 10) // 10% success with any sharp item. time = 24 /datum/surgery_step/mechanic_open/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] begins to unscrew the shell of [target]'s [parse_zone(target_zone)].", - "You begin to unscrew the shell of [target]'s [parse_zone(target_zone)]...") + display_results(user, target, "You begin to unscrew the shell of [target]'s [parse_zone(target_zone)]...", + "[user] begins to unscrew the shell of [target]'s [parse_zone(target_zone)].", + "[user] begins to unscrew the shell of [target]'s [parse_zone(target_zone)].") /datum/surgery_step/mechanic_incise/tool_check(mob/user, obj/item/tool) if(implement_type == /obj/item && !tool.is_sharp()) return FALSE - return TRUE - //close shell /datum/surgery_step/mechanic_close name = "screw shell" implements = list( TOOL_SCREWDRIVER = 100, - /obj/item/scalpel = 75, + TOOL_SCALPELl = 75, /obj/item/kitchen/knife = 50, /obj/item = 10) // 10% success with any sharp item. time = 24 /datum/surgery_step/mechanic_close/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] begins to screw the shell of [target]'s [parse_zone(target_zone)].", - "You begin to screw the shell of [target]'s [parse_zone(target_zone)]...") + display_results(user, target, "You begin to screw the shell of [target]'s [parse_zone(target_zone)]...", + "[user] begins to screw the shell of [target]'s [parse_zone(target_zone)].", + "[user] begins to screw the shell of [target]'s [parse_zone(target_zone)].") /datum/surgery_step/mechanic_close/tool_check(mob/user, obj/item/tool) if(implement_type == /obj/item && !tool.is_sharp()) return FALSE - return TRUE - //prepare electronics /datum/surgery_step/prepare_electronics name = "prepare electronics" implements = list( TOOL_MULTITOOL = 100, - /obj/item/hemostat = 10) // try to reboot internal controllers via short circuit with some conductor + TOOL_HEMOSTAT = 10) // try to reboot internal controllers via short circuit with some conductor time = 24 /datum/surgery_step/prepare_electronics/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] begins to prepare electronics in [target]'s [parse_zone(target_zone)].", - "You begin to prepare electronics in [target]'s [parse_zone(target_zone)]...") + display_results(user, target, "You begin to prepare electronics in [target]'s [parse_zone(target_zone)]...", + "[user] begins to prepare electronics in [target]'s [parse_zone(target_zone)].", + "[user] begins to prepare electronics in [target]'s [parse_zone(target_zone)].") //unwrench /datum/surgery_step/mechanic_unwrench name = "unwrench bolts" implements = list( TOOL_WRENCH = 100, - /obj/item/retractor = 10) + TOOL_RETRACTOR = 10) time = 24 /datum/surgery_step/mechanic_unwrench/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] begins to unwrench some bolts in [target]'s [parse_zone(target_zone)].", - "You begin to unwrench some bolts in [target]'s [parse_zone(target_zone)]...") + display_results(user, target, "You begin to unwrench some bolts in [target]'s [parse_zone(target_zone)]...", + "[user] begins to unwrench some bolts in [target]'s [parse_zone(target_zone)].", + "[user] begins to unwrench some bolts in [target]'s [parse_zone(target_zone)].") //wrench /datum/surgery_step/mechanic_wrench name = "wrench bolts" implements = list( TOOL_WRENCH = 100, - /obj/item/retractor = 10) + TOOL_RETRACTOR = 10) time = 24 /datum/surgery_step/mechanic_wrench/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] begins to wrench some bolts in [target]'s [parse_zone(target_zone)].", - "You begin to wrench some bolts in [target]'s [parse_zone(target_zone)]...") + display_results(user, target, "You begin to wrench some bolts in [target]'s [parse_zone(target_zone)]...", + "[user] begins to wrench some bolts in [target]'s [parse_zone(target_zone)].", + "[user] begins to wrench some bolts in [target]'s [parse_zone(target_zone)].") //open hatch /datum/surgery_step/open_hatch @@ -81,5 +82,6 @@ time = 10 /datum/surgery_step/open_hatch/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] begins to open the hatch holders in [target]'s [parse_zone(target_zone)].", - "You begin to open the hatch holders in [target]'s [parse_zone(target_zone)]...") \ No newline at end of file + display_results(user, target, "You begin to open the hatch holders in [target]'s [parse_zone(target_zone)]...", + "[user] begins to open the hatch holders in [target]'s [parse_zone(target_zone)].", + "[user] begins to open the hatch holders in [target]'s [parse_zone(target_zone)].") diff --git a/code/modules/surgery/organ_manipulation.dm b/code/modules/surgery/organ_manipulation.dm index 553de45c60..699b3f7f24 100644 --- a/code/modules/surgery/organ_manipulation.dm +++ b/code/modules/surgery/organ_manipulation.dm @@ -1,6 +1,6 @@ /datum/surgery/organ_manipulation name = "organ manipulation" - species = list(/mob/living/carbon/human, /mob/living/carbon/monkey) + target_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey) possible_locs = list(BODY_ZONE_CHEST, BODY_ZONE_HEAD) requires_real_bodypart = 1 steps = list( @@ -13,7 +13,6 @@ //there should be bone fixing /datum/surgery_step/close ) - /datum/surgery/organ_manipulation/soft possible_locs = list(BODY_ZONE_PRECISE_GROIN, BODY_ZONE_PRECISE_EYES, BODY_ZONE_PRECISE_MOUTH, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM) steps = list( @@ -24,11 +23,10 @@ /datum/surgery_step/manipulate_organs, /datum/surgery_step/close ) - /datum/surgery/organ_manipulation/alien - name = "alien organ manipulation" + name = "Alien organ manipulation" possible_locs = list(BODY_ZONE_CHEST, BODY_ZONE_HEAD, BODY_ZONE_PRECISE_GROIN, BODY_ZONE_PRECISE_EYES, BODY_ZONE_PRECISE_MOUTH, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM) - species = list(/mob/living/carbon/alien/humanoid) + target_mobtypes = list(/mob/living/carbon/alien/humanoid) steps = list( /datum/surgery_step/saw, /datum/surgery_step/incise, @@ -37,9 +35,8 @@ /datum/surgery_step/manipulate_organs, /datum/surgery_step/close ) - /datum/surgery/organ_manipulation/mechanic - name = "prosthesis organ manipulation" + name = "Prosthesis organ manipulation" possible_locs = list(BODY_ZONE_CHEST, BODY_ZONE_HEAD) requires_bodypart_type = BODYPART_ROBOTIC steps = list( @@ -51,7 +48,6 @@ /datum/surgery_step/mechanic_wrench, /datum/surgery_step/mechanic_close ) - /datum/surgery/organ_manipulation/mechanic/soft possible_locs = list(BODY_ZONE_PRECISE_GROIN, BODY_ZONE_PRECISE_EYES, BODY_ZONE_PRECISE_MOUTH, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM) steps = list( @@ -61,20 +57,17 @@ /datum/surgery_step/manipulate_organs, /datum/surgery_step/mechanic_close ) - /datum/surgery_step/manipulate_organs time = 64 name = "manipulate organs" repeatable = 1 implements = list(/obj/item/organ = 100, /obj/item/reagent_containers/food/snacks/organ = 0, /obj/item/organ_storage = 100) - var/implements_extract = list(/obj/item/hemostat = 100, TOOL_CROWBAR = 55) + var/implements_extract = list(TOOL_HEMOSTAT = 100, TOOL_CROWBAR = 55) var/current_type var/obj/item/organ/I = null - /datum/surgery_step/manipulate_organs/New() ..() implements = implements + implements_extract - /datum/surgery_step/manipulate_organs/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) I = null if(istype(tool, /obj/item/organ_storage)) @@ -92,9 +85,9 @@ if(target_zone != I.zone || target.getorganslot(I.slot)) to_chat(user, "There is no room for [I] in [target]'s [parse_zone(target_zone)]!") return -1 - - user.visible_message("[user] begins to insert [tool] into [target]'s [parse_zone(target_zone)].", - "You begin to insert [tool] into [target]'s [parse_zone(target_zone)]...") + display_results(user, target, "You begin to insert [tool] into [target]'s [parse_zone(target_zone)]...", + "[user] begins to insert [tool] into [target]'s [parse_zone(target_zone)].", + "[user] begins to insert something into [target]'s [parse_zone(target_zone)].") else if(implement_type in implements_extract) current_type = "extract" @@ -107,21 +100,20 @@ O.on_find(user) organs -= O organs[O.name] = O - I = input("Remove which organ?", "Surgery", null, null) as null|anything in organs if(I && user && target && user.Adjacent(target) && user.get_active_held_item() == tool) I = organs[I] if(!I) return -1 - user.visible_message("[user] begins to extract [I] from [target]'s [parse_zone(target_zone)].", - "You begin to extract [I] from [target]'s [parse_zone(target_zone)]...") + display_results(user, target, "You begin to extract [I] from [target]'s [parse_zone(target_zone)]...", + "[user] begins to extract [I] from [target]'s [parse_zone(target_zone)].", + "[user] begins to extract something from [target]'s [parse_zone(target_zone)].") else return -1 else if(istype(tool, /obj/item/reagent_containers/food/snacks/organ)) to_chat(user, "[tool] was bitten by someone! It's too damaged to use!") return -1 - /datum/surgery_step/manipulate_organs/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) if(current_type == "insert") if(istype(tool, /obj/item/organ_storage)) @@ -134,17 +126,20 @@ I = tool user.temporarilyRemoveItemFromInventory(I, TRUE) I.Insert(target) - user.visible_message("[user] inserts [tool] into [target]'s [parse_zone(target_zone)]!", - "You insert [tool] into [target]'s [parse_zone(target_zone)].") + display_results(user, target, "You insert [tool] into [target]'s [parse_zone(target_zone)].", + "[user] inserts [tool] into [target]'s [parse_zone(target_zone)]!", + "[user] inserts something into [target]'s [parse_zone(target_zone)]!") else if(current_type == "extract") if(I && I.owner == target) - user.visible_message("[user] successfully extracts [I] from [target]'s [parse_zone(target_zone)]!", - "You successfully extract [I] from [target]'s [parse_zone(target_zone)].") + display_results(user, target, "You successfully extract [I] from [target]'s [parse_zone(target_zone)].", + "[user] successfully extracts [I] from [target]'s [parse_zone(target_zone)]!", + "[user] successfully extracts something from [target]'s [parse_zone(target_zone)]!") log_combat(user, target, "surgically removed [I.name] from", addition="INTENT: [uppertext(user.a_intent)]") I.Remove(target) I.forceMove(get_turf(target)) else - user.visible_message("[user] can't seem to extract anything from [target]'s [parse_zone(target_zone)]!", - "You can't extract anything from [target]'s [parse_zone(target_zone)]!") + display_results(user, target, "You can't extract anything from [target]'s [parse_zone(target_zone)]!", + "[user] can't seem to extract anything from [target]'s [parse_zone(target_zone)]!", + "[user] can't seem to extract anything from [target]'s [parse_zone(target_zone)]!") return 0 diff --git a/code/modules/surgery/organic_steps.dm b/code/modules/surgery/organic_steps.dm index 01eb751f39..392244fb4b 100644 --- a/code/modules/surgery/organic_steps.dm +++ b/code/modules/surgery/organic_steps.dm @@ -1,102 +1,124 @@ - //make incision /datum/surgery_step/incise name = "make incision" - implements = list(/obj/item/scalpel = 100, /obj/item/melee/transforming/energy/sword = 75, /obj/item/kitchen/knife = 65, + implements = list(TOOL_SCALPEL = 100, /obj/item/melee/transforming/energy/sword = 75, /obj/item/kitchen/knife = 65, /obj/item/shard = 45, /obj/item = 30) // 30% success with any sharp item. time = 16 /datum/surgery_step/incise/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] begins to make an incision in [target]'s [parse_zone(target_zone)].", - "You begin to make an incision in [target]'s [parse_zone(target_zone)]...") + display_results(user, target, "You begin to make an incision in [target]'s [parse_zone(target_zone)]...", + "[user] begins to make an incision in [target]'s [parse_zone(target_zone)].", + "[user] begins to make an incision in [target]'s [parse_zone(target_zone)].") /datum/surgery_step/incise/tool_check(mob/user, obj/item/tool) if(implement_type == /obj/item && !tool.is_sharp()) return FALSE + return TRUE +/datum/surgery_step/incise/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + if ishuman(target) + var/mob/living/carbon/human/H = target + if (!(NOBLOOD in H.dna.species.species_traits)) + display_results(user, target, "Blood pools around the incision in [H]'s [parse_zone(target_zone)].", + "Blood pools around the incision in [H]'s [parse_zone(target_zone)].", + "") + H.bleed_rate += 3 + return TRUE +/datum/surgery_step/incise/nobleed //silly friendly! + +/datum/surgery_step/incise/nobleed/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You begin to carefully make an incision in [target]'s [parse_zone(target_zone)]...", + "[user] begins to carefully make an incision in [target]'s [parse_zone(target_zone)].", + "[user] begins to carefully make an incision in [target]'s [parse_zone(target_zone)].") + +/datum/surgery_step/incise/nobleed/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) return TRUE //clamp bleeders /datum/surgery_step/clamp_bleeders name = "clamp bleeders" - implements = list(/obj/item/hemostat = 100, TOOL_WIRECUTTER = 60, /obj/item/stack/packageWrap = 35, /obj/item/stack/cable_coil = 15) + implements = list(TOOL_HEMOSTAT = 100, TOOL_WIRECUTTER = 60, /obj/item/stack/packageWrap = 35, /obj/item/stack/cable_coil = 15) time = 24 /datum/surgery_step/clamp_bleeders/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] begins to clamp bleeders in [target]'s [parse_zone(target_zone)].", - "You begin to clamp bleeders in [target]'s [parse_zone(target_zone)]...") + display_results(user, target, "You begin to clamp bleeders in [target]'s [parse_zone(target_zone)]...", + "[user] begins to clamp bleeders in [target]'s [parse_zone(target_zone)].", + "[user] begins to clamp bleeders in [target]'s [parse_zone(target_zone)].") /datum/surgery_step/clamp_bleeders/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) if(locate(/datum/surgery_step/saw) in surgery.steps) target.heal_bodypart_damage(20,0) + if (ishuman(target)) + var/mob/living/carbon/human/H = target + H.bleed_rate = max( (H.bleed_rate - 3), 0) return ..() - - //retract skin /datum/surgery_step/retract_skin name = "retract skin" - implements = list(/obj/item/retractor = 100, TOOL_SCREWDRIVER = 45, TOOL_WIRECUTTER = 35) + implements = list(TOOL_RETRACTOR = 100, TOOL_SCREWDRIVER = 45, TOOL_WIRECUTTER = 35) time = 24 /datum/surgery_step/retract_skin/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] begins to retract the skin in [target]'s [parse_zone(target_zone)].", - "You begin to retract the skin in [target]'s [parse_zone(target_zone)]...") + display_results(user, target, "You begin to retract the skin in [target]'s [parse_zone(target_zone)]...", + "[user] begins to retract the skin in [target]'s [parse_zone(target_zone)].", + "[user] begins to retract the skin in [target]'s [parse_zone(target_zone)].") //close incision /datum/surgery_step/close name = "mend incision" - implements = list(/obj/item/cautery = 100, /obj/item/gun/energy/laser = 90, TOOL_WELDER = 70, + implements = list(TOOL_CAUTERY = 100, /obj/item/gun/energy/laser = 90, TOOL_WELDER = 70, /obj/item = 30) // 30% success with any hot item. time = 24 /datum/surgery_step/close/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] begins to mend the incision in [target]'s [parse_zone(target_zone)].", - "You begin to mend the incision in [target]'s [parse_zone(target_zone)]...") + display_results(user, target, "You begin to mend the incision in [target]'s [parse_zone(target_zone)]...", + "[user] begins to mend the incision in [target]'s [parse_zone(target_zone)].", + "[user] begins to mend the incision in [target]'s [parse_zone(target_zone)].") /datum/surgery_step/close/tool_check(mob/user, obj/item/tool) if(implement_type == TOOL_WELDER || implement_type == /obj/item) return tool.is_hot() - return TRUE - /datum/surgery_step/close/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) if(locate(/datum/surgery_step/saw) in surgery.steps) target.heal_bodypart_damage(45,0) + if (ishuman(target)) + var/mob/living/carbon/human/H = target + H.bleed_rate = max( (H.bleed_rate - 3), 0) return ..() - - - //saw bone /datum/surgery_step/saw name = "saw bone" - implements = list(/obj/item/circular_saw = 100, /obj/item/melee/transforming/energy/sword/cyborg/saw = 100, - /obj/item/melee/arm_blade = 75, /obj/item/mounted_chainsaw = 65, /obj/item/twohanded/required/chainsaw = 50, - /obj/item/twohanded/fireaxe = 50, /obj/item/hatchet = 35, /obj/item/kitchen/knife/butcher = 25) + implements = list(TOOL_SAW = 100, /obj/item/melee/arm_blade = 75, /obj/item/twohanded/fireaxe = 50, /obj/item/hatchet = 35, /obj/item/kitchen/knife/butcher = 25) time = 54 /datum/surgery_step/saw/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] begins to saw through the bone in [target]'s [parse_zone(target_zone)].", - "You begin to saw through the bone in [target]'s [parse_zone(target_zone)]...") + display_results(user, target, "You begin to saw through the bone in [target]'s [parse_zone(target_zone)]...", + "[user] begins to saw through the bone in [target]'s [parse_zone(target_zone)].", + "[user] begins to saw through the bone in [target]'s [parse_zone(target_zone)].") /datum/surgery_step/saw/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) target.apply_damage(50, BRUTE, "[target_zone]") - - user.visible_message("[user] saws [target]'s [parse_zone(target_zone)] open!", "You saw [target]'s [parse_zone(target_zone)] open.") + display_results(user, target, "You saw [target]'s [parse_zone(target_zone)] open.", + "[user] saws [target]'s [parse_zone(target_zone)] open!", + "[user] saws [target]'s [parse_zone(target_zone)] open!") return 1 //drill bone /datum/surgery_step/drill name = "drill bone" - implements = list(/obj/item/surgicaldrill = 100, /obj/item/screwdriver/power = 80, /obj/item/pickaxe/drill = 60, /obj/item/mecha_parts/mecha_equipment/drill = 60, TOOL_SCREWDRIVER = 20) + implements = list(TOOL_DRILL = 100, /obj/item/screwdriver/power = 80, /obj/item/pickaxe/drill = 60, TOOL_SCREWDRIVER = 20) time = 30 /datum/surgery_step/drill/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] begins to drill into the bone in [target]'s [parse_zone(target_zone)].", - "You begin to drill into the bone in [target]'s [parse_zone(target_zone)]...") + display_results(user, target, "You begin to drill into the bone in [target]'s [parse_zone(target_zone)]...", + "[user] begins to drill into the bone in [target]'s [parse_zone(target_zone)].", + "[user] begins to drill into the bone in [target]'s [parse_zone(target_zone)].") /datum/surgery_step/drill/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] drills into [target]'s [parse_zone(target_zone)]!", - "You drill into [target]'s [parse_zone(target_zone)].") + display_results(user, target, "You drill into [target]'s [parse_zone(target_zone)].", + "[user] drills into [target]'s [parse_zone(target_zone)]!", + "[user] drills into [target]'s [parse_zone(target_zone)]!") return 1 diff --git a/code/modules/surgery/organs/appendix.dm b/code/modules/surgery/organs/appendix.dm index 34a7e16ebf..1f3f2fff5b 100644 --- a/code/modules/surgery/organs/appendix.dm +++ b/code/modules/surgery/organs/appendix.dm @@ -3,7 +3,21 @@ icon_state = "appendix" zone = BODY_ZONE_PRECISE_GROIN slot = ORGAN_SLOT_APPENDIX - var/inflamed = 0 + healing_factor = STANDARD_ORGAN_HEALING + decay_factor = STANDARD_ORGAN_DECAY + + now_failing = "An explosion of pain erupts in your lower right abdomen!" + now_fixed = "The pain in your abdomen has subsided." + + var/inflamed + +/obj/item/organ/appendix/on_life() + ..() + if(!(organ_flags & ORGAN_FAILING)) + return + var/mob/living/carbon/M = owner + if(M) + M.adjustToxLoss(4, TRUE, TRUE) //forced to ensure people don't use it to gain tox as slime person /obj/item/organ/appendix/update_icon() if(inflamed) @@ -16,7 +30,7 @@ /obj/item/organ/appendix/Remove(mob/living/carbon/M, special = 0) for(var/datum/disease/appendicitis/A in M.diseases) A.cure() - inflamed = 1 + inflamed = TRUE update_icon() ..() diff --git a/code/modules/surgery/organs/augments_arms.dm b/code/modules/surgery/organs/augments_arms.dm index 33e62d21e4..e42fc91d47 100644 --- a/code/modules/surgery/organs/augments_arms.dm +++ b/code/modules/surgery/organs/augments_arms.dm @@ -121,7 +121,7 @@ playsound(get_turf(owner), 'sound/mecha/mechmove03.ogg', 50, 1) /obj/item/organ/cyberimp/arm/ui_action_click() - if(crit_fail || (!holder && !contents.len)) + if(crit_fail || (organ_flags & ORGAN_FAILING) || (!holder && !contents.len)) to_chat(owner, "The implant doesn't respond. It seems to be broken...") return @@ -145,7 +145,7 @@ . = ..() if(. & EMP_PROTECT_SELF) return - if(prob(30/severity) && owner && !crit_fail) + if(prob(30/severity) && owner && !(organ_flags & ORGAN_FAILING)) Retract() owner.visible_message("A loud bang comes from [owner]\'s [zone == BODY_ZONE_R_ARM ? "right" : "left"] arm!") playsound(get_turf(owner), 'sound/weapons/flashbang.ogg', 100, 1) @@ -154,6 +154,7 @@ owner.IgniteMob() owner.adjustFireLoss(25) crit_fail = 1 + organ_flags |= ORGAN_FAILING /obj/item/organ/cyberimp/arm/gun/laser @@ -185,11 +186,12 @@ zone = BODY_ZONE_L_ARM /obj/item/organ/cyberimp/arm/toolset/emag_act() - if(!(locate(/obj/item/kitchen/knife/combat/cyborg) in items_list)) - to_chat(usr, "You unlock [src]'s integrated knife!") - items_list += new /obj/item/kitchen/knife/combat/cyborg(src) - return 1 - return 0 + . = ..() + if(locate(/obj/item/kitchen/knife/combat/cyborg) in items_list) + return + to_chat(usr, "You unlock [src]'s integrated knife!") + items_list += new /obj/item/kitchen/knife/combat/cyborg(src) + return TRUE /obj/item/organ/cyberimp/arm/esword name = "arm-mounted energy blade" diff --git a/code/modules/surgery/organs/augments_chest.dm b/code/modules/surgery/organs/augments_chest.dm index ea336bea19..7156b8180b 100644 --- a/code/modules/surgery/organs/augments_chest.dm +++ b/code/modules/surgery/organs/augments_chest.dm @@ -144,7 +144,7 @@ /obj/item/organ/cyberimp/chest/thrusters/proc/toggle(silent = FALSE) if(!on) - if(crit_fail) + if(crit_fail || (organ_flags & ORGAN_FAILING)) if(!silent) to_chat(owner, "Your thrusters set seems to be broken!") return 0 diff --git a/code/modules/surgery/organs/augments_internal.dm b/code/modules/surgery/organs/augments_internal.dm index 06d523721d..114b92f10d 100644 --- a/code/modules/surgery/organs/augments_internal.dm +++ b/code/modules/surgery/organs/augments_internal.dm @@ -4,6 +4,7 @@ name = "cybernetic implant" desc = "A state-of-the-art implant that improves a baseline's functionality." status = ORGAN_ROBOTIC + organ_flags = ORGAN_SYNTHETIC var/implant_color = "#FFFFFF" var/implant_overlay var/syndicate_implant = FALSE //Makes the implant invisible to health analyzers and medical HUDs. @@ -102,7 +103,7 @@ /obj/item/organ/cyberimp/brain/anti_stun/on_life() ..() - if(crit_fail) + if(crit_fail || !(organ_flags & ORGAN_FAILING)) return owner.adjustStaminaLoss(-3.5) //Citadel edit, makes it more useful in Stamina based combat if(owner.AmountStun() > STUN_SET_AMOUNT) @@ -112,13 +113,15 @@ /obj/item/organ/cyberimp/brain/anti_stun/emp_act(severity) . = ..() - if(crit_fail || . & EMP_PROTECT_SELF) + if(crit_fail || (organ_flags & ORGAN_FAILING) || . & EMP_PROTECT_SELF) return crit_fail = TRUE + organ_flags |= ORGAN_FAILING addtimer(CALLBACK(src, .proc/reboot), 90 / severity) /obj/item/organ/cyberimp/brain/anti_stun/proc/reboot() crit_fail = FALSE + organ_flags &= ~ORGAN_FAILING //[[[[MOUTH]]]] diff --git a/code/modules/surgery/organs/autosurgeon.dm b/code/modules/surgery/organs/autosurgeon.dm index 0ba6fd7fcd..27bf575627 100644 --- a/code/modules/surgery/organs/autosurgeon.dm +++ b/code/modules/surgery/organs/autosurgeon.dm @@ -17,9 +17,10 @@ if(starting_organ) insert_organ(new starting_organ(src)) -/obj/item/autosurgeon/proc/insert_organ(var/obj/item/I) +/obj/item/autosurgeon/proc/insert_organ(var/obj/item/organ/I) storedorgan = I I.forceMove(src) + I.organ_flags |= ORGAN_FROZEN //Stops decay name = "[initial(name)] ([storedorgan.name])" /obj/item/autosurgeon/attack_self(mob/user)//when the object it used... @@ -99,6 +100,9 @@ /obj/item/autosurgeon/reviver starting_organ = /obj/item/organ/cyberimp/chest/reviver +/obj/item/autosurgeon/anti_drop + starting_organ = /obj/item/organ/cyberimp/brain/anti_drop + /obj/item/autosurgeon/penis desc = "A single use autosurgeon that contains a penis. A screwdriver can be used to remove it, but implants can't be placed back in." uses = 1 @@ -122,4 +126,4 @@ /obj/item/autosurgeon/womb desc = "A single use autosurgeon that contains a womb. A screwdriver can be used to remove it, but implants can't be placed back in." uses = 1 - starting_organ = /obj/item/organ/genital/womb \ No newline at end of file + starting_organ = /obj/item/organ/genital/womb diff --git a/code/modules/surgery/organs/ears.dm b/code/modules/surgery/organs/ears.dm index 8e191a41a9..0d3002915e 100644 --- a/code/modules/surgery/organs/ears.dm +++ b/code/modules/surgery/organs/ears.dm @@ -6,6 +6,14 @@ slot = ORGAN_SLOT_EARS gender = PLURAL + healing_factor = STANDARD_ORGAN_HEALING + decay_factor = STANDARD_ORGAN_DECAY + + low_threshold_passed = "Your ears begin to resonate with an internal ring sometimes." + now_failing = "You are unable to hear at all!" + now_fixed = "Noise slowly begins filling your ears once more." + low_threshold_cleared = "The ringing in your ears has died down." + // `deaf` measures "ticks" of deafness. While > 0, the person is unable // to hear anything. var/deaf = 0 @@ -23,17 +31,26 @@ /obj/item/organ/ears/on_life() if(!iscarbon(owner)) return + ..() var/mob/living/carbon/C = owner + if((damage < maxHealth) && (organ_flags & ORGAN_FAILING)) //ear damage can be repaired from the failing condition + organ_flags &= ~ORGAN_FAILING // genetic deafness prevents the body from using the ears, even if healthy if(HAS_TRAIT(C, TRAIT_DEAF)) deaf = max(deaf, 1) - else if(ear_damage < UNHEALING_EAR_DAMAGE) // if higher than UNHEALING_EAR_DAMAGE, no natural healing occurs. - ear_damage = max(ear_damage - 0.05, 0) + else if(!(organ_flags & ORGAN_FAILING)) // if this organ is failing, do not clear deaf stacks. deaf = max(deaf - 1, 0) + if(prob(damage / 20) && (damage > low_threshold)) + adjustEarDamage(0, 4) + SEND_SOUND(C, sound('sound/weapons/flash_ring.ogg')) + to_chat(C, "The ringing in your ears grows louder, blocking out any external noises for a moment.") + else if((organ_flags & ORGAN_FAILING) && (deaf == 0)) + deaf = 1 //stop being not deaf you deaf idiot /obj/item/organ/ears/proc/restoreEars() deaf = 0 ear_damage = 0 + organ_flags &= ~ORGAN_FAILING var/mob/living/carbon/C = owner @@ -99,4 +116,23 @@ name = "tin ears" desc = "The robust ears of a bronze golem. " damage_multiplier = 0.1 //STRONK - bang_protect = 1 //Fear me weaklings. + bang_protect = 1 //Fear me weaklings. + +/obj/item/organ/ears/cybernetic + name = "cybernetic ears" + icon_state = "ears-c" + desc = "a basic cybernetic designed to mimic the operation of ears." + damage_multiplier = 0.9 + organ_flags = ORGAN_SYNTHETIC + +/obj/item/organ/ears/cybernetic/upgraded + name = "upgraded cybernetic ears" + icon_state = "ears-c-u" + desc = "an advanced cybernetic ear, surpassing the performance of organic ears" + damage_multiplier = 0.5 + +/obj/item/organ/ears/cybernetic/emp_act(severity) + . = ..() + if(. & EMP_PROTECT_SELF) + return + damage += 40/severity diff --git a/code/modules/surgery/organs/eyes.dm b/code/modules/surgery/organs/eyes.dm index 98abb2528a..95258c709a 100644 --- a/code/modules/surgery/organs/eyes.dm +++ b/code/modules/surgery/organs/eyes.dm @@ -6,6 +6,19 @@ slot = ORGAN_SLOT_EYES gender = PLURAL + healing_factor = STANDARD_ORGAN_HEALING + decay_factor = STANDARD_ORGAN_DECAY + maxHealth = 0.5 * STANDARD_ORGAN_THRESHOLD //half the normal health max since we go blind at 30, a permanent blindness at 50 therefore makes sense unless medicine is administered + high_threshold = 0.3 * STANDARD_ORGAN_THRESHOLD //threshold at 30 + low_threshold = 0.15 * STANDARD_ORGAN_THRESHOLD //threshold at 15 + + low_threshold_passed = "Distant objects become somewhat less tangible." + high_threshold_passed = "Everything starts to look a lot less clear." + now_failing = "Darkness envelopes you, as your eyes go blind!" + now_fixed = "Color and shapes are once again perceivable." + high_threshold_cleared = "Your vision functions passably once more." + low_threshold_cleared = "Your vision is cleared of any ailment." + var/sight_flags = 0 var/see_in_dark = 2 var/eye_damage = 0 @@ -15,9 +28,12 @@ var/flash_protect = 0 var/see_invisible = SEE_INVISIBLE_LIVING var/lighting_alpha + var/damaged = FALSE //damaged indicates that our eyes are undergoing some level of negative effect /obj/item/organ/eyes/Insert(mob/living/carbon/M, special = FALSE, drop_if_replaced = FALSE) ..() + if(damage == initial(damage)) + clear_eye_trauma() if(ishuman(owner)) var/mob/living/carbon/human/HMN = owner old_eye_color = HMN.eye_color @@ -32,7 +48,9 @@ M.update_tint() owner.update_sight() + /obj/item/organ/eyes/Remove(mob/living/carbon/M, special = 0) + clear_eye_trauma() ..() if(ishuman(M) && eye_color) var/mob/living/carbon/human/HMN = M @@ -41,6 +59,34 @@ M.update_tint() M.update_sight() +/obj/item/organ/eyes/on_life() + ..() + var/mob/living/carbon/C = owner + //since we can repair fully damaged eyes, check if healing has occurred + if((organ_flags & ORGAN_FAILING) && (damage < maxHealth)) + organ_flags &= ~ORGAN_FAILING + C.cure_blind(EYE_DAMAGE) + //various degrees of "oh fuck my eyes", from "point a laser at your eye" to "staring at the Sun" intensities + if(damage > 20) + damaged = TRUE + if(organ_flags & ORGAN_FAILING) + C.become_blind(EYE_DAMAGE) + else if(damage > 30) + C.overlay_fullscreen("eye_damage", /obj/screen/fullscreen/impaired, 2) + else + C.overlay_fullscreen("eye_damage", /obj/screen/fullscreen/impaired, 1) + //called once since we don't want to keep clearing the screen of eye damage for people who are below 20 damage + else if(damaged) + damaged = FALSE + C.clear_fullscreen("eye_damage") + return + +/obj/item/organ/eyes/proc/clear_eye_trauma() + var/mob/living/carbon/C = owner + C.clear_fullscreen("eye_damage") + C.cure_blind(EYE_DAMAGE) + damaged = FALSE + /obj/item/organ/eyes/night_vision name = "shadow eyes" desc = "A spooky set of eyes that can see in the dark." @@ -71,6 +117,7 @@ /obj/item/organ/eyes/night_vision/zombie name = "undead eyes" desc = "Somewhat counterintuitively, these half-rotten eyes actually have superior vision to those of a living human." + sight_flags = SEE_MOBS /obj/item/organ/eyes/night_vision/nightmare name = "burning red eyes" @@ -88,15 +135,17 @@ icon_state = "cybernetic_eyeballs" desc = "Your vision is augmented." status = ORGAN_ROBOTIC + organ_flags = ORGAN_SYNTHETIC /obj/item/organ/eyes/robotic/emp_act(severity) . = ..() if(!owner || . & EMP_PROTECT_SELF) return - if(prob(10 * severity)) - return to_chat(owner, "Static obfuscates your vision!") owner.flash_act(visual = 1) + if(severity == EMP_HEAVY) + owner.adjustOrganLoss(ORGAN_SLOT_EYES, 20) + /obj/item/organ/eyes/robotic/xray name = "\improper X-ray eyes" @@ -137,7 +186,7 @@ M.become_blind("flashlight_eyes") -/obj/item/organ/eyes/robotic/flashlight/Remove(var/mob/living/carbon/M, var/special = 0) +/obj/item/organ/eyes/robotic/flashlight/Remove(var/mob/living/carbon/M, special = FALSE) eye.on = FALSE eye.update_brightness(M) eye.forceMove(src) @@ -169,7 +218,6 @@ var/list/obj/effect/abstract/eye_lighting/eye_lighting var/obj/effect/abstract/eye_lighting/on_mob var/image/mob_overlay - var/datum/component/mobhook /obj/item/organ/eyes/robotic/glow/Initialize() . = ..() @@ -185,7 +233,7 @@ /obj/item/organ/eyes/robotic/glow/proc/terminate_effects() if(owner && active) - deactivate() + deactivate(TRUE) active = FALSE clear_visuals(TRUE) STOP_PROCESSING(SSfastprocess, src) @@ -238,26 +286,12 @@ return deactivate(silent = TRUE) -/obj/item/organ/eyes/robotic/glow/Insert(mob/living/carbon/M, special = FALSE, drop_if_replaced = FALSE) - . = ..() - if (mobhook && mobhook.parent != M) - QDEL_NULL(mobhook) - if (!mobhook) - mobhook = M.AddComponent(/datum/component/redirect, list(COMSIG_ATOM_DIR_CHANGE = CALLBACK(src, .proc/update_visuals))) - -/obj/item/organ/eyes/robotic/glow/Remove(mob/living/carbon/M) - . = ..() - QDEL_NULL(mobhook) - -/obj/item/organ/eyes/robotic/glow/Destroy() - QDEL_NULL(mobhook) // mobhook is not our component - return ..() - /obj/item/organ/eyes/robotic/glow/proc/activate(silent = FALSE) start_visuals() if(!silent) to_chat(owner, "Your [src] clicks and makes a whining noise, before shooting out a beam of light!") active = TRUE + RegisterSignal(owner, COMSIG_ATOM_DIR_CHANGE, .proc/update_visuals) cycle_mob_overlay() /obj/item/organ/eyes/robotic/glow/proc/deactivate(silent = FALSE) @@ -265,6 +299,7 @@ if(!silent) to_chat(owner, "Your [src] shuts off!") active = FALSE + UnregisterSignal(owner, COMSIG_ATOM_DIR_CHANGE) remove_mob_overlay() /obj/item/organ/eyes/robotic/glow/proc/update_visuals(datum/source, olddir, newdir) @@ -335,7 +370,7 @@ if(!istype(parent)) return INITIALIZE_HINT_QDEL -/obj/item/organ/eyes/moth - name = "moth eyes" +/obj/item/organ/eyes/insect + name = "insect eyes" desc = "These eyes seem to have increased sensitivity to bright light, with no improvement to low light vision." flash_protect = -1 diff --git a/code/modules/surgery/organs/heart.dm b/code/modules/surgery/organs/heart.dm index 5852cba0c9..8e4caab436 100644 --- a/code/modules/surgery/organs/heart.dm +++ b/code/modules/surgery/organs/heart.dm @@ -4,12 +4,24 @@ icon_state = "heart-on" zone = BODY_ZONE_CHEST slot = ORGAN_SLOT_HEART + + healing_factor = STANDARD_ORGAN_HEALING + decay_factor = 3 * STANDARD_ORGAN_DECAY //designed to fail about 5 minutes after death + + low_threshold_passed = "Prickles of pain appear then die out from within your chest..." + high_threshold_passed = "Something inside your chest hurts, and the pain isn't subsiding. You notice yourself breathing far faster than before." + now_fixed = "Your heart begins to beat again." + high_threshold_cleared = "The pain in your chest has died down, and your breathing becomes more relaxed." + // Heart attack code is in code/modules/mob/living/carbon/human/life.dm var/beating = 1 var/icon_base = "heart" attack_verb = list("beat", "thumped") var/beat = BEAT_NONE//is this mob having a heatbeat sound played? if so, which? + var/failed = FALSE //to prevent constantly running failing code + var/operated = FALSE //whether the heart's been operated on to fix some of its damages + /obj/item/organ/heart/update_icon() if(beating) icon_state = "[icon_base]-on" @@ -49,7 +61,9 @@ return S /obj/item/organ/heart/on_life() + ..() if(owner.client && beating) + failed = FALSE var/sound/slowbeat = sound('sound/health/slowbeat.ogg', repeat = TRUE) var/sound/fastbeat = sound('sound/health/fastbeat.ogg', repeat = TRUE) var/mob/living/carbon/H = owner @@ -70,11 +84,18 @@ H.stop_sound_channel(CHANNEL_HEARTBEAT) beat = BEAT_NONE + if(organ_flags & ORGAN_FAILING) //heart broke, stopped beating, death imminent + if(owner.stat == CONSCIOUS) + owner.visible_message("[owner] clutches at [owner.p_their()] chest as if [owner.p_their()] heart is stopping!") + owner.set_heartattack(TRUE) + failed = TRUE + /obj/item/organ/heart/cursed name = "cursed heart" desc = "A heart that, when inserted, will force you to pump it manually." icon_state = "cursedheart-off" icon_base = "cursedheart" + decay_factor = 0 actions_types = list(/datum/action/item_action/organ_action/cursed_heart) var/last_pump = 0 var/add_colour = TRUE //So we're not constantly recreating colour datums @@ -153,18 +174,48 @@ name = "cybernetic heart" desc = "An electronic device designed to mimic the functions of an organic human heart. Offers no benefit over an organic heart other than being easy to make." icon_state = "heart-c" - synthetic = TRUE + organ_flags = ORGAN_SYNTHETIC -/obj/item/organ/heart/cybernetic/emp_act() +/obj/item/organ/heart/cybernetic/emp_act(severity) . = ..() if(. & EMP_PROTECT_SELF) return Stop() + addtimer(CALLBACK(src, .proc/Restart), 20/severity SECONDS) + damage += 100/severity + +/obj/item/organ/heart/cybernetic/upgraded + name = "upgraded cybernetic heart" + desc = "An electronic device designed to mimic the functions of an organic human heart. Also holds an emergency dose of epinephrine, used automatically after facing severe trauma. This upgraded model can regenerate its dose after use." + icon_state = "heart-c-u" + maxHealth = 2 * STANDARD_ORGAN_THRESHOLD + + //I put it on upgraded for now. + var/dose_available = TRUE + var/rid = /datum/reagent/medicine/epinephrine + var/ramount = 10 + +obj/item/organ/heart/cybernetic/upgraded/on_life() + . = ..() + if(dose_available && owner.health <= owner.crit_threshold && !owner.reagents.has_reagent(rid)) + owner.reagents.add_reagent(rid, ramount) + used_dose() + if(ramount < 10) //eats your nutrition to regen epinephrine + var/regen_amount = owner.nutrition/2000 + owner.nutrition -= regen_amount + ramount += regen_amount + +/obj/item/organ/heart/cybernetic/upgraded/proc/used_dose() + . = ..() + addtimer(VARSET_CALLBACK(src, dose_available, TRUE), 5 MINUTES) + ramount = 0 + + /obj/item/organ/heart/freedom name = "heart of freedom" desc = "This heart pumps with the passion to give... something freedom." - synthetic = TRUE //the power of freedom prevents heart attacks + organ_flags = ORGAN_SYNTHETIC //the power of freedom prevents heart attacks var/min_next_adrenaline = 0 /obj/item/organ/heart/freedom/on_life() diff --git a/code/modules/surgery/organs/liver.dm b/code/modules/surgery/organs/liver.dm index f666fc209b..01559c83c3 100755 --- a/code/modules/surgery/organs/liver.dm +++ b/code/modules/surgery/organs/liver.dm @@ -1,6 +1,7 @@ #define LIVER_DEFAULT_HEALTH 100 //amount of damage required for liver failure #define LIVER_DEFAULT_TOX_TOLERANCE 3 //amount of toxins the liver can filter out #define LIVER_DEFAULT_TOX_LETHALITY 0.01 //lower values lower how harmful toxins are to the liver +#define LIVER_SWELLING_MOVE_MODIFY "pharma" /obj/item/organ/liver name = "liver" @@ -9,19 +10,24 @@ zone = BODY_ZONE_CHEST slot = ORGAN_SLOT_LIVER desc = "Pairing suggestion: chianti and fava beans." - var/damage = 0 //liver damage, 0 is no damage, damage=maxHealth causes liver failure + + maxHealth = STANDARD_ORGAN_THRESHOLD + healing_factor = STANDARD_ORGAN_HEALING + decay_factor = STANDARD_ORGAN_DECAY + var/alcohol_tolerance = ALCOHOL_RATE//affects how much damage the liver takes from alcohol var/failing //is this liver failing? - var/maxHealth = LIVER_DEFAULT_HEALTH var/toxTolerance = LIVER_DEFAULT_TOX_TOLERANCE//maximum amount of toxins the liver can just shrug off var/toxLethality = LIVER_DEFAULT_TOX_LETHALITY//affects how much damage toxins do to the liver var/filterToxins = TRUE //whether to filter toxins + var/swelling = 0 + var/cachedmoveCalc = 1 /obj/item/organ/liver/on_life() var/mob/living/carbon/C = owner if(istype(C)) - if(!failing)//can't process reagents with a failing liver + if(!(organ_flags & ORGAN_FAILING))//can't process reagents with a failing liver //slowly heal liver damage damage = max(0, damage - 0.1) @@ -45,11 +51,40 @@ if(damage > maxHealth)//cap liver damage damage = maxHealth + if(swelling >= 10) + pharmacokinesis() + /obj/item/organ/liver/prepare_eat() var/obj/S = ..() S.reagents.add_reagent("iron", 5) return S +//Just in case +/obj/item/organ/liver/Remove(mob/living/carbon/M, special = 0) + ..() + M.remove_movespeed_modifier(LIVER_SWELLING_MOVE_MODIFY) + M.ResetBloodVol() //At the moment, this shouldn't allow application twice. You either have this OR a thirsty ferret. + sizeMoveMod(1, M) + +//Applies some of the effects to the patient. +/obj/item/organ/liver/proc/pharmacokinesis() + var/moveCalc = 1+((round(swelling) - 9)/3) + if(moveCalc == cachedmoveCalc)//reduce calculations + return + if(prob(5)) + to_chat(owner, "You feel a stange ache in your side, almost like a stitch. This pain is affecting your movements and making you feel lightheaded.") + var/mob/living/carbon/human/H = owner + H.add_movespeed_modifier(LIVER_SWELLING_MOVE_MODIFY, TRUE, 100, NONE, override = TRUE, multiplicative_slowdown = moveCalc) + H.AdjustBloodVol(moveCalc/3) + sizeMoveMod(moveCalc, H) + +/obj/item/organ/liver/proc/sizeMoveMod(var/value, mob/living/carbon/human/H) + if(cachedmoveCalc == value) + return + H.next_move_modifier /= cachedmoveCalc + H.next_move_modifier *= value + cachedmoveCalc = value + /obj/item/organ/liver/fly name = "insectoid liver" icon_state = "liver-x" //xenomorph liver? It's just a black liver so it fits. @@ -65,14 +100,15 @@ name = "cybernetic liver" icon_state = "liver-c" desc = "An electronic device designed to mimic the functions of a human liver. It has no benefits over an organic liver, but is easy to produce." - synthetic = TRUE + organ_flags = ORGAN_SYNTHETIC + maxHealth = 1.1 * STANDARD_ORGAN_THRESHOLD /obj/item/organ/liver/cybernetic/upgraded name = "upgraded cybernetic liver" icon_state = "liver-c-u" desc = "An upgraded version of the cybernetic liver, designed to improve upon organic livers. It is resistant to alcohol poisoning and is very robust at filtering toxins." alcohol_tolerance = 0.001 - maxHealth = 200 //double the health of a normal liver + maxHealth = 2 * STANDARD_ORGAN_THRESHOLD toxTolerance = 15 //can shrug off up to 15u of toxins toxLethality = 0.008 //20% less damage than a normal liver diff --git a/code/modules/surgery/organs/lungs.dm b/code/modules/surgery/organs/lungs.dm index 64b2c2ee90..6b0e4f01ae 100644 --- a/code/modules/surgery/organs/lungs.dm +++ b/code/modules/surgery/organs/lungs.dm @@ -1,3 +1,5 @@ +#define LUNGS_MAX_HEALTH 300 + /obj/item/organ/lungs name = "lungs" icon_state = "lungs" @@ -6,6 +8,21 @@ gender = PLURAL w_class = WEIGHT_CLASS_NORMAL + var/failed = FALSE + var/operated = FALSE //whether we can still have our damages fixed through surgery + + //health + maxHealth = 3 * STANDARD_ORGAN_THRESHOLD + + healing_factor = STANDARD_ORGAN_HEALING + decay_factor = STANDARD_ORGAN_DECAY + high_threshold = 0.6 * LUNGS_MAX_HEALTH //threshold at 180 + low_threshold = 0.3 * LUNGS_MAX_HEALTH //threshold at 90 + + high_threshold_passed = "You feel some sort of constriction around your chest as your breathing becomes shallow and rapid." + now_fixed = "Your lungs seem to once again be able to hold air." + high_threshold_cleared = "The constriction around your chest loosens as your breathing calms down." + //Breath damage var/safe_oxygen_min = 16 // Minimum safe partial pressure of O2, in kPa @@ -55,7 +72,38 @@ var/crit_stabilizing_reagent = "epinephrine" + +//TODO: lung health affects lung function +/obj/item/organ/lungs/onDamage(damage_mod) //damage might be too low atm. + var/cached_damage = damage + if (maxHealth == INFINITY) + return + if(cached_damage+damage_mod < 0) + cached_damage = 0 + return + + cached_damage += damage_mod + if ((cached_damage/ maxHealth) > 1) + to_chat(owner, "You feel your lungs collapse within your chest as you gasp for air, unable to inflate them anymore!") + owner.emote("gasp") + SSblackbox.record_feedback("tally", "fermi_chem", 1, "Lungs lost") + //qdel(src) - Handled elsewhere for now. + else if ((cached_damage / maxHealth) > 0.75) + to_chat(owner, "It's getting really hard to breathe!!") + owner.emote("gasp") + owner.Dizzy(3) + else if ((cached_damage / maxHealth) > 0.5) + owner.Dizzy(2) + to_chat(owner, "Your chest is really starting to hurt.") + owner.emote("cough") + else if ((cached_damage / maxHealth) > 0.2) + to_chat(owner, "You feel an ache within your chest.") + owner.emote("cough") + owner.Dizzy(1) + /obj/item/organ/lungs/proc/check_breath(datum/gas_mixture/breath, mob/living/carbon/human/H) +//TODO: add lung damage = less oxygen gains + var/breathModifier = (5-(5*(damage/maxHealth)/2)) //range 2.5 - 5 if((H.status_flags & GODMODE)) return if(HAS_TRAIT(H, TRAIT_NOBREATH)) @@ -124,7 +172,7 @@ else H.failed_last_breath = FALSE if(H.health >= H.crit_threshold) - H.adjustOxyLoss(-5) + H.adjustOxyLoss(-breathModifier) //More damaged lungs = slower oxy rate up to a factor of half gas_breathed = breath_gases[/datum/gas/oxygen] H.clear_alert("not_enough_oxy") @@ -153,7 +201,7 @@ else H.failed_last_breath = FALSE if(H.health >= H.crit_threshold) - H.adjustOxyLoss(-5) + H.adjustOxyLoss(-breathModifier) gas_breathed = breath_gases[/datum/gas/nitrogen] H.clear_alert("nitro") @@ -190,7 +238,7 @@ else H.failed_last_breath = FALSE if(H.health >= H.crit_threshold) - H.adjustOxyLoss(-5) + H.adjustOxyLoss(-breathModifier) gas_breathed = breath_gases[/datum/gas/carbon_dioxide] H.clear_alert("not_enough_co2") @@ -220,7 +268,7 @@ else H.failed_last_breath = FALSE if(H.health >= H.crit_threshold) - H.adjustOxyLoss(-5) + H.adjustOxyLoss(-breathModifier) gas_breathed = breath_gases[/datum/gas/plasma] H.clear_alert("not_enough_tox") @@ -244,6 +292,9 @@ else if(SA_pp > 0.01) // There is sleeping gas in their lungs, but only a little, so give them a bit of a warning if(prob(20)) H.emote(pick("giggle", "laugh")) + SEND_SIGNAL(owner, COMSIG_ADD_MOOD_EVENT, "chemical_euphoria", /datum/mood_event/chemical_euphoria) + else + SEND_SIGNAL(owner, COMSIG_CLEAR_MOOD_EVENT, "chemical_euphoria") // BZ @@ -252,7 +303,7 @@ H.hallucination += 10 H.reagents.add_reagent("bz_metabolites",5) if(prob(33)) - H.adjustBrainLoss(3, 150) + H.adjustOrganLoss(ORGAN_SLOT_BRAIN, 3, 150) else if(bz_pp > 0.01) H.hallucination += 5 @@ -368,10 +419,13 @@ var/cold_modifier = H.dna.species.coldmod if(breath_temperature < cold_level_3_threshold) H.apply_damage_type(cold_level_3_damage*cold_modifier, cold_damage_type) + H.adjustOrganLoss(ORGAN_SLOT_LUNGS, (cold_level_3_damage*cold_modifier*2)) if(breath_temperature > cold_level_3_threshold && breath_temperature < cold_level_2_threshold) H.apply_damage_type(cold_level_2_damage*cold_modifier, cold_damage_type) + H.adjustOrganLoss(ORGAN_SLOT_LUNGS, (cold_level_2_damage*cold_modifier*2)) if(breath_temperature > cold_level_2_threshold && breath_temperature < cold_level_1_threshold) H.apply_damage_type(cold_level_1_damage*cold_modifier, cold_damage_type) + H.adjustOrganLoss(ORGAN_SLOT_LUNGS, (cold_level_1_damage*cold_modifier*2)) if(breath_temperature < cold_level_1_threshold) if(prob(20)) to_chat(H, "You feel [cold_message] in your [name]!") @@ -380,14 +434,29 @@ var/heat_modifier = H.dna.species.heatmod if(breath_temperature > heat_level_1_threshold && breath_temperature < heat_level_2_threshold) H.apply_damage_type(heat_level_1_damage*heat_modifier, heat_damage_type) + H.adjustOrganLoss(ORGAN_SLOT_LUNGS, (heat_level_1_damage*heat_modifier*2)) if(breath_temperature > heat_level_2_threshold && breath_temperature < heat_level_3_threshold) H.apply_damage_type(heat_level_2_damage*heat_modifier, heat_damage_type) + H.adjustOrganLoss(ORGAN_SLOT_LUNGS, (heat_level_2_damage*heat_modifier*2)) if(breath_temperature > heat_level_3_threshold) H.apply_damage_type(heat_level_3_damage*heat_modifier, heat_damage_type) + H.adjustOrganLoss(ORGAN_SLOT_LUNGS, (heat_level_3_damage*heat_modifier*2)) if(breath_temperature > heat_level_1_threshold) if(prob(20)) to_chat(H, "You feel [hot_message] in your [name]!") + +/obj/item/organ/lungs/on_life() + ..() + if((!failed) && ((organ_flags & ORGAN_FAILING))) + if(owner.stat == CONSCIOUS) + owner.visible_message("[owner] grabs [owner.p_their()] throat, struggling for breath!", \ + "You suddenly feel like you can't breathe!") + failed = TRUE + else if(!(organ_flags & ORGAN_FAILING)) + failed = FALSE + return + /obj/item/organ/lungs/prepare_eat() var/obj/S = ..() S.reagents.add_reagent("salbutamol", 5) @@ -402,18 +471,22 @@ safe_oxygen_max = 0 // Like, at all. safe_toxins_min = 16 //We breath THIS! safe_toxins_max = 0 + maxHealth = INFINITY//I don't understand how plamamen work, so I'm not going to try t give them special lungs atm /obj/item/organ/lungs/cybernetic name = "cybernetic lungs" desc = "A cybernetic version of the lungs found in traditional humanoid entities. It functions the same as an organic lung and is merely meant as a replacement." icon_state = "lungs-c" - synthetic = TRUE + organ_flags = ORGAN_SYNTHETIC + maxHealth = 400 + safe_oxygen_min = 13 /obj/item/organ/lungs/cybernetic/emp_act() . = ..() if(. & EMP_PROTECT_SELF) return owner.losebreath = 20 + owner.adjustOrganLoss(ORGAN_SLOT_LUNGS, 25) /obj/item/organ/lungs/cybernetic/upgraded @@ -427,6 +500,7 @@ cold_level_1_threshold = 200 cold_level_2_threshold = 140 cold_level_3_threshold = 100 + maxHealth = 550 /obj/item/organ/lungs/ashwalker name = "ash lungs" @@ -449,8 +523,24 @@ safe_toxins_max = 0 //We breathe this to gain POWER. + cold_level_1_threshold = 285 // Remember when slimes used to be succeptable to cold? Well.... + cold_level_2_threshold = 260 + cold_level_3_threshold = 230 + + maxHealth = 250 + /obj/item/organ/lungs/slime/check_breath(datum/gas_mixture/breath, mob/living/carbon/human/H) . = ..() if (breath && breath.gases[/datum/gas/plasma]) var/plasma_pp = breath.get_breath_partial_pressure(breath.gases[/datum/gas/plasma]) owner.blood_volume += (0.2 * plasma_pp) // 10/s when breathing literally nothing but plasma, which will suffocate you. + +/obj/item/organ/lungs/yamerol + name = "Yamerol lungs" + desc = "A temporary pair of lungs made from self assembling yamerol molecules." + maxHealth = 200 + color = "#68e83a" + +/obj/item/organ/lungs/yamerol/on_life() + ..() + damage += 2 //Yamerol lungs are temporary diff --git a/code/modules/surgery/organs/organ_internal.dm b/code/modules/surgery/organs/organ_internal.dm index b16967b6b0..593614372a 100644 --- a/code/modules/surgery/organs/organ_internal.dm +++ b/code/modules/surgery/organs/organ_internal.dm @@ -1,3 +1,6 @@ +#define STANDARD_ORGAN_THRESHOLD 100 +#define STANDARD_ORGAN_HEALING 0.001 + /obj/item/organ name = "organ" icon = 'icons/obj/surgery.dmi' @@ -8,11 +11,23 @@ var/zone = BODY_ZONE_CHEST var/slot // DO NOT add slots with matching names to different zones - it will break internal_organs_slot list! - var/vital = 0 - //Was this organ implanted/inserted/etc, if true will not be removed during species change. - var/external = FALSE - var/synthetic = FALSE // To distinguish between organic and synthetic organs + var/organ_flags = 0 + var/maxHealth = STANDARD_ORGAN_THRESHOLD + var/damage = 0 //total damage this organ has sustained + ///Healing factor and decay factor function on % of maxhealth, and do not work by applying a static number per tick + var/healing_factor = 0 //fraction of maxhealth healed per on_life(), set to 0 for generic organs + var/decay_factor = 0 //same as above but when without a living owner, set to 0 for generic organs + var/high_threshold = STANDARD_ORGAN_THRESHOLD * 0.45 //when severe organ damage occurs + var/low_threshold = STANDARD_ORGAN_THRESHOLD * 0.1 //when minor organ damage occurs + ///Organ variables for determining what we alert the owner with when they pass/clear the damage thresholds + var/prev_damage = 0 + var/low_threshold_passed + var/high_threshold_passed + var/now_failing + var/now_fixed + var/high_threshold_cleared + var/low_threshold_cleared /obj/item/organ/proc/Insert(mob/living/carbon/M, special = 0, drop_if_replaced = TRUE) if(!iscarbon(M) || owner == M) @@ -26,6 +41,9 @@ else qdel(replaced) + //Hopefully this doesn't cause problems + organ_flags &= ~ORGAN_FROZEN + owner = M M.internal_organs |= src M.internal_organs_slot[slot] = src @@ -33,31 +51,111 @@ for(var/X in actions) var/datum/action/A = X A.Grant(M) + STOP_PROCESSING(SSobj, src) //Special is for instant replacement like autosurgeons -/obj/item/organ/proc/Remove(mob/living/carbon/M, special = 0) +/obj/item/organ/proc/Remove(mob/living/carbon/M, special = FALSE) owner = null if(M) M.internal_organs -= src if(M.internal_organs_slot[slot] == src) M.internal_organs_slot.Remove(slot) - if(vital && !special && !(M.status_flags & GODMODE)) + if((organ_flags & ORGAN_VITAL) && !special && !(M.status_flags & GODMODE)) M.death() for(var/X in actions) var/datum/action/A = X A.Remove(M) - + START_PROCESSING(SSobj, src) /obj/item/organ/proc/on_find(mob/living/finder) return -/obj/item/organ/proc/on_life() - return +/obj/item/organ/process() //runs decay when outside of a person AND ONLY WHEN OUTSIDE (i.e. long obj). + on_death() //Kinda hate doing it like this, but I really don't want to call process directly. + +//Sources; life.dm process_organs +/obj/item/organ/proc/on_death() //Runs when outside AND inside. + decay() + +//Applys the slow damage over time decay +/obj/item/organ/proc/decay() + if(!can_decay()) + STOP_PROCESSING(SSobj, src) + return + is_cold() + if(organ_flags & ORGAN_FROZEN) + return + applyOrganDamage(maxHealth * decay_factor) + +/obj/item/organ/proc/can_decay() + if(CHECK_BITFIELD(organ_flags, ORGAN_NO_SPOIL | ORGAN_SYNTHETIC | ORGAN_FAILING)) + return FALSE + return TRUE + +//Checks to see if the organ is frozen from temperature +/obj/item/organ/proc/is_cold() + var/freezing_objects = list(/obj/structure/closet/crate/freezer, /obj/structure/closet/secure_closet/freezer, /obj/structure/bodycontainer, /obj/item/autosurgeon) + if(istype(loc, /obj/))//Freezer of some kind, I hope. + if(is_type_in_list(loc, freezing_objects)) + if(!(organ_flags & ORGAN_FROZEN))//Incase someone puts them in when cold, but they warm up inside of the thing. (i.e. they have the flag, the thing turns it off, this rights it.) + organ_flags |= ORGAN_FROZEN + return TRUE + return + + var/local_temp + if(istype(loc, /turf/))//Only concern is adding an organ to a freezer when the area around it is cold. + var/turf/T = loc + var/datum/gas_mixture/enviro = T.return_air() + local_temp = enviro.temperature + + else if(istype(loc, /mob/) && !owner) + var/mob/M = loc + if(is_type_in_list(M.loc, freezing_objects)) + if(!(organ_flags & ORGAN_FROZEN)) + organ_flags |= ORGAN_FROZEN + return TRUE + var/turf/T = M.loc + var/datum/gas_mixture/enviro = T.return_air() + local_temp = enviro.temperature + + if(owner) + //Don't interfere with bodies frozen by structures. + if(is_type_in_list(owner.loc, freezing_objects)) + if(!(organ_flags & ORGAN_FROZEN)) + organ_flags |= ORGAN_FROZEN + return TRUE + local_temp = owner.bodytemperature + + if(!local_temp)//Shouldn't happen but in case + return + if(local_temp < 154)//I have a pretty shaky citation that states -120 allows indefinite cyrostorage + organ_flags |= ORGAN_FROZEN + return TRUE + organ_flags &= ~ORGAN_FROZEN + return FALSE + +/obj/item/organ/proc/on_life() //repair organ damage if the organ is not failing + if(organ_flags & ORGAN_FAILING) + return + if(is_cold()) + return + ///Damage decrements by a percent of its maxhealth + var/healing_amount = -(maxHealth * healing_factor) + ///Damage decrements again by a percent of its maxhealth, up to a total of 4 extra times depending on the owner's health + healing_amount -= owner.satiety > 0 ? 4 * healing_factor * owner.satiety / MAX_SATIETY : 0 + applyOrganDamage(healing_amount) //to FERMI_TWEAK + //Make it so each threshold is stuck. /obj/item/organ/examine(mob/user) - ..() - if(status == ORGAN_ROBOTIC && crit_fail) - to_chat(user, "[src] seems to be broken!") + . = ..() + if(organ_flags & ORGAN_FAILING) + if(status == ORGAN_ROBOTIC) + . += "[src] seems to be broken!" + return + . += "[src] has decayed for too long, and has turned a sickly color! It doesn't look like it will work anymore!" + return + if(damage > high_threshold) + . += "[src] is starting to look discolored." /obj/item/organ/proc/prepare_eat() @@ -78,6 +176,10 @@ foodtype = RAW | MEAT | GROSS +/obj/item/organ/Initialize() + . = ..() + START_PROCESSING(SSobj, src) + /obj/item/organ/Destroy() if(owner) // The special flag is important, because otherwise mobs can die @@ -100,13 +202,66 @@ /obj/item/organ/item_action_slot_check(slot,mob/user) return //so we don't grant the organ's action to mobs who pick up the organ. +///Adjusts an organ's damage by the amount "d", up to a maximum amount, which is by default max damage +/obj/item/organ/proc/applyOrganDamage(var/d, var/maximum = maxHealth) //use for damaging effects + if(!d) //Micro-optimization. + return + if(maximum < damage) + return + damage = CLAMP(damage + d, 0, maximum) + var/mess = check_damage_thresholds(owner) + prev_damage = damage + if(mess && owner) + to_chat(owner, mess) + +///SETS an organ's damage to the amount "d", and in doing so clears or sets the failing flag, good for when you have an effect that should fix an organ if broken +/obj/item/organ/proc/setOrganDamage(var/d) //use mostly for admin heals + applyOrganDamage(d - damage) + +/** check_damage_thresholds + * input: M (a mob, the owner of the organ we call the proc on) + * output: returns a message should get displayed. + * description: By checking our current damage against our previous damage, we can decide whether we've passed an organ threshold. + * If we have, send the corresponding threshold message to the owner, if such a message exists. + */ +/obj/item/organ/proc/check_damage_thresholds(var/M) + if(damage == prev_damage) + return + var/delta = damage - prev_damage + if(delta > 0) + if(damage >= maxHealth) + organ_flags |= ORGAN_FAILING + return now_failing + if(damage > high_threshold && prev_damage <= high_threshold) + return high_threshold_passed + if(damage > low_threshold && prev_damage <= low_threshold) + return low_threshold_passed + else + organ_flags &= ~ORGAN_FAILING + if(!owner)//Processing is stopped when the organ is dead and outside of someone. This hopefully should restart it if a removed organ is repaired outside of a body. + START_PROCESSING(SSobj, src) + if(prev_damage > low_threshold && damage <= low_threshold) + return low_threshold_cleared + if(prev_damage > high_threshold && damage <= high_threshold) + return high_threshold_cleared + if(prev_damage == maxHealth) + return now_fixed + +//Runs some code on the organ when damage is taken/healed +/obj/item/organ/proc/onDamage(var/d, var/maximum = maxHealth) + return + +//Runs some code on the organ when damage is taken/healed +/obj/item/organ/proc/onSetDamage(var/d, var/maximum = maxHealth) + return + //Looking for brains? //Try code/modules/mob/living/carbon/brain/brain_item.dm /mob/living/proc/regenerate_organs() return 0 -/mob/living/carbon/regenerate_organs() +/mob/living/carbon/regenerate_organs(only_one = FALSE) var/breathes = TRUE var/blooded = TRUE if(dna && dna.species) @@ -125,6 +280,8 @@ else LI = new() LI.Insert(src) + if(only_one) + return TRUE if(has_stomach && !getorganslot(ORGAN_SLOT_STOMACH)) var/obj/item/organ/stomach/S @@ -134,14 +291,20 @@ else S = new() S.Insert(src) + if(only_one) + return TRUE if(breathes && !getorganslot(ORGAN_SLOT_LUNGS)) var/obj/item/organ/lungs/L = new() L.Insert(src) + if(only_one) + return TRUE if(blooded && !getorganslot(ORGAN_SLOT_HEART)) var/obj/item/organ/heart/H = new() H.Insert(src) + if(only_one) + return TRUE if(!getorganslot(ORGAN_SLOT_TONGUE)) var/obj/item/organ/tongue/T @@ -153,6 +316,20 @@ // if they have no mutant tongues, give them a regular one T.Insert(src) + if(only_one) + return TRUE + + else if (!only_one) + var/obj/item/organ/tongue/oT = getorganslot(ORGAN_SLOT_TONGUE) + if(oT.name == "fluffy tongue") + var/obj/item/organ/tongue/T + if(dna && dna.species && dna.species.mutanttongue) + T = new dna.species.mutanttongue() + else + T = new() + oT.Remove(src) + qdel(oT) + T.Insert(src) if(!getorganslot(ORGAN_SLOT_EYES)) var/obj/item/organ/eyes/E @@ -163,6 +340,8 @@ else E = new() E.Insert(src) + if(only_one) + return TRUE if(!getorganslot(ORGAN_SLOT_EARS)) var/obj/item/organ/ears/ears @@ -172,9 +351,13 @@ ears = new ears.Insert(src) + if(only_one) + return TRUE if(!getorganslot(ORGAN_SLOT_TAIL)) var/obj/item/organ/tail/tail if(dna && dna.species && dna.species.mutanttail) tail = new dna.species.mutanttail tail.Insert(src) + if(only_one) + return TRUE diff --git a/code/modules/surgery/organs/stomach.dm b/code/modules/surgery/organs/stomach.dm index 24132bcf04..a1624efd61 100755 --- a/code/modules/surgery/organs/stomach.dm +++ b/code/modules/surgery/organs/stomach.dm @@ -8,12 +8,42 @@ desc = "Onaka ga suite imasu." var/disgust_metabolism = 1 -/obj/item/organ/stomach/on_life() - var/mob/living/carbon/human/H = owner + healing_factor = STANDARD_ORGAN_HEALING + decay_factor = STANDARD_ORGAN_DECAY - if(istype(H)) - H.dna.species.handle_digestion(H) + low_threshold_passed = "Your stomach flashes with pain before subsiding. Food doesn't seem like a good idea right now." + high_threshold_passed = "Your stomach flares up with constant pain- you can hardly stomach the idea of food right now!" + high_threshold_cleared = "The pain in your stomach dies down for now, but food still seems unappealing." + low_threshold_cleared = "The last bouts of pain in your stomach have died out." + +/obj/item/organ/stomach/on_life() + ..() + var/datum/reagent/consumable/nutriment/Nutri + if(ishuman(owner)) + var/mob/living/carbon/human/H = owner + if(!(organ_flags & ORGAN_FAILING)) + H.dna.species.handle_digestion(H) handle_disgust(H) + Nutri = locate(/datum/reagent/consumable/nutriment) in H.reagents.reagent_list + + if(Nutri) + if(prob((damage/40) * Nutri.volume * Nutri.volume)) + H.vomit(damage) + to_chat(H, "Your stomach reels in pain as you're incapable of holding down all that food!") + + else if(Nutri && damage > high_threshold) + if(prob((damage/10) * Nutri.volume * Nutri.volume)) + H.vomit(damage) + to_chat(H, "Your stomach reels in pain as you're incapable of holding down all that food!") + + + else if(iscarbon(owner)) + var/mob/living/carbon/C = owner + Nutri = locate(/datum/reagent/consumable/nutriment) in C.reagents.reagent_list + + if(damage < low_threshold) + return + /obj/item/organ/stomach/proc/handle_disgust(mob/living/carbon/human/H) if(H.disgust) diff --git a/code/modules/surgery/organs/tongue.dm b/code/modules/surgery/organs/tongue.dm index ccfc21f878..cee20dddee 100644 --- a/code/modules/surgery/organs/tongue.dm +++ b/code/modules/surgery/organs/tongue.dm @@ -1,3 +1,5 @@ +#define TONGUE_MAX_HEALTH 60 + /obj/item/organ/tongue name = "tongue" desc = "A fleshy muscle mostly used for lying." @@ -8,6 +10,7 @@ var/list/languages_possible var/say_mod = null var/taste_sensitivity = 15 // lower is more sensitive. + maxHealth = TONGUE_MAX_HEALTH var/modifies_speech = FALSE var/static/list/languages_possible_base = typecacheof(list( /datum/language/common, @@ -20,6 +23,8 @@ /datum/language/aphasia, /datum/language/slime, )) + healing_factor = STANDARD_ORGAN_HEALING*5 //Fast!! + decay_factor = STANDARD_ORGAN_DECAY/2 /obj/item/organ/tongue/Initialize(mapload) . = ..() @@ -27,6 +32,36 @@ /obj/item/organ/tongue/proc/handle_speech(datum/source, list/speech_args) +/obj/item/organ/tongue/emp_act(severity) + . = ..() + if(. & EMP_PROTECT_SELF) + return + if(organ_flags & ORGAN_SYNTHETIC) + var/errormessage = list("Runtime in tongue.dm, line 39: Undefined operation \"zapzap ow my tongue\"", "afhsjifksahgjkaslfhashfjsak", "-1.#IND", "Graham's number", "inside you all along", "awaiting at least 1 approving review before merging this taste request") + owner.say("The pH is appropriately [pick(errormessage)].") + +/obj/item/organ/tongue/applyOrganDamage(var/d, var/maximum = maxHealth) + + if(!d) //Micro-optimization. + return + if(maximum < damage) + return + damage = CLAMP(damage + d, 0, maximum) + var/mess = check_damage_thresholds(owner) + prev_damage = damage + if(mess && owner) + to_chat(owner, mess) + + if ((damage / maxHealth) > 1) + to_chat(owner, "Your tongue is singed beyond recognition, and disintegrates!") + SSblackbox.record_feedback("tally", "fermi_chem", 1, "Tongues lost to Fermi") + qdel(src) + else if ((damage / maxHealth) > 0.85) + to_chat(owner, "Your tongue feels like it's about to fall out!.") + else if ((damage / maxHealth) > 0.5) + to_chat(owner, "Your tongue is really starting to hurt.") + + /obj/item/organ/tongue/Insert(mob/living/carbon/M, special = 0) ..() if(say_mod && M.dna && M.dna.species) @@ -51,6 +86,7 @@ icon_state = "tonguelizard" say_mod = "hisses" taste_sensitivity = 10 // combined nose + tongue, extra sensitive + maxHealth = 40 //extra sensitivity means tongue is more susceptible to damage modifies_speech = TRUE /obj/item/organ/tongue/lizard/handle_speech(datum/source, list/speech_args) @@ -68,6 +104,7 @@ icon_state = "tonguefly" say_mod = "buzzes" taste_sensitivity = 25 // you eat vomit, this is a mercy + maxHealth = 80 //years of eatting trash has made your tongue strong modifies_speech = TRUE /obj/item/organ/tongue/fly/handle_speech(datum/source, list/speech_args) @@ -85,6 +122,7 @@ icon_state = "tongueayylmao" say_mod = "gibbers" taste_sensitivity = 101 // ayys cannot taste anything. + maxHealth = 120 //Ayys probe a lot modifies_speech = TRUE /obj/item/organ/tongue/abductor/handle_speech(datum/source, list/speech_args) @@ -113,6 +151,7 @@ icon_state = "tonguezombie" say_mod = "moans" taste_sensitivity = 32 + maxHealth = 65 //Stop! It's already dead...! modifies_speech = TRUE /obj/item/organ/tongue/zombie/handle_speech(datum/source, list/speech_args) @@ -137,6 +176,7 @@ icon_state = "tonguexeno" say_mod = "hisses" taste_sensitivity = 10 // LIZARDS ARE ALIENS CONFIRMED + maxHealth = 500 //They've a little mouth for a tongue, so it's pretty rhobust modifies_speech = TRUE // not really, they just hiss var/static/list/languages_possible_alien = typecacheof(list( /datum/language/xenocommon, @@ -157,8 +197,10 @@ desc = "Apparently skeletons alter the sounds they produce through oscillation of their teeth, hence their characteristic rattling." icon_state = "tonguebone" say_mod = "rattles" + organ_flags = ORGAN_NO_SPOIL attack_verb = list("bitten", "chattered", "chomped", "enamelled", "boned") taste_sensitivity = 101 // skeletons cannot taste anything + maxHealth = 75 //Take brute damage instead modifies_speech = TRUE var/chattering = FALSE var/phomeme_type = "sans" @@ -168,6 +210,16 @@ . = ..() phomeme_type = pick(phomeme_types) +/obj/item/organ/tongue/bone/applyOrganDamage(var/d, var/maximum = maxHealth) + if(d < 0) + return + if(!owner) + return + var/target = owner.get_bodypart(BODY_ZONE_HEAD) + owner.apply_damage(d, BURN, target) + to_chat(owner, "You feel your skull burning! Oof, your bones!") + return + /obj/item/organ/tongue/bone/handle_speech(datum/source, list/speech_args) if (chattering) chatter(speech_args[SPEECH_MESSAGE], phomeme_type, source) @@ -181,6 +233,7 @@ name = "plasma bone \"tongue\"" desc = "Like animated skeletons, Plasmamen vibrate their teeth in order to produce speech." icon_state = "tongueplasma" + maxHealth = "alien" modifies_speech = FALSE /obj/item/organ/tongue/robot @@ -192,6 +245,7 @@ attack_verb = list("beeped", "booped") modifies_speech = TRUE taste_sensitivity = 25 // not as good as an organic tongue + maxHealth = 100 //RoboTongue! var/electronics_magic = TRUE /obj/item/organ/tongue/robot/can_speak_in_language(datum/language/dt) @@ -200,8 +254,41 @@ /obj/item/organ/tongue/robot/handle_speech(datum/source, list/speech_args) speech_args[SPEECH_SPANS] |= SPAN_ROBOT +/obj/item/organ/tongue/fluffy + name = "fluffy tongue" + desc = "OwO what's this?" + icon_state = "tonguefluffy" + taste_sensitivity = 10 // extra sensitive and inquisitive uwu + maxHealth = 35 //Sensitive tongue! + modifies_speech = TRUE + +/obj/item/organ/tongue/fluffy/handle_speech(datum/source, list/speech_args) + var/message = speech_args[SPEECH_MESSAGE] + if(copytext(message, 1, 2) != "*") + message = replacetext(message, "ne", "nye") + message = replacetext(message, "nu", "nyu") + message = replacetext(message, "na", "nya") + message = replacetext(message, "no", "nyo") + message = replacetext(message, "ove", "uv") + message = replacetext(message, "l", "w") + message = replacetext(message, "r", "w") + message = lowertext(message) + speech_args[SPEECH_MESSAGE] = message + +/obj/item/organ/tongue/cybernetic + name = "cybernetic tongue" + desc = "A state of the art robotic tongue that can detect the pH of anything drank." + icon_state = "tonguecybernetic" + taste_sensitivity = 10 + maxHealth = 60 //It's robotic! + organ_flags = ORGAN_SYNTHETIC + +/obj/item/organ/tongue/cybernetic/handle_speech(datum/source, list/speech_args) + speech_args[SPEECH_SPANS] |= SPAN_ROBOT + /obj/item/organ/tongue/robot/ipc name = "positronic voicebox" say_mod = "beeps" desc = "A voice synthesizer used by IPCs to smoothly interface with organic lifeforms." - electronics_magic = FALSE \ No newline at end of file + electronics_magic = FALSE + organ_flags = ORGAN_SYNTHETIC diff --git a/code/modules/surgery/organs/vocal_cords.dm b/code/modules/surgery/organs/vocal_cords.dm index ad13de0a01..009cfce0a5 100644 --- a/code/modules/surgery/organs/vocal_cords.dm +++ b/code/modules/surgery/organs/vocal_cords.dm @@ -26,12 +26,14 @@ zone = BODY_ZONE_HEAD slot = ORGAN_SLOT_ADAMANTINE_RESONATOR icon_state = "adamantine_resonator" + decay_factor = 0 /obj/item/organ/vocal_cords/adamantine name = "adamantine vocal cords" desc = "When adamantine resonates, it causes all nearby pieces of adamantine to resonate as well. Adamantine golems use this to broadcast messages to nearby golems." actions_types = list(/datum/action/item_action/organ_action/use/adamantine_vocal_cords) icon_state = "adamantine_cords" + decay_factor = 0 /datum/action/item_action/organ_action/use/adamantine_vocal_cords/Trigger() if(!IsAvailable()) @@ -62,6 +64,7 @@ var/cooldown_mod = 1 var/base_multiplier = 1 spans = list("colossus","yell") + decay_factor = 0 /datum/action/item_action/organ_action/colossus name = "Voice of God" @@ -575,7 +578,7 @@ cooldown = COOLDOWN_MEME for(var/V in listeners) var/mob/living/carbon/human/H = V - if(H.canbearoused && H.has_dna()) // probably a redundant check but for good measure + if(H.canbearoused && H.has_dna() && HAS_TRAIT(H, TRAIT_NYMPHO)) // probably a redundant check but for good measure H.mob_climax(forced_climax=TRUE) //DAB @@ -608,6 +611,863 @@ return cooldown +////////////////////////////////////// +///////ENTHRAL VELVET CHORDS////////// +////////////////////////////////////// + +//Heavily modified voice of god code +/obj/item/organ/vocal_cords/velvet + name = "Velvet chords" + desc = "The voice spoken from these just make you want to drift off, sleep and obey." + icon_state = "velvet_chords" + actions_types = list(/datum/action/item_action/organ_action/velvet) + spans = list("velvet") + +/datum/action/item_action/organ_action/velvet + name = "Velvet chords" + var/obj/item/organ/vocal_cords/velvet/cords = null + +/datum/action/item_action/organ_action/velvet/New() + ..() + cords = target + +/datum/action/item_action/organ_action/velvet/IsAvailable() + return TRUE + +/datum/action/item_action/organ_action/velvet/Trigger() + . = ..() + var/command = input(owner, "Speak in a sultry tone", "Command") + if(QDELETED(src) || QDELETED(owner)) + return + if(!command) + return + owner.say(".x[command]") + +/obj/item/organ/vocal_cords/velvet/can_speak_with() + return TRUE + +/obj/item/organ/vocal_cords/velvet/handle_speech(message) //actually say the message + owner.say(message, spans = spans, sanitize = FALSE) + velvetspeech(message, owner, 1) + +////////////////////////////////////// +///////////FermiChem////////////////// +////////////////////////////////////// +//Removed span_list from input arguments. +/proc/velvetspeech(message, mob/living/user, base_multiplier = 1, message_admins = FALSE, debug = FALSE) + + if(!user || !user.can_speak() || user.stat) + return 0 //no cooldown + + var/log_message = message + + //FIND THRALLS + message = lowertext(message) + var/mob/living/list/listeners = list() + for(var/mob/living/L in get_hearers_in_view(8, user)) + if(L.can_hear() && !L.anti_magic_check(FALSE, TRUE) && L.stat != DEAD) + if(L.has_status_effect(/datum/status_effect/chem/enthrall))//Check to see if they have the status + var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)//Check to see if pet is on cooldown from last command and if the master is right + if(E.master != user) + continue + if(ishuman(L)) + var/mob/living/carbon/human/H = L + if(istype(H.ears, /obj/item/clothing/ears/earmuffs)) + continue + + if (E.cooldown > 0)//If they're on cooldown you can't give them more commands. + continue + listeners += L + + if(!listeners.len) + return 0 + + //POWER CALCULATIONS + + var/power_multiplier = base_multiplier + + // Not sure I want to give extra power to anyone at the moment...? We'll see how it turns out + if(user.mind) + //Chaplains are very good at indoctrinating + if(user.mind.assigned_role == "Chaplain") + power_multiplier *= 1.2 + //Command staff has authority + if(user.mind.assigned_role in GLOB.command_positions) + power_multiplier *= 1.1 + //Why are you speaking + if(user.mind.assigned_role == "Mime") + power_multiplier *= 0.5 + + //Cultists are closer to their gods and are better at indoctrinating + if(iscultist(user)) + power_multiplier *= 1.2 + else if (is_servant_of_ratvar(user)) + power_multiplier *= 1.2 + else if (is_devil(user))//The devil is supposed to be seductive, right? + power_multiplier *= 1.2 + + //range = 0.5 - 1.4~ + //most cases = 1 + + //Try to check if the speaker specified a name or a job to focus on + var/list/specific_listeners = list() + var/found_string = null + + //Get the proper job titles + message = get_full_job_name(message) + + for(var/V in listeners) + var/mob/living/L = V + if(dd_hasprefix(message, L.real_name)) + specific_listeners += L //focus on those with the specified name + //Cut out the name so it doesn't trigger commands + found_string = L.real_name + power_multiplier += 0.5 + + else if(dd_hasprefix(message, L.first_name())) + specific_listeners += L //focus on those with the specified name + //Cut out the name so it doesn't trigger commands + found_string = L.first_name() + power_multiplier += 0.5 + + else if(L.mind && L.mind.assigned_role && dd_hasprefix(message, L.mind.assigned_role)) + specific_listeners += L //focus on those with the specified job + //Cut out the job so it doesn't trigger commands + found_string = L.mind.assigned_role + power_multiplier += 0.25 + + if(specific_listeners.len) + listeners = specific_listeners + //power_multiplier *= (1 + (1/specific_listeners.len)) //Put this is if it becomes OP, power is judged internally on a thrall, so shouldn't be nessicary. + message = copytext(message, 0, 1)+copytext(message, 1 + length(found_string), length(message) + 1)//I have no idea what this does + + var/obj/item/organ/tongue/T = user.getorganslot(ORGAN_SLOT_TONGUE) + if (T.name == "fluffy tongue") //If you sound hillarious, it's hard to take you seriously. This is a way for other players to combat/reduce their effectiveness. + power_multiplier *= 0.75 + + if(debug == TRUE) + to_chat(world, "[user]'s power is [power_multiplier].") + + //Mixables + var/static/regex/enthral_words = regex("relax|obey|love|serve|docile|so easy|ara ara") + var/static/regex/reward_words = regex("good boy|good girl|good pet|good job") + var/static/regex/punish_words = regex("bad boy|bad girl|bad pet|bad job") + //phase 0 + var/static/regex/saymyname_words = regex("say my name|who am i|whoami") + var/static/regex/wakeup_words = regex("revert|awaken|snap") //works + //phase1 + var/static/regex/petstatus_words = regex("how are you|what is your status|are you okay") + var/static/regex/silence_words = regex("shut up|silence|be silent|ssh|quiet|hush") + var/static/regex/speak_words = regex("talk to me|speak") + var/static/regex/antiresist_words = regex("unable to resist|give in")//useful if you think your target is resisting a lot + var/static/regex/resist_words = regex("resist|snap out of it|fight")//useful if two enthrallers are fighting + var/static/regex/forget_words = regex("forget|muddled|awake and forget") + var/static/regex/attract_words = regex("come here|come to me|get over here|attract") + //phase 2 + var/static/regex/orgasm_words = regex("cum|orgasm|climax|squirt|heyo") //wah, lewd + var/static/regex/awoo_words = regex("howl|awoo|bark") + var/static/regex/nya_words = regex("nya|meow|mewl") + var/static/regex/sleep_words = regex("sleep|slumber|rest") + var/static/regex/strip_words = regex("strip|derobe|nude") + var/static/regex/walk_words = regex("slow down|walk") + var/static/regex/run_words = regex("run|speed up") + var/static/regex/liedown_words = regex("lie down") //TO ADD + var/static/regex/knockdown_words = regex("drop|fall|trip|knockdown|kneel") + //phase 3 + var/static/regex/statecustom_words = regex("state triggers|state your triggers") + var/static/regex/custom_words = regex("new trigger|listen to me") + var/static/regex/custom_words_words = regex("speak|echo|shock|cum|kneel|strip|trance")//What a descriptive name! + var/static/regex/custom_echo = regex("obsess|fills your mind|loop") + var/static/regex/instill_words = regex("feel|entice|overwhel") + var/static/regex/recognise_words = regex("recognise me|did you miss me?") + var/static/regex/objective_words = regex("new objective|obey this command|unable to resist|compulsed") + var/static/regex/heal_words = regex("live|heal|survive|mend|life|pets never die") + var/static/regex/stun_words = regex("stop|wait|stand still|hold on|halt") + var/static/regex/hallucinate_words = regex("get high|hallucinate") + var/static/regex/hot_words = regex("heat|hot|hell") + var/static/regex/cold_words = regex("cold|cool down|chill|freeze") + var/static/regex/getup_words = regex("get up") + var/static/regex/pacify_words = regex("more and more docile|complaisant|friendly|pacifist") + var/static/regex/charge_words = regex("charge|oorah|attack") + + var/distancelist = list(2,2,1.5,1.3,1.15,1,0.8,0.6,0.5,0.25) + + //CALLBACKS ARE USED FOR MESSAGES BECAUSE SAY IS HANDLED AFTER THE PROCESSING. + + //Tier 1 + //ENTHRAL mixable (works I think) + if(findtext(message, enthral_words)) + for(var/V in listeners) + var/mob/living/L = V + var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall) + power_multiplier *= distancelist[get_dist(user, V)+1] + if(L == user) + continue + if(length(message)) + E.enthrallTally += (power_multiplier*(((length(message))/200) + 1)) //encourage players to say more than one word. + else + E.enthrallTally += power_multiplier*1.25 //thinking about it, I don't know how this can proc + if(L.canbearoused) + if(L.client?.prefs.lewdchem) + addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "[E.enthrallGender] is so nice to listen to."), 5) + E.cooldown += 1 + + //REWARD mixable works + if(findtext(message, reward_words)) + for(var/V in listeners) + var/mob/living/L = V + var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall) + power_multiplier *= distancelist[get_dist(user, V)+1] + if(L == user) + continue + if (L.client?.prefs.lewdchem) + addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "[E.enthrallGender] has praised me!!"), 5) + if(HAS_TRAIT(L, TRAIT_NYMPHO)) + L.adjustArousalLoss(2*power_multiplier) + if(HAS_TRAIT(L, TRAIT_MASO)) + E.enthrallTally -= power_multiplier + E.resistanceTally += power_multiplier + E.cooldown += 1 + else + addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "I've been praised for doing a good job!"), 5) + E.resistanceTally -= power_multiplier + E.enthrallTally += power_multiplier + var/descmessage = "[(L.client?.prefs.lewdchem?"I feel so happy! I'm a good pet who [E.enthrallGender] loves!":"I did a good job!")]" + SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "enthrallpraise", /datum/mood_event/enthrallpraise, descmessage) + E.cooldown += 1 + + //PUNISH mixable works + else if(findtext(message, punish_words)) + for(var/V in listeners) + var/mob/living/L = V + var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall) + var/descmessage = "[(L.client?.prefs.lewdchem?"I've failed [E.enthrallGender]... What a bad, bad pet!":"I did a bad job...")]" + if(L == user) + continue + if (L.client?.prefs.lewdchem) + if(HAS_TRAIT(L, TRAIT_MASO)) + L.adjustArousalLoss(3*power_multiplier) + descmessage += "And yet, it feels so good..!" //I don't really understand masco, is this the right sort of thing they like? + E.enthrallTally += power_multiplier + E.resistanceTally -= power_multiplier + addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "I've let [E.enthrallGender] down...!"), 5) + else + addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "I've let [E.enthrallGender] down..."), 5) + else + addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "I've failed [E.master]..."), 5) + E.resistanceTally += power_multiplier + E.enthrallTally += power_multiplier + E.cooldown += 1 + SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "enthrallscold", /datum/mood_event/enthrallscold, descmessage) + E.cooldown += 1 + + + + //teir 0 + //SAY MY NAME works + if((findtext(message, saymyname_words))) + for(var/V in listeners) + var/mob/living/carbon/C = V + var/datum/status_effect/chem/enthrall/E = C.has_status_effect(/datum/status_effect/chem/enthrall) + REMOVE_TRAIT(C, TRAIT_MUTE, "enthrall") + C.silent = 0 + if(C.client?.prefs.lewdchem) + addtimer(CALLBACK(C, /atom/movable/proc/say, "[E.enthrallGender]"), 5) + else + addtimer(CALLBACK(C, /atom/movable/proc/say, "[E.master]"), 5) + + //WAKE UP + else if((findtext(message, wakeup_words))) + for(var/V in listeners) + var/mob/living/L = V + var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall) + L.SetSleeping(0)//Can you hear while asleep? + switch(E.phase) + if(0) + E.phase = 3 + E.status = null + user.emote("snap") + if(L.client?.prefs.lewdchem) + addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "The snapping of your [E.enthrallGender]'s fingers brings you back to your enthralled state, obedient and ready to serve."), 5) + else + addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "The snapping of [E.master]'s fingers brings you back to being under their influence."), 5) + to_chat(user, "You wake up [L]!") + + //tier 1 + + //PETSTATUS i.e. how they are + else if((findtext(message, petstatus_words))) + for(var/V in listeners) + var/mob/living/carbon/human/H = V + var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall) + REMOVE_TRAIT(H, TRAIT_MUTE, "enthrall") + var/speaktrigger = "" + //phase + switch(E.phase) + if(0) + continue + if(1) + addtimer(CALLBACK(H, /atom/movable/proc/say, "I feel happy being with you."), 5) + continue + if(2) + speaktrigger += "[(H.client?.prefs.lewdchem?"I think I'm in love with you... ":"I find you really inspirational, ")]" //' + if(3) + speaktrigger += "[(H.client?.prefs.lewdchem?"I'm devoted to being your pet":"I'm commited to following your cause!")]! " + if(4) + speaktrigger += "[(H.client?.prefs.lewdchem?"You are my whole world and all of my being belongs to you, ":"I cannot think of anything else but aiding your cause, ")] "//Redflags!! + + //mood + GET_COMPONENT_FROM(mood, /datum/component/mood, H) + switch(mood.sanity) + if(SANITY_GREAT to INFINITY) + speaktrigger += "I'm beyond elated!! " //did you mean byond elated? hohoho + if(SANITY_NEUTRAL to SANITY_GREAT) + speaktrigger += "I'm really happy! " + if(SANITY_DISTURBED to SANITY_NEUTRAL) + speaktrigger += "I'm a little sad, " + if(SANITY_UNSTABLE to SANITY_DISTURBED) + speaktrigger += "I'm really upset, " + if(SANITY_CRAZY to SANITY_UNSTABLE) + speaktrigger += "I'm about to fall apart without you! " + if(SANITY_INSANE to SANITY_CRAZY) + speaktrigger += "Hold me, please.. " + + //Withdrawal + switch(E.withdrawalTick) + if(10 to 36) //denial + speaktrigger += "I missed you, " + if(36 to 66) //barganing + speaktrigger += "I missed you, but I knew you'd come back for me! " + if(66 to 90) //anger + speaktrigger += "I couldn't take being away from you like that, " + if(90 to 140) //depression + speaktrigger += "I was so scared you'd never come back, " + if(140 to INFINITY) //acceptance + speaktrigger += "I'm hurt that you left me like that... I felt so alone... " + + //hunger + switch(H.nutrition) + if(0 to NUTRITION_LEVEL_STARVING) + speaktrigger += "I'm famished, please feed me..! " + if(NUTRITION_LEVEL_STARVING to NUTRITION_LEVEL_HUNGRY) + speaktrigger += "I'm so hungry... " + if(NUTRITION_LEVEL_HUNGRY to NUTRITION_LEVEL_FED) + speaktrigger += "I'm hungry, " + if(NUTRITION_LEVEL_FED to NUTRITION_LEVEL_WELL_FED) + speaktrigger += "I'm sated, " + if(NUTRITION_LEVEL_WELL_FED to NUTRITION_LEVEL_FULL) + speaktrigger += "I've a full belly! " + if(NUTRITION_LEVEL_FULL to INFINITY) + speaktrigger += "I'm fat... " + + //health + switch(H.health) + if(100 to INFINITY) + speaktrigger += "I feel fit, " + if(80 to 99) + speaktrigger += "I ache a little bit, " + if(40 to 80) + speaktrigger += "I'm really hurt, " + if(0 to 40) + speaktrigger += "I'm in a lot of pain, help! " + if(-INFINITY to 0) + speaktrigger += "I'm barely concious and in so much pain, please help me! " + //toxin + switch(H.getToxLoss()) + if(10 to 30) + speaktrigger += "I feel a bit queasy... " + if(30 to 60) + speaktrigger += "I feel nauseous... " + if(60 to INFINITY) + speaktrigger += "My head is pounding and I feel like I'm going to be sick... " + //oxygen + if (H.getOxyLoss() >= 25) + speaktrigger += "I can't breathe! " + //blind + if (HAS_TRAIT(H, TRAIT_BLIND)) + speaktrigger += "I can't see! " + //deaf..? + if (HAS_TRAIT(H, TRAIT_DEAF))//How the heck you managed to get here I have no idea, but just in case! + speaktrigger += "I can barely hear you! " + //And the brain damage. And the brain damage. And the brain damage. And the brain damage. And the brain damage. + switch(H.getOrganLoss(ORGAN_SLOT_BRAIN)) + if(20 to 40) + speaktrigger += "I have a mild head ache, " + if(40 to 80) + speaktrigger += "I feel disorentated and confused, " + if(80 to 120) + speaktrigger += "My head feels like it's about to explode, " + if(120 to 160) + speaktrigger += "You are the only thing keeping my mind sane, " + if(160 to INFINITY) + speaktrigger += "I feel like I'm on the brink of losing my mind, " + + //horny + if(HAS_TRAIT(H, TRAIT_NYMPHO) && H.canbearoused && H.client?.prefs.lewdchem) + switch(H.getArousalLoss()) + if(40 to 60) + speaktrigger += "I'm feeling a little horny, " + if(60 to 80) + speaktrigger += "I'm feeling horny, " + if(80 to INFINITY) + speaktrigger += "I'm really, really horny, " + + //collar + if(istype(H.wear_neck, /obj/item/clothing/neck/petcollar)) + speaktrigger += "I love the collar you gave me, " + //End + if(H.client?.prefs.lewdchem) + speaktrigger += "[E.enthrallGender]!" + else + speaktrigger += "[user.first_name()]!" + //say it! + addtimer(CALLBACK(H, /atom/movable/proc/say, "[speaktrigger]"), 5) + E.cooldown += 1 + + //SILENCE + else if((findtext(message, silence_words))) + for(var/mob/living/carbon/C in listeners) + var/datum/status_effect/chem/enthrall/E = C.has_status_effect(/datum/status_effect/chem/enthrall) + power_multiplier *= distancelist[get_dist(user, C)+1] + if (E.phase >= 3) //If target is fully enthralled, + ADD_TRAIT(C, TRAIT_MUTE, "enthrall") + else + C.silent += ((10 * power_multiplier) * E.phase) + addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, C, "You are unable to speak!"), 5) + to_chat(user, "You silence [C].") + E.cooldown += 3 + + //SPEAK + else if((findtext(message, speak_words)))//fix + for(var/mob/living/carbon/C in listeners) + var/datum/status_effect/chem/enthrall/E = C.has_status_effect(/datum/status_effect/chem/enthrall) + REMOVE_TRAIT(C, TRAIT_MUTE, "enthrall") + C.silent = 0 + E.cooldown += 3 + to_chat(user, "You [(C.client?.prefs.lewdchem?"allow [C] to speak again":"encourage [C] to speak again")].") + + + //Antiresist + else if((findtext(message, antiresist_words))) + for(var/V in listeners) + var/mob/living/L = V + var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall) + E.status = "Antiresist" + addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "Your mind clouds over, as you find yourself unable to resist!"), 5) + E.statusStrength = (1 * power_multiplier * E.phase) + E.cooldown += 15//Too short? yes, made 15 + to_chat(user, "You frustrate [L]'s attempts at resisting.") + + //RESIST + else if((findtext(message, resist_words))) + for(var/mob/living/carbon/C in listeners) + var/datum/status_effect/chem/enthrall/E = C.has_status_effect(/datum/status_effect/chem/enthrall) + power_multiplier *= distancelist[get_dist(user, C)+1] + E.deltaResist += (power_multiplier) + E.owner_resist() + E.cooldown += 2 + addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, C, "You are spurred into resisting from [user]'s words!'"), 5) + to_chat(user, "You spark resistance in [C].") + + //FORGET (A way to cancel the process) + else if((findtext(message, forget_words))) + for(var/mob/living/carbon/C in listeners) + var/datum/status_effect/chem/enthrall/E = C.has_status_effect(/datum/status_effect/chem/enthrall) + if(E.phase == 4) + addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, C, "You're unable to forget about [(C.client?.prefs.lewdchem?"the dominating presence of [E.enthrallGender]":"[E.master]")]!"), 5) + continue + addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, C, "You wake up, forgetting everything that just happened. You must've dozed off..? How embarassing!"), 5) + C.Sleeping(50) + switch(E.phase) + if(1 to 2) + E.phase = -1 + to_chat(C, "You have no recollection of being enthralled by [E.master]!") + to_chat(user, "You revert [C] back to their state before enthrallment.") + if(3) + E.phase = 0 + E.cooldown = 0 + if(C.client?.prefs.lewdchem) + addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, C, "You revert to yourself before being enthralled by your [E.enthrallGender], with no memory of what happened."), 5) + else + addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, C, "You revert to who you were before, with no memory of what happened with [E.master]."), 5) + to_chat(user, "You put [C] into a sleeper state, ready to turn them back at the snap of your fingers.") + + //ATTRACT + else if((findtext(message, attract_words))) + for(var/V in listeners) + var/mob/living/L = V + var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall) + L.throw_at(get_step_towards(user,L), 3 * power_multiplier, 1 * power_multiplier) + E.cooldown += 3 + addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "You are drawn towards [user]!"), 5) + to_chat(user, "You draw [L] towards you!") + + + //teir 2 + + /* removed for now + //ORGASM + else if((findtext(message, orgasm_words))) + for(var/V in listeners) + var/mob/living/carbon/human/H = V + var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall) + if(E.phase > 1) + if(HAS_TRAIT(H, TRAIT_NYMPHO) && H.canbearoused && H.client?.prefs.lewdchem) // probably a redundant check but for good measure + addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, H, "Your [E.enthrallGender] pushes you over the limit, overwhelming your body with pleasure."), 5) + H.mob_climax(forced_climax=TRUE) + H.SetStun(20) + H.setArousalLoss(H.min_arousal) + E.resistanceTally = 0 //makes resistance 0, but resets arousal, resistance buildup is faster unaroused (massively so). + E.enthrallTally += power_multiplier + E.cooldown += 6 + else + H.throw_at(get_step_towards(user,H), 3 * power_multiplier, 1 * power_multiplier) + */ + + + //awoo + else if((findtext(message, awoo_words))) + for(var/V in listeners) + var/mob/living/carbon/human/H = V + var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall) + switch(E.phase) + if(2 to INFINITY) + H.say("*awoo") + E.cooldown += 1 + + //Nya + else if((findtext(message, nya_words))) + for(var/V in listeners) + var/mob/living/carbon/human/H = V + var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall) + switch(E.phase) + if(2 to INFINITY) + playsound(get_turf(H), pick('sound/effects/meow1.ogg', 'modular_citadel/sound/voice/nya.ogg'), 50, 1, -1) //I'm very tempted to write a Fermis clause that makes them merowr.ogg if it's me. But, I also don't think snowflakism is okay. I would've gotten away for it too, if it wern't for my morals. + H.emote("me", 1, "lets out a nya!") + E.cooldown += 1 + + //SLEEP + else if((findtext(message, sleep_words))) + for(var/mob/living/carbon/C in listeners) + var/datum/status_effect/chem/enthrall/E = C.has_status_effect(/datum/status_effect/chem/enthrall) + switch(E.phase) + if(2 to INFINITY) + C.Sleeping(45 * power_multiplier) + E.cooldown += 10 + addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, C, "Drowsiness suddenly overwhelms you as you fall asleep!"), 5) + to_chat(user, "You send [C] to sleep.") + + //STRIP + else if((findtext(message, strip_words))) + for(var/V in listeners) + var/mob/living/carbon/human/H = V + var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall) + switch(E.phase) + if(2 to INFINITY) + var/items = H.get_contents() + for(var/obj/item/W in items) + if(W == H.wear_suit) + H.dropItemToGround(W, TRUE) + addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, H, "Before you can even think about it, you quickly remove your clothes in response to [(H.client?.prefs.lewdchem?"your [E.enthrallGender]'s command'":"[E.master]'s directive'")]."), 5) + E.cooldown += 10 + + //WALK + else if((findtext(message, walk_words))) + for(var/V in listeners) + var/mob/living/L = V + var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall) + switch(E.phase) + if(2 to INFINITY) + if(L.m_intent != MOVE_INTENT_WALK) + L.toggle_move_intent() + E.cooldown += 1 + addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "You slow down to a walk."), 5) + to_chat(user, "You encourage [L] to slow down.") + + //RUN + else if((findtext(message, run_words))) + for(var/V in listeners) + var/mob/living/L = V + var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall) + switch(E.phase) + if(2 to INFINITY) + if(L.m_intent != MOVE_INTENT_RUN) + L.toggle_move_intent() + E.cooldown += 1 + addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "You speed up into a jog!"), 5) + to_chat(user, "You encourage [L] to pick up the pace!") + + //LIE DOWN + else if(findtext(message, liedown_words)) + for(var/V in listeners) + var/mob/living/L = V + var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall) + switch(E.phase) + if(2 to INFINITY) + L.lay_down() + E.cooldown += 10 + addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "[(L.client?.prefs.lewdchem?"You eagerly lie down!":"You suddenly lie down!")]"), 5) + to_chat(user, "You encourage [L] to lie down.") + + //KNOCKDOWN + else if(findtext(message, knockdown_words)) + for(var/V in listeners) + var/mob/living/L = V + var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall) + switch(E.phase) + if(2 to INFINITY) + L.Knockdown(30 * power_multiplier * E.phase) + E.cooldown += 8 + addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "You suddenly drop to the ground!"), 5) + to_chat(user, "You encourage [L] to drop down to the ground.") + + //tier3 + + //STATE TRIGGERS + else if((findtext(message, statecustom_words)))//doesn't work + for(var/V in listeners) + var/mob/living/carbon/C = V + var/datum/status_effect/chem/enthrall/E = C.has_status_effect(/datum/status_effect/chem/enthrall) + if (E.phase == 3) + var/speaktrigger = "" + C.emote("me", 1, "whispers something quietly.") + if (get_dist(user, C) > 1)//Requires user to be next to their pet. + to_chat(user, "You need to be next to your pet to hear them!") + continue + for (var/trigger in E.customTriggers) + speaktrigger += "[trigger], " + to_chat(user, "[C] whispers, \"[speaktrigger] are my triggers.\"")//So they don't trigger themselves! + addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, C, "You whisper your triggers to [(C.client?.prefs.lewdchem?"Your [E.enthrallGender]":"[E.master]")]."), 5) + + + //CUSTOM TRIGGERS + else if((findtext(message, custom_words))) + for(var/V in listeners) + var/mob/living/carbon/human/H = V + var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall) + if(E.phase == 3) + if (get_dist(user, H) > 1)//Requires user to be next to their pet. + to_chat(user, "You need to be next to your pet to give them a new trigger!") + continue + else + user.emote("me", 1, "puts their hands upon [H.name]'s head and looks deep into their eyes, whispering something to them.") + user.SetStun(1000)//Hands are handy, so you have to stay still + H.SetStun(1000) + if (E.mental_capacity >= 5) + var/trigger = html_decode(stripped_input(user, "Enter the trigger phrase", MAX_MESSAGE_LEN)) + var/custom_words_words_list = list("Speak", "Echo", "Shock", "Cum", "Kneel", "Strip", "Trance", "Cancel") + var/trigger2 = input(user, "Pick an effect", "Effects") in custom_words_words_list + trigger2 = lowertext(trigger2) + if ((findtext(trigger2, custom_words_words))) + if (trigger2 == "speak" || trigger2 == "echo") + var/trigger3 = html_decode(stripped_input(user, "Enter the phrase spoken. Abusing this to self antag is bannable.", MAX_MESSAGE_LEN)) + E.customTriggers[trigger] = list(trigger2, trigger3) + log_game("FERMICHEM: [H] has been implanted by [user] with [trigger], triggering [trigger2], to send [trigger3].") + if(findtext(trigger3, "admin")) + message_admins("FERMICHEM: [user] maybe be trying to abuse MKUltra by implanting by [H] with [trigger], triggering [trigger2], to send [trigger3].") + else + E.customTriggers[trigger] = trigger2 + log_game("FERMICHEM: [H] has been implanted by [user] with [trigger], triggering [trigger2].") + E.mental_capacity -= 5 + addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, H, "[(H.client?.prefs.lewdchem?"your [E.enthrallGender]":"[E.master]")] whispers you a new trigger."), 5) + to_chat(user, "You sucessfully set the trigger word [trigger] in [H]") + else + to_chat(user, "Your pet looks at you confused, it seems they don't understand that effect!") + else + to_chat(user, "Your pet looks at you with a vacant blase expression, you don't think you can program anything else into them") + user.SetStun(0) + H.SetStun(0) + + //CUSTOM ECHO + else if((findtext(message, custom_echo))) + for(var/V in listeners) + var/mob/living/carbon/human/H = V + var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall) + if(E.phase == 3) + if (get_dist(user, H) > 1)//Requires user to be next to their pet. + to_chat(user, "You need to be next to your pet to give them a new echophrase!") + continue + else + user.emote("me", 1, "puts their hands upon [H.name]'s head and looks deep into their eyes, whispering something to them.") + user.SetStun(1000)//Hands are handy, so you have to stay still + H.SetStun(1000) + var/trigger = stripped_input(user, "Enter the loop phrase", MAX_MESSAGE_LEN) + var/customSpan = list("Notice", "Warning", "Hypnophrase", "Love", "Velvet") + var/trigger2 = input(user, "Pick the style", "Style") in customSpan + trigger2 = lowertext(trigger2) + E.customEcho = trigger + E.customSpan = trigger2 + user.SetStun(0) + H.SetStun(0) + to_chat(user, "You sucessfully set an echoing phrase in [H]") + + //CUSTOM OBJECTIVE + else if((findtext(message, objective_words))) + for(var/V in listeners) + var/mob/living/carbon/human/H = V + var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall) + if(E.phase == 3) + if (get_dist(user, H) > 1)//Requires user to be next to their pet. + to_chat(user, "You need to be next to your pet to give them a new objective!") + continue + else + user.emote("me", 1, "puts their hands upon [H.name]'s head and looks deep into their eyes, whispering something to them.'") + user.SetStun(1000)//So you can't run away! + H.SetStun(1000) + if (E.mental_capacity >= 200) + var/datum/objective/brainwashing/objective = stripped_input(user, "Add an objective to give your pet.", MAX_MESSAGE_LEN) + if(!LAZYLEN(objective)) + to_chat(user, "You can't give your pet an objective to do nothing!") + continue + //Pets don't understand harm + objective = replacetext(lowertext(objective), "kill", "hug") + objective = replacetext(lowertext(objective), "murder", "cuddle") + objective = replacetext(lowertext(objective), "harm", "snuggle") + objective = replacetext(lowertext(objective), "decapitate", "headpat") + objective = replacetext(lowertext(objective), "strangle", "meow at") + objective = replacetext(lowertext(objective), "suicide", "self-love") + message_admins("[H] has been implanted by [user] with the objective [objective].") + log_game("FERMICHEM: [H] has been implanted by [user] with the objective [objective] via MKUltra.") + addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, H, "[(H.client?.prefs.lewdchem?"Your [E.enthrallGender]":"[E.master]")] whispers you a new objective."), 5) + brainwash(H, objective) + E.mental_capacity -= 200 + to_chat(user, "You sucessfully give an objective to [H]") + else + to_chat(user, "Your pet looks at you with a vacant blasé expression, you don't think you can program anything else into them") + user.SetStun(0) + H.SetStun(0) + + //INSTILL + else if((findtext(message, instill_words))) + for(var/V in listeners) + var/mob/living/carbon/human/H = V + var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall) + if(E.phase == 3 && H.client?.prefs.lewdchem) + var/instill = stripped_input(user, "Instill an emotion in your [(user.client?.prefs.lewdchem?"Your pet":"listener")].", MAX_MESSAGE_LEN) + to_chat(H, "[instill]") + to_chat(user, "You sucessfully instill a feeling in [H]") + log_game("FERMICHEM: [H] has been instilled by [user] with [instill] via MKUltra.") + E.cooldown += 1 + + //RECOGNISE + else if((findtext(message, recognise_words))) + for(var/V in listeners) + var/mob/living/carbon/human/H = V + var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall) + if(E.phase > 1) + if(user.ckey == E.enthrallID && user.real_name == E.master.real_name) + E.master = user + addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, H, "[(H.client?.prefs.lewdchem?"You hear the words of your [E.enthrallGender] again!! They're back!!":"You recognise the voice of [E.master].")]"), 5) + to_chat(user, "[H] looks at you with sparkling eyes, recognising you!") + + //I dunno how to do state objectives without them revealing they're an antag + + //HEAL (maybe make this nap instead?) + else if(findtext(message, heal_words)) + for(var/V in listeners) + var/mob/living/L = V + var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall) + switch(E.phase) + if(3)//Tier 3 only + E.status = "heal" + E.statusStrength = (5 * power_multiplier) + E.cooldown += 5 + addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "You begin to lick your wounds."), 5) + L.Stun(15 * power_multiplier) + to_chat(user, "[L] begins to lick their wounds.") + + //STUN + else if(findtext(message, stun_words)) + for(var/V in listeners) + var/mob/living/L = V + var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall) + switch(E.phase) + if(3 to INFINITY) + L.Stun(40 * power_multiplier) + E.cooldown += 8 + addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "Your muscles freeze up!"), 5) + to_chat(user, "You cause [L] to freeze up!") + + //HALLUCINATE + else if(findtext(message, hallucinate_words)) + for(var/V in listeners) + var/mob/living/carbon/C = V + var/datum/status_effect/chem/enthrall/E = C.has_status_effect(/datum/status_effect/chem/enthrall) + switch(E.phase) + if(3 to INFINITY) + new /datum/hallucination/delusion(C, TRUE, null,150 * power_multiplier,0) + to_chat(user, "You send [C] on a trip.") + + //HOT + else if(findtext(message, hot_words)) + for(var/V in listeners) + var/mob/living/L = V + var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall) + switch(E.phase) + if(3 to INFINITY) + L.adjust_bodytemperature(50 * power_multiplier)//This seems nuts, reduced it, but then it didn't do anything, so I reverted it. + addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "You feel your metabolism speed up!"), 5) + to_chat(user, "You speed [L]'s metabolism up!") + + //COLD + else if(findtext(message, cold_words)) + for(var/V in listeners) + var/mob/living/L = V + var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall) + switch(E.phase) + if(3 to INFINITY) + L.adjust_bodytemperature(-50 * power_multiplier) + addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "You feel your metabolism slow down!"), 5) + to_chat(user, "You slow [L]'s metabolism down!") + + //GET UP + else if(findtext(message, getup_words)) + for(var/V in listeners) + var/mob/living/L = V + var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall) + switch(E.phase) + if(3 to INFINITY)//Tier 3 only + if(L.resting) + L.lay_down() //aka get up + L.SetStun(0) + L.SetKnockdown(0) + L.SetUnconscious(0) //i said get up i don't care if you're being tased + E.cooldown += 10 //This could be really strong + addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "You jump to your feet from sheer willpower!"), 5) + to_chat(user, "You spur [L] to their feet!") + + //PACIFY + else if(findtext(message, pacify_words)) + for(var/V in listeners) + var/mob/living/L = V + var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall) + switch(E.phase) + if(3)//Tier 3 only + E.status = "pacify" + E.cooldown += 10 + addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "You feel like never hurting anyone ever again."), 5) + to_chat(user, "You remove any intent to harm from [L]'s mind.") + + //CHARGE + else if(findtext(message, charge_words)) + for(var/V in listeners) + var/mob/living/L = V + var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall) + switch(E.phase) + if(3)//Tier 3 only + E.statusStrength = 2* power_multiplier + E.status = "charge" + E.cooldown += 10 + to_chat(user, "You rally [L], leading them into a charge!") + + if(message_admins || debug)//Do you want this in? + message_admins("[ADMIN_LOOKUPFLW(user)] has said '[log_message]' with a Velvet Voice, affecting [english_list(listeners)], with a power multiplier of [power_multiplier].") + log_game("FERMICHEM: [key_name(user)] ckey: [user.key] has said '[log_message]' with a Velvet Voice, affecting [english_list(listeners)], with a power multiplier of [power_multiplier].") + SSblackbox.record_feedback("tally", "fermi_chem", 1, "Times people have spoken with a velvet voice") + //SSblackbox.record_feedback("tally", "Velvet_voice", 1, log_message) If this is on, it fills the thing up and OOFs the server + + return + #undef COOLDOWN_STUN #undef COOLDOWN_DAMAGE diff --git a/code/modules/surgery/plastic_surgery.dm b/code/modules/surgery/plastic_surgery.dm index 54482ade73..fe22ffaede 100644 --- a/code/modules/surgery/plastic_surgery.dm +++ b/code/modules/surgery/plastic_surgery.dm @@ -1,21 +1,24 @@ /datum/surgery/plastic_surgery - name = "plastic surgery" + name = "Plastic surgery" steps = list(/datum/surgery_step/incise, /datum/surgery_step/retract_skin, /datum/surgery_step/reshape_face, /datum/surgery_step/close) possible_locs = list(BODY_ZONE_HEAD) - //reshape_face /datum/surgery_step/reshape_face name = "reshape face" - implements = list(/obj/item/scalpel = 100, /obj/item/kitchen/knife = 50, TOOL_WIRECUTTER = 35) + implements = list(TOOL_SCALPEL = 100, /obj/item/kitchen/knife = 50, TOOL_WIRECUTTER = 35) time = 64 /datum/surgery_step/reshape_face/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] begins to alter [target]'s appearance.", "You begin to alter [target]'s appearance...") + display_results(user, target, "You begin to alter [target]'s appearance...", + "[user] begins to alter [target]'s appearance.", + "[user] begins to make an incision in [target]'s face.") /datum/surgery_step/reshape_face/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) if(HAS_TRAIT_FROM(target, TRAIT_DISFIGURED, TRAIT_GENERIC)) REMOVE_TRAIT(target, TRAIT_DISFIGURED, TRAIT_GENERIC) - user.visible_message("[user] successfully restores [target]'s appearance!", "You successfully restore [target]'s appearance.") + display_results(user, target, "You successfully restore [target]'s appearance.", + "[user] successfully restores [target]'s appearance!", + "[user] finishes the operation on [target]'s face.") else var/list/names = list() if(!isabductor(user)) @@ -31,8 +34,18 @@ var/oldname = target.real_name target.real_name = chosen_name var/newname = target.real_name //something about how the code handles names required that I use this instead of target.real_name - user.visible_message("[user] alters [oldname]'s appearance completely, [target.p_they()] is now [newname]!", "You alter [oldname]'s appearance completely, [target.p_they()] is now [newname].") + display_results(user, target, "You alter [oldname]'s appearance completely, [target.p_they()] is now [newname].", + "[user] alters [oldname]'s appearance completely, [target.p_they()] is now [newname]!", + "[user] finishes the operation on [target]'s face.") if(ishuman(target)) var/mob/living/carbon/human/H = target H.sec_hud_set_ID() return 1 + return TRUE + +/datum/surgery_step/reshape_face/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You screw up, leaving [target]'s appearance disfigured!", + "[user] screws up, disfiguring [target]'s appearance!", + "[user] finishes the operation on [target]'s face.") + ADD_TRAIT(target, TRAIT_DISFIGURED, TRAIT_GENERIC) + return FALSE diff --git a/code/modules/surgery/prosthetic_replacement.dm b/code/modules/surgery/prosthetic_replacement.dm index 9032964ae4..8efa40a70a 100644 --- a/code/modules/surgery/prosthetic_replacement.dm +++ b/code/modules/surgery/prosthetic_replacement.dm @@ -1,26 +1,21 @@ /datum/surgery/prosthetic_replacement - name = "prosthetic replacement" + name = "Prosthetic replacement" steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/add_prosthetic) - species = list(/mob/living/carbon/human, /mob/living/carbon/monkey) + target_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey) possible_locs = list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG, BODY_ZONE_HEAD) requires_bodypart = FALSE //need a missing limb requires_bodypart_type = 0 - /datum/surgery/prosthetic_replacement/can_start(mob/user, mob/living/carbon/target) if(!iscarbon(target)) return 0 var/mob/living/carbon/C = target if(!C.get_bodypart(user.zone_selected)) //can only start if limb is missing return 1 - - - /datum/surgery_step/add_prosthetic name = "add prosthetic" implements = list(/obj/item/bodypart = 100, /obj/item/organ_storage = 100, /obj/item/twohanded/required/chainsaw = 100, /obj/item/melee/synthetic_arm_blade = 100) time = 32 var/organ_rejection_dam = 0 - /datum/surgery_step/add_prosthetic/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) if(istype(tool, /obj/item/organ_storage)) if(!tool.contents.len) @@ -48,16 +43,19 @@ organ_rejection_dam = 30 if(target_zone == BP.body_zone) //so we can't replace a leg with an arm, or a human arm with a monkey arm. - user.visible_message("[user] begins to replace [target]'s [parse_zone(target_zone)].", "You begin to replace [target]'s [parse_zone(target_zone)]...") + display_results(user, target, "You begin to replace [target]'s [parse_zone(target_zone)] with [tool]...", + "[user] begins to replace [target]'s [parse_zone(target_zone)] with [tool].", + "[user] begins to replace [target]'s [parse_zone(target_zone)].") else to_chat(user, "[tool] isn't the right type for [parse_zone(target_zone)].") return -1 else if(target_zone == BODY_ZONE_L_ARM || target_zone == BODY_ZONE_R_ARM) - user.visible_message("[user] begins to attach [tool] onto [target].", "You begin to attach [tool] onto [target]...") + display_results(user, target, "You begin to attach [tool] onto [target]...", + "[user] begins to attach [tool] onto [target]'s [parse_zone(target_zone)].", + "[user] begins to attach something onto [target]'s [parse_zone(target_zone)].") else to_chat(user, "[tool] must be installed onto an arm.") return -1 - /datum/surgery_step/add_prosthetic/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) if(istype(tool, /obj/item/organ_storage)) tool.icon_state = initial(tool.icon_state) @@ -69,13 +67,17 @@ L.attach_limb(target) if(organ_rejection_dam) target.adjustToxLoss(organ_rejection_dam) - user.visible_message("[user] successfully replaces [target]'s [parse_zone(target_zone)]!", "You succeed in replacing [target]'s [parse_zone(target_zone)].") + display_results(user, target, "You succeed in replacing [target]'s [parse_zone(target_zone)].", + "[user] successfully replaces [target]'s [parse_zone(target_zone)] with [tool]!", + "[user] successfully replaces [target]'s [parse_zone(target_zone)]!") return 1 else var/obj/item/bodypart/L = target.newBodyPart(target_zone, FALSE, FALSE) L.is_pseudopart = TRUE L.attach_limb(target) - user.visible_message("[user] finishes attaching [tool]!", "You attach [tool].") + display_results(user, target, "You attach [tool].", + "[user] finishes attaching [tool]!", + "[user] finishes the attachment procedure!") qdel(tool) if(istype(tool, /obj/item/twohanded/required/chainsaw)) var/obj/item/mounted_chainsaw/new_arm = new(target) @@ -85,4 +87,3 @@ var/obj/item/melee/arm_blade/new_arm = new(target,TRUE,TRUE) target_zone == BODY_ZONE_R_ARM ? target.put_in_r_hand(new_arm) : target.put_in_l_hand(new_arm) return 1 - diff --git a/code/modules/surgery/remove_embedded_object.dm b/code/modules/surgery/remove_embedded_object.dm index 451ae02dac..0c3a3b55a5 100644 --- a/code/modules/surgery/remove_embedded_object.dm +++ b/code/modules/surgery/remove_embedded_object.dm @@ -2,23 +2,20 @@ name = "removal of embedded objects" steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/remove_object) possible_locs = list(BODY_ZONE_R_ARM,BODY_ZONE_L_ARM,BODY_ZONE_R_LEG,BODY_ZONE_L_LEG,BODY_ZONE_CHEST,BODY_ZONE_HEAD) - - /datum/surgery_step/remove_object name = "remove embedded objects" time = 32 accept_hand = 1 var/obj/item/bodypart/L = null - - /datum/surgery_step/remove_object/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) L = surgery.operated_bodypart if(L) - user.visible_message("[user] looks for objects embedded in [target]'s [parse_zone(user.zone_selected)].", "You look for objects embedded in [target]'s [parse_zone(user.zone_selected)]...") + display_results(user, target, "You look for objects embedded in [target]'s [parse_zone(user.zone_selected)]...", + "[user] looks for objects embedded in [target]'s [parse_zone(user.zone_selected)].", + "[user] looks for something in [target]'s [parse_zone(user.zone_selected)].") else user.visible_message("[user] looks for [target]'s [parse_zone(user.zone_selected)].", "You look for [target]'s [parse_zone(user.zone_selected)]...") - /datum/surgery_step/remove_object/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) if(L) if(ishuman(target)) @@ -33,11 +30,12 @@ SEND_SIGNAL(H, COMSIG_CLEAR_MOOD_EVENT, "embedded") if(objects > 0) - user.visible_message("[user] successfully removes [objects] objects from [H]'s [L]!", "You successfully remove [objects] objects from [H]'s [L.name].") + display_results(user, target, "You successfully remove [objects] objects from [H]'s [L.name].", + "[user] successfully removes [objects] objects from [H]'s [L]!", + "[user] successfully removes [objects] objects from [H]'s [L]!") else to_chat(user, "You find no objects embedded in [H]'s [L]!") else to_chat(user, "You can't find [target]'s [parse_zone(user.zone_selected)], let alone any objects embedded in it!") - return 1 diff --git a/code/modules/surgery/surgery.dm b/code/modules/surgery/surgery.dm index b013e7f252..e81cbf528f 100644 --- a/code/modules/surgery/surgery.dm +++ b/code/modules/surgery/surgery.dm @@ -1,155 +1,172 @@ -/datum/surgery - var/name = "surgery" - var/desc = "surgery description" - var/status = 1 - var/list/steps = list() //Steps in a surgery - var/step_in_progress = 0 //Actively performing a Surgery - var/can_cancel = 1 //Can cancel this surgery after step 1 with cautery - var/list/species = list(/mob/living/carbon/human) //Acceptable Species - var/location = BODY_ZONE_CHEST //Surgery location - var/requires_bodypart_type = BODYPART_ORGANIC //Prevents you from performing an operation on incorrect limbs. 0 for any limb type - var/list/possible_locs = list() //Multiple locations - var/ignore_clothes = 0 //This surgery ignores clothes - var/mob/living/carbon/target //Operation target mob - var/obj/item/bodypart/operated_bodypart //Operable body part - var/requires_bodypart = TRUE //Surgery available only when a bodypart is present, or only when it is missing. - var/success_multiplier = 0 //Step success propability multiplier - var/requires_real_bodypart = 0 //Some surgeries don't work on limbs that don't really exist - -/datum/surgery/New(surgery_target, surgery_location, surgery_bodypart) - ..() - if(surgery_target) - target = surgery_target - target.surgeries += src - if(surgery_location) - location = surgery_location - if(surgery_bodypart) - operated_bodypart = surgery_bodypart - -/datum/surgery/Destroy() - if(target) - target.surgeries -= src - target = null - operated_bodypart = null - return ..() - - -/datum/surgery/proc/can_start(mob/user, mob/living/carbon/target) - // if 0 surgery wont show up in list - // put special restrictions here - return 1 - -/datum/surgery/proc/next_step(mob/user, intent) - if(step_in_progress) - return 1 - - var/try_to_fail = FALSE - if(intent == INTENT_DISARM) - try_to_fail = TRUE - - var/datum/surgery_step/S = get_surgery_step() - if(S) - var/obj/item/tool = user.get_active_held_item() - if(S.try_op(user, target, user.zone_selected, tool, src, try_to_fail)) - return TRUE - if(iscyborg(user) && user.a_intent != INTENT_HARM) //to save asimov borgs a LOT of heartache - return TRUE - if(tool.item_flags & SURGICAL_TOOL) //Just because you used the wrong tool it doesn't mean you meant to whack the patient with it - to_chat(user, "This step requires a different tool!") - return TRUE - -/datum/surgery/proc/get_surgery_step() - var/step_type = steps[status] - return new step_type - -/datum/surgery/proc/get_surgery_next_step() - if(status < steps.len) - var/step_type = steps[status + 1] - return new step_type - else - return null - -/datum/surgery/proc/complete() - SSblackbox.record_feedback("tally", "surgeries_completed", 1, type) - qdel(src) - -/datum/surgery/proc/get_propability_multiplier() - var/propability = 0.5 - var/turf/T = get_turf(target) - - if(locate(/obj/structure/table/optable, T)) - propability = 1 - else if(locate(/obj/structure/table, T)) - propability = 0.8 - else if(locate(/obj/structure/bed, T)) - propability = 0.7 - - return propability + success_multiplier - -/datum/surgery/advanced - name = "advanced surgery" - -/datum/surgery/advanced/can_start(mob/user, mob/living/carbon/target) - if(!..()) - return FALSE - //Abductor scientists need no instructions - if(isabductor(user)) - var/mob/living/carbon/human/H = user - var/datum/species/abductor/S = H.dna.species - if(S.scientist) - return TRUE - - if(iscyborg(user)) - var/mob/living/silicon/robot/R = user - var/obj/item/surgical_processor/SP = locate() in R.module.modules - if(!SP) - return FALSE - if(type in SP.advanced_surgeries) - return TRUE - - var/turf/T = get_turf(target) - var/obj/structure/table/optable/table = locate(/obj/structure/table/optable, T) - if(!table || !table.computer) - return FALSE - if(table.computer.stat & (NOPOWER|BROKEN)) - return FALSE - if(type in table.computer.advanced_surgeries) - return TRUE - -/obj/item/disk/surgery - name = "Surgery Procedure Disk" - desc = "A disk that contains advanced surgery procedures, must be loaded into an Operating Console." - icon_state = "datadisk1" - materials = list(MAT_METAL=300, MAT_GLASS=100) - var/list/surgeries - -/obj/item/disk/surgery/debug - name = "Debug Surgery Disk" - desc = "A disk that contains all existing surgery procedures." - icon_state = "datadisk1" - materials = list(MAT_METAL=300, MAT_GLASS=100) - -/obj/item/disk/surgery/debug/Initialize() - . = ..() - surgeries = subtypesof(/datum/surgery/advanced) - -//INFO -//Check /mob/living/carbon/attackby for how surgery progresses, and also /mob/living/carbon/attack_hand. -//As of Feb 21 2013 they are in code/modules/mob/living/carbon/carbon.dm, lines 459 and 51 respectively. -//Other important variables are var/list/surgeries (/mob/living) and var/list/internal_organs (/mob/living/carbon) -// var/list/bodyparts (/mob/living/carbon/human) is the LIMBS of a Mob. -//Surgical procedures are initiated by attempt_initiate_surgery(), which is called by surgical drapes and bedsheets. - - -//TODO -//specific steps for some surgeries (fluff text) -//more interesting failure options -//randomised complications -//more surgeries! -//add a probability modifier for the state of the surgeon- health, twitching, etc. blindness, god forbid. -//helper for converting a zone_sel.selecting to body part (for damage) - - -//RESOLVED ISSUES //"Todo" jobs that have been completed -//combine hands/feet into the arms - Hands/feet were removed - RR -//surgeries (not steps) that can be initiated on any body part (corresponding with damage locations) - Call this one done, see possible_locs var - c0 +/datum/surgery + var/name = "surgery" + var/desc = "surgery description" + var/status = 1 + var/list/steps = list() //Steps in a surgery + var/step_in_progress = 0 //Actively performing a Surgery + var/can_cancel = 1 //Can cancel this surgery after step 1 with cautery + var/list/target_mobtypes = list(/mob/living/carbon/human) //Acceptable Species + var/location = BODY_ZONE_CHEST //Surgery location + var/requires_bodypart_type = BODYPART_ORGANIC //Prevents you from performing an operation on incorrect limbs. 0 for any limb type + var/list/possible_locs = list() //Multiple locations + var/ignore_clothes = 0 //This surgery ignores clothes + var/mob/living/carbon/target //Operation target mob + var/obj/item/bodypart/operated_bodypart //Operable body part + var/requires_bodypart = TRUE //Surgery available only when a bodypart is present, or only when it is missing. + var/success_multiplier = 0 //Step success propability multiplier + var/requires_real_bodypart = 0 //Some surgeries don't work on limbs that don't really exist + var/lying_required = TRUE //Does the vicitm needs to be lying down. + var/requires_tech = FALSE + var/replaced_by + +/datum/surgery/New(surgery_target, surgery_location, surgery_bodypart) + ..() + if(surgery_target) + target = surgery_target + target.surgeries += src + if(surgery_location) + location = surgery_location + if(surgery_bodypart) + operated_bodypart = surgery_bodypart + +/datum/surgery/Destroy() + if(target) + target.surgeries -= src + target = null + operated_bodypart = null + return ..() + + +/datum/surgery/proc/can_start(mob/user, mob/living/patient) //FALSE to not show in list + . = TRUE + if(replaced_by == /datum/surgery) + return FALSE + + if(HAS_TRAIT(user, TRAIT_SURGEON) || HAS_TRAIT(user.mind, TRAIT_SURGEON)) + if(replaced_by) + return FALSE + else + return TRUE + + if(!requires_tech && !replaced_by) + return TRUE + // True surgeons (like abductor scientists) need no instructions + + if(requires_tech) + . = FALSE + + if(iscyborg(user)) + var/mob/living/silicon/robot/R = user + var/obj/item/surgical_processor/SP = locate() in R.module.modules + if(SP) + if (replaced_by in SP.advanced_surgeries) + return . + if(type in SP.advanced_surgeries) + return TRUE + + + var/turf/T = get_turf(patient) + var/obj/structure/table/optable/table = locate(/obj/structure/table/optable, T) + if(table) + if(!table.computer) + return . + if(table.computer.stat & (NOPOWER|BROKEN)) + return . + if(replaced_by in table.computer.advanced_surgeries) + return FALSE + if(type in table.computer.advanced_surgeries) + return TRUE + +/datum/surgery/proc/next_step(mob/user, intent) + if(step_in_progress) + return 1 + + var/try_to_fail = FALSE + if(intent == INTENT_DISARM) + try_to_fail = TRUE + + var/datum/surgery_step/S = get_surgery_step() + if(S) + var/obj/item/tool = user.get_active_held_item() + if(S.try_op(user, target, user.zone_selected, tool, src, try_to_fail)) + return TRUE + if(iscyborg(user) && user.a_intent != INTENT_HARM) //to save asimov borgs a LOT of heartache + return TRUE + if(tool.item_flags & SURGICAL_TOOL) //Just because you used the wrong tool it doesn't mean you meant to whack the patient with it + to_chat(user, "This step requires a different tool!") + return TRUE + +/datum/surgery/proc/get_surgery_step() + var/step_type = steps[status] + return new step_type + +/datum/surgery/proc/get_surgery_next_step() + if(status < steps.len) + var/step_type = steps[status + 1] + return new step_type + else + return null + +/datum/surgery/proc/complete() + SSblackbox.record_feedback("tally", "surgeries_completed", 1, type) + qdel(src) + +/datum/surgery/proc/get_propability_multiplier() + var/propability = 0.5 + var/turf/T = get_turf(target) + + if(locate(/obj/structure/table/optable, T)) + propability = 1 + else if(locate(/obj/structure/table, T)) + propability = 0.8 + else if(locate(/obj/structure/bed, T)) + propability = 0.7 + + return propability + success_multiplier + +/datum/surgery/advanced + name = "advanced surgery" + requires_tech = TRUE + +/obj/item/disk/surgery + name = "Surgery Procedure Disk" + desc = "A disk that contains advanced surgery procedures, must be loaded into an Operating Console." + icon_state = "datadisk1" + materials = list(MAT_METAL=300, MAT_GLASS=100) + var/list/surgeries + +/obj/item/disk/surgery/debug + name = "Debug Surgery Disk" + desc = "A disk that contains all existing surgery procedures." + icon_state = "datadisk1" + materials = list(MAT_METAL=300, MAT_GLASS=100) + +/obj/item/disk/surgery/debug/Initialize() + . = ..() + surgeries = list() + var/list/req_tech_surgeries = subtypesof(/datum/surgery) + for(var/i in req_tech_surgeries) + var/datum/surgery/beep = i + if(initial(beep.requires_tech)) + surgeries += beep + +//INFO +//Check /mob/living/carbon/attackby for how surgery progresses, and also /mob/living/carbon/attack_hand. +//As of Feb 21 2013 they are in code/modules/mob/living/carbon/carbon.dm, lines 459 and 51 respectively. +//Other important variables are var/list/surgeries (/mob/living) and var/list/internal_organs (/mob/living/carbon) +// var/list/bodyparts (/mob/living/carbon/human) is the LIMBS of a Mob. +//Surgical procedures are initiated by attempt_initiate_surgery(), which is called by surgical drapes and bedsheets. + + +//TODO +//specific steps for some surgeries (fluff text) +//more interesting failure options +//randomised complications +//more surgeries! +//add a probability modifier for the state of the surgeon- health, twitching, etc. blindness, god forbid. +//helper for converting a zone_sel.selecting to body part (for damage) + + +//RESOLVED ISSUES //"Todo" jobs that have been completed +//combine hands/feet into the arms - Hands/feet were removed - RR +//surgeries (not steps) that can be initiated on any body part (corresponding with damage locations) - Call this one done, see possible_locs var - c0 \ No newline at end of file diff --git a/code/modules/surgery/surgery_step.dm b/code/modules/surgery/surgery_step.dm index f670b80167..71f813a5b5 100644 --- a/code/modules/surgery/surgery_step.dm +++ b/code/modules/surgery/surgery_step.dm @@ -2,118 +2,104 @@ var/name var/list/implements = list() //format is path = probability of success. alternatively var/implement_type = null //the current type of implement used. This has to be stored, as the actual typepath of the tool may not match the list type. - var/accept_hand = 0 //does the surgery step require an open hand? If true, ignores implements. Compatible with accept_any_item. - var/accept_any_item = 0 //does the surgery step accept any item? If true, ignores implements. Compatible with require_hand. + var/accept_hand = FALSE //does the surgery step require an open hand? If true, ignores implements. Compatible with accept_any_item. + var/accept_any_item = FALSE //does the surgery step accept any item? If true, ignores implements. Compatible with require_hand. var/time = 10 //how long does the step take? - var/repeatable = 0 //can this step be repeated? Make shure it isn't last step, or it used in surgery with `can_cancel = 1`. Or surgion will be stuck in the loop + var/repeatable = FALSE //can this step be repeated? Make shure it isn't last step, or it used in surgery with `can_cancel = 1`. Or surgion will be stuck in the loop var/list/chems_needed = list() //list of chems needed to complete the step. Even on success, the step will have no effect if there aren't the chems required in the mob. var/require_all_chems = TRUE //any on the list or all on the list? + var/silicons_obey_prob = FALSE -/datum/surgery_step/proc/try_op(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, try_to_fail = FALSE) +/datum/surgery_step/proc/try_op(mob/user, mob/living/target, target_zone, obj/item/tool, datum/surgery/surgery, try_to_fail = FALSE) var/success = FALSE if(accept_hand) if(!tool) success = TRUE if(iscyborg(user)) success = TRUE - if(accept_any_item) if(tool && tool_check(user, tool)) success = TRUE - else if(tool) for(var/key in implements) var/match = FALSE - if(ispath(key) && istype(tool, key)) match = TRUE else if(tool.tool_behaviour == key) match = TRUE - if(match) implement_type = key if(tool_check(user, tool)) success = TRUE break - if(success) if(target_zone == surgery.location) if(get_location_accessible(target, target_zone) || surgery.ignore_clothes) - initiate(user, target, target_zone, tool, surgery, try_to_fail) - return 1 + return initiate(user, target, target_zone, tool, surgery, try_to_fail) else to_chat(user, "You need to expose [target]'s [parse_zone(target_zone)] to perform surgery on it!") - return 1 //returns 1 so we don't stab the guy in the dick or wherever. - + return TRUE //returns TRUE so we don't stab the guy in the dick or wherever. if(repeatable) var/datum/surgery_step/next_step = surgery.get_surgery_next_step() if(next_step) surgery.status++ if(next_step.try_op(user, target, user.zone_selected, user.get_active_held_item(), surgery)) - return 1 + return TRUE else surgery.status-- + return FALSE - if(iscyborg(user) && user.a_intent != INTENT_HARM) //to save asimov borgs a LOT of heartache - return 1 - - return 0 - - -/datum/surgery_step/proc/initiate(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, try_to_fail = FALSE) - surgery.step_in_progress = 1 - +/datum/surgery_step/proc/initiate(mob/user, mob/living/target, target_zone, obj/item/tool, datum/surgery/surgery, try_to_fail = FALSE) + surgery.step_in_progress = TRUE var/speed_mod = 1 - + var/advance = FALSE if(preop(user, target, target_zone, tool, surgery) == -1) - surgery.step_in_progress = 0 - return - + surgery.step_in_progress = FALSE + return FALSE if(tool) speed_mod = tool.toolspeed - if(do_after(user, time * speed_mod, target = target)) - var/advance = 0 var/prob_chance = 100 - if(implement_type) //this means it isn't a require hand or any item step. prob_chance = implements[implement_type] prob_chance *= surgery.get_propability_multiplier() - if((prob(prob_chance) || iscyborg(user)) && chem_check(target) && !try_to_fail) + if((prob(prob_chance) || (iscyborg(user) && !silicons_obey_prob)) && chem_check(target) && !try_to_fail) if(success(user, target, target_zone, tool, surgery)) - advance = 1 + advance = TRUE else if(failure(user, target, target_zone, tool, surgery)) - advance = 1 - + advance = TRUE if(advance && !repeatable) surgery.status++ if(surgery.status > surgery.steps.len) surgery.complete() + surgery.step_in_progress = FALSE + return advance - surgery.step_in_progress = 0 +/datum/surgery_step/proc/preop(mob/user, mob/living/target, target_zone, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You begin to perform surgery on [target]...", + "[user] begins to perform surgery on [target].", + "[user] begins to perform surgery on [target].") +/datum/surgery_step/proc/success(mob/user, mob/living/target, target_zone, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You succeed.", + "[user] succeeds!", + "[user] finishes.") + return TRUE -/datum/surgery_step/proc/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] begins to perform surgery on [target].", "You begin to perform surgery on [target]...") - - -/datum/surgery_step/proc/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] succeeds!", "You succeed.") - return 1 - -/datum/surgery_step/proc/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - user.visible_message("[user] screws up!", "You screw up!") - return 0 +/datum/surgery_step/proc/failure(mob/user, mob/living/target, target_zone, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You screw up!", + "[user] screws up!", + "[user] finishes.", TRUE) //By default the patient will notice if the wrong thing has been cut + return FALSE /datum/surgery_step/proc/tool_check(mob/user, obj/item/tool) - return 1 + return TRUE -/datum/surgery_step/proc/chem_check(mob/living/carbon/target) +/datum/surgery_step/proc/chem_check(mob/living/target) if(!LAZYLEN(chems_needed)) return TRUE - if(require_all_chems) . = TRUE for(var/R in chems_needed) @@ -124,7 +110,6 @@ for(var/R in chems_needed) if(target.reagents.has_reagent(R)) return TRUE - /datum/surgery_step/proc/get_chem_list() if(!LAZYLEN(chems_needed)) return @@ -135,3 +120,11 @@ var/chemname = temp.name chems += chemname return english_list(chems, and_text = require_all_chems ? " and " : " or ") + +//Replaces visible_message during operations so only people looking over the surgeon can tell what they're doing, allowing for shenanigans. +/datum/surgery_step/proc/display_results(mob/user, mob/living/carbon/target, self_message, detailed_message, vague_message, target_detailed = FALSE) + var/list/detailed_mobs = get_hearers_in_view(1, user) //Only the surgeon and people looking over his shoulder can see the operation clearly + if(!target_detailed) + detailed_mobs -= target //The patient can't see well what's going on, unless it's something like getting cut + user.visible_message(detailed_message, self_message, vision_distance = 1, ignored_mobs = target_detailed ? null : target) + user.visible_message(vague_message, "", ignored_mobs = detailed_mobs) diff --git a/code/modules/surgery/tools.dm b/code/modules/surgery/tools.dm index db7445e0b0..001ef8d0e6 100644 --- a/code/modules/surgery/tools.dm +++ b/code/modules/surgery/tools.dm @@ -7,16 +7,30 @@ item_flags = SURGICAL_TOOL flags_1 = CONDUCT_1 w_class = WEIGHT_CLASS_TINY + tool_behaviour = TOOL_RETRACTOR + toolspeed = 1 -/obj/item/retractor/adv - name = "Advanced Retractor" - desc = "A high-class, premium retractor, featuring precision crafted, silver-plated hook-ends and an electrum handle." +/obj/item/retractor/advanced + name = "mechanical pinches" + desc = "An agglomerate of rods and gears." icon = 'icons/obj/surgery.dmi' - icon_state = "retractor" - materials = list(MAT_METAL=6000, MAT_GLASS=3000) - flags_1 = CONDUCT_1 - w_class = WEIGHT_CLASS_TINY - toolspeed = 0.65 + icon_state = "retractor_a" + toolspeed = 0.7 + +/obj/item/retractor/advanced/attack_self(mob/user) + playsound(get_turf(user), 'sound/items/change_drill.ogg', 50, TRUE) + if(tool_behaviour == TOOL_RETRACTOR) + tool_behaviour = TOOL_HEMOSTAT + to_chat(user, "You configure the gears of [src], they are now in hemostat mode.") + icon_state = "hemostat_a" + else + tool_behaviour = TOOL_RETRACTOR + to_chat(user, "You configure the gears of [src], they are now in retractor mode.") + icon_state = "retractor_a" + +/obj/item/retractor/advanced/examine(mob/living/user) + . = ..() + to_chat(user, "You focus the lenses of [src], it is now in mending mode.") + icon_state = "cautery_a" + else + tool_behaviour = TOOL_DRILL + to_chat(user, "You dilate the lenses of [src], it is now in drilling mode.") + icon_state = "surgicaldrill_a" + +/obj/item/surgicaldrill/advanced/examine(mob/living/user) + . = ..() + to_chat(user, "") /obj/item/surgicaldrill/augment name = "surgical drill" @@ -159,30 +167,47 @@ attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") hitsound = 'sound/weapons/bladeslice.ogg' sharpness = IS_SHARP_ACCURATE + tool_behaviour = TOOL_SCALPEL + toolspeed = 1 /obj/item/scalpel/Initialize() . = ..() AddComponent(/datum/component/butchering, 80 * toolspeed, 100, 0) -/obj/item/scalpel/adv - name = "Precision Scalpel" - desc = "A perfectly balanced electrum scalpel with a silicon-coated edge to eliminate wear and tear." +/obj/item/scalpel/advanced + name = "laser scalpel" + desc = "An advanced scalpel which uses laser technology to cut." icon = 'icons/obj/surgery.dmi' - icon_state = "scalpel" - lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' - flags_1 = CONDUCT_1 - force = 8 - w_class = WEIGHT_CLASS_TINY - throwforce = 7 - throw_speed = 3 - throw_range = 6 - materials = list(MAT_METAL=4000, MAT_GLASS=1000) - attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") - toolspeed = 0.65 - hitsound = 'sound/weapons/bladeslice.ogg' + icon_state = "scalpel_a" + hitsound = 'sound/weapons/blade1.ogg' + force = 16 + toolspeed = 0.7 + light_color = LIGHT_COLOR_GREEN sharpness = IS_SHARP_ACCURATE +/obj/item/scalpel/advanced/Initialize() + . = ..() + set_light(1) + +/obj/item/scalpel/advanced/attack_self(mob/user) + playsound(get_turf(user), 'sound/machines/click.ogg', 50, TRUE) + if(tool_behaviour == TOOL_SCALPEL) + tool_behaviour = TOOL_SAW + to_chat(user, "You increase the power of [src], now it can cut bones.") + set_light(2) + force += 1 //we don't want to ruin sharpened stuff + icon_state = "saw_a" + else + tool_behaviour = TOOL_SCALPEL + to_chat(user, "You lower the power of [src], it can no longer cut bones.") + set_light(1) + force -= 1 + icon_state = "scalpel_a" + +/obj/item/scalpel/advanced/examine(mob/living/user) + . = ..() + to_chat(user, "") + /obj/item/scalpel/augment name = "scalpel" desc = "Ultra-sharp blade attached directly to your bone for extra-accuracy." @@ -224,30 +249,13 @@ materials = list(MAT_METAL=10000, MAT_GLASS=6000) attack_verb = list("attacked", "slashed", "sawed", "cut") sharpness = IS_SHARP + tool_behaviour = TOOL_SAW + toolspeed = 1 /obj/item/circular_saw/Initialize() . = ..() AddComponent(/datum/component/butchering, 40 * toolspeed, 100, 5, 'sound/weapons/circsawhit.ogg') //saws are very accurate and fast at butchering -/obj/item/circular_saw/adv - name = "Diamond-Grit Circular Saw" - desc = "For those Assistants with REALLY thick skulls." - icon = 'icons/obj/surgery.dmi' - icon_state = "saw" - lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' - hitsound = 'sound/weapons/circsawhit.ogg' - throwhitsound = 'sound/weapons/pierce.ogg' - flags_1 = CONDUCT_1 - force = 13 - w_class = WEIGHT_CLASS_NORMAL - throwforce = 6 - throw_speed = 1 - throw_range = 3 - materials = list(MAT_METAL=10000, MAT_GLASS=6000) - attack_verb = list("attacked", "slashed", "sawed", "cut") - toolspeed = 0.65 - sharpness = IS_SHARP /obj/item/circular_saw/augment name = "circular saw" @@ -332,7 +340,7 @@ icon_state = "spectrometer" item_flags = NOBLUDGEON var/list/advanced_surgeries = list() - + /obj/item/surgical_processor/afterattack(obj/item/O, mob/user, proximity) . = ..() if(!proximity) diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm index 1831f38940..61af0eaf78 100644 --- a/code/modules/uplink/uplink_items.dm +++ b/code/modules/uplink/uplink_items.dm @@ -75,6 +75,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) var/player_minimum //The minimum crew size needed for this item to be added to uplinks. var/purchase_log_vis = TRUE // Visible in the purchase log? var/restricted = FALSE // Adds restrictions for VR/Events + var/illegal_tech = TRUE // Can this item be deconstructed to unlock certain techweb research nodes? /datum/uplink_item/New() . = ..() @@ -290,6 +291,22 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) /datum/uplink_item/dangerous category = "Conspicuous and Dangerous Weapons" +/datum/uplink_item/dangerous/pistol + name = "Stechkin Pistol" + desc = "A small, easily concealable handgun that uses 10mm auto rounds in 8-round magazines and is compatible \ + with suppressors." + item = /obj/item/gun/ballistic/automatic/pistol + cost = 7 + exclude_modes = list(/datum/game_mode/nuclear/clown_ops) + +/datum/uplink_item/dangerous/revolver + name = "Syndicate Revolver" + desc = "A brutally simple syndicate revolver that fires .357 Magnum rounds and has 7 chambers." + item = /obj/item/gun/ballistic/revolver/syndie + cost = 13 + surplus = 50 + exclude_modes = list(/datum/game_mode/nuclear/clown_ops) + /datum/uplink_item/dangerous/rawketlawnchair name = "84mm Rocket Propelled Grenade Launcher" desc = "A reusable rocket propelled grenade launcher preloaded with a low-yield 84mm HE round. \ @@ -494,14 +511,6 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) surplus = 25 include_modes = list(/datum/game_mode/nuclear) -/datum/uplink_item/dangerous/pistol - name = "Stechkin Pistol" - desc = "A small, easily concealable handgun that uses 10mm auto rounds in 8-round magazines and is compatible \ - with suppressors." - item = /obj/item/gun/ballistic/automatic/pistol - cost = 7 - exclude_modes = list(/datum/game_mode/nuclear/clown_ops) - /datum/uplink_item/dangerous/bolt_action name = "Surplus Rifle" desc = "A horribly outdated bolt action weapon. You've got to be desperate to use this." @@ -509,14 +518,6 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) cost = 2 include_modes = list(/datum/game_mode/nuclear) -/datum/uplink_item/dangerous/revolver - name = "Syndicate Revolver" - desc = "A brutally simple Syndicate revolver that fires .357 Magnum rounds and has 7 chambers." - item = /obj/item/gun/ballistic/revolver/syndie - cost = 13 - surplus = 50 - exclude_modes = list(/datum/game_mode/nuclear/clown_ops) - /datum/uplink_item/dangerous/foamsmg name = "Toy Submachine Gun" desc = "A fully-loaded Donksoft bullpup submachine gun that fires riot grade darts with a 20-round magazine." @@ -563,6 +564,12 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) cost = 13 surplus = 0 +/datum/uplink_item/dangerous/phantomthief + name = "Syndicate Mask" + desc = "A cheap plastic mask fitted with an adrenaline autoinjector, which can be used by simply tensing your muscles" + item = /obj/item/clothing/glasses/phantomthief/syndicate + cost = 2 + /datum/uplink_item/stealthy_weapons/dart_pistol name = "Dart Pistol" desc = "A miniaturized version of a normal syringe gun. It is very quiet when fired and can fit into any \ @@ -763,6 +770,7 @@ datum/uplink_item/stealthy_weapons/taeclowndo_shoes item = /obj/item/ammo_box/a357 cost = 4 exclude_modes = list(/datum/game_mode/nuclear/clown_ops) + illegal_tech = FALSE /datum/uplink_item/ammo/a40mm name = "40mm Grenade" @@ -892,6 +900,7 @@ datum/uplink_item/stealthy_weapons/taeclowndo_shoes item = /obj/item/ammo_box/foambox/riot cost = 2 surplus = 0 + illegal_tech = FALSE /datum/uplink_item/ammo/bioterror name = "Box of Bioterror Syringes" @@ -1263,9 +1272,44 @@ datum/uplink_item/stealthy_weapons/taeclowndo_shoes //Space Suits and Hardsuits /datum/uplink_item/suits - category = "Space Suits and Hardsuits" + category = "Space Suits, Hardsuits and Clothing" surplus = 40 +/datum/uplink_item/suits/turtlenck + name = "Tactical Turtleneck" + desc = "A slightly armored suit that has no sensor on them, if someone sees you in this hope they think its a fake." + item = /obj/item/clothing/under/syndicate + cost = 1 + exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) //They already get these + +/datum/uplink_item/suits/turtlenck_skirt + name = "Tactical Skirtleneck" + desc = "A slightly armored suit that has no sensor on them, if someone sees you in this hope they think its a fake." + item = /obj/item/clothing/under/syndicate/skirt + cost = 1 + exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) //They already get these + +/datum/uplink_item/suits/padding + name = "Soft Padding" + desc = "Padding to add to a jumpsuit to help against melee and bullets." + item = /obj/item/clothing/accessory/padding + cost = 2 + exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) + +/datum/uplink_item/suits/kevlar + name = "Kevlar sheets" + desc = "Kevlar sheets to add to jumpsuit to help against bullets and melee." + item = /obj/item/clothing/accessory/kevlar + cost = 2 + exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) + +/datum/uplink_item/suits/plastic + name = "Plastic sheet" + desc = "Plastic body sheet to add to a jumpsuit to help against laser and energy harm." + item = /obj/item/clothing/accessory/plastics + cost = 2 + exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) + /datum/uplink_item/suits/space_suit name = "Syndicate Space Suit" desc = "This red and black Syndicate space suit is less encumbering than Nanotrasen variants, \ @@ -1307,6 +1351,19 @@ datum/uplink_item/stealthy_weapons/taeclowndo_shoes /datum/uplink_item/device_tools category = "Devices and Tools" +/datum/uplink_item/device_tools/emag + name = "Cryptographic Sequencer" + desc = "The cryptographic sequencer, electromagnetic card, or emag, is a small card that unlocks hidden functions \ + in electronic devices, subverts intended functions, and easily breaks security mechanisms." + item = /obj/item/card/emag + cost = 6 + +/datum/uplink_item/device_tools/emagrecharge + name = "Electromagnet Charging Device" + desc = "A small device intended for recharging Cryptographic Sequencers. Using it will add five extra charges to the Cryptographic Sequencer." + item = /obj/item/emagrecharge + cost = 2 + /datum/uplink_item/device_tools/cutouts name = "Adaptive Cardboard Cutouts" desc = "These cardboard cutouts are coated with a thin material that prevents discoloration and makes the images on them appear more lifelike. \ @@ -1375,19 +1432,6 @@ datum/uplink_item/stealthy_weapons/taeclowndo_shoes cost = 1 exclude_modes = list(/datum/game_mode/nuclear) -/datum/uplink_item/device_tools/emag - name = "Cryptographic Sequencer" - desc = "The cryptographic sequencer, electromagnetic card, or emag, is a small card that unlocks hidden functions \ - in electronic devices, subverts intended functions, and easily breaks security mechanisms." - item = /obj/item/card/emag - cost = 6 - -/datum/uplink_item/device_tools/emagrecharge - name = "Electromagnet Charging Device" - desc = "A small device intended for recharging Cryptographic Sequencers. Using it will add five extra charges to the Cryptographic Sequencer." - item = /obj/item/emagrecharge - cost = 2 - /datum/uplink_item/device_tools/fakenucleardisk name = "Decoy Nuclear Authentication Disk" desc = "It's just a normal disk. Visually it's identical to the real deal, but it won't hold up under closer scrutiny by the Captain. \ @@ -1418,6 +1462,7 @@ datum/uplink_item/stealthy_weapons/taeclowndo_shoes desc = "A cheap bottle of one use syndicate brand super glue. \ Use on any item to make it undroppable. \ Be careful not to glue an item you're already holding!" + exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) item = /obj/item/syndie_glue cost = 2 @@ -1445,9 +1490,10 @@ datum/uplink_item/stealthy_weapons/taeclowndo_shoes /datum/uplink_item/device_tools/singularity_beacon name = "Power Beacon" desc = "When screwed to wiring attached to an electric grid and activated, this large device pulls any \ - active gravitational singularities or tesla balls towards it. This will not work when the engine is still \ - in containment. Because of its size, it cannot be carried. Ordering this \ - sends you a small beacon that will teleport the larger beacon to your location upon activation." + active gravitational singularities or tesla balls towards it (provided they are not safely \ + contained), as well as increasing the odds of incoming meteor waves. \ + Because of its size, it cannot be carried. Ordering this sends you a small beacon \ + that will teleport the larger beacon to your location upon activation." item = /obj/item/sbeacondrop cost = 14 @@ -1796,7 +1842,7 @@ datum/uplink_item/stealthy_weapons/taeclowndo_shoes desc = "A single-use autoinjector which contains an experimental serum that causes rapid muscular growth in Hominidae. \ Side-affects may include hypertrichosis, violent outbursts, and an unending affinity for bananas." item = /obj/item/reagent_containers/hypospray/magillitis - cost = 15 + cost = 8 restricted_roles = list("Geneticist", "Chief Medical Officer") /datum/uplink_item/role_restricted/modified_syringe_gun @@ -1884,6 +1930,7 @@ datum/uplink_item/stealthy_weapons/taeclowndo_shoes item = /obj/item/toy/syndicateballoon cost = 20 cant_discount = TRUE + illegal_tech = FALSE /datum/uplink_item/badass/syndiecash name = "Syndicate Briefcase Full of Cash" @@ -1907,9 +1954,11 @@ datum/uplink_item/stealthy_weapons/taeclowndo_shoes item = /obj/item/toy/cards/deck/syndicate cost = 1 surplus = 40 + illegal_tech = FALSE /datum/uplink_item/badass/syndiecigs name = "Syndicate Smokes" desc = "Strong flavor, dense smoke, infused with omnizine." item = /obj/item/storage/fancy/cigarettes/cigpack_syndicate cost = 2 + illegal_tech = FALSE diff --git a/code/modules/vehicles/cars/clowncar.dm b/code/modules/vehicles/cars/clowncar.dm index 63ef4fda5a..e504ea84f2 100644 --- a/code/modules/vehicles/cars/clowncar.dm +++ b/code/modules/vehicles/cars/clowncar.dm @@ -63,11 +63,13 @@ DumpMobs(TRUE) /obj/vehicle/sealed/car/clowncar/emag_act(mob/user) + . = ..() if(obj_flags & EMAGGED) return obj_flags |= EMAGGED to_chat(user, "You scramble the clowncar child safety lock and a panel with 6 colorful buttons appears!") initialize_controller_action_type(/datum/action/vehicle/sealed/RollTheDice, VEHICLE_CONTROL_DRIVE) + return TRUE /obj/vehicle/sealed/car/clowncar/Destroy() playsound(src, 'sound/vehicles/clowncar_fart.ogg', 100) diff --git a/code/modules/vehicles/scooter.dm b/code/modules/vehicles/scooter.dm index 9af5b13a7d..8c21b050aa 100644 --- a/code/modules/vehicles/scooter.dm +++ b/code/modules/vehicles/scooter.dm @@ -75,7 +75,7 @@ H.adjustStaminaLoss(40) var/head_slot = H.get_item_by_slot(SLOT_HEAD) if(!head_slot || !(istype(head_slot,/obj/item/clothing/head/helmet) || istype(head_slot,/obj/item/clothing/head/hardhat))) - H.adjustBrainLoss(3) + H.adjustOrganLoss(ORGAN_SLOT_BRAIN, 3) H.updatehealth() visible_message("[src] crashes into [A], sending [H] flying!") playsound(src, 'sound/effects/bang.ogg', 50, 1) @@ -201,7 +201,7 @@ H.adjustStaminaLoss(10) var/head_slot = H.get_item_by_slot(SLOT_HEAD) if(!head_slot || !(istype(head_slot,/obj/item/clothing/head/helmet) || istype(head_slot,/obj/item/clothing/head/hardhat))) - H.adjustBrainLoss(1) + H.adjustOrganLoss(ORGAN_SLOT_BRAIN, 1) H.updatehealth() visible_message("[src] crashes into [A], sending [H] flying!") playsound(src, 'sound/effects/bang.ogg', 50, 1) diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm index 410952397d..5165343993 100644 --- a/code/modules/vending/_vending.dm +++ b/code/modules/vending/_vending.dm @@ -65,7 +65,7 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C var/scan_id = 1 var/obj/item/coin/coin var/obj/item/stack/spacecash/bill - + var/global/vending_cache = list() //used for storing the icons of items being vended var/dish_quants = list() //used by the snack machine's custom compartment to count dishes. @@ -306,10 +306,12 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C . = ..() /obj/machinery/vending/emag_act(mob/user) + . = ..() if(obj_flags & EMAGGED) return obj_flags |= EMAGGED to_chat(user, "You short out the product lock on [src].") + return TRUE /obj/machinery/vending/_try_interact(mob/user) if(seconds_electrified && !(stat & NOPOWER)) diff --git a/code/modules/vending/autodrobe.dm b/code/modules/vending/autodrobe.dm index a265a4e907..3879fc70cb 100644 --- a/code/modules/vending/autodrobe.dm +++ b/code/modules/vending/autodrobe.dm @@ -7,107 +7,109 @@ product_slogans = "Dress for success!;Suited and booted!;It's show time!;Why leave style up to fate? Use AutoDrobe!" vend_reply = "Thank you for using AutoDrobe!" products = list(/obj/item/clothing/suit/chickensuit = 1, - /obj/item/clothing/head/chicken = 1, - /obj/item/clothing/under/gladiator = 1, - /obj/item/clothing/head/helmet/gladiator = 1, - /obj/item/clothing/under/gimmick/rank/captain/suit = 1, - /obj/item/clothing/head/flatcap = 1, - /obj/item/clothing/suit/toggle/labcoat/mad = 1, - /obj/item/clothing/shoes/jackboots = 1, - /obj/item/clothing/under/schoolgirl = 1, - /obj/item/clothing/under/schoolgirl/red = 1, - /obj/item/clothing/under/schoolgirl/green = 1, - /obj/item/clothing/under/schoolgirl/orange = 1, - /obj/item/clothing/head/kitty = 1, - /obj/item/clothing/under/skirt/black = 1, - /obj/item/clothing/head/beret = 1, - /obj/item/clothing/accessory/waistcoat = 1, - /obj/item/clothing/under/suit_jacket = 1, - /obj/item/clothing/head/that = 1, - /obj/item/clothing/under/kilt = 1, - /obj/item/clothing/head/beret = 1, - /obj/item/clothing/accessory/waistcoat = 1, - /obj/item/clothing/glasses/monocle =1, - /obj/item/clothing/head/bowler = 1, - /obj/item/cane = 1, - /obj/item/clothing/under/sl_suit = 1, - /obj/item/clothing/mask/fakemoustache = 1, - /obj/item/clothing/suit/bio_suit/plaguedoctorsuit = 1, - /obj/item/clothing/head/plaguedoctorhat = 1, - /obj/item/clothing/mask/gas/plaguedoctor = 1, - /obj/item/clothing/suit/toggle/owlwings = 1, - /obj/item/clothing/under/owl = 1, - /obj/item/clothing/mask/gas/owl_mask = 1, - /obj/item/clothing/suit/toggle/owlwings/griffinwings = 1, - /obj/item/clothing/under/griffin = 1, - /obj/item/clothing/shoes/griffin = 1, - /obj/item/clothing/head/griffin = 1, - /obj/item/clothing/suit/apron = 1, - /obj/item/clothing/under/waiter = 1, - /obj/item/clothing/suit/jacket/miljacket = 1, - /obj/item/clothing/under/pirate = 1, - /obj/item/clothing/suit/pirate = 1, - /obj/item/clothing/head/pirate = 1, - /obj/item/clothing/head/bandana = 1, - /obj/item/clothing/head/bandana = 1, - /obj/item/clothing/under/soviet = 1, - /obj/item/clothing/head/ushanka = 1, - /obj/item/clothing/suit/imperium_monk = 1, - /obj/item/clothing/mask/gas/cyborg = 1, - /obj/item/clothing/suit/holidaypriest = 1, - /obj/item/clothing/head/wizard/marisa/fake = 1, - /obj/item/clothing/suit/wizrobe/marisa/fake = 1, - /obj/item/clothing/under/sundress = 1, - /obj/item/clothing/head/witchwig = 1, - /obj/item/staff/broom = 1, - /obj/item/clothing/suit/wizrobe/fake = 1, - /obj/item/clothing/head/wizard/fake = 1, - /obj/item/staff = 3, - /obj/item/clothing/under/rank/mime/skirt = 1, - /obj/item/clothing/under/gimmick/rank/captain/suit/skirt = 1, - /obj/item/clothing/mask/gas/sexyclown = 1, - /obj/item/clothing/under/rank/clown/sexy = 1, - /obj/item/clothing/mask/gas/sexymime = 1, - /obj/item/clothing/under/sexymime = 1, - /obj/item/clothing/mask/rat/bat = 1, - /obj/item/clothing/mask/rat/bee = 1, - /obj/item/clothing/mask/rat/bear = 1, - /obj/item/clothing/mask/rat/raven = 1, - /obj/item/clothing/mask/rat/jackal = 1, - /obj/item/clothing/mask/rat/fox = 1, - /obj/item/clothing/mask/frog = 1, - /obj/item/clothing/mask/rat/tribal = 1, - /obj/item/clothing/mask/rat = 1, - /obj/item/clothing/suit/apron/overalls = 1, - /obj/item/clothing/head/rabbitears =1, - /obj/item/clothing/head/sombrero = 1, - /obj/item/clothing/head/sombrero/green = 1, - /obj/item/clothing/suit/poncho = 1, - /obj/item/clothing/suit/poncho/green = 1, - /obj/item/clothing/suit/poncho/red = 1, - /obj/item/clothing/under/maid = 1, - /obj/item/clothing/under/janimaid = 1, - /obj/item/clothing/glasses/cold=1, - /obj/item/clothing/glasses/heat=1, - /obj/item/clothing/suit/whitedress = 1, - /obj/item/clothing/under/jester = 1, - /obj/item/clothing/head/jester = 1, - /obj/item/clothing/under/villain = 1, - /obj/item/clothing/shoes/singery = 1, - /obj/item/clothing/under/singery = 1, - /obj/item/clothing/shoes/singerb = 1, - /obj/item/clothing/under/singerb = 1, - /obj/item/clothing/suit/hooded/carp_costume = 1, - /obj/item/clothing/suit/hooded/ian_costume = 1, - /obj/item/clothing/suit/hooded/bee_costume = 1, - /obj/item/clothing/suit/snowman = 1, - /obj/item/clothing/head/snowman = 1, - /obj/item/clothing/mask/joy = 1, - /obj/item/clothing/head/cueball = 1, - /obj/item/clothing/under/scratch = 1, - /obj/item/clothing/under/sailor = 1, - /obj/item/clothing/ears/headphones = 2, - /obj/item/clothing/head/wig/random = 3) + /obj/item/clothing/head/chicken = 1, + /obj/item/clothing/under/gladiator = 1, + /obj/item/clothing/head/helmet/gladiator = 1, + /obj/item/clothing/under/gimmick/rank/captain/suit = 1, + /obj/item/clothing/head/flatcap = 1, + /obj/item/clothing/suit/toggle/labcoat/mad = 1, + /obj/item/clothing/shoes/jackboots = 1, + /obj/item/clothing/under/schoolgirl = 1, + /obj/item/clothing/under/schoolgirl/red = 1, + /obj/item/clothing/under/schoolgirl/green = 1, + /obj/item/clothing/under/schoolgirl/orange = 1, + /obj/item/clothing/head/kitty = 1, + /obj/item/clothing/under/skirt/black = 1, + /obj/item/clothing/head/beret = 1, + /obj/item/clothing/accessory/waistcoat = 1, + /obj/item/clothing/under/suit_jacket = 1, + /obj/item/clothing/head/that = 1, + /obj/item/clothing/under/kilt = 1, + /obj/item/clothing/head/beret = 1, + /obj/item/clothing/accessory/waistcoat = 1, + /obj/item/clothing/glasses/monocle =1, + /obj/item/clothing/head/bowler = 1, + /obj/item/cane = 1, + /obj/item/clothing/under/sl_suit = 1, + /obj/item/clothing/mask/fakemoustache = 1, + /obj/item/clothing/suit/bio_suit/plaguedoctorsuit = 1, + /obj/item/clothing/head/plaguedoctorhat = 1, + /obj/item/clothing/mask/gas/plaguedoctor = 1, + /obj/item/clothing/suit/toggle/owlwings = 1, + /obj/item/clothing/under/owl = 1, + /obj/item/clothing/mask/gas/owl_mask = 1, + /obj/item/clothing/suit/toggle/owlwings/griffinwings = 1, + /obj/item/clothing/under/griffin = 1, + /obj/item/clothing/shoes/griffin = 1, + /obj/item/clothing/head/griffin = 1, + /obj/item/clothing/suit/apron = 1, + /obj/item/clothing/under/waiter = 1, + /obj/item/clothing/suit/jacket/miljacket = 1, + /obj/item/clothing/under/pirate = 1, + /obj/item/clothing/suit/pirate = 1, + /obj/item/clothing/head/pirate = 1, + /obj/item/clothing/head/bandana = 1, + /obj/item/clothing/head/bandana = 1, + /obj/item/clothing/under/soviet = 1, + /obj/item/clothing/head/ushanka = 1, + /obj/item/clothing/suit/imperium_monk = 1, + /obj/item/clothing/mask/gas/cyborg = 1, + /obj/item/clothing/suit/chaplain/holidaypriest = 1, + /obj/item/clothing/head/wizard/marisa/fake = 1, + /obj/item/clothing/suit/wizrobe/marisa/fake = 1, + /obj/item/clothing/under/sundress = 1, + /obj/item/clothing/head/witchwig = 1, + /obj/item/staff/broom = 1, + /obj/item/clothing/suit/wizrobe/fake = 1, + /obj/item/clothing/head/wizard/fake = 1, + /obj/item/staff = 3, + /obj/item/clothing/under/rank/mime/skirt = 1, + /obj/item/clothing/under/gimmick/rank/captain/suit/skirt = 1, + /obj/item/clothing/mask/gas/sexyclown = 1, + /obj/item/clothing/under/rank/clown/sexy = 1, + /obj/item/clothing/mask/gas/sexymime = 1, + /obj/item/clothing/under/sexymime = 1, + /obj/item/clothing/mask/rat/bat = 1, + /obj/item/clothing/mask/rat/bee = 1, + /obj/item/clothing/mask/rat/bear = 1, + /obj/item/clothing/mask/rat/raven = 1, + /obj/item/clothing/mask/rat/jackal = 1, + /obj/item/clothing/mask/rat/fox = 1, + /obj/item/clothing/mask/frog = 1, + /obj/item/clothing/mask/rat/tribal = 1, + /obj/item/clothing/mask/rat = 1, + /obj/item/clothing/suit/apron/overalls = 1, + /obj/item/clothing/head/rabbitears =1, + /obj/item/clothing/head/sombrero = 1, + /obj/item/clothing/head/sombrero/green = 1, + /obj/item/clothing/suit/poncho = 1, + /obj/item/clothing/suit/poncho/green = 1, + /obj/item/clothing/suit/poncho/red = 1, + /obj/item/clothing/under/maid = 1, + /obj/item/clothing/under/janimaid = 1, + /obj/item/clothing/glasses/cold=1, + /obj/item/clothing/glasses/heat=1, + /obj/item/clothing/suit/whitedress = 1, + /obj/item/clothing/under/jester = 1, + /obj/item/clothing/head/jester = 1, + /obj/item/clothing/under/villain = 1, + /obj/item/clothing/shoes/singery = 1, + /obj/item/clothing/under/singery = 1, + /obj/item/clothing/shoes/singerb = 1, + /obj/item/clothing/under/singerb = 1, + /obj/item/clothing/suit/hooded/carp_costume = 1, + /obj/item/clothing/suit/hooded/ian_costume = 1, + /obj/item/clothing/suit/hooded/bee_costume = 1, + /obj/item/clothing/suit/snowman = 1, + /obj/item/clothing/head/snowman = 1, + /obj/item/clothing/mask/joy = 1, + /obj/item/clothing/head/cueball = 1, + /obj/item/clothing/under/scratch = 1, + /obj/item/clothing/under/sailor = 1, + /obj/item/clothing/ears/headphones = 2, + /obj/item/clothing/head/wig/random = 3, + /obj/item/clothing/suit/ran = 2, + /obj/item/clothing/head/ran = 2) contraband = list(/obj/item/clothing/suit/judgerobe = 1, /obj/item/clothing/head/powdered_wig = 1, /obj/item/gun/magic/wand = 2, @@ -122,7 +124,7 @@ /obj/item/clothing/shoes/roman = 1, /obj/item/shield/riot/roman/fake = 1, /obj/item/skub = 1, - /obj/item/clothing/under/lobster = 1, // CIT CHANGES + /obj/item/clothing/under/lobster = 1, // CIT CHANGES /obj/item/clothing/head/lobsterhat = 1, /obj/item/clothing/head/drfreezehat = 1, /obj/item/clothing/suit/dracula = 1, diff --git a/code/modules/vending/clothesmate.dm b/code/modules/vending/clothesmate.dm index 1497992fe8..b232184975 100644 --- a/code/modules/vending/clothesmate.dm +++ b/code/modules/vending/clothesmate.dm @@ -99,7 +99,9 @@ /obj/item/clothing/suit/jacket/letterman_red = 3, /obj/item/clothing/ears/headphones = 10, /obj/item/clothing/suit/apron/purple_bartender = 4, - /obj/item/clothing/under/rank/bartender/purple = 4) + /obj/item/clothing/under/rank/bartender/purple = 4, + /obj/item/clothing/accessory/attrocious_pokadots = 8, + /obj/item/clothing/accessory/black_white_pokadots = 8) contraband = list(/obj/item/clothing/under/syndicate/tacticool = 3, /obj/item/clothing/under/syndicate/tacticool/skirt = 3, /obj/item/clothing/mask/balaclava = 3, @@ -109,7 +111,8 @@ /obj/item/clothing/suit/jacket/letterman_syndie = 5, /obj/item/clothing/under/jabroni = 2, /obj/item/clothing/suit/vapeshirt = 2, - /obj/item/clothing/under/geisha = 4) + /obj/item/clothing/under/geisha = 4, + /obj/item/clothing/accessory/syndi_pokadots = 4) premium = list(/obj/item/clothing/under/suit_jacket/checkered = 4, /obj/item/clothing/head/mailman = 2, /obj/item/clothing/under/rank/mailman = 2, @@ -117,7 +120,8 @@ /obj/item/clothing/suit/jacket/leather/overcoat = 4, /obj/item/clothing/under/pants/mustangjeans = 3, /obj/item/clothing/neck/necklace/dope = 5, - /obj/item/clothing/suit/jacket/letterman_nanotrasen = 5) + /obj/item/clothing/suit/jacket/letterman_nanotrasen = 5, + /obj/item/clothing/accessory/nt_pokadots = 5) refill_canister = /obj/item/vending_refill/clothing /obj/item/vending_refill/clothing diff --git a/code/modules/vending/drinnerware.dm b/code/modules/vending/drinnerware.dm index 749a3b7c2b..3b036c0d90 100644 --- a/code/modules/vending/drinnerware.dm +++ b/code/modules/vending/drinnerware.dm @@ -9,7 +9,9 @@ /obj/item/kitchen/rollingpin = 2, /obj/item/reagent_containers/food/drinks/drinkingglass = 8, /obj/item/clothing/suit/apron/chef = 2, + /obj/item/storage/box/cups = 2, /obj/item/reagent_containers/food/condiment/pack/ketchup = 5, + /obj/item/reagent_containers/food/condiment/pack/mustard = 5, /obj/item/reagent_containers/food/condiment/pack/hotsauce = 5, /obj/item/reagent_containers/food/condiment/pack/astrotame = 5, /obj/item/reagent_containers/food/condiment/saltshaker = 5, diff --git a/code/modules/vending/engivend.dm b/code/modules/vending/engivend.dm index 9358d1652f..1b66dd5eb6 100644 --- a/code/modules/vending/engivend.dm +++ b/code/modules/vending/engivend.dm @@ -7,12 +7,12 @@ products = list(/obj/item/clothing/glasses/meson/engine = 5, /obj/item/clothing/glasses/welding = 5, /obj/item/multitool = 5, - /obj/item/construction/rcd/loaded = 3, + /obj/item/construction/rcd/loaded/upgraded = 3, /obj/item/grenade/chem_grenade/smart_metal_foam = 10, /obj/item/geiger_counter = 6, /obj/item/stock_parts/cell/high = 10, - /obj/item/electronics/airlock = 10, - /obj/item/electronics/apc = 10, + /obj/item/electronics/airlock = 10, + /obj/item/electronics/apc = 10, /obj/item/electronics/airalarm = 10, /obj/item/electronics/firealarm = 10, /obj/item/electronics/firelock = 10, diff --git a/code/modules/vending/medical.dm b/code/modules/vending/medical.dm index 523606aa6a..44dca6b257 100644 --- a/code/modules/vending/medical.dm +++ b/code/modules/vending/medical.dm @@ -28,7 +28,9 @@ contraband = list(/obj/item/reagent_containers/pill/tox = 3, /obj/item/reagent_containers/pill/morphine = 4, /obj/item/reagent_containers/pill/charcoal = 6) - premium = list(/obj/item/storage/box/hug/medical = 1, + premium = list(/obj/item/reagent_containers/medspray/synthflesh = 2, + /obj/item/storage/box/hug/medical = 1, + /obj/item/storage/pill_bottle/psicodine = 2, /obj/item/reagent_containers/hypospray/medipen = 3, /obj/item/storage/belt/medical = 3, /obj/item/wrench/medical = 1, diff --git a/code/modules/vending/megaseed.dm b/code/modules/vending/megaseed.dm index 4594048256..d230f40af0 100644 --- a/code/modules/vending/megaseed.dm +++ b/code/modules/vending/megaseed.dm @@ -15,6 +15,7 @@ /obj/item/seeds/chili = 3, /obj/item/seeds/cocoapod = 3, /obj/item/seeds/coffee = 3, + /obj/item/seeds/cotton = 3, /obj/item/seeds/corn = 3, /obj/item/seeds/eggplant = 3, /obj/item/seeds/grape = 3, @@ -23,6 +24,7 @@ /obj/item/seeds/lime = 3, /obj/item/seeds/onion = 3, /obj/item/seeds/orange = 3, + /obj/item/seeds/peach = 3, /obj/item/seeds/peanutseed = 3, /obj/item/seeds/pineapple = 3, /obj/item/seeds/potato = 3, @@ -31,7 +33,9 @@ /obj/item/seeds/replicapod = 3, /obj/item/seeds/wheat/rice = 3, /obj/item/seeds/soya = 3, + /obj/item/seeds/sugarcane = 3, /obj/item/seeds/sunflower = 3, + /obj/item/seeds/strawberry = 3, /obj/item/seeds/tea = 3, /obj/item/seeds/tobacco = 3, /obj/item/seeds/tomato = 3, diff --git a/code/modules/vending/wardrobes.dm b/code/modules/vending/wardrobes.dm index 19b524b74d..fbc7713f25 100644 --- a/code/modules/vending/wardrobes.dm +++ b/code/modules/vending/wardrobes.dm @@ -129,6 +129,7 @@ /obj/item/clothing/head/soft/black = 3, /obj/item/clothing/mask/bandana/skull = 2) premium = list(/obj/item/radio/headset/headset_rob = 2) //Cit change + contraband = list(/obj/item/clothing/suit/hooded/techpriest = 2) refill_canister = /obj/item/vending_refill/wardrobe/robo_wardrobe /obj/item/vending_refill/wardrobe/robo_wardrobe @@ -226,8 +227,8 @@ name = "ChefDrobe" desc = "This vending machine might not dispense meat, but it certainly dispenses chef related clothing." icon_state = "chefdrobe" - product_ads = "Our clothes are guaranteed to protect you from food splatters!" - vend_reply = "Thank you for using the ChefDrobe!" + product_ads = "Our clothes are guaranteed to protect you from food splatters!;Now stocking recipe books!" + vend_reply = "Thank you for using the ChefDrobe!;Just like your grandmother's old recipes!" products = list(/obj/item/clothing/under/waiter = 3, /obj/item/radio/headset/headset_srv = 4, /obj/item/clothing/accessory/waistcoat = 3, @@ -240,7 +241,8 @@ /obj/item/clothing/under/rank/chef/skirt = 2, /obj/item/clothing/head/chefhat = 2, /obj/item/reagent_containers/rag = 3, - /obj/item/book/granter/crafting_recipe/cooking_sweets_101 = 2) + /obj/item/book/granter/crafting_recipe/cooking_sweets_101 = 2, + /obj/item/book/granter/crafting_recipe/coldcooking = 2) refill_canister = /obj/item/vending_refill/wardrobe/chef_wardrobe /obj/item/vending_refill/wardrobe/chef_wardrobe @@ -316,9 +318,12 @@ /obj/item/clothing/under/rank/chaplain = 2, /obj/item/clothing/under/rank/chaplain/skirt = 2, /obj/item/clothing/shoes/sneakers/black = 2, - /obj/item/clothing/suit/nun = 2, + /obj/item/clothing/suit/chaplain/nun = 2, /obj/item/clothing/head/nun_hood = 2, - /obj/item/clothing/suit/holidaypriest = 2, + /obj/item/clothing/suit/chaplain/holidaypriest = 2, + /obj/item/clothing/suit/chaplain/pharaoh = 2, + /obj/item/clothing/head/nemes = 1, + /obj/item/clothing/head/pharaoh = 1, /obj/item/storage/fancy/candle_box = 3) refill_canister = /obj/item/vending_refill/wardrobe/chap_wardrobe @@ -337,7 +342,8 @@ /obj/item/clothing/suit/toggle/labcoat/chemist = 3, /obj/item/storage/backpack/chemistry = 3, /obj/item/storage/backpack/satchel/chem = 3, - /obj/item/storage/bag/chemistry = 3) + /obj/item/storage/bag/chemistry = 3, + /obj/item/fermichem/pHbooklet = 3)//pH indicator) refill_canister = /obj/item/vending_refill/wardrobe/chem_wardrobe /obj/item/vending_refill/wardrobe/chem_wardrobe diff --git a/modular_citadel/code/modules/vore/eating/belly_dat_vr.dm b/code/modules/vore/eating/belly_dat_vr.dm similarity index 100% rename from modular_citadel/code/modules/vore/eating/belly_dat_vr.dm rename to code/modules/vore/eating/belly_dat_vr.dm diff --git a/modular_citadel/code/modules/vore/eating/belly_obj_vr.dm b/code/modules/vore/eating/belly_obj.dm similarity index 79% rename from modular_citadel/code/modules/vore/eating/belly_obj_vr.dm rename to code/modules/vore/eating/belly_obj.dm index c4b2fbf5b1..741aff5f9a 100644 --- a/modular_citadel/code/modules/vore/eating/belly_obj_vr.dm +++ b/code/modules/vore/eating/belly_obj.dm @@ -38,6 +38,7 @@ var/swallow_time = 10 SECONDS // for mob transfering automation var/vore_capacity = 1 // simple animal nom capacity var/is_wet = TRUE // Is this belly inside slimy parts? + var/wet_loop = TRUE // Does this belly have a slimy internal loop? //I don't think we've ever altered these lists. making them static until someone actually overrides them somewhere. var/tmp/static/list/digest_modes = list(DM_HOLD,DM_DIGEST,DM_HEAL,DM_NOISY,DM_ABSORB,DM_UNABSORB) // Possible digest modes @@ -138,13 +139,17 @@ "digest_messages_prey", "examine_messages", "emote_lists", - "is_wet" + "is_wet", + "wet_loop" ) //ommitted list // "shrink_grow_size", -/obj/belly/New(var/newloc) - . = ..(newloc) +/obj/belly/Initialize() + . = ..() + take_ownership(src.loc) + +/obj/belly/proc/take_ownership(var/newloc) //If not, we're probably just in a prefs list or something. if(isliving(newloc)) owner = loc @@ -167,13 +172,22 @@ to_chat(owner,"[thing] slides into your [lowertext(name)].") //Sound w/ antispam flag setting - if(is_wet && (world.time > recent_sound)) - var/turf/source = get_turf(owner) - var/sound/eating = GLOB.vore_sounds[vore_sound] - for(var/mob/living/M in get_hearers_in_view(3, source)) - if(M.client && M.client.prefs.cit_toggles & EATING_NOISES) - SEND_SOUND(M, eating) - recent_sound = (world.time + 20 SECONDS) + if(vore_sound && !recent_sound) + if((world.time + NORMIE_HEARCHECK) > last_hearcheck) + LAZYCLEARLIST(hearing_mobs) + for(var/mob/living/H in get_hearers_in_view(3, owner)) + if(!H.client || !(H.client.prefs.cit_toggles & EATING_NOISES)) + continue + LAZYADD(hearing_mobs, H) + last_hearcheck = world.time + for(var/mob/living/H in hearing_mobs) + if(H && H.client && (isturf(H.loc) || (H.loc != src.contents))) + var/sound/eating = GLOB.pred_vore_sounds[vore_sound] + SEND_SOUND(H,eating) + else if(H && H in contents && H.client) + var/sound/eating = GLOB.prey_vore_sounds[vore_sound] + SEND_SOUND(H,eating) + recent_sound = TRUE //Messages if it's a mob if(isliving(thing)) @@ -185,7 +199,7 @@ // If that location is another mob, contents are transferred into whichever of its bellies the owning mob is in. // Returns the number of mobs so released. /obj/belly/proc/release_all_contents(var/include_absorbed = FALSE, var/silent = FALSE) - var/atom/destination = drop_location() +// var/atom/destination = drop_location() //Don't bother if we don't have contents if(!contents.len) return FALSE @@ -205,22 +219,30 @@ SEND_SIGNAL(L, COMSIG_CLEAR_MOOD_EVENT, "fedprey", /datum/mood_event/fedprey) SEND_SIGNAL(OW, COMSIG_ADD_MOOD_EVENT, "emptypred", /datum/mood_event/emptypred) SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "emptyprey", /datum/mood_event/emptyprey) - AM.forceMove(destination) // Move the belly contents into the same location as belly's owner. - count++ - for(var/mob/living/M in get_hearers_in_view(2, get_turf(owner))) - if(M.client && (M.client.prefs.cit_toggles & EATING_NOISES)) - var/sound/releasement = GLOB.release_sounds[release_sound] - SEND_SOUND(M, releasement) + count += release_specific_contents(AM, silent = TRUE) //Clean up our own business items_preserved.Cut() - if(isanimal(owner)) - owner.update_icons() + owner.update_icons() if(!silent) + if(release_sound && !recent_sound) + if((world.time + NORMIE_HEARCHECK) > last_hearcheck) + LAZYCLEARLIST(hearing_mobs) + for(var/mob/living/H in get_hearers_in_view(3, owner)) + if(!H.client || !(H.client.prefs.cit_toggles & EATING_NOISES)) + continue + LAZYADD(hearing_mobs, H) + last_hearcheck = world.time + for(var/mob/living/H in hearing_mobs) + if(H && H.client && (isturf(H.loc) || (H.loc != src.contents))) + var/sound/releasement = GLOB.pred_release_sounds[release_sound] + SEND_SOUND(H,releasement) + else if(H && H in contents && H.client) + var/sound/releasement = GLOB.prey_release_sounds[release_sound] + SEND_SOUND(H,releasement) + recent_sound = TRUE owner.visible_message("[owner] expels everything from their [lowertext(name)]!") - items_preserved.Cut() - owner.update_icons() return count @@ -233,16 +255,13 @@ M.forceMove(drop_location()) // Move the belly contents into the same location as belly's owner. items_preserved -= M - if(!silent) - for(var/mob/living/H in get_hearers_in_view(2, get_turf(owner))) - if(H.client && (H.client.prefs.cit_toggles & EATING_NOISES)) - var/sound/releasement = GLOB.release_sounds[release_sound] - SEND_SOUND(H, releasement) + if(istype(M,/mob/living)) var/mob/living/ML = M var/mob/living/OW = owner - ML.stop_sound_channel(CHANNEL_PREYLOOP) + if(ML.client) + ML.stop_sound_channel(CHANNEL_PREYLOOP) //Stop the internal loop, it'll restart if the isbelly check on next tick anyway ML.cure_blind("belly_[REF(src)]") SEND_SIGNAL(OW, COMSIG_CLEAR_MOOD_EVENT, "fedpred", /datum/mood_event/fedpred) SEND_SIGNAL(ML, COMSIG_CLEAR_MOOD_EVENT, "fedprey", /datum/mood_event/fedprey) @@ -261,12 +280,27 @@ Pred.reagents.trans_to(Prey, Pred.reagents.total_volume / absorbed_count) //Clean up our own business - if(isanimal(owner)) - owner.update_icons() + owner.update_icons() if(!silent) + if(release_sound && !recent_sound) + if((world.time + NORMIE_HEARCHECK) > last_hearcheck) + LAZYCLEARLIST(hearing_mobs) + for(var/mob/living/H in get_hearers_in_view(3, owner)) + if(!H.client || !(H.client.prefs.cit_toggles & EATING_NOISES)) + continue + LAZYADD(hearing_mobs, H) + last_hearcheck = world.time + for(var/mob/living/H in hearing_mobs) + if(H && H.client && (isturf(H.loc) || (H.loc != src.contents))) + var/sound/releasement = GLOB.pred_release_sounds[release_sound] + SEND_SOUND(H,releasement) + else if(H && H in contents && H.client) + var/sound/releasement = GLOB.prey_release_sounds[release_sound] + SEND_SOUND(H,releasement) + recent_sound = TRUE owner.visible_message("[owner] expels [M] from their [lowertext(name)]!") - owner.update_icons() + return TRUE // Actually perform the mechanics of devouring the tasty prey. @@ -310,15 +344,26 @@ /obj/belly/proc/transfer_contents(var/atom/movable/content, var/obj/belly/target, silent = FALSE) if(!(content in src) || !istype(target)) return + content.forceMove(target) for(var/mob/living/M in contents) M.cure_blind("belly_[REF(src)]") - target.nom_mob(content, target.owner) - if(!silent) - var/turf/source = get_turf(owner) - var/sound/eating = GLOB.vore_sounds[vore_sound] - for(var/mob/living/M in get_hearers_in_view(3, source)) - if(M.client && M.client.prefs.cit_toggles & EATING_NOISES) - SEND_SOUND(M, eating) +// target.nom_mob(content, target.owner) + if(vore_sound && !recent_sound && !silent) + if((world.time + NORMIE_HEARCHECK) > last_hearcheck) + LAZYCLEARLIST(hearing_mobs) + for(var/mob/living/H in get_hearers_in_view(3, owner)) + if(!H.client || !(H.client.prefs.cit_toggles & EATING_NOISES)) + continue + LAZYADD(hearing_mobs, H) + last_hearcheck = world.time + for(var/mob/living/H in hearing_mobs) + if(H && H.client && (isturf(H.loc) || (H.loc != src.contents))) + var/sound/eating = GLOB.pred_vore_sounds[vore_sound] + SEND_SOUND(H,eating) + else if(H && H in contents && H.client) + var/sound/eating = GLOB.prey_vore_sounds[vore_sound] + SEND_SOUND(H,eating) + recent_sound = TRUE owner.updateVRPanel() for(var/mob/living/M in contents) @@ -422,9 +467,12 @@ if(!M.dropItemToGround(W)) qdel(W) + //Incase they have the loop going, let's double check to stop it. + M.stop_sound_channel(CHANNEL_PREYLOOP) + // Delete the digested mob qdel(M) - M.stop_sound_channel(CHANNEL_PREYLOOP) + //Update owner owner.updateVRPanel() @@ -468,7 +516,7 @@ /obj/belly/drop_location() //Should be the case 99.99% of the time if(owner) - return owner.loc + return owner.drop_location() //Sketchy fallback for safety, put them somewhere safe. else if(ismob(src)) testing("[src] (\ref[src]) doesn't have an owner, and dropped someone at a latespawn point!") @@ -523,24 +571,31 @@ struggle_outer_message = "" + struggle_outer_message + "" struggle_user_message = "" + struggle_user_message + "" - var/turf/source = get_turf(owner) - var/sound/struggle_snuggle = sound(get_sfx("struggle_sound")) + var/sound/pred_struggle_snuggle = sound(get_sfx("struggle_sound")) + var/sound/prey_struggle_snuggle = sound(get_sfx("prey_struggle")) var/sound/struggle_rustle = sound(get_sfx("rustle")) + LAZYCLEARLIST(hearing_mobs) + for(var/mob/living/H in get_hearers_in_view(3, owner)) + if(!H.client || !(H.client.prefs.cit_toggles & EATING_NOISES)) + continue + LAZYADD(hearing_mobs, H) + if(is_wet) - for(var/mob/living/M in get_hearers_in_view(3, source)) - if(M.client && M.client.prefs.cit_toggles & EATING_NOISES) - SEND_SOUND(M, struggle_snuggle) + for(var/mob/living/H in hearing_mobs) + if(H && H.client && (isturf(H.loc) || (H.loc != src.contents))) + SEND_SOUND(H,pred_struggle_snuggle) + else if(H && H in contents && H.client) + SEND_SOUND(H,prey_struggle_snuggle) else - for(var/mob/living/M in get_hearers_in_view(3, source)) - if(M.client && M.client.prefs.cit_toggles & EATING_NOISES) - SEND_SOUND(M, struggle_rustle) + for(var/mob/living/H in hearing_mobs) + if(H && H.client) + SEND_SOUND(H, struggle_rustle) - var/list/watching = hearers(3, owner) - for(var/mob/living/M in watching) - if(M.client && (M.client.prefs.cit_toggles & EATING_NOISES)) //Might as well censor the normies here too. - M.show_message(struggle_outer_message, 1) // visible + for(var/mob/living/H in hearing_mobs) + if(H && H.client && (isturf(H.loc))) + H.show_message(struggle_outer_message, 1) // visible to_chat(R,struggle_user_message) @@ -549,8 +604,10 @@ to_chat(R,"You start to climb out of \the [lowertext(name)].") to_chat(owner,"Someone is attempting to climb out of your [lowertext(name)]!") if(do_after(R, escapetime)) - if((owner.stat || escapable) && (R.loc == src)) //Can still escape? + if((escapable) && (R.loc == src)) //Can still escape? release_specific_contents(R) + to_chat(R,"You climb out of \the [lowertext(name)].") + to_chat(owner,"[R] climbs out of your [lowertext(name)]!") return else if(R.loc != src) //Aren't even in the belly. Quietly fail. return @@ -558,41 +615,41 @@ to_chat(R,"Your attempt to escape [lowertext(name)] has failed!") to_chat(owner,"The attempt to escape from your [lowertext(name)] has failed!") return - else if(prob(transferchance) && transferlocation) //Next, let's have it see if they end up getting into an even bigger mess then when they started. - var/obj/belly/dest_belly - for(var/belly in owner.vore_organs) - var/obj/belly/B = belly - if(B.name == transferlocation) - dest_belly = B - break + else if(prob(transferchance) && transferlocation) //Next, let's have it see if they end up getting into an even bigger mess then when they started. + var/obj/belly/dest_belly + for(var/belly in owner.vore_organs) + var/obj/belly/B = belly + if(B.name == transferlocation) + dest_belly = B + break - if(!dest_belly) - to_chat(owner, "Something went wrong with your belly transfer settings. Your [lowertext(name)] has had it's transfer chance and transfer location cleared as a precaution.") - transferchance = 0 - transferlocation = null + if(!dest_belly) + to_chat(owner, "Something went wrong with your belly transfer settings. Your [lowertext(name)] has had it's transfer chance and transfer location cleared as a precaution.") + transferchance = 0 + transferlocation = null + return + + to_chat(R,"Your attempt to escape [lowertext(name)] has failed and your struggles only results in you sliding into [owner]'s [transferlocation]!") + to_chat(owner,"Someone slid into your [transferlocation] due to their struggling inside your [lowertext(name)]!") + transfer_contents(R, dest_belly) return - to_chat(R,"Your attempt to escape [lowertext(name)] has failed and your struggles only results in you sliding into [owner]'s [transferlocation]!") - to_chat(owner,"Someone slid into your [transferlocation] due to their struggling inside your [lowertext(name)]!") - transfer_contents(R, dest_belly) - return + else if(prob(absorbchance) && digest_mode != DM_ABSORB) //After that, let's have it run the absorb chance. + to_chat(R,"In response to your struggling, \the [lowertext(name)] begins to cling more tightly...") + to_chat(owner,"You feel your [lowertext(name)] start to cling onto its contents...") + digest_mode = DM_ABSORB + return - else if(prob(absorbchance) && digest_mode != DM_ABSORB) //After that, let's have it run the absorb chance. - to_chat(R,"In response to your struggling, \the [lowertext(name)] begins to cling more tightly...") - to_chat(owner,"You feel your [lowertext(name)] start to cling onto its contents...") - digest_mode = DM_ABSORB - return + else if(prob(digestchance) && digest_mode != DM_DIGEST) //Finally, let's see if it should run the digest chance. + to_chat(R,"In response to your struggling, \the [lowertext(name)] begins to get more active...") + to_chat(owner,"You feel your [lowertext(name)] beginning to become active!") + digest_mode = DM_DIGEST + return - else if(prob(digestchance) && digest_mode != DM_DIGEST) //Finally, let's see if it should run the digest chance. - to_chat(R,"In response to your struggling, \the [lowertext(name)] begins to get more active...") - to_chat(owner,"You feel your [lowertext(name)] beginning to become active!") - digest_mode = DM_DIGEST - return - - else //Nothing interesting happened. - to_chat(R,"You make no progress in escaping [owner]'s [lowertext(name)].") - to_chat(owner,"Your prey appears to be unable to make any progress in escaping your [lowertext(name)].") - return + else //Nothing interesting happened. + to_chat(R,"You make no progress in escaping [owner]'s [lowertext(name)].") + to_chat(owner,"Your prey appears to be unable to make any progress in escaping your [lowertext(name)].") + return /obj/belly/proc/get_mobs_and_objs_in_belly() var/list/see = list() @@ -639,6 +696,7 @@ dupe.swallow_time = swallow_time dupe.vore_capacity = vore_capacity dupe.is_wet = is_wet + dupe.wet_loop = wet_loop //// Object-holding variables //struggle_messages_outside - strings diff --git a/modular_citadel/code/modules/vore/eating/bellymodes_vr.dm b/code/modules/vore/eating/bellymodes.dm similarity index 74% rename from modular_citadel/code/modules/vore/eating/bellymodes_vr.dm rename to code/modules/vore/eating/bellymodes.dm index 9356c25f57..0ecaf49abc 100644 --- a/modular_citadel/code/modules/vore/eating/bellymodes_vr.dm +++ b/code/modules/vore/eating/bellymodes.dm @@ -4,35 +4,43 @@ recent_sound = FALSE return SSBELLIES_IGNORED + if(!owner) + qdel(src) + SSbellies.belly_list -= src + return SSBELLIES_PROCESSED + if(loc != owner) - if(istype(owner)) - loc = owner + if(isliving(owner)) //we don't have machine based bellies. (yet :honk:) + forceMove(owner) else + SSbellies.belly_list -= src qdel(src) return SSBELLIES_PROCESSED next_process = times_fired + (6 SECONDS/wait) //Set up our next process time. + var/to_update = FALSE /////////////////////////// Auto-Emotes /////////////////////////// if(contents.len && next_emote <= times_fired) next_emote = times_fired + round(emote_time/wait,1) var/list/EL = emote_lists[digest_mode] - for(var/mob/living/M in contents) - if(M.digestable || !(digest_mode == DM_DIGEST)) // don't give digesty messages to indigestible people - to_chat(M,"[pick(EL)]") + if(LAZYLEN(EL)) + for(var/mob/living/M in contents) + if(M.digestable || !(digest_mode == DM_DIGEST)) // don't give digesty messages to indigestible people + to_chat(M,"[pick(EL)]") ///////////////////// Prey Loop Refresh/hack ////////////////////// for(var/mob/living/M in contents) - if(isbelly(M.loc)) + if(M && isbelly(M.loc)) if(world.time > M.next_preyloop) - if(is_wet) + if(is_wet && wet_loop) if(!M.client) continue M.stop_sound_channel(CHANNEL_PREYLOOP) // sanity just in case if(M.client.prefs.cit_toggles & DIGESTION_NOISES) - var/sound/preyloop = sound('sound/vore/prey/loop.ogg', repeat = TRUE) + var/sound/preyloop = sound('sound/vore/prey/loop.ogg') M.playsound_local(get_turf(src),preyloop, 80,0, channel = CHANNEL_PREYLOOP) - M.next_preyloop = (world.time + 52 SECONDS) + M.next_preyloop = (world.time + 51 SECONDS) /////////////////////////// Exit Early //////////////////////////// @@ -50,7 +58,6 @@ var/sound/prey_death = sound(get_sfx("death_prey")) var/sound/pred_digest = sound(get_sfx("digest_pred")) var/sound/pred_death = sound(get_sfx("death_pred")) - var/turf/source = get_turf(owner) ///////////////////////////// DM_HOLD ///////////////////////////// if(digest_mode == DM_HOLD) @@ -64,18 +71,18 @@ for (var/mob/living/M in contents) if(prob(25)) - if((world.time - NORMIE_HEARCHECK) > last_hearcheck) + if((world.time + NORMIE_HEARCHECK) > last_hearcheck) LAZYCLEARLIST(hearing_mobs) - for(var/mob/living/H in get_hearers_in_view(3, source)) + for(var/mob/living/H in get_hearers_in_view(3, owner)) if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES)) continue LAZYADD(hearing_mobs, H) last_hearcheck = world.time for(var/mob/living/H in hearing_mobs) - if(!isbelly(H.loc)) - H.playsound_local(source, null, 45, falloff = 0, S = pred_digest) - else if(H in contents) - H.playsound_local(source, null, 65, falloff = 0, S = prey_digest) + if(H && H.client && (isturf(H.loc) || (H.loc != src.contents))) + SEND_SOUND(H,pred_digest) + else if(H && H in contents && H.client) + SEND_SOUND(H,prey_digest) //Pref protection! if (!M.digestable || M.absorbed) @@ -101,21 +108,22 @@ M.visible_message("You watch as [owner]'s form loses its additions.") owner.nutrition += 400 // so eating dead mobs gives you *something*. - if((world.time - NORMIE_HEARCHECK) > last_hearcheck) + if((world.time + NORMIE_HEARCHECK) > last_hearcheck) LAZYCLEARLIST(hearing_mobs) - for(var/mob/living/H in get_hearers_in_view(3, source)) + for(var/mob/living/H in get_hearers_in_view(3, owner)) if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES)) continue LAZYADD(hearing_mobs, H) last_hearcheck = world.time for(var/mob/living/H in hearing_mobs) - if(!isbelly(H.loc)) - H.playsound_local(source, null, 45, falloff = 0, S = pred_death) - else if(H in contents) - H.playsound_local(source, null, 65, falloff = 0, S = prey_death) + if(H && H.client && (isturf(H.loc) || (H.loc != src.contents))) + SEND_SOUND(H,pred_death) + else if(H && H in contents && H.client) + SEND_SOUND(H,prey_death) M.stop_sound_channel(CHANNEL_PREYLOOP) digestion_death(M) owner.update_icons() + to_update = TRUE continue @@ -130,48 +138,45 @@ if(istype(T,/obj/item/reagent_containers/food) || istype(T,/obj/item/organ)) digest_item(T) - owner.updateVRPanel() - ///////////////////////////// DM_HEAL ///////////////////////////// if(digest_mode == DM_HEAL) for (var/mob/living/M in contents) if(prob(25)) - if((world.time - NORMIE_HEARCHECK) > last_hearcheck) + if((world.time + NORMIE_HEARCHECK) > last_hearcheck) LAZYCLEARLIST(hearing_mobs) - for(var/mob/living/H in get_hearers_in_view(3, source)) + for(var/mob/living/H in get_hearers_in_view(3, owner)) if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES)) continue LAZYADD(hearing_mobs, H) last_hearcheck = world.time for(var/mob/living/H in hearing_mobs) - if(!isbelly(H.loc)) - H.playsound_local(source, null, 45, falloff = 0, S = pred_digest) - else if(H in contents) - H.playsound_local(source, null, 65, falloff = 0, S = prey_digest) + if(H && H.client && (isturf(H.loc) || (H.loc != src.contents))) + SEND_SOUND(H,pred_digest) + else if(H && H in contents && H.client) + SEND_SOUND(H,prey_digest) if(M.stat != DEAD) if(owner.nutrition >= NUTRITION_LEVEL_STARVING && (M.health < M.maxHealth)) M.adjustBruteLoss(-3) M.adjustFireLoss(-3) owner.nutrition -= 5 - return ////////////////////////// DM_NOISY ///////////////////////////////// //for when you just want people to squelch around if(digest_mode == DM_NOISY) if(prob(35)) - if((world.time - NORMIE_HEARCHECK) > last_hearcheck) + if((world.time + NORMIE_HEARCHECK) > last_hearcheck) LAZYCLEARLIST(hearing_mobs) - for(var/mob/living/H in get_hearers_in_view(3, source)) + for(var/mob/living/H in get_hearers_in_view(3, owner)) if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES)) continue LAZYADD(hearing_mobs, H) last_hearcheck = world.time for(var/mob/living/H in hearing_mobs) - if(!isbelly(H.loc)) - H.playsound_local(source, null, 45, falloff = 0, S = pred_digest) - else if(H in contents) - H.playsound_local(source, null, 65, falloff = 0, S = prey_digest) + if(H && H.client && (isturf(H.loc) || (H.loc != src.contents))) + SEND_SOUND(H,pred_digest) + else if(H && H in contents && H.client) + SEND_SOUND(H,prey_digest) //////////////////////////// DM_ABSORB //////////////////////////// @@ -180,18 +185,18 @@ for (var/mob/living/M in contents) if(prob(10))//Less often than gurgles. People might leave this on forever. - if((world.time - NORMIE_HEARCHECK) > last_hearcheck) + if((world.time + NORMIE_HEARCHECK) > last_hearcheck) LAZYCLEARLIST(hearing_mobs) - for(var/mob/living/H in get_hearers_in_view(3, source)) + for(var/mob/living/H in get_hearers_in_view(3, owner)) if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES)) continue LAZYADD(hearing_mobs, H) last_hearcheck = world.time for(var/mob/living/H in hearing_mobs) - if(!isbelly(H.loc)) - H.playsound_local(source, null, 45, falloff = 0, S = pred_digest) - else if(H in contents) - H.playsound_local(source, null, 65, falloff = 0, S = prey_digest) + if(H && H.client && (isturf(H.loc) || (H.loc != src.contents))) + SEND_SOUND(H,pred_digest) + else if(H && H in contents && H.client) + SEND_SOUND(H,prey_digest) if(M.absorbed) continue @@ -202,16 +207,18 @@ owner.nutrition += oldnutrition else if(M.nutrition < 100) //When they're finally drained. absorb_living(M) + to_update = TRUE //////////////////////////// DM_UNABSORB //////////////////////////// else if(digest_mode == DM_UNABSORB) for (var/mob/living/M in contents) if(M.absorbed && owner.nutrition >= 100) - M.absorbed = 0 + M.absorbed = FALSE to_chat(M,"You suddenly feel solid again ") to_chat(owner,"You feel like a part of you is missing.") owner.nutrition -= 100 + to_update = TRUE //////////////////////////DM_DRAGON ///////////////////////////////////// //because dragons need snowflake guts @@ -222,18 +229,18 @@ for (var/mob/living/M in contents) if(prob(55)) //if you're hearing this, you're a vore ho anyway. - if((world.time - NORMIE_HEARCHECK) > last_hearcheck) + if((world.time + NORMIE_HEARCHECK) > last_hearcheck) LAZYCLEARLIST(hearing_mobs) - for(var/mob/living/H in get_hearers_in_view(3, source)) + for(var/mob/living/H in get_hearers_in_view(3, owner)) if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES)) continue LAZYADD(hearing_mobs, H) last_hearcheck = world.time for(var/mob/living/H in hearing_mobs) - if(!isbelly(H.loc)) - H.playsound_local(source, null, 45, falloff = 0, S = pred_digest) - else if(H in contents) - H.playsound_local(source, null, 65, falloff = 0, S = prey_digest) + if(H && H.client && (isturf(H.loc) || (H.loc != src.contents))) + SEND_SOUND(H,pred_digest) + else if(H && H in contents && H.client) + SEND_SOUND(H,prey_digest) //No digestion protection for megafauna. @@ -255,22 +262,23 @@ to_chat(owner, "[digest_alert_owner]") to_chat(M, "[digest_alert_prey]") M.visible_message("You watch as [owner]'s guts loudly rumble as it finishes off a meal.") - if((world.time - NORMIE_HEARCHECK) > last_hearcheck) + if((world.time + NORMIE_HEARCHECK) > last_hearcheck) LAZYCLEARLIST(hearing_mobs) - for(var/mob/living/H in get_hearers_in_view(3, source)) + for(var/mob/living/H in get_hearers_in_view(3, owner)) if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES)) continue LAZYADD(hearing_mobs, H) last_hearcheck = world.time for(var/mob/living/H in hearing_mobs) - if(!isbelly(H.loc)) - H.playsound_local(source, null, 45, falloff = 0, S = pred_death) - else if(H in contents) - H.playsound_local(source, null, 65, falloff = 0, S = prey_death) + if(H && H.client && (isturf(H.loc) || (H.loc != src.contents))) + SEND_SOUND(H,pred_death) + else if(H && H in contents && H.client) + SEND_SOUND(H,prey_death) M.spill_organs(FALSE,TRUE,TRUE) M.stop_sound_channel(CHANNEL_PREYLOOP) digestion_death(M) owner.update_icons() + to_update = TRUE continue @@ -285,4 +293,11 @@ if(istype(T,/obj/item/reagent_containers/food) || istype(T,/obj/item/organ)) digest_item(T) - owner.updateVRPanel() \ No newline at end of file + if(to_update) + for(var/mob/living/M in contents) + if(M.client) + M.updateVRPanel() + if(owner.client) + owner.updateVRPanel() + + return SSBELLIES_PROCESSED \ No newline at end of file diff --git a/modular_citadel/code/modules/vore/eating/digest_act_vr.dm b/code/modules/vore/eating/digest_act.dm similarity index 100% rename from modular_citadel/code/modules/vore/eating/digest_act_vr.dm rename to code/modules/vore/eating/digest_act.dm diff --git a/modular_citadel/code/modules/vore/eating/living_vr.dm b/code/modules/vore/eating/living.dm similarity index 93% rename from modular_citadel/code/modules/vore/eating/living_vr.dm rename to code/modules/vore/eating/living.dm index d9adde04d1..9fdb7aa764 100644 --- a/modular_citadel/code/modules/vore/eating/living_vr.dm +++ b/code/modules/vore/eating/living.dm @@ -8,7 +8,7 @@ var/feeding = FALSE // Are we going to feed someone else? var/vore_taste = null // What the character tastes like var/no_vore = FALSE // If the character/mob can vore. - var/openpanel = 0 // Is the vore panel open? + var/openpanel = FALSE // Is the vore panel open? var/absorbed = FALSE //are we absorbed? var/next_preyloop var/vore_init = FALSE //Has this mob's vore been initialized yet? @@ -23,16 +23,16 @@ M.verbs += /mob/living/proc/escapeOOC if(M.no_vore) //If the mob isn't supposed to have a stomach, let's not give it an insidepanel so it can make one for itself, or a stomach. - return 1 + return TRUE M.verbs += /mob/living/proc/insidePanel //Tries to load prefs if a client is present otherwise gives freebie stomach - spawn(10 SECONDS) // long delay because the server delays in its startup. just on the safe side. + spawn(2 SECONDS) // long delay because the server delays in its startup. just on the safe side. if(M) M.init_vore() - //Return 1 to hook-caller - return 1 + //return TRUE to hook-caller + return TRUE /mob/living/proc/init_vore() vore_init = TRUE @@ -54,10 +54,10 @@ LAZYINITLIST(vore_organs) var/obj/belly/B = new /obj/belly(src) vore_selected = B - B.immutable = 1 + B.immutable = TRUE B.name = "Stomach" B.desc = "It appears to be rather warm and wet. Makes sense, considering it's inside [name]." - B.can_taste = 1 + B.can_taste = TRUE return TRUE // Handle being clicked, perhaps with something to devour @@ -84,7 +84,7 @@ return feed_self_to_grabbed(user, pred) - if(pred == user) //you click yourself + else if(pred == user) //you click yourself if(!is_vore_predator(src)) to_chat(user, "You aren't voracious enough.") return @@ -126,7 +126,7 @@ //Sanity if(!user || !prey || !pred || !istype(belly) || !(belly in pred.vore_organs)) testing("[user] attempted to feed [prey] to [pred], via [lowertext(belly.name)] but it went wrong.") - return FALSE + return if (!prey.devourable) to_chat(user, "This can't be eaten!") @@ -151,9 +151,14 @@ user.visible_message(attempt_msg) // Now give the prey time to escape... return if they did - var/swallow_time = delay || ishuman(prey) ? belly.human_prey_swallow_time : belly.nonhuman_prey_swallow_time + var/swallow_time + if(delay) + swallow_time = delay + else + swallow_time = istype(prey, /mob/living/carbon/human) ? belly.human_prey_swallow_time : belly.nonhuman_prey_swallow_time - if(!do_mob(src, user, swallow_time)) + //Timer and progress bar + if(!do_after(user, swallow_time, prey)) return FALSE // Prey escaped (or user disabled) before timer expired. if(!prey.Adjacent(user)) //double check'd just in case they moved during the timer and the do_mob didn't fail for whatever reason @@ -162,13 +167,6 @@ // If we got this far, nom successful! Announce it! user.visible_message(success_msg) - // incredibly contentious eating noises time - var/turf/source = get_turf(user) - var/sound/eating = GLOB.vore_sounds[belly.vore_sound] - for(var/mob/living/M in get_hearers_in_view(3, source)) - if(M.client && M.client.prefs.cit_toggles & EATING_NOISES) - SEND_SOUND(M, eating) - // Actually shove prey into the belly. belly.nom_mob(prey, user) stop_pulling() @@ -183,7 +181,7 @@ if(prey.ckey) prey_stat = prey.stat//only return this if they're not an unmonkey or whatever if(!prey.client)//if they disconnected, tell us - prey_braindead = 1 + prey_braindead = TRUE if (pred == user) message_admins("[ADMIN_LOOKUPFLW(pred)] ate [ADMIN_LOOKUPFLW(prey)][!prey_braindead ? "" : " (BRAINDEAD)"][prey_stat ? " (DEAD/UNCONSCIOUS)" : ""].") pred.log_message("[key_name(pred)] ate [key_name(prey)].", LOG_ATTACK) @@ -212,15 +210,15 @@ //Other overridden resists go here - return 0 + return FALSE // internal slimy button in case the loop stops playing but the player wants to hear it /mob/living/proc/preyloop_refresh() set name = "Internal loop refresh" set category = "Vore" + src.stop_sound_channel(CHANNEL_PREYLOOP) // sanity just in case if(isbelly(loc)) - src.stop_sound_channel(CHANNEL_PREYLOOP) // sanity just in case - var/sound/preyloop = sound('sound/vore/prey/loop.ogg', repeat = TRUE) + var/sound/preyloop = sound('sound/vore/prey/loop.ogg') SEND_SOUND(src, preyloop) else to_chat(src, "You aren't inside anything, you clod.") @@ -265,28 +263,28 @@ // /mob/living/proc/save_vore_prefs() if(!client || !client.prefs_vr) - return 0 + return FALSE if(!copy_to_prefs_vr()) - return 0 + return FALSE if(!client.prefs_vr.save_vore()) - return 0 + return FALSE - return 1 + return TRUE /mob/living/proc/apply_vore_prefs() if(!client || !client.prefs_vr) - return 0 + return FALSE if(!client.prefs_vr.load_vore()) - return 0 + return FALSE if(!copy_from_prefs_vr()) - return 0 + return FALSE - return 1 + return TRUE /mob/living/proc/copy_to_prefs_vr() if(!client || !client.prefs_vr) to_chat(src,"You attempted to save your vore prefs but somehow you're in this character without a client.prefs_vr variable. Tell a dev.") - return 0 + return FALSE var/datum/vore_preferences/P = client.prefs_vr @@ -302,7 +300,7 @@ P.belly_prefs = serialized - return 1 + return TRUE // // Proc for applying vore preferences, given bellies @@ -310,7 +308,7 @@ /mob/living/proc/copy_from_prefs_vr() if(!client || !client.prefs_vr) to_chat(src,"You attempted to apply your vore prefs but somehow you're in this character without a client.prefs_vr variable. Tell a dev.") - return 0 + return FALSE vorepref_init = TRUE var/datum/vore_preferences/P = client.prefs_vr @@ -325,7 +323,7 @@ for(var/entry in P.belly_prefs) list_to_object(entry,src) - return 1 + return TRUE // // Release everything in every vore organ diff --git a/modular_citadel/code/modules/vore/eating/vore_vr.dm b/code/modules/vore/eating/vore.dm similarity index 94% rename from modular_citadel/code/modules/vore/eating/vore_vr.dm rename to code/modules/vore/eating/vore.dm index dc813d70aa..a9b14dcdc8 100644 --- a/modular_citadel/code/modules/vore/eating/vore_vr.dm +++ b/code/modules/vore/eating/vore.dm @@ -84,22 +84,22 @@ GLOBAL_LIST_EMPTY(vore_preferences_datums) /datum/vore_preferences/proc/load_vore() if(!client || !client_ckey) - return 0 //No client, how can we save? + return FALSE //No client, how can we save? if(!client.prefs || !client.prefs.default_slot) - return 0 //Need to know what character to load! + return FALSE //Need to know what character to load! slot = client.prefs.default_slot load_path(client_ckey,slot) - if(!path) return 0 //Path couldn't be set? + if(!path) return FALSE //Path couldn't be set? if(!fexists(path)) //Never saved before save_vore() //Make the file first - return 1 + return TRUE var/list/json_from_file = json_decode(file2text(path)) if(!json_from_file) - return 0 //My concern grows + return FALSE //My concern grows var/version = json_from_file["version"] json_from_file = patch_version(json_from_file,version) @@ -120,11 +120,11 @@ GLOBAL_LIST_EMPTY(vore_preferences_datums) if(isnull(belly_prefs)) belly_prefs = list() - return 1 + return TRUE /datum/vore_preferences/proc/save_vore() if(!path) - return 0 + return FALSE var/version = VORE_VERSION //For "good times" use in the future var/list/settings_list = list( @@ -140,7 +140,7 @@ GLOBAL_LIST_EMPTY(vore_preferences_datums) var/json_to_file = json_encode(settings_list) if(!json_to_file) testing("Saving: [path] failed jsonencode") - return 0 + return FALSE //Write it out //#ifdef RUST_G @@ -153,9 +153,9 @@ GLOBAL_LIST_EMPTY(vore_preferences_datums) //#endif if(!fexists(path)) testing("Saving: [path] failed file write") - return 0 + return FALSE - return 1 + return TRUE /* commented out list things "allowmobvore" = allowmobvore, diff --git a/modular_citadel/code/modules/vore/eating/voreitems.dm b/code/modules/vore/eating/voreitems.dm similarity index 100% rename from modular_citadel/code/modules/vore/eating/voreitems.dm rename to code/modules/vore/eating/voreitems.dm diff --git a/modular_citadel/code/modules/vore/eating/vorepanel_vr.dm b/code/modules/vore/eating/vorepanel.dm similarity index 92% rename from modular_citadel/code/modules/vore/eating/vorepanel_vr.dm rename to code/modules/vore/eating/vorepanel.dm index ae7da895a6..962fe54af7 100644 --- a/modular_citadel/code/modules/vore/eating/vorepanel_vr.dm +++ b/code/modules/vore/eating/vorepanel.dm @@ -21,10 +21,10 @@ picker_holder.popup = new(src, "insidePanel","Vore Panel", 450, 700, picker_holder) picker_holder.popup.set_content(dat) picker_holder.popup.open() - src.openpanel = 1 + src.openpanel = TRUE /mob/living/proc/updateVRPanel() //Panel popup update call from belly events. - if(src.openpanel == 1) + if(src.openpanel == TRUE) var/datum/vore_look/picker_holder = new() picker_holder.loop = picker_holder picker_holder.selected = vore_selected @@ -40,7 +40,7 @@ // /datum/vore_look var/obj/belly/selected - var/show_interacts = 0 + var/show_interacts = FALSE var/datum/browser/popup var/loop = null; // Magic self-reference to stop the handler from being GC'd before user takes action. @@ -163,6 +163,9 @@ //Belly Type button dat += "
    Is Fleshy:" dat += "[selected.is_wet ? "Yes" : "No"]" + if(selected.is_wet) + dat += "
    Internal loop for prey?:" + dat += "[selected.wet_loop ? "Yes" : "No"]" //Digest Mode Button dat += "
    Belly Mode:" @@ -241,21 +244,19 @@ dat += "
    " switch(user.digestable) if(TRUE) - dat += "Toggle Digestable (Currently: ON)" + dat += "
    Toggle Digestable (Currently: ON)" if(FALSE) - dat += "Toggle Digestable (Currently: OFF)" - + dat += "
    Toggle Digestable (Currently: OFF)" switch(user.devourable) if(TRUE) - dat += "
    Toggle Devourable (Currently: ON)" + dat += "
    Toggle Devourable (Currently: ON)" if(FALSE) - dat += "
    Toggle Devourable (Currently: OFF)" - + dat += "
    Toggle Devourable (Currently: OFF)" switch(user.feeding) if(TRUE) - dat += "
    Toggle Feeding (Currently: ON)" + dat += "
    Toggle Feeding (Currently: ON)" if(FALSE) - dat += "
    Toggle Feeding (Currently: OFF)" + dat += "
    Toggle Feeding (Currently: OFF)" //Returns the dat html to the vore_look return dat @@ -266,12 +267,12 @@ if(href_list["close"]) qdel(src) // Cleanup - user.openpanel = 0 + user.openpanel = FALSE return if(href_list["show_int"]) show_interacts = !show_interacts - return 1 //Force update + return TRUE //Force update if(href_list["int_help"]) alert("These control how your belly responds to someone using 'resist' while inside you. The percent chance to trigger each is listed below, \ @@ -279,13 +280,13 @@ These only function as long as interactions are turned on in general. Keep in mind, the 'belly mode' interactions (digest/absorb) \ will affect all prey in that belly, if one resists and triggers digestion/absorption. If multiple trigger at the same time, \ only the first in the order of 'Escape > Transfer > Absorb > Digest' will occur.","Interactions Help") - return 0 //Force update + return FALSE //Force update if(href_list["outsidepick"]) var/atom/movable/tgt = locate(href_list["outsidepick"]) var/obj/belly/OB = locate(href_list["outsidebelly"]) if(!(tgt in OB)) //Aren't here anymore, need to update menu. - return 1 + return TRUE var/intent = "Examine" if(istype(tgt,/mob/living)) @@ -298,7 +299,7 @@ if("Help Out") //Help the inside-mob out if(user.stat || user.absorbed || M.absorbed) to_chat(user,"You can't do that in your state!") - return 1 + return TRUE to_chat(user,"You begin to push [M] to freedom!") to_chat(M,"[usr] begins to push you to freedom!") @@ -317,11 +318,11 @@ if("Devour") //Eat the inside mob if(user.absorbed || user.stat) to_chat(user,"You can't do that in your state!") - return 1 + return TRUE if(!user.vore_selected) to_chat(user,"Pick a belly on yourself first!") - return 1 + return TRUE var/obj/belly/TB = user.vore_selected to_chat(user,"You begin to [lowertext(TB.vore_verb)] [M] into your [lowertext(TB.name)]!") @@ -339,7 +340,7 @@ var/obj/item/T = tgt if(!(tgt in OB)) //Doesn't exist anymore, update. - return 1 + return TRUE intent = alert("What do you want to do to that?","Query","Examine","Use Hand") switch(intent) if("Examine") @@ -348,7 +349,7 @@ if("Use Hand") if(user.stat) to_chat(user,"You can't do that in your state!") - return 1 + return TRUE user.ClickOn(T) sleep(5) //Seems to exit too fast for the panel to update @@ -361,23 +362,23 @@ intent = alert("Eject all, Move all?","Query","Eject all","Cancel","Move all") switch(intent) if("Cancel") - return 0 + return FALSE if("Eject all") if(user.stat) to_chat(user,"You can't do that in your state!") - return 0 + return FALSE selected.release_all_contents() if("Move all") if(user.stat) to_chat(user,"You can't do that in your state!") - return 0 + return FALSE var/obj/belly/choice = input("Move all where?","Select Belly") as null|anything in user.vore_organs if(!choice) - return 0 + return FALSE for(var/atom/movable/tgt in selected) to_chat(tgt,"You're squished from [user]'s [lowertext(selected)] to their [lowertext(choice.name)]!") @@ -385,7 +386,7 @@ var/atom/movable/tgt = locate(href_list["insidepick"]) if(!(tgt in selected)) //Old menu, needs updating because they aren't really there. - return 1 //Forces update + return TRUE //Forces update intent = "Examine" intent = alert("Examine, Eject, Move? Examine if you want to leave this box.","Query","Examine","Eject","Move") switch(intent) @@ -395,25 +396,25 @@ if("Eject") if(user.stat) to_chat(user,"You can't do that in your state!") - return 0 + return FALSE selected.release_specific_contents(tgt) if("Move") if(user.stat) to_chat(user,"You can't do that in your state!") - return 0 + return FALSE var/obj/belly/choice = input("Move [tgt] where?","Select Belly") as null|anything in user.vore_organs if(!choice || !(tgt in selected)) - return 0 + return FALSE to_chat(tgt,"You're squished from [user]'s [lowertext(selected.name)] to their [lowertext(choice.name)]!") selected.transfer_contents(tgt, choice) if(href_list["newbelly"]) if(user.vore_organs.len >= BELLIES_MAX) - return 0 + return FALSE var/new_name = html_encode(input(usr,"New belly's name:","New Belly") as text|null) @@ -430,7 +431,7 @@ if(failure_msg) //Something went wrong. alert(user,failure_msg,"Error!") - return 0 + return FALSE var/obj/belly/NB = new(user) NB.name = new_name @@ -459,19 +460,22 @@ if(failure_msg) //Something went wrong. alert(user,failure_msg,"Error!") - return 0 + return FALSE selected.name = new_name if(href_list["b_wetness"]) selected.is_wet = !selected.is_wet + if(href_list["b_wetloop"]) + selected.wet_loop = !selected.wet_loop + if(href_list["b_mode"]) var/list/menu_list = selected.digest_modes var/new_mode = input("Choose Mode (currently [selected.digest_mode])") as null|anything in menu_list if(!new_mode) - return 0 + return FALSE selected.digest_mode = new_mode if(href_list["b_desc"]) @@ -539,12 +543,12 @@ if(length(new_verb) > BELLIES_NAME_MAX || length(new_verb) < BELLIES_NAME_MIN) alert("Entered verb length invalid (must be longer than [BELLIES_NAME_MIN], no longer than [BELLIES_NAME_MAX]).","Error") - return 0 + return FALSE selected.vore_verb = new_verb if(href_list["b_release"]) - var/choice = input(user,"Currently set to [selected.release_sound]","Select Sound") as null|anything in GLOB.release_sounds + var/choice = input(user,"Currently set to [selected.release_sound]","Select Sound") as null|anything in GLOB.pred_release_sounds if(!choice) return @@ -552,12 +556,12 @@ selected.release_sound = choice if(href_list["b_releasesoundtest"]) - var/sound/releasetest = GLOB.release_sounds[selected.release_sound] + var/sound/releasetest = GLOB.prey_release_sounds[selected.release_sound] if(releasetest) SEND_SOUND(user, releasetest) if(href_list["b_sound"]) - var/choice = input(user,"Currently set to [selected.vore_sound]","Select Sound") as null|anything in GLOB.vore_sounds + var/choice = input(user,"Currently set to [selected.vore_sound]","Select Sound") as null|anything in GLOB.pred_vore_sounds if(!choice) return @@ -565,7 +569,7 @@ selected.vore_sound = choice if(href_list["b_soundtest"]) - var/sound/voretest = GLOB.vore_sounds[selected.vore_sound] + var/sound/voretest = GLOB.prey_vore_sounds[selected.vore_sound] if(voretest) SEND_SOUND(user, voretest) @@ -586,17 +590,17 @@ selected.bulge_size = (new_bulge/100) if(href_list["b_escapable"]) - if(selected.escapable == 0) //Possibly escapable and special interactions. - selected.escapable = 1 + if(selected.escapable == FALSE) //Possibly escapable and special interactions. + selected.escapable = TRUE to_chat(usr,"Prey now have special interactions with your [lowertext(selected.name)] depending on your settings.") - else if(selected.escapable == 1) //Never escapable. - selected.escapable = 0 + else if(selected.escapable == TRUE) //Never escapable. + selected.escapable = FALSE to_chat(usr,"Prey will not be able to have special interactions with your [lowertext(selected.name)].") - show_interacts = 0 //Force the hiding of the panel + show_interacts = FALSE //Force the hiding of the panel else alert("Something went wrong. Your stomach will now not have special interactions. Press the button enable them again and tell a dev.","Error") //If they somehow have a varable that's not 0 or 1 - selected.escapable = 0 - show_interacts = 0 //Force the hiding of the panel + selected.escapable = FALSE + show_interacts = FALSE //Force the hiding of the panel if(href_list["b_escapechance"]) var/escape_chance_input = input(user, "Set prey escape chance on resist (as %)", "Prey Escape Chance") as num|null @@ -617,7 +621,7 @@ var/obj/belly/choice = input("Where do you want your [lowertext(selected.name)] to lead if prey resists?","Select Belly") as null|anything in (user.vore_organs + "None - Remove" - selected) if(!choice) //They cancelled, no changes - return 0 + return FALSE else if(choice == "None - Remove") selected.transferlocation = null else @@ -636,7 +640,7 @@ if(href_list["b_del"]) var/alert = alert("Are you sure you want to delete your [lowertext(selected.name)]?","Confirmation","Delete","Cancel") if(!alert == "Delete") - return 0 + return FALSE var/failure_msg = "" @@ -657,7 +661,7 @@ if(failure_msg) alert(user,failure_msg,"Error!") - return 0 + return FALSE qdel(selected) selected = user.vore_organs[1] @@ -674,7 +678,7 @@ if(href_list["applyprefs"]) var/alert = alert("Are you sure you want to reload character slot preferences? This will remove your current vore organs and eject their contents.","Confirmation","Reload","Cancel") if(!alert == "Reload") - return 0 + return FALSE if(!user.apply_vore_prefs()) alert("ERROR: Vore preferences failed to apply!","Error") else @@ -683,19 +687,19 @@ if(href_list["setflavor"]) var/new_flavor = html_encode(input(usr,"What your character tastes like (40ch limit). This text will be printed to the pred after 'X tastes of...' so just put something like 'strawberries and cream':","Character Flavor",user.vore_taste) as text|null) if(!new_flavor) - return 0 + return FALSE new_flavor = readd_quotes(new_flavor) if(length(new_flavor) > FLAVOR_MAX) alert("Entered flavor/taste text too long. [FLAVOR_MAX] character limit.","Error!") - return 0 + return FALSE user.vore_taste = new_flavor if(href_list["toggledg"]) var/choice = alert(user, "This button is for those who don't like being digested. It can make you undigestable to all mobs. Digesting you is currently: [user.digestable ? "Allowed" : "Prevented"]", "", "Allow Digestion", "Cancel", "Prevent Digestion") switch(choice) if("Cancel") - return 0 + return FALSE if("Allow Digestion") user.digestable = TRUE if("Prevent Digestion") @@ -708,7 +712,7 @@ var/choice = alert(user, "This button is for those who don't like vore at all. Devouring you is currently: [user.devourable ? "Allowed" : "Prevented"]", "", "Allow Devourment", "Cancel", "Prevent Devourment") switch(choice) if("Cancel") - return 0 + return FALSE if("Allow Devourment") user.devourable = TRUE if("Prevent Devourment") @@ -721,7 +725,7 @@ var/choice = alert(user, "This button is to toggle your ability to be fed to others. Feeding predators is currently: [user.feeding ? "Allowed" : "Prevented"]", "", "Allow Feeding", "Cancel", "Prevent Feeding") switch(choice) if("Cancel") - return 0 + return FALSE if("Allow Feeding") user.feeding = TRUE if("Prevent Feeding") @@ -731,4 +735,4 @@ user.client.prefs_vr.feeding = user.feeding //Refresh when interacted with, returning 1 makes vore_look.Topic update - return 1 \ No newline at end of file + return TRUE \ No newline at end of file diff --git a/modular_citadel/code/modules/vore/hook-defs_vr.dm b/code/modules/vore/hook-defs.dm similarity index 100% rename from modular_citadel/code/modules/vore/hook-defs_vr.dm rename to code/modules/vore/hook-defs.dm diff --git a/modular_citadel/code/modules/vore/persistence.dm b/code/modules/vore/persistence.dm similarity index 100% rename from modular_citadel/code/modules/vore/persistence.dm rename to code/modules/vore/persistence.dm diff --git a/modular_citadel/code/modules/vore/resizing/grav_pull_vr.dm b/code/modules/vore/resizing/grav_pull_vr.dm similarity index 100% rename from modular_citadel/code/modules/vore/resizing/grav_pull_vr.dm rename to code/modules/vore/resizing/grav_pull_vr.dm diff --git a/modular_citadel/code/modules/vore/resizing/holder_micro_vr.dm b/code/modules/vore/resizing/holder_micro_vr.dm similarity index 100% rename from modular_citadel/code/modules/vore/resizing/holder_micro_vr.dm rename to code/modules/vore/resizing/holder_micro_vr.dm diff --git a/modular_citadel/code/modules/vore/resizing/resize_vr.dm b/code/modules/vore/resizing/resize_vr.dm similarity index 100% rename from modular_citadel/code/modules/vore/resizing/resize_vr.dm rename to code/modules/vore/resizing/resize_vr.dm diff --git a/modular_citadel/code/modules/vore/resizing/sizechemicals.dm b/code/modules/vore/resizing/sizechemicals.dm similarity index 98% rename from modular_citadel/code/modules/vore/resizing/sizechemicals.dm rename to code/modules/vore/resizing/sizechemicals.dm index 1164bf65d6..f83ba2ce76 100644 --- a/modular_citadel/code/modules/vore/resizing/sizechemicals.dm +++ b/code/modules/vore/resizing/sizechemicals.dm @@ -84,7 +84,7 @@ return /datum/reagent/medicine/sizeoxadone/overdose_process(mob/living/M) - M.adjustBrainLoss(1) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 1) M.adjustToxLoss(1) ..() . = 1 diff --git a/modular_citadel/code/modules/vore/resizing/sizegun_vr.dm b/code/modules/vore/resizing/sizegun_vr.dm similarity index 100% rename from modular_citadel/code/modules/vore/resizing/sizegun_vr.dm rename to code/modules/vore/resizing/sizegun_vr.dm diff --git a/modular_citadel/code/modules/vore/trycatch_vr.dm b/code/modules/vore/trycatch.dm similarity index 100% rename from modular_citadel/code/modules/vore/trycatch_vr.dm rename to code/modules/vore/trycatch.dm diff --git a/code/modules/zombie/items.dm b/code/modules/zombie/items.dm index 9a2455f56d..0f6ef14cd1 100644 --- a/code/modules/zombie/items.dm +++ b/code/modules/zombie/items.dm @@ -13,6 +13,7 @@ hitsound = 'sound/hallucinations/growl1.ogg' force = 21 // Just enough to break airlocks with melee attacks damtype = "brute" + total_mass = TOTAL_MASS_HAND_REPLACEMENT /obj/item/zombie_hand/Initialize() . = ..() @@ -72,5 +73,5 @@ user.adjustFireLoss(-hp_gained, 0) user.adjustCloneLoss(-hp_gained, 0) user.updatehealth() - user.adjustBrainLoss(-hp_gained) // Zom Bee gibbers "BRAAAAISNSs!1!" + user.adjustOrganLoss(ORGAN_SLOT_BRAIN, -hp_gained) // Zom Bee gibbers "BRAAAAISNSs!1!" user.nutrition = min(user.nutrition + hp_gained, NUTRITION_LEVEL_FULL) diff --git a/config/admins.txt b/config/admins.txt index 27a2178e2c..1fdf480dd3 100644 --- a/config/admins.txt +++ b/config/admins.txt @@ -1,11 +1,11 @@ -############################################################################################### -# Basically, ckey goes first. Rank goes after the "=" # -# Case is not important for ckey. # -# Case IS important for the rank. # -# All punctuation (spaces etc) EXCEPT '-', '_' and '@' will be stripped from rank names. # -# Ranks can be anything defined in admin_ranks.txt # -# NOTE: if the rank-name cannot be found in admin_ranks.txt, they will not be adminned! ~Carn # -# NOTE: syntax was changed to allow hyphenation of ranknames, since spaces are stripped. # -############################################################################################### - -yourckeygoeshere = Host +############################################################################################### +# Basically, ckey goes first. Rank goes after the "=" # +# Case is not important for ckey. # +# Case IS important for the rank. # +# All punctuation (spaces etc) EXCEPT '-', '_' and '@' will be stripped from rank names. # +# Ranks can be anything defined in admin_ranks.txt # +# NOTE: if the rank-name cannot be found in admin_ranks.txt, they will not be adminned! ~Carn # +# NOTE: syntax was changed to allow hyphenation of ranknames, since spaces are stripped. # +############################################################################################### + +yourckeygoeshere = Host \ No newline at end of file diff --git a/config/config.txt b/config/config.txt index 3bc9f873a9..0501d1fd2f 100644 --- a/config/config.txt +++ b/config/config.txt @@ -4,6 +4,7 @@ $include game_options.txt $include dbconfig.txt $include comms.txt $include antag_rep.txt +$include donator_groupings.txt # You can use the @ character at the beginning of a config option to lock it from being edited in-game # Example usage: @@ -145,6 +146,9 @@ LOG_MANIFEST ## Enable logging pictures # LOG_PICTURES +## log virus and actions +LOG_VIRUS + ##Log camera pictures - Must have picture logging enabled PICTURE_LOGGING_CAMERA @@ -229,22 +233,22 @@ CHECK_RANDOMIZER # SERVER ss13.example.com:2506 ## forum address -# FORUMURL http://tgstation13.org/phpBB/index.php +# FORUMURL https://citadel-station.net/forum/ ## Wiki address -# WIKIURL http://www.tgstation13.org/wiki +# WIKIURL https://katlin.dog/citadel-wiki ## Rules address -# RULESURL http://www.tgstation13.org/wiki/Rules +# RULESURL https://katlin.dog/citadel-rules/main ## Github address -# GITHUBURL https://www.github.com/tgstation/tgstation +# GITHUBURL https://github.com/Citadel-Station-13/Citadel-Station-13 ## Round specific stats address ## Link to round specific parsed logs; IE statbus. It is appended with the RoundID automatically by ticker/Reboot() ## This will take priority over the game logs address during reboot. ## Example: https://atlantaned.space/statbus/round.php?round= -# ROUNDSTATSURL +# ROUNDSTATSURL http://citadel-station.net/slimbus/ ## Game Logs address ## Incase you don't have a fancy parsing system, but still want players to be able to find where you keep your server's logs. @@ -254,10 +258,10 @@ CHECK_RANDOMIZER ## Github repo id ##This can be found by going to https://api.github.com/users//repos ##Or https://api.github.com/orgs//repos if the repo owner is an organization -# GITHUBREPOID 3234987 +# GITHUBREPOID 62485194 ## Ban appeals URL - usually for a forum or wherever people should go to contact your admins. -# BANAPPEALS http://justanotherday.example.com +# BANAPPEALS https://citadel-station.net/forum/viewforum.php?f=8&sid=a0ce5331d5594ef6d49661609c6f4ff9 ## System command that invokes youtube-dl, used by Play Internet Sound. ## You can install youtube-dl with diff --git a/config/donator_groupings.txt b/config/donator_groupings.txt new file mode 100644 index 0000000000..b26d1efe22 --- /dev/null +++ b/config/donator_groupings.txt @@ -0,0 +1,8 @@ +#this is a bad system but I'm lazy so it piggybacks off config loader system. +#Specify group followed by ckey for each ckey. + +#TIER_1_DONATORS test_ckey + +#TIER_2_DONATORS test_ckey + +#TIER_3_DONATORS test_ckey diff --git a/config/game_options.txt b/config/game_options.txt index 6d59f10807..02d620eb31 100644 --- a/config/game_options.txt +++ b/config/game_options.txt @@ -267,6 +267,10 @@ ALLOW_AI_MULTICAM ## Uncomment to prevent the security cyborg module from being chosen #DISABLE_SECBORG +## Determines the minimum alert level for the security cyborg model to be chosen +## 0: Green, 1:Blue, 2:Amber, 3:Red, 4:Delta +MINIMUM_SECBORG_ALERT 3 + ## Peacekeeper Borg ### ## Uncomment to prevent the peacekeeper cyborg module from being chosen #DISABLE_PEACEBORG @@ -410,7 +414,7 @@ ROUNDSTART_RACES human ## Races that are strictly worse than humans that could probably be turned on without balance concerns ROUNDSTART_RACES lizard #ROUNDSTART_RACES fly -#ROUNDSTART_RACES moth +#ROUNDSTART_RACES insect ROUNDSTART_RACES plasmaman #ROUNDSTART_RACES shadow ROUNDSTART_RACES felinid diff --git a/config/spaceRuinBlacklist.txt b/config/spaceRuinBlacklist.txt index cba9a01e73..deafa47969 100644 --- a/config/spaceRuinBlacklist.txt +++ b/config/spaceRuinBlacklist.txt @@ -49,3 +49,4 @@ #_maps/RandomRuins/SpaceRuins/bigape.dmm #_maps/RandomRuins/SpaceRuins/arcade.dmm #_maps/RandomRuins/SpaceRuins/spacehermit.dmm +#_maps/RandomRuins/SpaceRuins/advancedlab.dmm diff --git a/goon/browserassets/css/browserOutput.css b/goon/browserassets/css/browserOutput.css new file mode 100644 index 0000000000..174aa8a22f --- /dev/null +++ b/goon/browserassets/css/browserOutput.css @@ -0,0 +1,877 @@ +/***************************************** +* +* GLOBAL STYLES +* +******************************************/ +html, body { + padding: 0; + margin: 0; + height: 100%; + color: #000000; +} +body { + background: #E0E0E0; /*CIT CHANGE - darkens chatbox a lil*/ + font-family: Verdana, sans-serif; + font-size: 9pt; + line-height: 1.2; + overflow-x: hidden; + overflow-y: scroll; + word-wrap: break-word; +} + +em { + font-style: normal; + font-weight: bold; +} + +img { + margin: 0; + padding: 0; + line-height: 1; + -ms-interpolation-mode: nearest-neighbor; + image-rendering: pixelated; +} +img.icon { + height: 1em; + min-height: 16px; + width: auto; + vertical-align: bottom; +} + + +.r:before { /* "repeated" badge class for combined messages */ + content: 'x'; +} +.r { + display: inline-block; + min-width: 0.5em; + font-size: 0.7em; + padding: 0.2em 0.3em; + line-height: 1; + color: white; + text-align: center; + white-space: nowrap; + vertical-align: middle; + background-color: crimson; + border-radius: 10px; +} + +a {color: #0000ff;} +a.visited {color: #ff00ff;} +a:visited {color: #ff00ff;} +a.popt {text-decoration: none;} + +/***************************************** +* +* OUTPUT NOT RELATED TO ACTUAL MESSAGES +* +******************************************/ +#loading { + position: fixed; + width: 300px; + height: 150px; + text-align: center; + left: 50%; + top: 50%; + margin: -75px 0 0 -150px; +} +#loading i {display: block; padding-bottom: 3px;} + +#messages { + font-size: 13px; + padding: 3px; + margin: 0; + word-wrap: break-word; +} +#newMessages { + position: fixed; + display: block; + bottom: 0; + right: 0; + padding: 8px; + background: #ddd; + text-decoration: none; + font-variant: small-caps; + font-size: 1.1em; + font-weight: bold; + color: #333; +} +#newMessages:hover {background: #ccc;} +#newMessages i {vertical-align: middle; padding-left: 3px;} +#ping { + position: fixed; + top: 0; + right: 80px; + width: 45px; + background: #ddd; + height: 30px; + padding: 8px 0 2px 0; +} +#ping i {display: block; text-align: center;} +#ping .ms { + display: block; + text-align: center; + font-size: 8pt; + padding-top: 2px; +} +#userBar { + position: fixed; + top: 0; + right: 0; +} +#userBar .subCell { + background: #ddd; + height: 30px; + padding: 5px 0; + display: block; + color: #333; + text-decoration: none; + line-height: 28px; + border-top: 1px solid #b4b4b4; +} +#userBar .subCell:hover {background: #ccc;} +#userBar .toggle { + width: 40px; + background: #ccc; + border-top: 0; + float: right; + text-align: center; +} +#userBar .sub {clear: both; display: none; width: 160px;} +#userBar .sub.scroll {overflow-y: scroll;} +#userBar .sub.subCell {padding: 3px 0 3px 8px; line-height: 30px; font-size: 0.9em; clear: both;} +#userBar .sub span { + display: block; + line-height: 30px; + float: left; +} +#userBar .sub i { + display: block; + padding: 0 5px; + font-size: 1.1em; + width: 22px; + text-align: center; + line-height: 30px; + float: right; +} +#userBar .sub input { + position: absolute; + padding: 7px 5px; + width: 121px; + line-height: 30px; + float: left; +} +#userBar .topCell {border-top: 0;} + +/* POPUPS */ +.popup { + position: fixed; + top: 50%; + left: 50%; + background: #ddd; +} +.popup .close { + position: absolute; + background: #aaa; + top: 0; + right: 0; + color: #333; + text-decoration: none; + z-index: 2; + padding: 0 10px; + height: 30px; + line-height: 30px; +} +.popup .close:hover {background: #999;} +.popup .head { + background: #999; + color: #ddd; + padding: 0 10px; + height: 30px; + line-height: 30px; + text-transform: uppercase; + font-size: 0.9em; + font-weight: bold; + border-bottom: 2px solid green; +} +.popup input {border: 1px solid #999; background: #fff; margin: 0; padding: 5px; outline: none; color: #333;} +.popup input[type=text]:hover, .popup input[type=text]:active, .popup input[type=text]:focus {border-color: green;} +.popup input[type=submit] {padding: 5px 10px; background: #999; color: #ddd; text-transform: uppercase; font-size: 0.9em; font-weight: bold;} +.popup input[type=submit]:hover, .popup input[type=submit]:focus, .popup input[type=submit]:active {background: #aaa; cursor: pointer;} + +.changeFont {padding: 10px;} +.changeFont a {display: block; text-decoration: none; padding: 3px; color: #333;} +.changeFont a:hover {background: #ccc;} + +.highlightPopup {padding: 10px; text-align: center;} +.highlightPopup input[type=text] {display: block; width: 215px; text-align: left; margin-top: 5px;} +.highlightPopup input.highlightColor {background-color: #FFFF00;} +.highlightPopup input.highlightTermSubmit {margin-top: 5px;} + +/* ADMIN CONTEXT MENU */ +.contextMenu { + background-color: #ddd; + position: fixed; + margin: 2px; + width: 150px; +} +.contextMenu a { + display: block; + padding: 2px 5px; + text-decoration: none; + color: #333; +} + +.contextMenu a:hover { + background-color: #ccc; +} + +/* ADMIN FILTER MESSAGES MENU */ +.filterMessages {padding: 5px;} +.filterMessages div {padding: 2px 0;} +.filterMessages input {} +.filterMessages label {} + +.icon-stack {height: 1em; line-height: 1em; width: 1em; vertical-align: middle; margin-top: -2px;} + + +/***************************************** +* +* OUTPUT ACTUALLY RELATED TO MESSAGES +* +******************************************/ + +/* MOTD */ +.motd {color: #638500; font-family: Verdana, sans-serif;} +.motd h1, .motd h2, .motd h3, .motd h4, .motd h5, .motd h6 {color: #638500; text-decoration: underline;} +.motd a, .motd a:link, .motd a:visited, .motd a:active, .motd a:hover {color: #638500;} + +/* ADD HERE FOR BOLD */ +.bold, .name, .prefix, .ooc, .looc, .adminooc, .admin, .medal, .yell {font-weight: bold;} + +/* ADD HERE FOR ITALIC */ +.italic, .italics, .emote {font-style: italic;} + +/* OUTPUT COLORS */ +.highlight {background: yellow;} + +h1, h2, h3, h4, h5, h6 {color: #0000ff;font-family: Georgia, Verdana, sans-serif;} +h1.alert, h2.alert {color: #000000;} + +em {font-style: normal; font-weight: bold;} + +.ooc { font-weight: bold;} +.adminobserverooc {color: #0099cc; font-weight: bold;} +.adminooc {color: #700038; font-weight: bold;} + +.adminobserver {color: #996600; font-weight: bold;} +.admin {color: #386aff; font-weight: bold;} + +.name { font-weight: bold;} + +.say {} +.deadsay {color: #5c00e6;} +.binarysay {color: #20c20e; background-color: #000000; display: block;} +.binarysay a {color: #00ff00;} +.binarysay a:active, .binarysay a:visited {color: #88ff88;} +.radio {color: #008000;} +.sciradio {color: #993399;} +.comradio {color: #948f02;} +.secradio {color: #a30000;} +.medradio {color: #337296;} +.engradio {color: #fb5613;} +.suppradio {color: #a8732b;} +.servradio {color: #6eaa2c;} +.syndradio {color: #6d3f40;} +.centcomradio {color: #686868;} +.aiprivradio {color: #ff00ff;} +.redteamradio {color: #ff0000;} +.blueteamradio {color: #0000ff;} + +.yell { font-weight: bold;} + +.alert {color: #ff0000;} +h1.alert, h2.alert {color: #000000;} + +.emote { font-style: italic;} +.selecteddna {color: #ffffff; background-color: #001B1B} + +.attack {color: #ff0000;} +.disarm {color: #990000;} +.passive {color: #660000;} + +.userdanger {color: #ff0000; font-weight: bold; font-size: 24px;} +.danger {color: #ff0000;} +.warning {color: #ff0000; font-style: italic;} +.boldwarning {color: #ff0000; font-style: italic; font-weight: bold} +.announce {color: #228b22; font-weight: bold;} +.boldannounce {color: #ff0000; font-weight: bold;} +.greenannounce {color: #00ff00; font-weight: bold;} +.rose {color: #ff5050;} +.info {color: #0000CC;} +.notice {color: #000099;} +.boldnotice {color: #000099; font-weight: bold;} +.adminnotice {color: #0000ff;} +.adminhelp {color: #ff0000; font-weight: bold;} +.unconscious {color: #0000ff; font-weight: bold;} +.suicide {color: #ff5050; font-style: italic;} +.green {color: #03ff39;} +.nicegreen {color: #14a833;} +.shadowling {color: #3b2769;} +.cult {color: #960000;} + +.cultitalic {color: #960000; font-style: italic;} +.cultbold {color: #960000; font-style: italic; font-weight: bold;} +.cultboldtalic {color: #960000; font-weight: bold; font-size: 24px;} + +.cultlarge {color: #960000; font-weight: bold; font-size: 24px;} +.narsie {color: #960000; font-weight: bold; font-size: 120px;} +.narsiesmall {color: #960000; font-weight: bold; font-size: 48px;} +.colossus {color: #7F282A; font-size: 40px;} +.hierophant {color: #660099; font-weight: bold; font-style: italic;} +.hierophant_warning {color: #660099; font-style: italic;} +.purple {color: #5e2d79;} +.holoparasite {color: #35333a;} + +.revennotice {color: #1d2953;} +.revenboldnotice {color: #1d2953; font-weight: bold;} +.revenbignotice {color: #1d2953; font-weight: bold; font-size: 24px;} +.revenminor {color: #823abb} +.revenwarning {color: #760fbb; font-style: italic;} +.revendanger {color: #760fbb; font-weight: bold; font-size: 24px;} +.umbra {color: #5000A0;} +.umbra_emphasis {color: #5000A0; font-weight: bold; font-style: italic;} +.umbra_large {color: #5000A0; font-size: 24px; font-weight: bold; font-style: italic;} + +.deconversion_message {color: #5000A0; font-size: 24px; font-style: italic;} + +.brass {color: #BE8700;} +.heavy_brass {color: #BE8700; font-weight: bold; font-style: italic;} +.large_brass {color: #BE8700; font-size: 24px;} +.big_brass {color: #BE8700; font-size: 24px; font-weight: bold; font-style: italic;} +.ratvar {color: #BE8700; font-size: 48px; font-weight: bold; font-style: italic;} +.alloy {color: #42474D;} +.heavy_alloy {color: #42474D; font-weight: bold; font-style: italic;} +.nezbere_large {color: #42474D; font-size: 24px; font-weight: bold; font-style: italic;} +.nezbere {color: #42474D; font-weight: bold; font-style: italic;} +.nezbere_small {color: #42474D;} +.sevtug_large {color: #AF0AAF; font-size: 24px; font-weight: bold; font-style: italic;} +.sevtug {color: #AF0AAF; font-weight: bold; font-style: italic;} +.sevtug_small {color: #AF0AAF;} +.inathneq_large {color: #1E8CE1; font-size: 24px; font-weight: bold; font-style: italic;} +.inathneq {color: #1E8CE1; font-weight: bold; font-style: italic;} +.inathneq_small {color: #1E8CE1;} +.nzcrentr_large {color: #DAAA18; font-size: 24px; font-weight: bold; font-style: italic;} +.nzcrentr {color: #DAAA18; font-weight: bold; font-style: italic;} +.nzcrentr_small {color: #DAAA18;} +.neovgre_large {color: #6E001A; font-size: 24px; font-weight: bold; font-style: italic;} +.neovgre {color: #6E001A; font-weight: bold; font-style: italic;} +.neovgre_small {color: #6E001A;} + +.newscaster {color: #800000;} +.ghostalert {color: #5c00e6; font-style: italic; font-weight: bold;} + +.alien {color: #543354;} +.noticealien {color: #00c000;} +.alertalien {color: #00c000; font-weight: bold;} +.changeling {color: #800080; font-style: italic;} + +.spider {color: #4d004d;} + +.interface {color: #330033;} + +.sans {font-family: "Comic Sans MS", cursive, sans-serif;} +.papyrus {font-family: "Papyrus", cursive, sans-serif;} +.robot {font-family: "Courier New", cursive, sans-serif;} + +.command_headset {font-weight: bold; font-size: 24px;} +.small {font-size: 8px;} +.big {font-size: 24px;} +.reallybig {font-size: 32px;} +.extremelybig {font-size: 40px;} +.greentext {color: #00FF00; font-size: 24px;} +.redtext {color: #FF0000; font-size: 24px;} +.clown {color: #FF69Bf; font-size: 24px; font-family: "Comic Sans MS", cursive, sans-serif; font-weight: bold;} +.his_grace {color: #15D512; font-family: "Courier New", cursive, sans-serif; font-style: italic;} +.spooky {color: #FF6100;} +.velvet {color: #660015; font-weight: bold; animation: velvet 5000ms infinite;} +@keyframes velvet { + 0% { color: #400020; } + 40% { color: #FF0000; } + 50% { color: #FF8888; } + 60% { color: #FF0000; } + 100% { color: #400020; } +} + +.hypnophrase {color: #202020; font-weight: bold; animation: hypnocolor 1500ms infinite;} +@keyframes hypnocolor { + 0% { color: #202020; } + 25% { color: #4b02ac; } + 50% { color: #9f41f1; } + 75% { color: #541c9c; } + 100% { color: #7adbf3; } +} + +.phobia {color: #dd0000; font-weight: bold; animation: phobia 750ms infinite;} +@keyframes phobia { + 0% { color: #f75a5a; } + 50% { color: #dd0000; } + 100% { color: #f75a5a; } +} + +.icon {height: 1em; width: auto;} + +.memo {color: #638500; text-align: center;} +.memoedit {text-align: center; font-size: 16px;} +.abductor {color: #800080; font-style: italic;} +.mind_control {color: #A00D6F; font-size: 3; font-weight: bold; font-style: italic;} +.slime {color: #00CED1;} +.drone {color: #848482;} +.monkey {color: #975032;} +.swarmer {color: #2C75FF;} +.resonate {color: #298F85;} + +.monkeyhive {color: #774704;} +.monkeylead {color: #774704; font-size: 2;} + +.connectionClosed, .fatalError {background: red; color: white; padding: 5px;} +.connectionClosed.restored {background: green;} +.internal.boldnshit {color: blue; font-weight: bold;} + +/* HELPER CLASSES */ +.text-normal {font-weight: normal; font-style: normal;} +.hidden {display: none; visibility: hidden;}/***************************************** +* +* GLOBAL STYLES +* +******************************************/ +html, body { + padding: 0; + margin: 0; + height: 100%; + color: #000000; +} +body { + background: #E0E0E0; /*CIT CHANGE - darkens chatbox a lil*/ + font-family: Verdana, sans-serif; + font-size: 9pt; + line-height: 1.2; + overflow-x: hidden; + overflow-y: scroll; + word-wrap: break-word; +} + +em { + font-style: normal; + font-weight: bold; +} + +img { + margin: 0; + padding: 0; + line-height: 1; + -ms-interpolation-mode: nearest-neighbor; + image-rendering: pixelated; +} +img.icon { + height: 1em; + min-height: 16px; + width: auto; + vertical-align: bottom; +} + + +.r:before { /* "repeated" badge class for combined messages */ + content: 'x'; +} +.r { + display: inline-block; + min-width: 0.5em; + font-size: 0.7em; + padding: 0.2em 0.3em; + line-height: 1; + color: white; + text-align: center; + white-space: nowrap; + vertical-align: middle; + background-color: crimson; + border-radius: 10px; +} + +a {color: #0000ff;} +a.visited {color: #ff00ff;} +a:visited {color: #ff00ff;} +a.popt {text-decoration: none;} + +/***************************************** +* +* OUTPUT NOT RELATED TO ACTUAL MESSAGES +* +******************************************/ +#loading { + position: fixed; + width: 300px; + height: 150px; + text-align: center; + left: 50%; + top: 50%; + margin: -75px 0 0 -150px; +} +#loading i {display: block; padding-bottom: 3px;} + +#messages { + font-size: 13px; + padding: 3px; + margin: 0; + word-wrap: break-word; +} +#newMessages { + position: fixed; + display: block; + bottom: 0; + right: 0; + padding: 8px; + background: #ddd; + text-decoration: none; + font-variant: small-caps; + font-size: 1.1em; + font-weight: bold; + color: #333; +} +#newMessages:hover {background: #ccc;} +#newMessages i {vertical-align: middle; padding-left: 3px;} +#ping { + position: fixed; + top: 0; + right: 80px; + width: 45px; + background: #ddd; + height: 30px; + padding: 8px 0 2px 0; +} +#ping i {display: block; text-align: center;} +#ping .ms { + display: block; + text-align: center; + font-size: 8pt; + padding-top: 2px; +} +#userBar { + position: fixed; + top: 0; + right: 0; +} +#userBar .subCell { + background: #ddd; + height: 30px; + padding: 5px 0; + display: block; + color: #333; + text-decoration: none; + line-height: 28px; + border-top: 1px solid #b4b4b4; +} +#userBar .subCell:hover {background: #ccc;} +#userBar .toggle { + width: 40px; + background: #ccc; + border-top: 0; + float: right; + text-align: center; +} +#userBar .sub {clear: both; display: none; width: 160px;} +#userBar .sub.scroll {overflow-y: scroll;} +#userBar .sub.subCell {padding: 3px 0 3px 8px; line-height: 30px; font-size: 0.9em; clear: both;} +#userBar .sub span { + display: block; + line-height: 30px; + float: left; +} +#userBar .sub i { + display: block; + padding: 0 5px; + font-size: 1.1em; + width: 22px; + text-align: center; + line-height: 30px; + float: right; +} +#userBar .sub input { + position: absolute; + padding: 7px 5px; + width: 121px; + line-height: 30px; + float: left; +} +#userBar .topCell {border-top: 0;} + +/* POPUPS */ +.popup { + position: fixed; + top: 50%; + left: 50%; + background: #ddd; +} +.popup .close { + position: absolute; + background: #aaa; + top: 0; + right: 0; + color: #333; + text-decoration: none; + z-index: 2; + padding: 0 10px; + height: 30px; + line-height: 30px; +} +.popup .close:hover {background: #999;} +.popup .head { + background: #999; + color: #ddd; + padding: 0 10px; + height: 30px; + line-height: 30px; + text-transform: uppercase; + font-size: 0.9em; + font-weight: bold; + border-bottom: 2px solid green; +} +.popup input {border: 1px solid #999; background: #fff; margin: 0; padding: 5px; outline: none; color: #333;} +.popup input[type=text]:hover, .popup input[type=text]:active, .popup input[type=text]:focus {border-color: green;} +.popup input[type=submit] {padding: 5px 10px; background: #999; color: #ddd; text-transform: uppercase; font-size: 0.9em; font-weight: bold;} +.popup input[type=submit]:hover, .popup input[type=submit]:focus, .popup input[type=submit]:active {background: #aaa; cursor: pointer;} + +.changeFont {padding: 10px;} +.changeFont a {display: block; text-decoration: none; padding: 3px; color: #333;} +.changeFont a:hover {background: #ccc;} + +.highlightPopup {padding: 10px; text-align: center;} +.highlightPopup input[type=text] {display: block; width: 215px; text-align: left; margin-top: 5px;} +.highlightPopup input.highlightColor {background-color: #FFFF00;} +.highlightPopup input.highlightTermSubmit {margin-top: 5px;} + +/* ADMIN CONTEXT MENU */ +.contextMenu { + background-color: #ddd; + position: fixed; + margin: 2px; + width: 150px; +} +.contextMenu a { + display: block; + padding: 2px 5px; + text-decoration: none; + color: #333; +} + +.contextMenu a:hover { + background-color: #ccc; +} + +/* ADMIN FILTER MESSAGES MENU */ +.filterMessages {padding: 5px;} +.filterMessages div {padding: 2px 0;} +.filterMessages input {} +.filterMessages label {} + +.icon-stack {height: 1em; line-height: 1em; width: 1em; vertical-align: middle; margin-top: -2px;} + + +/***************************************** +* +* OUTPUT ACTUALLY RELATED TO MESSAGES +* +******************************************/ + +/* MOTD */ +.motd {color: #638500; font-family: Verdana, sans-serif;} +.motd h1, .motd h2, .motd h3, .motd h4, .motd h5, .motd h6 {color: #638500; text-decoration: underline;} +.motd a, .motd a:link, .motd a:visited, .motd a:active, .motd a:hover {color: #638500;} + +/* ADD HERE FOR BOLD */ +.bold, .name, .prefix, .ooc, .looc, .adminooc, .admin, .medal, .yell {font-weight: bold;} + +/* ADD HERE FOR ITALIC */ +.italic, .italics, .emote {font-style: italic;} + +/* OUTPUT COLORS */ +.highlight {background: yellow;} + +h1, h2, h3, h4, h5, h6 {color: #0000ff;font-family: Georgia, Verdana, sans-serif;} +h1.alert, h2.alert {color: #000000;} + +em {font-style: normal; font-weight: bold;} + +.ooc { font-weight: bold;} +.adminobserverooc {color: #0099cc; font-weight: bold;} +.adminooc {color: #700038; font-weight: bold;} + +.adminsay {color: #FF4500; font-weight: bold;} +.admin {color: #386aff; font-weight: bold;} + +.name { font-weight: bold;} + +.say {} +.deadsay {color: #5c00e6;} +.binarysay {color: #20c20e; background-color: #000000; display: block;} +.binarysay a {color: #00ff00;} +.binarysay a:active, .binarysay a:visited {color: #88ff88;} +.radio {color: #008000;} +.sciradio {color: #993399;} +.comradio {color: #948f02;} +.secradio {color: #a30000;} +.medradio {color: #337296;} +.engradio {color: #fb5613;} +.suppradio {color: #a8732b;} +.servradio {color: #6eaa2c;} +.syndradio {color: #6d3f40;} +.centcomradio {color: #686868;} +.aiprivradio {color: #ff00ff;} +.redteamradio {color: #ff0000;} +.blueteamradio {color: #0000ff;} + +.yell { font-weight: bold;} + +.alert {color: #ff0000;} +h1.alert, h2.alert {color: #000000;} + +.emote { font-style: italic;} +.selecteddna {color: #ffffff; background-color: #001B1B} + +.attack {color: #ff0000;} +.disarm {color: #990000;} +.passive {color: #660000;} + +.userdanger {color: #ff0000; font-weight: bold; font-size: 24px;} +.danger {color: #ff0000;} +.warning {color: #ff0000; font-style: italic;} +.boldwarning {color: #ff0000; font-style: italic; font-weight: bold} +.announce {color: #228b22; font-weight: bold;} +.boldannounce {color: #ff0000; font-weight: bold;} +.greenannounce {color: #00ff00; font-weight: bold;} +.rose {color: #ff5050;} +.info {color: #0000CC;} +.notice {color: #000099;} +.boldnotice {color: #000099; font-weight: bold;} +.adminnotice {color: #0000ff;} +.adminhelp {color: #ff0000; font-weight: bold;} +.unconscious {color: #0000ff; font-weight: bold;} +.suicide {color: #ff5050; font-style: italic;} +.green {color: #03ff39;} +.nicegreen {color: #14a833;} +.userlove {color: #FF1493; font-style: italic; font-weight: bold; text-shadow: 0 0 6px #ff6dbc;} +.love {color: #ff006a; font-style: italic; text-shadow: 0 0 6px #ff6d6d;} +.shadowling {color: #3b2769;} +.cult {color: #960000;} + +.cultitalic {color: #960000; font-style: italic;} +.cultbold {color: #960000; font-style: italic; font-weight: bold;} +.cultboldtalic {color: #960000; font-weight: bold; font-size: 24px;} + +.cultlarge {color: #960000; font-weight: bold; font-size: 24px;} +.narsie {color: #960000; font-weight: bold; font-size: 120px;} +.narsiesmall {color: #960000; font-weight: bold; font-size: 48px;} +.colossus {color: #7F282A; font-size: 40px;} +.hierophant {color: #660099; font-weight: bold; font-style: italic;} +.hierophant_warning {color: #660099; font-style: italic;} +.purple {color: #5e2d79;} +.holoparasite {color: #35333a;} + +.revennotice {color: #1d2953;} +.revenboldnotice {color: #1d2953; font-weight: bold;} +.revenbignotice {color: #1d2953; font-weight: bold; font-size: 24px;} +.revenminor {color: #823abb} +.revenwarning {color: #760fbb; font-style: italic;} +.revendanger {color: #760fbb; font-weight: bold; font-size: 24px;} +.umbra {color: #5000A0;} +.umbra_emphasis {color: #5000A0; font-weight: bold; font-style: italic;} +.umbra_large {color: #5000A0; font-size: 24px; font-weight: bold; font-style: italic;} + +.deconversion_message {color: #5000A0; font-size: 24px; font-style: italic;} + +.brass {color: #BE8700;} +.heavy_brass {color: #BE8700; font-weight: bold; font-style: italic;} +.large_brass {color: #BE8700; font-size: 24px;} +.big_brass {color: #BE8700; font-size: 24px; font-weight: bold; font-style: italic;} +.ratvar {color: #BE8700; font-size: 48px; font-weight: bold; font-style: italic;} +.alloy {color: #42474D;} +.heavy_alloy {color: #42474D; font-weight: bold; font-style: italic;} +.nezbere_large {color: #42474D; font-size: 24px; font-weight: bold; font-style: italic;} +.nezbere {color: #42474D; font-weight: bold; font-style: italic;} +.nezbere_small {color: #42474D;} +.sevtug_large {color: #AF0AAF; font-size: 24px; font-weight: bold; font-style: italic;} +.sevtug {color: #AF0AAF; font-weight: bold; font-style: italic;} +.sevtug_small {color: #AF0AAF;} +.inathneq_large {color: #1E8CE1; font-size: 24px; font-weight: bold; font-style: italic;} +.inathneq {color: #1E8CE1; font-weight: bold; font-style: italic;} +.inathneq_small {color: #1E8CE1;} +.nzcrentr_large {color: #DAAA18; font-size: 24px; font-weight: bold; font-style: italic;} +.nzcrentr {color: #DAAA18; font-weight: bold; font-style: italic;} +.nzcrentr_small {color: #DAAA18;} +.neovgre_large {color: #6E001A; font-size: 24px; font-weight: bold; font-style: italic;} +.neovgre {color: #6E001A; font-weight: bold; font-style: italic;} +.neovgre_small {color: #6E001A;} + +.newscaster {color: #800000;} +.ghostalert {color: #5c00e6; font-style: italic; font-weight: bold;} + +.alien {color: #543354;} +.noticealien {color: #00c000;} +.alertalien {color: #00c000; font-weight: bold;} +.changeling {color: #800080; font-style: italic;} + +.spider {color: #4d004d;} + +.interface {color: #330033;} + +.sans {font-family: "Comic Sans MS", cursive, sans-serif;} +.papyrus {font-family: "Papyrus", cursive, sans-serif;} +.robot {font-family: "Courier New", cursive, sans-serif;} + +.command_headset {font-weight: bold; font-size: 24px;} +.small {font-size: 8px;} +.big {font-size: 24px;} +.reallybig {font-size: 32px;} +.extremelybig {font-size: 40px;} +.greentext {color: #00FF00; font-size: 24px;} +.redtext {color: #FF0000; font-size: 24px;} +.clown {color: #FF69Bf; font-size: 24px; font-family: "Comic Sans MS", cursive, sans-serif; font-weight: bold;} +.hypnophrase {color: #202020; font-weight: bold; animation: hypnocolor 1500ms infinite;} +@keyframes hypnocolor { + 0% { color: #202020; } + 25% { color: #4b02ac; } + 50% { color: #9f41f1; } + 75% { color: #541c9c; } + 100% { color: #7adbf3; } +} + +.phobia {color: #dd0000; font-weight: bold; animation: phobia 750ms infinite;} +@keyframes phobia { + 0% { color: #f75a5a; } + 50% { color: #dd0000; } + 100% { color: #f75a5a; } +} +.his_grace {color: #15D512; font-family: "Courier New", cursive, sans-serif; font-style: italic;} + +.icon {height: 1em; width: auto;} + +.memo {color: #638500; text-align: center;} +.memoedit {text-align: center; font-size: 16px;} +.abductor {color: #800080; font-style: italic;} +.mind_control {color: #A00D6F; font-size: 3; font-weight: bold; font-style: italic;} +.slime {color: #00CED1;} +.drone {color: #848482;} +.monkey {color: #975032;} +.swarmer {color: #2C75FF;} +.resonate {color: #298F85;} + +.monkeyhive {color: #774704;} +.monkeylead {color: #774704; font-size: 2;} + +.connectionClosed, .fatalError {background: red; color: white; padding: 5px;} +.connectionClosed.restored {background: green;} +.internal.boldnshit {color: blue; font-weight: bold;} + +/* HELPER CLASSES */ +.text-normal {font-weight: normal; font-style: normal;} +.hidden {display: none; visibility: hidden;} diff --git a/html/changelogs/AutoChangeLog-pr-8349.yml b/html/changelogs/AutoChangeLog-pr-8349.yml new file mode 100644 index 0000000000..de4c08624a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8349.yml @@ -0,0 +1,5 @@ +author: "Trilbyspaceclone" +delete-after: True +changes: + - rscadd: "more bountys" + - rscdel: "Nitryl bounty" diff --git a/html/changelogs/AutoChangeLog-pr-8401.yml b/html/changelogs/AutoChangeLog-pr-8401.yml new file mode 100644 index 0000000000..0043ffa202 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8401.yml @@ -0,0 +1,6 @@ +author: "Ghommie" +delete-after: True +changes: + - refactor: "Refactored implants to not be located inside mobs codewise, akin to organs." + - bugfix: "Fixed gps tracking implants." + - bugfix: "Fixed item not being dumped out of storage implants onto the owner's turf upon removal." diff --git a/html/changelogs/AutoChangeLog-pr-8537.yml b/html/changelogs/AutoChangeLog-pr-8537.yml new file mode 100644 index 0000000000..a537ba1c3a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8537.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "Fixes emags wasting charges on un-emaggable & co stuff." diff --git a/html/changelogs/AutoChangeLog-pr-8615.yml b/html/changelogs/AutoChangeLog-pr-8615.yml new file mode 100644 index 0000000000..878b7957b9 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8615.yml @@ -0,0 +1,5 @@ +author: "Ghommie" +delete-after: True +changes: + - refactor: "turned virtual reality into a component datum, which is then applied to spawned virtual mobs. +This fixes mob transformations (such as wabbajack and monkeyizing) breaking the previously hardcoded behaviour and trapping you in VR, also enabling a more concrete virtual reality inception experience." diff --git a/html/changelogs/AutoChangeLog-pr-8636.yml b/html/changelogs/AutoChangeLog-pr-8636.yml new file mode 100644 index 0000000000..3b291661b5 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8636.yml @@ -0,0 +1,4 @@ +author: "Trilbyspaceclone" +delete-after: True +changes: + - bugfix: "fixed airless place" diff --git a/html/changelogs/AutoChangeLog-pr-8649.yml b/html/changelogs/AutoChangeLog-pr-8649.yml new file mode 100644 index 0000000000..c8f61cc24e --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8649.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - tweak: "The default amount of z-levels reserved specifically for space ruin generation has been increased from 1 to 2" diff --git a/html/changelogs/AutoChangeLog-pr-8660.yml b/html/changelogs/AutoChangeLog-pr-8660.yml new file mode 100644 index 0000000000..710c4489ea --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8660.yml @@ -0,0 +1,4 @@ +author: "Trilbyspaceclone" +delete-after: True +changes: + - code_imp: "Changes some files to be better" diff --git a/html/changelogs/AutoChangeLog-pr-8673.yml b/html/changelogs/AutoChangeLog-pr-8673.yml new file mode 100644 index 0000000000..6ff2c7135c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8673.yml @@ -0,0 +1,4 @@ +author: "Trilbyspaceclone" +delete-after: True +changes: + - balance: "As all things are not" diff --git a/html/changelogs/AutoChangeLog-pr-8763.yml b/html/changelogs/AutoChangeLog-pr-8763.yml new file mode 100644 index 0000000000..d99b529656 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8763.yml @@ -0,0 +1,4 @@ +author: "Trilbyspaceclone" +delete-after: True +changes: + - balance: "bone satchles" diff --git a/html/changelogs/AutoChangeLog-pr-8774.yml b/html/changelogs/AutoChangeLog-pr-8774.yml new file mode 100644 index 0000000000..7ba01cc6aa --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8774.yml @@ -0,0 +1,4 @@ +author: "Sishen1542" +delete-after: True +changes: + - bugfix: "Removed the human check for cult conversion of captain/chaplain minds." diff --git a/html/changelogs/AutoChangeLog-pr-8900.yml b/html/changelogs/AutoChangeLog-pr-8900.yml new file mode 100644 index 0000000000..cbb910c3d5 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8900.yml @@ -0,0 +1,4 @@ +author: "Seris02" +delete-after: True +changes: + - rscadd: "Abductor Replication Lab ruin and advanced tools" diff --git a/html/changelogs/AutoChangeLog-pr-8908.yml b/html/changelogs/AutoChangeLog-pr-8908.yml new file mode 100644 index 0000000000..d9cbd5abed --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8908.yml @@ -0,0 +1,5 @@ +author: "Ghommie" +delete-after: True +changes: + - balance: "Improved the zelus flask to be more viable for bottle smashing than the average barman's selection." + - code_imp: "Very slight bottle smashing code clean up, stupid const vars." diff --git a/html/changelogs/AutoChangeLog-pr-8913.yml b/html/changelogs/AutoChangeLog-pr-8913.yml new file mode 100644 index 0000000000..ccac6aef16 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8913.yml @@ -0,0 +1,4 @@ +author: "Trilbyspaceclone" +delete-after: True +changes: + - rscadd: "Added new chairs" diff --git a/html/changelogs/AutoChangeLog-pr-8914.yml b/html/changelogs/AutoChangeLog-pr-8914.yml new file mode 100644 index 0000000000..ea7f548d6a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8914.yml @@ -0,0 +1,13 @@ +author: "Ghommie (original PRs by Mickyan, Anturk, ShizCalev, nemvar and Naksu)" +delete-after: True +changes: + - rscadd: "After rigorous mandatory art training for the crew, many new graffiti styles are now available" + - bugfix: "Cleaned up some crayon and spraycan code for futureproofing." + - bugfix: "Spraypainting blast doors no longer makes them see-through." + - balance: "Paint remover now works on blast doors and the like." + - rscadd: "Most objects can now be colored using a spray can." + - spellcheck: "Added visible message to spraying objects and windows." + - rscadd: "Colored lights now shine in different colours." + - rscdel: "Removed individual buttons text in crayon/spraycan UI, speeding it up." + - bugfix: "Text mode buffer is actually visible in the UI." + - tweak: "Last letter of a text mode buffer no longer rotates out to be replaced with \"a\", allowing the text mode to be used for individual symbols." diff --git a/html/changelogs/AutoChangeLog-pr-8927.yml b/html/changelogs/AutoChangeLog-pr-8927.yml new file mode 100644 index 0000000000..3a87d7652e --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8927.yml @@ -0,0 +1,5 @@ +author: "Ghommie" +delete-after: True +changes: + - balance: "toned down the stamina costs of some of the bulkier weapons." + - code_imp: "repathed hypereutactic blades to be a subtype of dual sabers. Way less copypasta." diff --git a/html/changelogs/AutoChangeLog-pr-8932.yml b/html/changelogs/AutoChangeLog-pr-8932.yml new file mode 100644 index 0000000000..d9038ef1a5 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8932.yml @@ -0,0 +1,7 @@ +author: "EmeraldSundisk" +delete-after: True +changes: + - rscadd: "Adds a gun range to Box Station" + - rscadd: "Provides some extra power grid connections" + - rscdel: "Sunglasses and Earmuffs removed from the Warden's Office - they can be found at the range instead" + - tweak: "Rearranges a few objects within the prison as to accommodate the new gun range" diff --git a/html/changelogs/AutoChangeLog-pr-8937.yml b/html/changelogs/AutoChangeLog-pr-8937.yml new file mode 100644 index 0000000000..20302e4c49 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8937.yml @@ -0,0 +1,5 @@ +author: "Ghommie" +delete-after: True +changes: + - rscadd: "sort of overhauled darkmode/lightmode to /vg/station's, also reincluding the pre-existing black'n'white theme." + - bugfix: "Fixed LOOC color, fixed .userlove and .love span classes being a bit too blurry on dark mode." diff --git a/html/changelogs/AutoChangeLog-pr-8968.yml b/html/changelogs/AutoChangeLog-pr-8968.yml new file mode 100644 index 0000000000..0a0b0e84d0 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8968.yml @@ -0,0 +1,4 @@ +author: "Trilbyspaceclone" +delete-after: True +changes: + - bugfix: "oversight in benos" diff --git a/html/changelogs/AutoChangeLog-pr-8986.yml b/html/changelogs/AutoChangeLog-pr-8986.yml new file mode 100644 index 0000000000..810631f5f5 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8986.yml @@ -0,0 +1,6 @@ +author: "Ghommie" +delete-after: True +changes: + - rscadd: "reworked ninja's stealth mode. Increased invisibility, but engaging in combat, attacking or throwing things, bumping people will temporarily lower it." + - rscadd: "Ninja shoes are even stealthier." + - code_imp: "cleaned up some 2014 tier processing code horror." diff --git a/html/changelogs/AutoChangeLog-pr-8992.yml b/html/changelogs/AutoChangeLog-pr-8992.yml new file mode 100644 index 0000000000..299792fee3 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8992.yml @@ -0,0 +1,5 @@ +author: "Chayse" +delete-after: True +changes: + - rscadd: "Assorted space-worthy helmets can now act as masks for internals." + - refactor: "Internals code can now check any item with the ALLOWSINTERNALS flag through the GET_INTERNAL_SLOTS define. For now this only checks head and mask slots, since those are the most realistically speaking usable ones." diff --git a/html/changelogs/AutoChangeLog-pr-8998.yml b/html/changelogs/AutoChangeLog-pr-8998.yml new file mode 100644 index 0000000000..981e746fc9 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8998.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "High luminosity eyes can now be properly deactivated and won't illuminate your surroundings again until turned back on." diff --git a/html/changelogs/AutoChangeLog-pr-9010.yml b/html/changelogs/AutoChangeLog-pr-9010.yml new file mode 100644 index 0000000000..52aed38e2c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9010.yml @@ -0,0 +1,4 @@ +author: "BurgerBB" +delete-after: True +changes: + - balance: "Activating the nuclear device during war-ops informs the crew of the nuke's position." diff --git a/html/changelogs/AutoChangeLog-pr-9019.yml b/html/changelogs/AutoChangeLog-pr-9019.yml new file mode 100644 index 0000000000..8006c134e3 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9019.yml @@ -0,0 +1,6 @@ +author: "Ghommie" +delete-after: True +changes: + - balance: "MRE menu 3 has cuban nachos instead of a chili now." + - bugfix: "Removed the illustration overlay from MREs, looks pretty weird otherwise." + - rscadd: "MRE menu 4, vegetarian." diff --git a/html/changelogs/AutoChangeLog-pr-9021.yml b/html/changelogs/AutoChangeLog-pr-9021.yml new file mode 100644 index 0000000000..e8809f1d7e --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9021.yml @@ -0,0 +1,4 @@ +author: "Ghommie (by Floyd / Qustinnus, Arathian)" +delete-after: True +changes: + - rscadd: "The robotocist now has robe to show his love for toasters" diff --git a/html/changelogs/AutoChangeLog-pr-9022.yml b/html/changelogs/AutoChangeLog-pr-9022.yml new file mode 100644 index 0000000000..4fb48506e4 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9022.yml @@ -0,0 +1,4 @@ +author: "Ghommie (by nemvar)" +delete-after: True +changes: + - tweak: "Dwarfs are now more robust." diff --git a/html/changelogs/AutoChangeLog-pr-9032.yml b/html/changelogs/AutoChangeLog-pr-9032.yml new file mode 100644 index 0000000000..53adfa0920 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9032.yml @@ -0,0 +1,7 @@ +author: "Ghommie (original PRs by subject217, AarontheIdiot, pireamaineach, Gousaid67 and SouDescolado)" +delete-after: True +changes: + - balance: "Removed plasmamen species speedmod in favor of a slowdown for envirosuits." + - rscadd: "Nanotrasen has began deploying departementalized enviro plasmasuits to the station! plasmamens can now benefit from some of the bonuses aswell as the color pattern of their job, while allowing others to easily determine their profession!" + - bugfix: "Benevolent Nanotrasen makes gulag available for everyone! (Plasmamen retain their equipment and don't die.)" + - rscdel: "Removes code that theoretically limits plasmamen from being clowns and mimes, but actually doesn't." diff --git a/html/changelogs/AutoChangeLog-pr-9045.yml b/html/changelogs/AutoChangeLog-pr-9045.yml new file mode 100644 index 0000000000..8917707ae3 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9045.yml @@ -0,0 +1,8 @@ +author: "CameronWoof" +delete-after: True +changes: + - tweak: "Fluid-producing sexual organs no longer start full" + - tweak: "Sexual organ fluid capacity decreased from 50 to 15" + - tweak: "Sexual organ production rate decreased from 5u to 0.035u per two seconds." + - tweak: "Sexual fluid decals no longer contain reagents" + - tweak: "Sexual fluids cannot by synthesized (e.g., by the Odysseus)" diff --git a/html/changelogs/AutoChangeLog-pr-9046.yml b/html/changelogs/AutoChangeLog-pr-9046.yml new file mode 100644 index 0000000000..24e7035a88 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9046.yml @@ -0,0 +1,4 @@ +author: "Sishen1542" +delete-after: True +changes: + - tweak: "density = 0" diff --git a/html/changelogs/AutoChangeLog-pr-9050.yml b/html/changelogs/AutoChangeLog-pr-9050.yml new file mode 100644 index 0000000000..3b12a12f17 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9050.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "fixes a few bad touchs on combat mode pushing." diff --git a/html/changelogs/AutoChangeLog-pr-9052.yml b/html/changelogs/AutoChangeLog-pr-9052.yml new file mode 100644 index 0000000000..a75b6c51ae --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9052.yml @@ -0,0 +1,4 @@ +author: "kevinz000" +delete-after: True +changes: + - balance: "Hierophant now goes sicko mode, but hey, at least you can't be multi-hit by melee waves!" diff --git a/html/changelogs/AutoChangeLog-pr-9054.yml b/html/changelogs/AutoChangeLog-pr-9054.yml new file mode 100644 index 0000000000..5952c9ecfd --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9054.yml @@ -0,0 +1,4 @@ +author: "Sishen1542" +delete-after: True +changes: + - balance: "hugboxing mining loot" diff --git a/html/changelogs/AutoChangeLog-pr-9057.yml b/html/changelogs/AutoChangeLog-pr-9057.yml new file mode 100644 index 0000000000..4df1b23ca7 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9057.yml @@ -0,0 +1,4 @@ +author: "EgoSumStultus" +delete-after: True +changes: + - rscadd: "Adds male AI vox." diff --git a/html/changelogs/AutoChangeLog-pr-9061.yml b/html/changelogs/AutoChangeLog-pr-9061.yml new file mode 100644 index 0000000000..4fc9d10ba5 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9061.yml @@ -0,0 +1,5 @@ +author: "deathride58" +delete-after: True +changes: + - tweak: "The femur breaker now uses `*scream` instead of forced speech. This means that the femur breaker will no longer spam deadchat with \"AAAAAAAAAHHHHHHHHHH!!\"" + - tweak: "The femur breaker will now guarantee that the victim falls into crit, which will make it harder to perform torture scenes with it since the victim can just succumb." diff --git a/html/changelogs/AutoChangeLog-pr-9062.yml b/html/changelogs/AutoChangeLog-pr-9062.yml new file mode 100644 index 0000000000..12102204c3 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9062.yml @@ -0,0 +1,4 @@ +author: "Trilbyspaceclone" +delete-after: True +changes: + - spellcheck: "less bad wording in slime" diff --git a/html/changelogs/AutoChangeLog-pr-9064.yml b/html/changelogs/AutoChangeLog-pr-9064.yml new file mode 100644 index 0000000000..6e775c1eb4 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9064.yml @@ -0,0 +1,4 @@ +author: "Cebutris" +delete-after: True +changes: + - rscadd: "Hugs of the North Star! Get them from the arcades (if you're lucky) and hug your friends at INCREDIBLE hihg speeds!" diff --git a/html/changelogs/AutoChangeLog-pr-9069.yml b/html/changelogs/AutoChangeLog-pr-9069.yml new file mode 100644 index 0000000000..0439515dd3 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9069.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "Fixes clock cult Abscond scripture not dragging pulled mobs into Reebe. Also fixes blood cult tele runes teleporting you from the source turf to the source turf." diff --git a/html/changelogs/AutoChangeLog-pr-9070.yml b/html/changelogs/AutoChangeLog-pr-9070.yml new file mode 100644 index 0000000000..2013550dd2 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9070.yml @@ -0,0 +1,5 @@ +author: "Linzolle" +delete-after: True +changes: + - rscadd: "inhands sprite for rainbow knife" + - tweak: "colour of highlight on the regular knife when held in the right hand" diff --git a/html/changelogs/AutoChangeLog-pr-9071.yml b/html/changelogs/AutoChangeLog-pr-9071.yml new file mode 100644 index 0000000000..40ae43867f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9071.yml @@ -0,0 +1,4 @@ +author: "Yakumo Chen" +delete-after: True +changes: + - balance: "Autocloning now requires tier 4 parts" diff --git a/html/changelogs/AutoChangeLog-pr-9077.yml b/html/changelogs/AutoChangeLog-pr-9077.yml new file mode 100644 index 0000000000..2f42e36dd6 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9077.yml @@ -0,0 +1,8 @@ +author: "original by actioninja, port by sishen1542" +delete-after: True +changes: + - tweak: "Medical and Security consoles now check access on worn or inhand ID instead of requiring an inserted ID" + - tweak: "mining vendor now reads from ID in hand or on person instead of requiring an inserted ID" + - bugfix: "ORM is functional again (for real this time)" + - tweak: "ORM claim points button transfers points to worn/inhand ID instead of to an inserted ID, no longer accepts insertions" + - tweak: "Same for gulag consoles" diff --git a/html/changelogs/AutoChangeLog-pr-9078.yml b/html/changelogs/AutoChangeLog-pr-9078.yml new file mode 100644 index 0000000000..2e202ec43a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9078.yml @@ -0,0 +1,7 @@ +author: "kappa-sama" +delete-after: True +changes: + - rscdel: "Removed racism" + - tweak: "Teleporter calibration actually matters to all roundstart players" + - balance: "Slows down teleportation with the console/hub/teleporter setup if you care for your species." + - balance: "Dedicated non-humans can now get hulk without having to become human." diff --git a/html/changelogs/AutoChangeLog-pr-9079.yml b/html/changelogs/AutoChangeLog-pr-9079.yml new file mode 100644 index 0000000000..42aa732e16 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9079.yml @@ -0,0 +1,4 @@ +author: "Sishen1542" +delete-after: True +changes: + - balance: "ling blade now has 40 armor pen" diff --git a/html/changelogs/AutoChangeLog-pr-9080.yml b/html/changelogs/AutoChangeLog-pr-9080.yml new file mode 100644 index 0000000000..1ae1e3e2aa --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9080.yml @@ -0,0 +1,4 @@ +author: "Fermis" +delete-after: True +changes: + - rscadd: "Adds 3 new music tracks." diff --git a/html/changelogs/AutoChangeLog-pr-9081.yml b/html/changelogs/AutoChangeLog-pr-9081.yml new file mode 100644 index 0000000000..c66148e446 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9081.yml @@ -0,0 +1,4 @@ +author: "BurgerBB" +delete-after: True +changes: + - balance: "Central Command informs you when a Meteor Storm is about to hit 5 to 10 minutes before it happens." diff --git a/html/changelogs/AutoChangeLog-pr-9083.yml b/html/changelogs/AutoChangeLog-pr-9083.yml new file mode 100644 index 0000000000..74b4d95ca3 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9083.yml @@ -0,0 +1,4 @@ +author: "Trilbyspaceclone" +delete-after: True +changes: + - rscadd: "strawbarries and such" diff --git a/html/changelogs/AutoChangeLog-pr-9084.yml b/html/changelogs/AutoChangeLog-pr-9084.yml new file mode 100644 index 0000000000..c2569d10b4 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9084.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "fixes clock cult mass recall." diff --git a/html/changelogs/AutoChangeLog-pr-9085.yml b/html/changelogs/AutoChangeLog-pr-9085.yml new file mode 100644 index 0000000000..92f5dc4cf8 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9085.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "Fixes underwear colors a bit." diff --git a/html/changelogs/AutoChangeLog-pr-9086.yml b/html/changelogs/AutoChangeLog-pr-9086.yml new file mode 100644 index 0000000000..4dea682d47 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9086.yml @@ -0,0 +1,4 @@ +author: "original by TheChosenEvilOne, port by sishen1542" +delete-after: True +changes: + - rscadd: "Ported dynamic mode from /vg/, originally made by @DeityLink, @Kurfursten and @ShiftyRail" diff --git a/html/changelogs/AutoChangeLog-pr-9089.yml b/html/changelogs/AutoChangeLog-pr-9089.yml new file mode 100644 index 0000000000..dc1e351f25 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9089.yml @@ -0,0 +1,6 @@ +author: "original by Tlaltecuhtli, port by sishen1542" +delete-after: True +changes: + - rscadd: "rcd disk that gives rcd computer frame and machine frame designs" + - rscadd: "upgraded rcd in CE lockers" + - tweak: "moved deconstruction to the upgrade disk, ashwalker rcd comes upgraded" diff --git a/html/changelogs/AutoChangeLog-pr-9097.yml b/html/changelogs/AutoChangeLog-pr-9097.yml new file mode 100644 index 0000000000..941c0e7b98 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9097.yml @@ -0,0 +1,4 @@ +author: "lolman360" +delete-after: True +changes: + - rscadd: "NT has authorized shipments or Cotton to Megaseed Servitors. It's time to start picking, liggers." diff --git a/html/changelogs/AutoChangeLog-pr-9098.yml b/html/changelogs/AutoChangeLog-pr-9098.yml new file mode 100644 index 0000000000..6e11eaeb90 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9098.yml @@ -0,0 +1,4 @@ +author: "Cebutris" +delete-after: True +changes: + - bugfix: "Tea Aspera now properly contains tea powder" diff --git a/html/changelogs/AutoChangeLog-pr-9099.yml b/html/changelogs/AutoChangeLog-pr-9099.yml new file mode 100644 index 0000000000..d3caa658f2 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9099.yml @@ -0,0 +1,6 @@ +author: "Fermis" +delete-after: True +changes: + - tweak: "tweaked Neurotoxin" + - balance: "added more depth to Neurotoxin" + - bugfix: "fixed the inability to create Neurotoxin" diff --git a/html/changelogs/AutoChangeLog-pr-9100.yml b/html/changelogs/AutoChangeLog-pr-9100.yml new file mode 100644 index 0000000000..81141b3b0c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9100.yml @@ -0,0 +1,4 @@ +author: "Cebutris" +delete-after: True +changes: + - tweak: "Breasts no longer lactate by default, lactation is now a preference" diff --git a/html/changelogs/AutoChangeLog-pr-9101.yml b/html/changelogs/AutoChangeLog-pr-9101.yml new file mode 100644 index 0000000000..174619dd49 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9101.yml @@ -0,0 +1,4 @@ +author: "Sishen1542, original by XDTM" +delete-after: True +changes: + - rscadd: "Surgery steps are now shown in detail only to the surgeon and anyone standing adjacent to them; the patient and people watching from further away get a more vague/ambiguous description." diff --git a/html/changelogs/AutoChangeLog-pr-9107.yml b/html/changelogs/AutoChangeLog-pr-9107.yml new file mode 100644 index 0000000000..65a14b9576 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9107.yml @@ -0,0 +1,4 @@ +author: "Bhijn" +delete-after: True +changes: + - bugfix: "You can now actually use the resist hotkey to resist out of handcuffs. Woah, revolutionary" diff --git a/html/changelogs/AutoChangeLog-pr-9109.yml b/html/changelogs/AutoChangeLog-pr-9109.yml new file mode 100644 index 0000000000..137ca7f325 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9109.yml @@ -0,0 +1,4 @@ +author: "Trilbyspaceclone" +delete-after: True +changes: + - rscadd: "amazing things like tea of catnip, catnip and plant" diff --git a/html/changelogs/AutoChangeLog-pr-9113.yml b/html/changelogs/AutoChangeLog-pr-9113.yml new file mode 100644 index 0000000000..1bdae7cab9 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9113.yml @@ -0,0 +1,5 @@ +author: "Fermis" +delete-after: True +changes: + - bugfix: "fixes fermichem reactions for tiny volumes work" + - tweak: "makes quantisation level for chemistry finer" diff --git a/html/changelogs/AutoChangeLog-pr-9115.yml b/html/changelogs/AutoChangeLog-pr-9115.yml new file mode 100644 index 0000000000..32c3109c43 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9115.yml @@ -0,0 +1,4 @@ +author: "Thalpy" +delete-after: True +changes: + - bugfix: "fixes message_admins in SDZF" diff --git a/html/changelogs/AutoChangeLog-pr-9119.yml b/html/changelogs/AutoChangeLog-pr-9119.yml new file mode 100644 index 0000000000..756c3edcb2 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9119.yml @@ -0,0 +1,4 @@ +author: "Linzolle" +delete-after: True +changes: + - rscadd: "mining shuttle console can now be printed after computer consoles have been researched" diff --git a/html/changelogs/AutoChangeLog-pr-9122.yml b/html/changelogs/AutoChangeLog-pr-9122.yml new file mode 100644 index 0000000000..1d3ff248fb --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9122.yml @@ -0,0 +1,6 @@ +author: "Sishen1542" +delete-after: True +changes: + - rscadd: "fun" + - rscdel: "bad stuff" + - balance: "mech bad" diff --git a/html/changelogs/AutoChangeLog-pr-9126.yml b/html/changelogs/AutoChangeLog-pr-9126.yml new file mode 100644 index 0000000000..c3e54a8f2d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9126.yml @@ -0,0 +1,4 @@ +author: "original by Skoglol, port by sishen1542" +delete-after: True +changes: + - balance: "Added lots of new virus cures, made cure difficulty scale more consistently. Cures are now picked from a list of possible cures per resistance level, multiple diseases at the same level no longer always share a cure. Looking at you table salt." diff --git a/html/changelogs/AutoChangeLog-pr-9130.yml b/html/changelogs/AutoChangeLog-pr-9130.yml new file mode 100644 index 0000000000..f10e72a6ce --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9130.yml @@ -0,0 +1,9 @@ +author: "Owai-Seek" +delete-after: True +changes: + - rscadd: "custodial cruiser cargo crate" + - tweak: "removed light replacer from power designs and moved to misc designs" + - tweak: "added pimpin ride to custodial locator" + - tweak: "added additional items to janibelt whitelist" + - tweak: "made plant DNA manipulator unwrenchable" + - balance: "reduced janitor premium supply costs" diff --git a/html/changelogs/AutoChangeLog-pr-9132.yml b/html/changelogs/AutoChangeLog-pr-9132.yml new file mode 100644 index 0000000000..f9dee17687 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9132.yml @@ -0,0 +1,4 @@ +author: "Toriate" +delete-after: True +changes: + - imageadd: "Updated the sprites of all the regular crates" diff --git a/html/changelogs/AutoChangeLog-pr-9133.yml b/html/changelogs/AutoChangeLog-pr-9133.yml new file mode 100644 index 0000000000..50bfced879 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9133.yml @@ -0,0 +1,4 @@ +author: "Raptorizer" +delete-after: True +changes: + - tweak: "Doubled peach spawn rate" diff --git a/html/changelogs/AutoChangeLog-pr-9134.yml b/html/changelogs/AutoChangeLog-pr-9134.yml new file mode 100644 index 0000000000..f0be3bdd0a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9134.yml @@ -0,0 +1,4 @@ +author: "Arturlang" +delete-after: True +changes: + - tweak: "Advanced toxin filtration nanites now heal slimes" diff --git a/html/changelogs/AutoChangeLog-pr-9136.yml b/html/changelogs/AutoChangeLog-pr-9136.yml new file mode 100644 index 0000000000..7bb9e3ccf2 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9136.yml @@ -0,0 +1,4 @@ +author: "Sishen1542" +delete-after: True +changes: + - balance: "rebalances strained muscles" diff --git a/html/changelogs/AutoChangeLog-pr-9137.yml b/html/changelogs/AutoChangeLog-pr-9137.yml new file mode 100644 index 0000000000..a61a3dbe6f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9137.yml @@ -0,0 +1,5 @@ +author: "Sishen1542" +delete-after: True +changes: + - rscadd: "added in the assistant response team" + - bugfix: "fixed up access on the centcom hangar button" diff --git a/html/changelogs/AutoChangeLog-pr-9138.yml b/html/changelogs/AutoChangeLog-pr-9138.yml new file mode 100644 index 0000000000..b78d505c5a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9138.yml @@ -0,0 +1,4 @@ +author: "kappa-sama" +delete-after: True +changes: + - bugfix: "seed" diff --git a/html/changelogs/AutoChangeLog-pr-9141.yml b/html/changelogs/AutoChangeLog-pr-9141.yml new file mode 100644 index 0000000000..86230537de --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9141.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - bugfix: "Fixed another runtime in warp whistles." diff --git a/html/changelogs/AutoChangeLog-pr-9142.yml b/html/changelogs/AutoChangeLog-pr-9142.yml new file mode 100644 index 0000000000..75fbfe4155 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9142.yml @@ -0,0 +1,4 @@ +author: "Trilbyspaceclone" +delete-after: True +changes: + - tweak: "glue uplinks" diff --git a/html/changelogs/AutoChangeLog-pr-9145.yml b/html/changelogs/AutoChangeLog-pr-9145.yml new file mode 100644 index 0000000000..27e5712dd0 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9145.yml @@ -0,0 +1,4 @@ +author: "Trilbyspaceclone" +delete-after: True +changes: + - rscadd: "RPDs to drones" diff --git a/html/changelogs/AutoChangeLog-pr-9147.yml b/html/changelogs/AutoChangeLog-pr-9147.yml new file mode 100644 index 0000000000..7f1dcb7e7e --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9147.yml @@ -0,0 +1,5 @@ +author: "Code-Cygnet" +delete-after: True +changes: + - rscadd: "Added new things - Mind trait, alcohol reagent, chemical reagent, drink sprite and recipe." + - imageadd: "added commander_and_chief sprite to drinks.dmi" diff --git a/html/changelogs/AutoChangeLog-pr-9149.yml b/html/changelogs/AutoChangeLog-pr-9149.yml new file mode 100644 index 0000000000..8a10035d1f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9149.yml @@ -0,0 +1,4 @@ +author: "Trilbyspaceclone" +delete-after: True +changes: + - rscadd: "Armor and such" diff --git a/html/changelogs/AutoChangeLog-pr-9150.yml b/html/changelogs/AutoChangeLog-pr-9150.yml new file mode 100644 index 0000000000..585ea0a149 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9150.yml @@ -0,0 +1,5 @@ +author: "Trilbyspaceclone" +delete-after: True +changes: + - rscadd: "flavor" + - bugfix: "maybe a runtime" diff --git a/html/changelogs/AutoChangeLog-pr-9151.yml b/html/changelogs/AutoChangeLog-pr-9151.yml new file mode 100644 index 0000000000..ed01c0d137 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9151.yml @@ -0,0 +1,4 @@ +author: "Trilbyspaceclone" +delete-after: True +changes: + - rscadd: "chameloen clothing" diff --git a/html/changelogs/AutoChangeLog-pr-9155.yml b/html/changelogs/AutoChangeLog-pr-9155.yml new file mode 100644 index 0000000000..ad16ff6276 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9155.yml @@ -0,0 +1,4 @@ +author: "Poojawa" +delete-after: True +changes: + - server: "Poly's speech now echos to the chat bot." diff --git a/html/changelogs/AutoChangeLog-pr-9162.yml b/html/changelogs/AutoChangeLog-pr-9162.yml new file mode 100644 index 0000000000..a415ce8bbc --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9162.yml @@ -0,0 +1,5 @@ +author: "Sishen1542" +delete-after: True +changes: + - balance: "storage tweaks for belt briefcase" + - imageadd: "codersprite for belt briefcase" diff --git a/html/changelogs/AutoChangeLog-pr-9164.yml b/html/changelogs/AutoChangeLog-pr-9164.yml new file mode 100644 index 0000000000..08d7ccec18 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9164.yml @@ -0,0 +1,4 @@ +author: "lolman360" +delete-after: True +changes: + - imageadd: "missing durathread sprites" diff --git a/html/changelogs/AutoChangeLog-pr-9168.yml b/html/changelogs/AutoChangeLog-pr-9168.yml new file mode 100644 index 0000000000..2375f6a28a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9168.yml @@ -0,0 +1,4 @@ +author: "Seris02" +delete-after: True +changes: + - rscadd: "Added looc hotkey" diff --git a/html/changelogs/AutoChangeLog-pr-9169.yml b/html/changelogs/AutoChangeLog-pr-9169.yml new file mode 100644 index 0000000000..2a9d3ae34b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9169.yml @@ -0,0 +1,8 @@ +author: "EmeraldSundisk" +delete-after: True +changes: + - rscadd: "Adds a mass driver to Delta Station's chapel" + - rscadd: "Adds a second means of entry into the chapel" + - tweak: "Slightly expands the chapel to make room for the driver, slight adjustment to air systems" + - tweak: "Clears a path in the station exterior for the mass driver to work properly" + - tweak: "Nearby maintenance loot has been relocated to accommodate the chapel expansion, surrounding area has been \"cleaned up\" somewhat" diff --git a/html/changelogs/AutoChangeLog-pr-9170.yml b/html/changelogs/AutoChangeLog-pr-9170.yml new file mode 100644 index 0000000000..566d427605 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9170.yml @@ -0,0 +1,5 @@ +author: "Trilbyspaceclone" +delete-after: True +changes: + - rscadd: "tons of peach themed items" + - spellcheck: "caje" diff --git a/html/changelogs/AutoChangeLog-pr-9172.yml b/html/changelogs/AutoChangeLog-pr-9172.yml new file mode 100644 index 0000000000..751cfa6d26 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9172.yml @@ -0,0 +1,4 @@ +author: "kevinz000" +delete-after: True +changes: + - rscadd: "Racking shotguns is now more threatening." diff --git a/html/changelogs/AutoChangeLog-pr-9175.yml b/html/changelogs/AutoChangeLog-pr-9175.yml new file mode 100644 index 0000000000..d3aa92d42d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9175.yml @@ -0,0 +1,5 @@ +author: "lolman360" +delete-after: True +changes: + - rscadd: "Added durathread jumpskirt" + - imageadd: "Duraskirt sprites and rolled down jumpsuit sprites." diff --git a/html/changelogs/AutoChangeLog-pr-9177.yml b/html/changelogs/AutoChangeLog-pr-9177.yml new file mode 100644 index 0000000000..4b8a06c8af --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9177.yml @@ -0,0 +1,5 @@ +author: "JTGSZ" +delete-after: True +changes: + - tweak: "Added one more gang boss slot bringing total to 4 from 3" + - bugfix: "Fixed Gang Boss being able to be deconverted" diff --git a/html/changelogs/AutoChangeLog-pr-9178.yml b/html/changelogs/AutoChangeLog-pr-9178.yml new file mode 100644 index 0000000000..2a6de13f5e --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9178.yml @@ -0,0 +1,4 @@ +author: "Bhijn" +delete-after: True +changes: + - bugfix: "the `!tgs poly` command now actually works" diff --git a/html/changelogs/AutoChangeLog-pr-9180.yml b/html/changelogs/AutoChangeLog-pr-9180.yml new file mode 100644 index 0000000000..e184ad3205 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9180.yml @@ -0,0 +1,4 @@ +author: "Bhijn" +delete-after: True +changes: + - rscadd: "Poly now has a 0.01% chance per squawk to speak through the TGS relay." diff --git a/html/changelogs/AutoChangeLog-pr-9183.yml b/html/changelogs/AutoChangeLog-pr-9183.yml new file mode 100644 index 0000000000..dc5b5a8bdb --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9183.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "Fixes Blood Cult conversion prompts" diff --git a/html/changelogs/AutoChangeLog-pr-9184.yml b/html/changelogs/AutoChangeLog-pr-9184.yml new file mode 100644 index 0000000000..d0b4d1fa7e --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9184.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - rscdel: "Removes an obnoxious temporary overlay var." diff --git a/html/changelogs/AutoChangeLog-pr-9186.yml b/html/changelogs/AutoChangeLog-pr-9186.yml new file mode 100644 index 0000000000..f0497ee7c2 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9186.yml @@ -0,0 +1,5 @@ +author: "Sishen1542" +delete-after: True +changes: + - rscadd: "added pharaoh gear to chaplain vendor" + - spellcheck: "fixed typos in pharaoh items" diff --git a/html/changelogs/AutoChangeLog-pr-9189.yml b/html/changelogs/AutoChangeLog-pr-9189.yml new file mode 100644 index 0000000000..cf9b0c70a3 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9189.yml @@ -0,0 +1,5 @@ +author: "Sishen1542" +delete-after: True +changes: + - rscadd: "made laser minigun not shitcode and also craftable" + - soundadd: "added new fire sounds for the laser minigun" diff --git a/html/changelogs/AutoChangeLog-pr-9191.yml b/html/changelogs/AutoChangeLog-pr-9191.yml new file mode 100644 index 0000000000..242e268017 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9191.yml @@ -0,0 +1,6 @@ +author: "Linzolle" +delete-after: True +changes: + - rscadd: "can now carry people on your back by aggressive grabbing them while they are laying down and then dragging their sprite onto yours." + - tweak: "dragging people who are prone is now much slower, and carrying them will allow you to move faster at the cost of taking 5 seconds to lift them up onto your back." + - tweak: "pacifists can now aggressive grab (cannot table slam people though)" diff --git a/html/changelogs/AutoChangeLog-pr-9194.yml b/html/changelogs/AutoChangeLog-pr-9194.yml new file mode 100644 index 0000000000..24299209ea --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9194.yml @@ -0,0 +1,4 @@ +author: "kappa-sama" +delete-after: True +changes: + - tweak: "added obj/item/key to wallet whitelist" diff --git a/html/changelogs/AutoChangeLog-pr-9199.yml b/html/changelogs/AutoChangeLog-pr-9199.yml new file mode 100644 index 0000000000..bf0219c7d9 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9199.yml @@ -0,0 +1,7 @@ +author: "Tupinambis" +delete-after: True +changes: + - balance: "added a small fire delay (3 ticks) to automatic shotguns" + - balance: "Reduced buckshot brute damage by 20%. (12.5 -> 10 brute per pellet) (75 -> 60 brute at close range)" + - balance: "Reduced rubbershot stamina damage by 40% (25 -> 15 stamina per pellet) (150 -> 90 stamina at close range)" + - balance: "Reduced beanbag stamina damage by 12.5% (80 -> 70 stamina per shot)" diff --git a/html/changelogs/AutoChangeLog-pr-9200.yml b/html/changelogs/AutoChangeLog-pr-9200.yml new file mode 100644 index 0000000000..d1be09ee4a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9200.yml @@ -0,0 +1,4 @@ +author: "Owai-Seek" +delete-after: True +changes: + - bugfix: "fixed them strawberries" diff --git a/html/changelogs/AutoChangeLog-pr-9203.yml b/html/changelogs/AutoChangeLog-pr-9203.yml new file mode 100644 index 0000000000..0ad87d26c1 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9203.yml @@ -0,0 +1,4 @@ +author: "Trilbyspaceclone" +delete-after: True +changes: + - imageadd: "redid brass tools to look better*" diff --git a/html/changelogs/AutoChangeLog-pr-9204.yml b/html/changelogs/AutoChangeLog-pr-9204.yml new file mode 100644 index 0000000000..3b70354fd9 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9204.yml @@ -0,0 +1,4 @@ +author: "Trilbyspaceclone" +delete-after: True +changes: + - bugfix: "/cursed from a item path" diff --git a/html/changelogs/AutoChangeLog-pr-9208.yml b/html/changelogs/AutoChangeLog-pr-9208.yml new file mode 100644 index 0000000000..1645164266 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9208.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "colorable socks can be colored again." diff --git a/html/changelogs/AutoChangeLog-pr-9209.yml b/html/changelogs/AutoChangeLog-pr-9209.yml new file mode 100644 index 0000000000..5ed81d6856 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9209.yml @@ -0,0 +1,4 @@ +author: "original by redmoogle, port by sishen1542" +delete-after: True +changes: + - rscadd: "Added support for 3 new gasses; Tritium, Pluoxium, and BZ" diff --git a/html/changelogs/AutoChangeLog-pr-9210.yml b/html/changelogs/AutoChangeLog-pr-9210.yml new file mode 100644 index 0000000000..b02811e7a8 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9210.yml @@ -0,0 +1,7 @@ +author: "EmeraldSundisk" +delete-after: True +changes: + - tweak: "CentCom has noticed the lack of coffins in Delta Station's chapel and provided some, but in exchange for reducing the chapel morgue's capacity." + - tweak: "Fixed a maintenance door the chaplain should have been able to open." + - bugfix: "Fixes space areas outside the driver +removal: CentCom Defense Analysts have ordered the maintenance hatch to the Mass Driver room be removed citing \"security concerns\"." diff --git a/html/changelogs/AutoChangeLog-pr-9211.yml b/html/changelogs/AutoChangeLog-pr-9211.yml new file mode 100644 index 0000000000..ab5eeb4e45 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9211.yml @@ -0,0 +1,7 @@ +author: "Trilbyspaceclone" +delete-after: True +changes: + - rscadd: "Almost all clothing and most weaponds can be sold for pocket change" + - tweak: "Cargo costs of packets and selling" + - balance: "Lowered mat selling as well as most if not all bountys" + - code_imp: "Adds more files for easy finding/adding in packs" diff --git a/html/changelogs/AutoChangeLog-pr-9212.yml b/html/changelogs/AutoChangeLog-pr-9212.yml new file mode 100644 index 0000000000..48e8b8b4d3 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9212.yml @@ -0,0 +1,5 @@ +author: "dapnee" +delete-after: True +changes: + - rscadd: "Plasmaglass tables, spears, tiny plasmaglass shards" + - bugfix: "Plasmaglass structures now drop plasmaglass shards instead of nothing" diff --git a/html/changelogs/AutoChangeLog-pr-9214.yml b/html/changelogs/AutoChangeLog-pr-9214.yml new file mode 100644 index 0000000000..edc41426f2 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9214.yml @@ -0,0 +1,7 @@ +author: "original by GuyonBroadway, SkowronX, and Arizon5. port by sishen1542 and kerse" +delete-after: True +changes: + - rscadd: "Clockwork cultists may now summon forth Neovgre, the ratvrarian super weapon. This powerful mech can be summoned when applications scripture has been unlocked, boasts superior offensive and defensive capabilities, however once a pilot enters he cannot leave and is doomed to die with the mech." + - imageadd: "Sexy Sprite work courtesy or SkowronX from /tg/" + - imageadd: "brass edits by Arizon5" + - soundadd: "steamy laser by kerse" diff --git a/html/changelogs/AutoChangeLog-pr-9216.yml b/html/changelogs/AutoChangeLog-pr-9216.yml new file mode 100644 index 0000000000..0be9314dbc --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9216.yml @@ -0,0 +1,4 @@ +author: "Trilbyspaceclone" +delete-after: True +changes: + - bugfix: "oops not being blacklisted" diff --git a/html/changelogs/AutoChangeLog-pr-9219.yml b/html/changelogs/AutoChangeLog-pr-9219.yml new file mode 100644 index 0000000000..138991e507 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9219.yml @@ -0,0 +1,4 @@ +author: "Trilbyspaceclone" +delete-after: True +changes: + - bugfix: "ports a fix" diff --git a/html/changelogs/AutoChangeLog-pr-9221.yml b/html/changelogs/AutoChangeLog-pr-9221.yml new file mode 100644 index 0000000000..0256c4a7c9 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9221.yml @@ -0,0 +1,9 @@ +author: "Sishen1542" +delete-after: True +changes: + - rscadd: "holy lasrifle, hypertool, divine lightblade, and blessed baseball bat. Four new holy weapons!" + - balance: "stamina and force tweaks for most holy weapons." + - tweak: "prayer beads no longer deconvert after a 10 second timer, now just inject holy water for delayed effect" + - tweak: "cultist runes are now destroyed with a bible or a null rod" + - tweak: "bo-staff now functions as a nerfed sleepy carp staff" + - bugfix: "fixed kevinz code to add in non-null rod child items as holy weapons" diff --git a/html/changelogs/AutoChangeLog-pr-9226.yml b/html/changelogs/AutoChangeLog-pr-9226.yml new file mode 100644 index 0000000000..17bafbf36b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9226.yml @@ -0,0 +1,4 @@ +author: "Trilbyspaceclone" +delete-after: True +changes: + - code_imp: "removes some cit-modular things" diff --git a/html/changelogs/AutoChangeLog-pr-9227.yml b/html/changelogs/AutoChangeLog-pr-9227.yml new file mode 100644 index 0000000000..9f6bfabdc4 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9227.yml @@ -0,0 +1,4 @@ +author: "Trilbyspaceclone" +delete-after: True +changes: + - bugfix: "Missing sprites with bad ones" diff --git a/html/changelogs/AutoChangeLog-pr-9229.yml b/html/changelogs/AutoChangeLog-pr-9229.yml new file mode 100644 index 0000000000..5c617f6ab0 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9229.yml @@ -0,0 +1,4 @@ +author: "Trilbyspaceclone" +delete-after: True +changes: + - tweak: "emag charge amount" diff --git a/html/changelogs/AutoChangeLog-pr-9234.yml b/html/changelogs/AutoChangeLog-pr-9234.yml new file mode 100644 index 0000000000..47fc449e73 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9234.yml @@ -0,0 +1,6 @@ +author: "Trilbyspaceclone" +delete-after: True +changes: + - rscadd: "Reebe QoL aka creep in gear" + - bugfix: "???" + - server: "HEY MADE THE REEBEEE WAY SMALLER - Making it less lagging hopefully" diff --git a/html/changelogs/AutoChangeLog-pr-9235.yml b/html/changelogs/AutoChangeLog-pr-9235.yml new file mode 100644 index 0000000000..112f34a7f0 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9235.yml @@ -0,0 +1,5 @@ +author: "Yakumo Chen" +delete-after: True +changes: + - rscdel: "Removes autoscan" + - balance: "Scanning people now requires someone to operate the cloning computer regardless of part level." diff --git a/html/changelogs/AutoChangeLog-pr-9238.yml b/html/changelogs/AutoChangeLog-pr-9238.yml new file mode 100644 index 0000000000..b2eb8db233 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9238.yml @@ -0,0 +1,4 @@ +author: "Trilbyspaceclone" +delete-after: True +changes: + - rscadd: "Surgerys and spays in bags" diff --git a/html/changelogs/AutoChangeLog-pr-9239.yml b/html/changelogs/AutoChangeLog-pr-9239.yml new file mode 100644 index 0000000000..781dcd82b6 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9239.yml @@ -0,0 +1,4 @@ +author: "Trilbyspaceclone" +delete-after: True +changes: + - tweak: "earthbloods stam regen" diff --git a/html/changelogs/AutoChangeLog-pr-9241.yml b/html/changelogs/AutoChangeLog-pr-9241.yml new file mode 100644 index 0000000000..1cb08cd8d0 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9241.yml @@ -0,0 +1,6 @@ +author: "Alonefromhell" +delete-after: True +changes: + - rscadd: "Ported Oracle UI, a framework for self-updating and neat UI's" + - refactor: "Paper now uses OUI" + - refactor: "Bins now use OUI" diff --git a/html/changelogs/AutoChangeLog-pr-9242.yml b/html/changelogs/AutoChangeLog-pr-9242.yml new file mode 100644 index 0000000000..1e47385e67 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9242.yml @@ -0,0 +1,4 @@ +author: "kappa-sama" +delete-after: True +changes: + - tweak: "blood cult ritual daggers fit in jack/combat boots" diff --git a/html/changelogs/AutoChangeLog-pr-9246.yml b/html/changelogs/AutoChangeLog-pr-9246.yml new file mode 100644 index 0000000000..adffae737b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9246.yml @@ -0,0 +1,8 @@ +author: "Linzolle" +delete-after: True +changes: + - bugfix: "blood on your body floating a bit to your right if you're a taur" + - bugfix: "some suits having no icon on tauric characters" + - tweak: "front facing CMO hardsuit icon for naga taurs" + - tweak: "colour of medical cross on CMO hardsuit for taurs" + - bugfix: "taur body and jumpsuit showing through mining suits" diff --git a/html/changelogs/AutoChangeLog-pr-9247.yml b/html/changelogs/AutoChangeLog-pr-9247.yml new file mode 100644 index 0000000000..4f6e0b0875 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9247.yml @@ -0,0 +1,4 @@ +author: "Fermi" +delete-after: True +changes: + - bugfix: "Fixes tiny runaway decimals in reagents system." diff --git a/html/changelogs/AutoChangeLog-pr-9248.yml b/html/changelogs/AutoChangeLog-pr-9248.yml new file mode 100644 index 0000000000..3e6eff727c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9248.yml @@ -0,0 +1,4 @@ +author: "Trilbyspaceclone" +delete-after: True +changes: + - imageadd: "Red to Blue/Black crosses as questioned by Bhijn" diff --git a/html/changelogs/AutoChangeLog-pr-9249.yml b/html/changelogs/AutoChangeLog-pr-9249.yml new file mode 100644 index 0000000000..b2ef0c2d46 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9249.yml @@ -0,0 +1,4 @@ +author: "Trilbyspaceclone" +delete-after: True +changes: + - bugfix: "clean bot not cleaning basic cleanables" diff --git a/html/changelogs/AutoChangeLog-pr-9251.yml b/html/changelogs/AutoChangeLog-pr-9251.yml new file mode 100644 index 0000000000..c40c2e05fc --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9251.yml @@ -0,0 +1,5 @@ +author: "Linzolle" +delete-after: True +changes: + - tweak: "all chaplain suits can hold the same items in suit storage" + - code_imp: "improvement to organisation for chaplain suits" diff --git a/html/changelogs/AutoChangeLog-pr-9256.yml b/html/changelogs/AutoChangeLog-pr-9256.yml new file mode 100644 index 0000000000..dcf039a2a0 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9256.yml @@ -0,0 +1,4 @@ +author: "Fermi" +delete-after: True +changes: + - bugfix: "SDGF: Fixes infinite clones." diff --git a/html/changelogs/AutoChangeLog-pr-9257.yml b/html/changelogs/AutoChangeLog-pr-9257.yml new file mode 100644 index 0000000000..79b5ae3645 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9257.yml @@ -0,0 +1,4 @@ +author: "Fermi" +delete-after: True +changes: + - bugfix: "fixed an angery PR" diff --git a/html/changelogs/AutoChangeLog-pr-9260.yml b/html/changelogs/AutoChangeLog-pr-9260.yml new file mode 100644 index 0000000000..f94d9772f9 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9260.yml @@ -0,0 +1,4 @@ +author: "dapnee" +delete-after: True +changes: + - rscadd: "Trim lines!" diff --git a/html/changelogs/AutoChangeLog-pr-9263.yml b/html/changelogs/AutoChangeLog-pr-9263.yml new file mode 100644 index 0000000000..36a03fa125 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9263.yml @@ -0,0 +1,4 @@ +author: "Trilbyspaceclone" +delete-after: True +changes: + - rscadd: "new traitor bundle" diff --git a/html/changelogs/AutoChangeLog-pr-9267.yml b/html/changelogs/AutoChangeLog-pr-9267.yml new file mode 100644 index 0000000000..a894c0d468 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9267.yml @@ -0,0 +1,4 @@ +author: "Tupinambis" +delete-after: True +changes: + - balance: "Engivend RCDs now vend upgraded RCDs" diff --git a/html/changelogs/AutoChangeLog-pr-9269.yml b/html/changelogs/AutoChangeLog-pr-9269.yml new file mode 100644 index 0000000000..693588208e --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9269.yml @@ -0,0 +1,5 @@ +author: "Fermis" +delete-after: True +changes: + - tweak: "re-enables femichem explosions in grenades." + - tweak: "adds nuance to the SDGF and hatmium explosions." diff --git a/html/changelogs/AutoChangeLog-pr-9275.yml b/html/changelogs/AutoChangeLog-pr-9275.yml new file mode 100644 index 0000000000..cd74273366 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9275.yml @@ -0,0 +1,5 @@ +author: "Fermis" +delete-after: True +changes: + - bugfix: "Fixes analyse function on ChemMasters to correctly display purity." + - bugfix: "Fixes the custom transfer for buffer to beaker button." diff --git a/html/changelogs/AutoChangeLog-pr-9276.yml b/html/changelogs/AutoChangeLog-pr-9276.yml new file mode 100644 index 0000000000..f778c26c13 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9276.yml @@ -0,0 +1,6 @@ +author: "Trilbyspaceclone" +delete-after: True +changes: + - rscadd: "trash" + - imageadd: "eye bleed +:add: misstakes" diff --git a/html/changelogs/AutoChangeLog-pr-9277.yml b/html/changelogs/AutoChangeLog-pr-9277.yml new file mode 100644 index 0000000000..4bf92cd32e --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9277.yml @@ -0,0 +1,11 @@ +author: "Poojawa" +delete-after: True +changes: + - rscadd: "Added new wings to Insects and separated fluff from old ones, they're Insect's new body markings now without being per-limb (for now)." + - rscadd: "Horns are now available to mammals, and they have their own color." + - rscadd: "Legs are no longer a binary hack code, but actually something that can be changed. Framework for tauric adaptations." + - rscdel: "Purged Modular Citadel's sprite_accessories." + - bugfix: "improved the quality of a number of sprites." + - tweak: "Moths are now all insects. Avians and Aquatics are all anthromorphics. Just as planned." + - rscadd: "Anthromorphs can choose their preferred gibbing meat. I guess. Snowflakes are weird." + - bugfix: "Additional Gentlemen names." diff --git a/html/changelogs/AutoChangeLog-pr-9278.yml b/html/changelogs/AutoChangeLog-pr-9278.yml new file mode 100644 index 0000000000..3ec1eb839a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9278.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - bugfix: "Spamming forged packets no longer crashes the server." diff --git a/html/changelogs/AutoChangeLog-pr-9279.yml b/html/changelogs/AutoChangeLog-pr-9279.yml new file mode 100644 index 0000000000..572f40e643 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9279.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "Fixed undergarments color preferences resetting each round." diff --git a/html/changelogs/AutoChangeLog-pr-9282.yml b/html/changelogs/AutoChangeLog-pr-9282.yml new file mode 100644 index 0000000000..5a27defb41 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9282.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "Fixed a few dozen suits' body coverage inconsistencies. These changes shouldn't affect armor and utility vests for most." diff --git a/html/changelogs/AutoChangeLog-pr-9283.yml b/html/changelogs/AutoChangeLog-pr-9283.yml new file mode 100644 index 0000000000..33e02f8539 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9283.yml @@ -0,0 +1,4 @@ +author: "Trilbyspaceclone" +delete-after: True +changes: + - rscdel: "Removed old things!" diff --git a/html/changelogs/AutoChangeLog-pr-9287.yml b/html/changelogs/AutoChangeLog-pr-9287.yml new file mode 100644 index 0000000000..3bf2844b41 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9287.yml @@ -0,0 +1,4 @@ +author: "Fermis" +delete-after: True +changes: + - rscadd: "Debug option: Generate Wikichems" diff --git a/html/changelogs/AutoChangeLog-pr-9288.yml b/html/changelogs/AutoChangeLog-pr-9288.yml new file mode 100644 index 0000000000..8a684431bf --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9288.yml @@ -0,0 +1,4 @@ +author: "Trilbyspaceclone" +delete-after: True +changes: + - bugfix: "UI memes" diff --git a/html/changelogs/AutoChangeLog-pr-9289.yml b/html/changelogs/AutoChangeLog-pr-9289.yml new file mode 100644 index 0000000000..7abf947bfc --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9289.yml @@ -0,0 +1,4 @@ +author: "Sishen1542" +delete-after: True +changes: + - bugfix: "fixing chems for strained muscles" diff --git a/html/changelogs/AutoChangeLog-pr-9292.yml b/html/changelogs/AutoChangeLog-pr-9292.yml new file mode 100644 index 0000000000..33168f9c43 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9292.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "Fixed clown shoes and work boots." diff --git a/html/changelogs/AutoChangeLog-pr-9293.yml b/html/changelogs/AutoChangeLog-pr-9293.yml new file mode 100644 index 0000000000..a99bf1ab41 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9293.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "Fixed some overlay bug that happens when legcuffed and then handcuffed." diff --git a/html/changelogs/AutoChangeLog-pr-9295.yml b/html/changelogs/AutoChangeLog-pr-9295.yml new file mode 100644 index 0000000000..a96540c11b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9295.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - balance: "Slowed down police baton and tele baton speed by 75%, should be still be faster than the legacy speed (2 seconds) by 0.6 seconds. Telescopic batons' stamina cost per swing is now on par with police batons, ergo more expensive." diff --git a/html/changelogs/AutoChangeLog-pr-9296.yml b/html/changelogs/AutoChangeLog-pr-9296.yml new file mode 100644 index 0000000000..101ec1aaa8 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9296.yml @@ -0,0 +1,9 @@ +author: "EmeraldSundisk" +delete-after: True +changes: + - rscadd: "Increases the number of plots to 9 (from 5)" + - rscadd: "Additional lighting placed directly outside the garden" + - tweak: "Cleans up the area to reflect use. Moves the seed extractor to a more central location" + - tweak: "Relocates the seed packs on botany's counter to the garden +removal: Removes wooden barricades outside the garden" + - config: "Renames \"Abandoned Garden\" area designation to \"Maintenance Garden\", but does not replace the icon in Dream Maker" diff --git a/html/changelogs/AutoChangeLog-pr-9298.yml b/html/changelogs/AutoChangeLog-pr-9298.yml new file mode 100644 index 0000000000..8301acbbd6 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9298.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "Fixed undershirts n socks colors prefs." diff --git a/html/changelogs/AutoChangeLog-pr-9302.yml b/html/changelogs/AutoChangeLog-pr-9302.yml new file mode 100644 index 0000000000..4f6ed4d336 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9302.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - bugfix: "Things that access job_preferences now explicitly access keys, which means it no longer attempts to access invalid indices and runtimes as a result." diff --git a/html/changelogs/AutoChangeLog-pr-9304.yml b/html/changelogs/AutoChangeLog-pr-9304.yml new file mode 100644 index 0000000000..f4a919c52f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9304.yml @@ -0,0 +1,4 @@ +author: "Trilbyspaceclone" +delete-after: True +changes: + - rscadd: "Blue space blood bag" diff --git a/html/changelogs/AutoChangeLog-pr-9306.yml b/html/changelogs/AutoChangeLog-pr-9306.yml new file mode 100644 index 0000000000..0a560c8090 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9306.yml @@ -0,0 +1,5 @@ +author: "kappa-sama" +delete-after: True +changes: + - tweak: "voidcells can now unlock alien tech" + - balance: "rebalanced tech trees (not really)" diff --git a/html/changelogs/AutoChangeLog-pr-9307.yml b/html/changelogs/AutoChangeLog-pr-9307.yml new file mode 100644 index 0000000000..de787a4274 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9307.yml @@ -0,0 +1,4 @@ +author: "BurgerLUA" +delete-after: True +changes: + - balance: "Rebalanced special jetpacks." diff --git a/html/changelogs/AutoChangeLog-pr-9309.yml b/html/changelogs/AutoChangeLog-pr-9309.yml new file mode 100644 index 0000000000..b3aef0372b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9309.yml @@ -0,0 +1,6 @@ +author: "Fermis" +delete-after: True +changes: + - rscadd: "graft synthtissue surgery, new reagent synthtissue" + - tweak: "neurine fixes brain objs +merge: combines fermichem's lung damage with tg's" diff --git a/html/changelogs/AutoChangeLog-pr-9310.yml b/html/changelogs/AutoChangeLog-pr-9310.yml new file mode 100644 index 0000000000..34ded5a0db --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9310.yml @@ -0,0 +1,4 @@ +author: "GrayRachnid" +delete-after: True +changes: + - rscadd: "Added windoors to all the flaps on delta." diff --git a/html/changelogs/AutoChangeLog-pr-9312.yml b/html/changelogs/AutoChangeLog-pr-9312.yml new file mode 100644 index 0000000000..487b79393b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9312.yml @@ -0,0 +1,9 @@ +author: "XDTM" +delete-after: True +changes: + - rscadd: "Added the experimental dissection surgery, which can be performed once per corpse to gain techweb points." + - rscadd: "Rarer specimens are more valuable, so xenos and rare species are more efficient subjects." + - rscadd: "Added two new surgery procedures, under the Experimental Surgery techweb node." + - rscadd: "Ligament Hook makes it so you can attach limbs manually (like skeletons) but makes dismemberment more likely as well." + - rscadd: "Ligament Reinforcement prevents dismemberment, but makes limbs easier to disable through damage." + - tweak: "Golem limbs can now be disabled, although they are still undismemberable." diff --git a/html/changelogs/AutoChangeLog-pr-9314.yml b/html/changelogs/AutoChangeLog-pr-9314.yml new file mode 100644 index 0000000000..317fb48592 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9314.yml @@ -0,0 +1,4 @@ +author: "Trilbyspaceclone" +delete-after: True +changes: + - tweak: "blood costs" diff --git a/html/changelogs/AutoChangeLog-pr-9316.yml b/html/changelogs/AutoChangeLog-pr-9316.yml new file mode 100644 index 0000000000..f4074bcee8 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9316.yml @@ -0,0 +1,5 @@ +author: "Fermis" +delete-after: True +changes: + - rscadd: "on_mob_dead(), bitflags and CHECK_MULTIPLE_BITFIELDS" + - refactor: "refactored fermichem vars, moved impure chems into their own reagents subtype" diff --git a/html/changelogs/AutoChangeLog-pr-9317.yml b/html/changelogs/AutoChangeLog-pr-9317.yml new file mode 100644 index 0000000000..11d58e79ce --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9317.yml @@ -0,0 +1,7 @@ +author: "Ghommie (original PR by CrazyClown12)" +delete-after: True +changes: + - tweak: "The chloral hydrate inside of the sleepy pen is no longer slower acting than chloral hydrate made in chemistry." + - tweak: "The chloral hydrate inside of cookies synthesised by emagged borgs is no longer slower acting than chloral hydrate made in chemistry." + - balance: "Slight tirizene buff." + - rscdel: "Delayed chloral hydrate" diff --git a/html/changelogs/AutoChangeLog-pr-9318.yml b/html/changelogs/AutoChangeLog-pr-9318.yml new file mode 100644 index 0000000000..5f7f4af654 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9318.yml @@ -0,0 +1,4 @@ +author: "Fermis" +delete-after: True +changes: + - bugfix: "Fixes small residues of chems that won't go away!" diff --git a/html/changelogs/AutoChangeLog-pr-9320.yml b/html/changelogs/AutoChangeLog-pr-9320.yml new file mode 100644 index 0000000000..605de17ab2 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9320.yml @@ -0,0 +1,5 @@ +author: "Ghommie (original PR by harmonyn)" +delete-after: True +changes: + - balance: "Resisting out of bucklecuffs takes more/less time depending on the handcuffs you used, i.e., fake handcuffs will not bucklecuff someone for ages." + - tweak: "fake handcuffs shouldn't no longer demoralize restrained criminals scums." diff --git a/html/changelogs/AutoChangeLog-pr-9321.yml b/html/changelogs/AutoChangeLog-pr-9321.yml new file mode 100644 index 0000000000..d0c4f6d18d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9321.yml @@ -0,0 +1,6 @@ +author: "Linzolle" +delete-after: True +changes: + - bugfix: "blood halberd not going back to 17 force after unwielding" + - spellcheck: "unnecessary 's at the end of blood rites healing" + - rscadd: "QoL to blood rites, examine the ritual aura to view how many blood charges are left" diff --git a/html/changelogs/AutoChangeLog-pr-9322.yml b/html/changelogs/AutoChangeLog-pr-9322.yml new file mode 100644 index 0000000000..2d2632bb81 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9322.yml @@ -0,0 +1,4 @@ +author: "Sishen1542" +delete-after: True +changes: + - bugfix: "narsie no longer asks for consent" diff --git a/html/changelogs/AutoChangeLog-pr-9324.yml b/html/changelogs/AutoChangeLog-pr-9324.yml new file mode 100644 index 0000000000..39879be110 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9324.yml @@ -0,0 +1,5 @@ +author: "TerraGS / Skoglol" +delete-after: True +changes: + - rscadd: "Adds toggleable light and blinking charge indicator to kinetic crusher" + - rscadd: "Kinetic crusher can now be one-hand carried. You'll still need two hand to use it." diff --git a/html/changelogs/AutoChangeLog-pr-9326.yml b/html/changelogs/AutoChangeLog-pr-9326.yml new file mode 100644 index 0000000000..582230dedb --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9326.yml @@ -0,0 +1,4 @@ +author: "YakumoChen" +delete-after: True +changes: + - tweak: "AEGs brought more in line with current radiation system. Try not to get EMP'd." diff --git a/html/changelogs/AutoChangeLog-pr-9331.yml b/html/changelogs/AutoChangeLog-pr-9331.yml new file mode 100644 index 0000000000..0ecd5dfad7 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9331.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "You can now alt-click to rotate machinery such as the tachyon-droppler array or emitters again." diff --git a/html/changelogs/AutoChangeLog-pr-9332.yml b/html/changelogs/AutoChangeLog-pr-9332.yml new file mode 100644 index 0000000000..e8a2aa1faa --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9332.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "Sofas can't be wielded and transformed back into plain chairs anymore." diff --git a/html/changelogs/AutoChangeLog-pr-9334.yml b/html/changelogs/AutoChangeLog-pr-9334.yml new file mode 100644 index 0000000000..cc31ec8896 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9334.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - rscadd: "Enables emojis for PDA messages." diff --git a/html/changelogs/AutoChangeLog-pr-9335.yml b/html/changelogs/AutoChangeLog-pr-9335.yml new file mode 100644 index 0000000000..b36c0957dd --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9335.yml @@ -0,0 +1,6 @@ +author: "Raptorizer" +delete-after: True +changes: + - tweak: "tweaked numbers/variables" + - balance: "rebalanced numbers/variables" + - spellcheck: "removed unneeded code" diff --git a/html/changelogs/AutoChangeLog-pr-9336.yml b/html/changelogs/AutoChangeLog-pr-9336.yml new file mode 100644 index 0000000000..3f86da234e --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9336.yml @@ -0,0 +1,8 @@ +author: "Fermis" +delete-after: True +changes: + - tweak: "tweaked beaker health and allows use of syringes/droppers on chem_heaters" + - soundadd: "added a sound for when beakers take temperature damage." + - imageadd: "added some icons for melting beakers" + - refactor: "refactored how beakers take damage" + - bugfix: "fixes how beakers would only take one instance of damage on pH damage" diff --git a/html/changelogs/AutoChangeLog-pr-9338.yml b/html/changelogs/AutoChangeLog-pr-9338.yml new file mode 100644 index 0000000000..e5909f52ae --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9338.yml @@ -0,0 +1,4 @@ +author: "lolman360" +delete-after: True +changes: + - bugfix: "Fixes an undocumented change to the naming of Plasmamen." diff --git a/html/changelogs/AutoChangeLog-pr-9339.yml b/html/changelogs/AutoChangeLog-pr-9339.yml new file mode 100644 index 0000000000..eeb5ae632c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9339.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - balance: "Removes revenant blight's shabby toxin damage in favor of mood maluses, and a dangerous necropolis curse if not cured in time. Remember" diff --git a/html/changelogs/AutoChangeLog-pr-9341.yml b/html/changelogs/AutoChangeLog-pr-9341.yml new file mode 100644 index 0000000000..e017f2941e --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9341.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - tweak: "Blood cult altar, forge and archives now use radial menus." diff --git a/html/changelogs/AutoChangeLog-pr-9342.yml b/html/changelogs/AutoChangeLog-pr-9342.yml new file mode 100644 index 0000000000..75d441f143 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9342.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "Fixed some machineries' UIs." diff --git a/html/changelogs/AutoChangeLog-pr-9343.yml b/html/changelogs/AutoChangeLog-pr-9343.yml new file mode 100644 index 0000000000..04eb1995ef --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9343.yml @@ -0,0 +1,9 @@ +author: "Linzolle" +delete-after: True +changes: + - code_imp: "surgery cleanup" + - tweak: "dissection available round-start" + - rscadd: "better dissection surgeries from RnD, gives more points" + - rscadd: "abductors can now see what glands do" + - code_imp: "antagonist abductors now have a surgeon trait that teaches them every surgery rather than having it just check if they're an abductor" + - rscadd: "muscled veins surgery" diff --git a/html/changelogs/AutoChangeLog-pr-9344.yml b/html/changelogs/AutoChangeLog-pr-9344.yml new file mode 100644 index 0000000000..c45c9269b6 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9344.yml @@ -0,0 +1,6 @@ +author: "Ghommie (original PRs by Time-Green and Qustinnus)" +delete-after: True +changes: + - tweak: "loot crates can't explode after unlocking anymore" + - bugfix: "jumping into loot crates no longers causes them to go boom" + - bugfix: "You can now deconstruct abandoned crates with a welder without making them go boom. After unlocking them, of course." diff --git a/html/changelogs/AutoChangeLog-pr-9348.yml b/html/changelogs/AutoChangeLog-pr-9348.yml new file mode 100644 index 0000000000..a58556b992 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9348.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - tweak: "blood and clock cultists messages from metabolizing" diff --git a/html/changelogs/AutoChangeLog-pr-9349.yml b/html/changelogs/AutoChangeLog-pr-9349.yml new file mode 100644 index 0000000000..e51b826f01 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9349.yml @@ -0,0 +1,5 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "Fixed advanced medical scanners borg upgrades." + - bugfix: "Fixes certain borg upgrades being unapplicable on dogborg counterparts of the target cyborg type." diff --git a/html/changelogs/AutoChangeLog-pr-9351.yml b/html/changelogs/AutoChangeLog-pr-9351.yml new file mode 100644 index 0000000000..d235985d0e --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9351.yml @@ -0,0 +1,4 @@ +author: "Yakumo Chen" +delete-after: True +changes: + - balance: "removed antimagic component from holymelon" diff --git a/html/changelogs/AutoChangeLog-pr-9352.yml b/html/changelogs/AutoChangeLog-pr-9352.yml new file mode 100644 index 0000000000..e34277b531 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9352.yml @@ -0,0 +1,4 @@ +author: "JTGSZ" +delete-after: True +changes: + - tweak: "Gave Qualifies_for_Rank Check back its checks in job controller." diff --git a/html/changelogs/AutoChangeLog-pr-9356.yml b/html/changelogs/AutoChangeLog-pr-9356.yml new file mode 100644 index 0000000000..65aacda077 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9356.yml @@ -0,0 +1,9 @@ +author: "EmeraldSundisk" +delete-after: True +changes: + - rscadd: "Expands the chapel mass driver room to make it easier to use" + - rscadd: "Rearranges the chapel backroom so there are now six coffins and burial garments roundstart" + - tweak: "Cleans up the Janitor's office" + - tweak: "Readjusts the station exterior so mass-driven coffins (hopefully) have less friction" + - bugfix: "Adds a fan to the chapel driver" + - bugfix: "The Janitor missed a few spots around the newly renovated Maintenance Garden" diff --git a/html/changelogs/AutoChangeLog-pr-9359.yml b/html/changelogs/AutoChangeLog-pr-9359.yml new file mode 100644 index 0000000000..1eb933e4c5 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9359.yml @@ -0,0 +1,6 @@ +author: "Bhijn" +delete-after: True +changes: + - balance: "The point production mode of radiation collectors has been reverted to the original behavior of using all of the stored power every process cycle instead of just 4% of it" + - tweak: "Radiation collectors now display the amount of power/research points they're producing per minute rather than per process cycle, which should hopefully clear up a lot of confusion." + - tweak: "Radiation collectors also display what's happening to the gas within them, which should make it a lot more obvious as to how you get tritium." diff --git a/html/changelogs/AutoChangeLog-pr-9365.yml b/html/changelogs/AutoChangeLog-pr-9365.yml new file mode 100644 index 0000000000..1a0543f28e --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9365.yml @@ -0,0 +1,7 @@ +author: "Ghommie (original PR by 81Denton, kriskog and nemvar)" +delete-after: True +changes: + - spellcheck: "Sleepers now show a message if players try to unscrew the maintenance hatch while they're occupied or open. Fixed typos in sleeper/organ harvester messages." + - tweak: "Sleepers and dna scanners can now be pried open with crowbars." + - tweak: "You can open and close sleepers and dna scanners by alt-clicking them." + - bugfix: "The scanner's hatch now must be closed (on top of being unoccupied), just like sleepers, before being screwdriverable. This fixes a tricky door stuck issue with the machine." diff --git a/html/changelogs/AutoChangeLog-pr-9367.yml b/html/changelogs/AutoChangeLog-pr-9367.yml new file mode 100644 index 0000000000..f875262781 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9367.yml @@ -0,0 +1,6 @@ +author: "Poojawa" +delete-after: True +changes: + - rscadd: "Medical huds are now calibrated for Radioactive wavelengths." + - balance: "Engineering equipment, blue space, and common storage containers are radiation protected" + - bugfix: "fixed suit storage not cleaning radiation levels of everything stuffed into them." diff --git a/html/changelogs/AutoChangeLog-pr-9368.yml b/html/changelogs/AutoChangeLog-pr-9368.yml new file mode 100644 index 0000000000..9d95e6c62b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9368.yml @@ -0,0 +1,6 @@ +author: "Seris02" +delete-after: True +changes: + - tweak: "made the autoprocess button relevant" + - tweak: "changes so that spooktober starts earlier" + - bugfix: "fixed the dark blue lum major effect" diff --git a/html/changelogs/AutoChangeLog-pr-9373.yml b/html/changelogs/AutoChangeLog-pr-9373.yml new file mode 100644 index 0000000000..0dc7d7a85f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9373.yml @@ -0,0 +1,4 @@ +author: "Trilbyspaceclone" +delete-after: True +changes: + - rscadd: "Beebal and Honeybalm plants" diff --git a/html/changelogs/AutoChangeLog-pr-9374.yml b/html/changelogs/AutoChangeLog-pr-9374.yml new file mode 100644 index 0000000000..f43f28118b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9374.yml @@ -0,0 +1,5 @@ +author: "kappa-sama" +delete-after: True +changes: + - rscadd: "hugbox (/s)" + - tweak: "ashwalker spawn text now tells them \"i\" \"c\" not to leave lavaland" diff --git a/html/changelogs/AutoChangeLog-pr-9377.yml b/html/changelogs/AutoChangeLog-pr-9377.yml new file mode 100644 index 0000000000..26587eb6c6 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9377.yml @@ -0,0 +1,4 @@ +author: "Fermis" +delete-after: True +changes: + - bugfix: "fixes Janitor grenades." diff --git a/html/changelogs/AutoChangeLog-pr-9379.yml b/html/changelogs/AutoChangeLog-pr-9379.yml new file mode 100644 index 0000000000..05301d3f72 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9379.yml @@ -0,0 +1,4 @@ +author: "Chayse" +delete-after: True +changes: + - tweak: "Medbay doors can now be opened by anyone from the inside without having to press the exit button." diff --git a/html/changelogs/AutoChangeLog-pr-9380.yml b/html/changelogs/AutoChangeLog-pr-9380.yml new file mode 100644 index 0000000000..0d42ef7276 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9380.yml @@ -0,0 +1,6 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "Fixed people being shovable hrough windows, windoors and the such." + - rscadd: "You can now shove people into disposal bins." + - refactor: "refactored altdisarm(), ergo the \"shoving people around\" proc." diff --git a/html/changelogs/AutoChangeLog-pr-9382.yml b/html/changelogs/AutoChangeLog-pr-9382.yml new file mode 100644 index 0000000000..c82a6a4309 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9382.yml @@ -0,0 +1,4 @@ +author: "Chayse" +delete-after: True +changes: + - bugfix: "Borgs now have the necessary dexterity to unbuckle people from themselves and from bucklable objects." diff --git a/html/changelogs/AutoChangeLog-pr-9384.yml b/html/changelogs/AutoChangeLog-pr-9384.yml new file mode 100644 index 0000000000..a941371f1c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9384.yml @@ -0,0 +1,4 @@ +author: "Chayse" +delete-after: True +changes: + - bugfix: "Fixes the Trek Uniform/Suit worn icons" diff --git a/html/changelogs/AutoChangeLog-pr-9385.yml b/html/changelogs/AutoChangeLog-pr-9385.yml new file mode 100644 index 0000000000..36c0f7c105 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9385.yml @@ -0,0 +1,4 @@ +author: "Sishen1542" +delete-after: True +changes: + - bugfix: "removed reflect from divine lightblade" diff --git a/html/changelogs/AutoChangeLog-pr-9386.yml b/html/changelogs/AutoChangeLog-pr-9386.yml new file mode 100644 index 0000000000..8426b0be7c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9386.yml @@ -0,0 +1,4 @@ +author: "original by Bumtickley00, port by sishen1542" +delete-after: True +changes: + - tweak: "Suit storage units will now also remove radiation from mobs." diff --git a/html/changelogs/AutoChangeLog-pr-9387.yml b/html/changelogs/AutoChangeLog-pr-9387.yml new file mode 100644 index 0000000000..6fa03cd817 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9387.yml @@ -0,0 +1,4 @@ +author: "original by: WJohnston, Antur, Arcane, plapatin, sprites by cogwerks and edited by mrdoombringer. port by sishen1542" +delete-after: True +changes: + - rscadd: "THE GOOSE IS LOOSE" diff --git a/html/changelogs/AutoChangeLog-pr-9388.yml b/html/changelogs/AutoChangeLog-pr-9388.yml new file mode 100644 index 0000000000..9c42745219 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9388.yml @@ -0,0 +1,4 @@ +author: "original by Skoglol, port by sishen1542" +delete-after: True +changes: + - admin: "Dynamic gamemode now more auto-deadmin friendly." diff --git a/html/changelogs/AutoChangeLog-pr-9389.yml b/html/changelogs/AutoChangeLog-pr-9389.yml new file mode 100644 index 0000000000..4ed6439d5b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9389.yml @@ -0,0 +1,4 @@ +author: "Weblure" +delete-after: True +changes: + - rscadd: "Added the relevant Beepsky animations from TG's aibots.dmi file to Cit's aibots.dmi file." diff --git a/html/changelogs/AutoChangeLog-pr-9391.yml b/html/changelogs/AutoChangeLog-pr-9391.yml new file mode 100644 index 0000000000..1b4525f717 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9391.yml @@ -0,0 +1,4 @@ +author: "GrayRachnid" +delete-after: True +changes: + - balance: "rebalanced k9dogborgs" diff --git a/html/changelogs/AutoChangeLog-pr-9393.yml b/html/changelogs/AutoChangeLog-pr-9393.yml new file mode 100644 index 0000000000..ef03eb483f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9393.yml @@ -0,0 +1,4 @@ +author: "Chayse" +delete-after: True +changes: + - bugfix: "AIs can now once more talk through holopads successfully" diff --git a/html/changelogs/AutoChangeLog-pr-9394.yml b/html/changelogs/AutoChangeLog-pr-9394.yml new file mode 100644 index 0000000000..2c1c89877b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9394.yml @@ -0,0 +1,5 @@ +author: "EmeraldSundisk" +delete-after: True +changes: + - bugfix: "Readjusts positioning of Delta's QM keycard device" + - bugfix: "Cleaned up a few spots I missed in #9356, particularly around the janitor's office" diff --git a/html/changelogs/AutoChangeLog-pr-9401.yml b/html/changelogs/AutoChangeLog-pr-9401.yml new file mode 100644 index 0000000000..ba40c9af65 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9401.yml @@ -0,0 +1,4 @@ +author: "actioninja" +delete-after: True +changes: + - bugfix: "APC UI autoupdates correctly" diff --git a/html/changelogs/AutoChangeLog-pr-9404.yml b/html/changelogs/AutoChangeLog-pr-9404.yml new file mode 100644 index 0000000000..635b2f8aaf --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9404.yml @@ -0,0 +1,4 @@ +author: "Poojawa" +delete-after: True +changes: + - bugfix: "QM is able to hire/fire people to their department now." diff --git a/html/changelogs/AutoChangeLog-pr-9405.yml b/html/changelogs/AutoChangeLog-pr-9405.yml new file mode 100644 index 0000000000..ee4bce83bd --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9405.yml @@ -0,0 +1,5 @@ +author: "Thalpy" +delete-after: True +changes: + - tweak: "Alkaline buffer recipe so people don't get grumpy and expanded the pH range" + - bugfix: "fixes buffers" diff --git a/html/changelogs/AutoChangeLog-pr-9406.yml b/html/changelogs/AutoChangeLog-pr-9406.yml new file mode 100644 index 0000000000..bf4048528d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9406.yml @@ -0,0 +1,6 @@ +author: "Twaticus & Poojawa" +delete-after: True +changes: + - rscadd: "Added new carpets from TauCetiStation!" + - rscadd: "More Liquid carpet chemicals, mix carpet with certain reagents to get different colors!" + - refactor: "Tablets have a better means of being assembled codewise. nothing's different on player end." diff --git a/html/changelogs/AutoChangeLog-pr-9407.yml b/html/changelogs/AutoChangeLog-pr-9407.yml new file mode 100644 index 0000000000..dbfadaebb7 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9407.yml @@ -0,0 +1,4 @@ +author: "AdmiralPancakes1" +delete-after: True +changes: + - rscadd: "Cryo cell shortcuts: alt-click toggles the doors, ctrl-click toggles the power" diff --git a/html/changelogs/AutoChangeLog-pr-9410.yml b/html/changelogs/AutoChangeLog-pr-9410.yml new file mode 100644 index 0000000000..910b9f6f2e --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9410.yml @@ -0,0 +1,5 @@ +author: "Poojawa" +delete-after: True +changes: + - bugfix: "cryopod UI isn't complete shit anymore" + - bugfix: "Cryopods purge silicon gear more efficiently now. Same with ghosts." diff --git a/html/changelogs/AutoChangeLog-pr-9412.yml b/html/changelogs/AutoChangeLog-pr-9412.yml new file mode 100644 index 0000000000..3ea4bbdb46 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9412.yml @@ -0,0 +1,4 @@ +author: "Ghommie (original PR by AnturK)" +delete-after: True +changes: + - bugfix: "Supermatter now melt walls if it finds itself in one." diff --git a/html/changelogs/AutoChangeLog-pr-9413.yml b/html/changelogs/AutoChangeLog-pr-9413.yml new file mode 100644 index 0000000000..b352549d0b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9413.yml @@ -0,0 +1,4 @@ +author: "Poojawa" +delete-after: True +changes: + - balance: "Med Sprays are now more aligned with patch mechanics" diff --git a/html/changelogs/AutoChangeLog-pr-9414.yml b/html/changelogs/AutoChangeLog-pr-9414.yml new file mode 100644 index 0000000000..e5b03cd5fa --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9414.yml @@ -0,0 +1,4 @@ +author: "Poojawa" +delete-after: True +changes: + - balance: "Chemistry is encouraged to be more varied in their healing, as well as careful in its application" diff --git a/html/changelogs/AutoChangeLog-pr-9415.yml b/html/changelogs/AutoChangeLog-pr-9415.yml new file mode 100644 index 0000000000..19d407b03e --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9415.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - tweak: "war ops is now lowpop friendly and doesn't require roughly 54 starting players anymore." diff --git a/html/changelogs/AutoChangeLog-pr-9416.yml b/html/changelogs/AutoChangeLog-pr-9416.yml new file mode 100644 index 0000000000..cf36873498 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9416.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - rscadd: "Singularity beacons now also moderately increases the odds meteor waves, while lowering their estimeed arrival countdown." diff --git a/html/changelogs/AutoChangeLog-pr-9418.yml b/html/changelogs/AutoChangeLog-pr-9418.yml new file mode 100644 index 0000000000..9950590005 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9418.yml @@ -0,0 +1,19 @@ +author: "Ghommie (original PRs by zeroisthebiggay, AnturK, MrDoomBringer, Cobby, ATHATH, optimumtact, GranpaWalton, Skoglol)" +delete-after: True +changes: + - bugfix: "Blob overminds, sentient diseases, etc. can no longer dump out boxes. Sorry gamers." + - rscadd: "Sentient Disease now has almost all symptoms at its disposal." + - code_imp: "Adding single-symptom disease abilities is super easy now." + - bugfix: "Sentient Disease can now hear (not sure if this was a bug or intentional)." + - rscadd: "Sentient Disease is a linguist and knows all languages. Still cannot speak." + - tweak: "Gives Sentient Diseases a medical hud to observe their victims further with." + - bugfix: "Fixes and moves around some on_stage_change() and Start()-related things for virus symptoms and (sentient) diseases." + - bugfix: "The inorganic biology symptom should work properly now when bought by a sentient disease." + - bugfix: "Oxyloss icon no-longer shows up when someone has the self respiration symptom" + - tweak: "The self respiration now makes you not contract diseases through the air and not breathe in smoke" + - bugfix: "Sentient diseases can no longer pick two cures that react and disappear when eaten." + - balance: "Sentient disease cures are now consistently harder, will only pick cures from tier 6 and up." + - bugfix: "Disease cures should now stay the same for all infected mobs." + - rscadd: "The regenerative coma symptom has a new resistance 4 threshold effect! Said threshold effect will give hosts of the symptom's virus the TRAIT_STABLECRIT trait if its threshold is met." + - bugfix: "An obscure, probably never reported before bug that may or may not exist involving sentient diseases and the self-respiration symptom should be fixed now (if it even existed in the first place)." + - balance: "The cooldown time between each removal or addition of a symptom for sentient diseases has been brought down from an agonizingly long 2 minutes to a more reasonable 1 minute." diff --git a/html/changelogs/AutoChangeLog-pr-9421.yml b/html/changelogs/AutoChangeLog-pr-9421.yml new file mode 100644 index 0000000000..8b2e8a3982 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9421.yml @@ -0,0 +1,6 @@ +author: "Ghommie (original PRs by Akrilla, Arkatos and Denton)" +delete-after: True +changes: + - tweak: "Sprays cans have a cap on how dark you can make objects. Art is uneffected." + - bugfix: "Fixed a bug where you could get cyborg spraycans via pyrite extracts." + - rscadd: "Added an infinite spraycan for admins to spawn." diff --git a/html/changelogs/AutoChangeLog-pr-9427.yml b/html/changelogs/AutoChangeLog-pr-9427.yml new file mode 100644 index 0000000000..bb1665fba5 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9427.yml @@ -0,0 +1,7 @@ +author: "Ghommie && Kevinz000" +delete-after: True +changes: + - balance: "Lichdom and necromantic stone skeletons are now of the spaceproof kind too." + - tweak: "skeletons now also like dairy products." + - rscdel: "Halloween roundstart skeletons and zombies are no more spaceproof." + - rscadd: "You can choose to set your species to zombie or skeleton through the pride mirror yet again, Alas they are not of the spaceproof kind either." diff --git a/html/changelogs/AutoChangeLog-pr-9431.yml b/html/changelogs/AutoChangeLog-pr-9431.yml new file mode 100644 index 0000000000..65f825b278 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9431.yml @@ -0,0 +1,4 @@ +author: "Ghommie (original PR by Denton)" +delete-after: True +changes: + - balance: "You can no longer reveal the 'illegal tech' research node by deconstructing .357 speedloaders, riot dart boxes, syndicate cigarettes, syndicate playing cards or syndicate balloons." diff --git a/html/changelogs/AutoChangeLog-pr-9432.yml b/html/changelogs/AutoChangeLog-pr-9432.yml new file mode 100644 index 0000000000..a0cf63d8ee --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9432.yml @@ -0,0 +1,6 @@ +author: "Putnam3145" +delete-after: True +changes: + - tweak: "Bottles in PanD.E.M.I.C 2200 can now be replaced with an inhand bottle directly" + - tweak: "Ejecting a bottle from the PanD.E.M.I.C 2200 puts it directly into the user's hand" + - tweak: "Alt-clicking the PanD.E.M.I.C 2200 ejects the current bottle" diff --git a/html/changelogs/AutoChangeLog-pr-9434.yml b/html/changelogs/AutoChangeLog-pr-9434.yml new file mode 100644 index 0000000000..d6ad25361a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9434.yml @@ -0,0 +1,5 @@ +author: "EmeraldSundisk" +delete-after: True +changes: + - rscadd: "Adds some potted plants around Box Station" + - bugfix: "The tile mentioned in #9409 should now be radiation-free." diff --git a/html/changelogs/AutoChangeLog-pr-9435.yml b/html/changelogs/AutoChangeLog-pr-9435.yml new file mode 100644 index 0000000000..4c7a2ab1a1 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9435.yml @@ -0,0 +1,4 @@ +author: "Linzolle" +delete-after: True +changes: + - bugfix: "having one of your hands used up if you fireman carry but the person being carried dismounts any way other than you dropping them" diff --git a/html/changelogs/AutoChangeLog-pr-9437.yml b/html/changelogs/AutoChangeLog-pr-9437.yml new file mode 100644 index 0000000000..262fd2a86e --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9437.yml @@ -0,0 +1,4 @@ +author: "JTGSZ" +delete-after: True +changes: + - rscadd: "Optional species based clothing restrictions" diff --git a/html/changelogs/AutoChangeLog-pr-9439.yml b/html/changelogs/AutoChangeLog-pr-9439.yml new file mode 100644 index 0000000000..e72b3bd25d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9439.yml @@ -0,0 +1,5 @@ +author: "JTGSZ" +delete-after: True +changes: + - tweak: "Gang Dominator excessive wall check tweaked to 25 open turfs" + - bugfix: "Gang Dominator no longer functions off-station." diff --git a/html/changelogs/AutoChangeLog-pr-9441.yml b/html/changelogs/AutoChangeLog-pr-9441.yml new file mode 100644 index 0000000000..a1321fb3a3 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9441.yml @@ -0,0 +1,6 @@ +author: "lolman360" +delete-after: True +changes: + - tweak: "chainsaw kind of weapons and the mecha drill and the CLAMP can now be used with 100% accuracy for surgery" + - refactor: "surgery tools now work on defines" + - balance: "advanced surgerytools can now switch types instead of just being faster" diff --git a/html/changelogs/AutoChangeLog-pr-9442.yml b/html/changelogs/AutoChangeLog-pr-9442.yml new file mode 100644 index 0000000000..1cde8b15f4 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9442.yml @@ -0,0 +1,4 @@ +author: "YakumoChen" +delete-after: True +changes: + - tweak: "Jetpacks no longer last twice as long between air refills." diff --git a/html/changelogs/AutoChangeLog-pr-9443.yml b/html/changelogs/AutoChangeLog-pr-9443.yml new file mode 100644 index 0000000000..6bc7507ea9 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9443.yml @@ -0,0 +1,4 @@ +author: "Thalpy" +delete-after: True +changes: + - bugfix: "fixes broken compiler because a var changed name" diff --git a/html/changelogs/AutoChangeLog-pr-9444.yml b/html/changelogs/AutoChangeLog-pr-9444.yml new file mode 100644 index 0000000000..0a317feda1 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9444.yml @@ -0,0 +1,8 @@ +author: "Fermis" +delete-after: True +changes: + - bugfix: "fixes reaction mechanics at low volumes" + - bugfix: "stops reactions constantly bubbling on the edge of reaction temperature" + - bugfix: "stops small amount reactions from occurring, and prevents disappearing tiny numbers" + - tweak: "Reduced minimum reaction volume from 1 to 0.01" + - refactor: "cleaned up Fermichem" diff --git a/html/changelogs/AutoChangeLog-pr-9445.yml b/html/changelogs/AutoChangeLog-pr-9445.yml new file mode 100644 index 0000000000..0d479fa63a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9445.yml @@ -0,0 +1,4 @@ +author: "Thalpy" +delete-after: True +changes: + - bugfix: "impure travis var anger" diff --git a/html/changelogs/AutoChangeLog-pr-9446.yml b/html/changelogs/AutoChangeLog-pr-9446.yml new file mode 100644 index 0000000000..46c3ffc0ae --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9446.yml @@ -0,0 +1,4 @@ +author: "Sishen1542" +delete-after: True +changes: + - bugfix: "teleporting a locker is bad" diff --git a/html/changelogs/AutoChangeLog-pr-9450.yml b/html/changelogs/AutoChangeLog-pr-9450.yml new file mode 100644 index 0000000000..7616262604 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9450.yml @@ -0,0 +1,4 @@ +author: "JTGSZ" +delete-after: True +changes: + - rscadd: "Adds more control over species based offsets." diff --git a/html/changelogs/AutoChangeLog-pr-9451.yml b/html/changelogs/AutoChangeLog-pr-9451.yml new file mode 100644 index 0000000000..12843efb68 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9451.yml @@ -0,0 +1,4 @@ +author: "Ghommie (original PR by ShizCalev)" +delete-after: True +changes: + - bugfix: "As a non-human mob, hovering your cursor over an inventory slot while holding an object in your active hand shouldn't runtime now." diff --git a/html/changelogs/AutoChangeLog-pr-9452.yml b/html/changelogs/AutoChangeLog-pr-9452.yml new file mode 100644 index 0000000000..638c3249df --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9452.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "non-alphanumeric graffiti decals will no longer display as \"letter\"." diff --git a/html/changelogs/AutoChangeLog-pr-9456.yml b/html/changelogs/AutoChangeLog-pr-9456.yml new file mode 100644 index 0000000000..e4392394b8 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9456.yml @@ -0,0 +1,7 @@ +author: "Fermis" +delete-after: True +changes: + - rscadd: "Adds Jacqueline the Pumpqueen and her familiar Bartholomew for the spooky season" + - soundadd: "Adds a giggle" + - imageadd: "Adds cauldron, Jacq and Jacq o lanterns, and a costume for halloween! +mapedit: adds a new landmark so Bartholomew can spawn somewhere sensible." diff --git a/html/changelogs/AutoChangeLog-pr-9458.yml b/html/changelogs/AutoChangeLog-pr-9458.yml new file mode 100644 index 0000000000..44fc8370d8 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9458.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - balance: "Nerfs cyborg disabler and its internal power cell to hold 25 disabler beam shots rather than 43/44, just like a normal disabler." diff --git a/html/changelogs/AutoChangeLog-pr-9459.yml b/html/changelogs/AutoChangeLog-pr-9459.yml new file mode 100644 index 0000000000..5b4cf5736a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9459.yml @@ -0,0 +1,4 @@ +author: "dapnee" +delete-after: True +changes: + - bugfix: "You can now make plasmaglass tables again." diff --git a/html/changelogs/AutoChangeLog-pr-9461.yml b/html/changelogs/AutoChangeLog-pr-9461.yml new file mode 100644 index 0000000000..91288f23fe --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9461.yml @@ -0,0 +1,4 @@ +author: "r4d6" +delete-after: True +changes: + - rscadd: "Added decoratives angel wings for Mammalians only" diff --git a/html/changelogs/AutoChangeLog-pr-9463.yml b/html/changelogs/AutoChangeLog-pr-9463.yml new file mode 100644 index 0000000000..3a465c5a05 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9463.yml @@ -0,0 +1,6 @@ +author: "Owai-Seek" +delete-after: True +changes: + - rscadd: "false codpiece" + - rscadd: "crocin/camphor bottles" + - tweak: "updated kinkmate item list" diff --git a/html/changelogs/AutoChangeLog-pr-9464.yml b/html/changelogs/AutoChangeLog-pr-9464.yml new file mode 100644 index 0000000000..79a5960abd --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9464.yml @@ -0,0 +1,4 @@ +author: "JTGSZ" +delete-after: True +changes: + - bugfix: "qualifies_for_rank now checks latejoin menu" diff --git a/html/changelogs/AutoChangeLog-pr-9466.yml b/html/changelogs/AutoChangeLog-pr-9466.yml new file mode 100644 index 0000000000..473ec04eec --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9466.yml @@ -0,0 +1,5 @@ +author: "Bhijn" +delete-after: True +changes: + - tweak: "Security borgs and K9s are now only available during red alert or higher." + - server: "Headmins or other folks with access to the server's config can choose the minimum alert level for secborgs to be chosen via the MINIMUM_SECBORG_ALERT config option. See the default game_options.txt for more info." diff --git a/html/changelogs/AutoChangeLog-pr-9467.yml b/html/changelogs/AutoChangeLog-pr-9467.yml new file mode 100644 index 0000000000..b57d60f9dd --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9467.yml @@ -0,0 +1,4 @@ +author: "Bhijn" +delete-after: True +changes: + - bugfix: "The server no longer attempts to check if the CID matches the IP of any bans, or if the IP matches any CIDs of any active bans, during client analyzation" diff --git a/html/changelogs/AutoChangeLog-pr-9472.yml b/html/changelogs/AutoChangeLog-pr-9472.yml new file mode 100644 index 0000000000..dd0aac8954 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9472.yml @@ -0,0 +1,5 @@ +author: "Fermis" +delete-after: True +changes: + - bugfix: "fixes food reactions and explosion runtimes," + - bugfix: "fixes the too much yes problem" diff --git a/html/changelogs/AutoChangeLog-pr-9473.yml b/html/changelogs/AutoChangeLog-pr-9473.yml new file mode 100644 index 0000000000..def08d4acd --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9473.yml @@ -0,0 +1,4 @@ +author: "PersianXerxes" +delete-after: True +changes: + - code_imp: "Adds the clockwork_warp_allowed flag to the Captain's Office area, set to FALSE the same way it is for the chapel and armory." diff --git a/html/changelogs/AutoChangeLog-pr-9474.yml b/html/changelogs/AutoChangeLog-pr-9474.yml new file mode 100644 index 0000000000..1e3737f1a5 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9474.yml @@ -0,0 +1,4 @@ +author: "Putnam3145" +delete-after: True +changes: + - bugfix: "neural nanites only work/drain if you have brain damage or traumas the nanites can fix" diff --git a/html/changelogs/AutoChangeLog-pr-9477.yml b/html/changelogs/AutoChangeLog-pr-9477.yml new file mode 100644 index 0000000000..cf13d15860 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9477.yml @@ -0,0 +1,8 @@ +author: "Fermis" +delete-after: True +changes: + - bugfix: "Heart, Tongue and stomach regen." + - bugfix: "lung damage threshholds." + - bugfix: "Graft synthtissue" + - bugfix: "Skeleton's burning for no reason" + - bugfix: "Organ freezing handling." diff --git a/html/changelogs/AutoChangeLog-pr-9478.yml b/html/changelogs/AutoChangeLog-pr-9478.yml new file mode 100644 index 0000000000..d2c80d08fb --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9478.yml @@ -0,0 +1,4 @@ +author: "Putnam3145" +delete-after: True +changes: + - tweak: "Pod people can no longer get fat from standing in the light" diff --git a/html/changelogs/AutoChangeLog-pr-9479.yml b/html/changelogs/AutoChangeLog-pr-9479.yml new file mode 100644 index 0000000000..cea218193e --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9479.yml @@ -0,0 +1,4 @@ +author: "lolman360" +delete-after: True +changes: + - bugfix: "fixes bug with new surgerytools examine" diff --git a/html/changelogs/AutoChangeLog-pr-9482.yml b/html/changelogs/AutoChangeLog-pr-9482.yml new file mode 100644 index 0000000000..4624f4696b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9482.yml @@ -0,0 +1,5 @@ +author: "Fermis" +delete-after: True +changes: + - bugfix: "Fixes chemistry books to point to the right wiki, and keeps tg's just in case" + - tweak: "Changes top right wiki button location to go to both wikis" diff --git a/html/changelogs/AutoChangeLog-pr-9483.yml b/html/changelogs/AutoChangeLog-pr-9483.yml new file mode 100644 index 0000000000..36cce96d9f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9483.yml @@ -0,0 +1,5 @@ +author: "ZeroNetAlpha" +delete-after: True +changes: + - tweak: "Cleans up autoylathe code and brings it back in line with the regular autolathe." + - bugfix: "Fixes autoylathe interface not updating propperly." diff --git a/html/changelogs/AutoChangeLog-pr-9486.yml b/html/changelogs/AutoChangeLog-pr-9486.yml new file mode 100644 index 0000000000..c624e6472c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9486.yml @@ -0,0 +1,4 @@ +author: "ZeroNetAlpha" +delete-after: True +changes: + - tweak: "Silicons are now consumable by scrub pups." diff --git a/html/changelogs/AutoChangeLog-pr-9488.yml b/html/changelogs/AutoChangeLog-pr-9488.yml new file mode 100644 index 0000000000..dd5ac89610 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9488.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "Adds some missing species_traits for cloth, clockwork and cult golems." diff --git a/html/changelogs/AutoChangeLog-pr-9489.yml b/html/changelogs/AutoChangeLog-pr-9489.yml new file mode 100644 index 0000000000..a395af0749 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9489.yml @@ -0,0 +1,4 @@ +author: "Ghommie (original PR by nemvar)" +delete-after: True +changes: + - imageadd: "Some drinks have new icons or slightly altered icons. In particular Wizz Fizz, Bug Spray, Jack Rose, Champagne and Applejack." diff --git a/html/changelogs/AutoChangeLog-pr-9491.yml b/html/changelogs/AutoChangeLog-pr-9491.yml new file mode 100644 index 0000000000..0bfd6b6ee2 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9491.yml @@ -0,0 +1,4 @@ +author: "Poojawa" +delete-after: True +changes: + - bugfix: "fixed missing deco wing states" diff --git a/html/changelogs/AutoChangeLog-pr-9492.yml b/html/changelogs/AutoChangeLog-pr-9492.yml new file mode 100644 index 0000000000..5481265898 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9492.yml @@ -0,0 +1,5 @@ +author: "Ghommie" +delete-after: True +changes: + - rscadd: "Added towel linen bins, found in dormitory restrooms. Also enhanced the bedsheet bins found in some stations' dormitories" + - imageadd: "Resprited bedsheet bins in 3/4 perspective" diff --git a/html/changelogs/AutoChangeLog-pr-9493.yml b/html/changelogs/AutoChangeLog-pr-9493.yml new file mode 100644 index 0000000000..69aef9dbec --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9493.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - tweak: "Made SDGF ghost poll message less verbose, made the experimental cloner's complaint with the former, and added ghost poll ignore options for both." diff --git a/html/changelogs/AutoChangeLog-pr-9498.yml b/html/changelogs/AutoChangeLog-pr-9498.yml new file mode 100644 index 0000000000..d01f41e555 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9498.yml @@ -0,0 +1,4 @@ +author: "JTGSZ" +delete-after: True +changes: + - rscadd: "Added Halloween Dwarves, for Halloween... Yep." diff --git a/html/changelogs/AutoChangeLog-pr-9499.yml b/html/changelogs/AutoChangeLog-pr-9499.yml new file mode 100644 index 0000000000..a4d41485cd --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9499.yml @@ -0,0 +1,4 @@ +author: "r4d6" +delete-after: True +changes: + - rscadd: "Added blindfolds to the Loadout list" diff --git a/html/changelogs/AutoChangeLog-pr-9502.yml b/html/changelogs/AutoChangeLog-pr-9502.yml new file mode 100644 index 0000000000..71939adfd8 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9502.yml @@ -0,0 +1,4 @@ +author: "Putnam3145" +delete-after: True +changes: + - tweak: "PanD.E.M.I.C 2200 now ejects onto itself instead of onto user if user's hands are full" diff --git a/html/changelogs/AutoChangeLog-pr-9503.yml b/html/changelogs/AutoChangeLog-pr-9503.yml new file mode 100644 index 0000000000..7b79ad7185 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9503.yml @@ -0,0 +1,6 @@ +author: "deathride58" +delete-after: True +changes: + - balance: "The taser's electrode has been reworked. Instead of being a strong knockdown that deals a heavy amount of stamloss, it now causes a weak knockdown, applies a debilitating status effect for 5 seconds, and deals 35 stamloss on hit up to a maximum 50 total stamloss." + - balance: "Roundstart turrets now have a nonlethal projectile that gets used when they're set to stun and the target is resting" + - tweak: "Hybrid tasers now have disablers set as their default mode." diff --git a/html/changelogs/AutoChangeLog-pr-9504.yml b/html/changelogs/AutoChangeLog-pr-9504.yml new file mode 100644 index 0000000000..4915c1a2ea --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9504.yml @@ -0,0 +1,4 @@ +author: "Poojawa" +delete-after: True +changes: + - bugfix: "fixed a few things related to vore content" diff --git a/html/changelogs/AutoChangeLog-pr-9505.yml b/html/changelogs/AutoChangeLog-pr-9505.yml new file mode 100644 index 0000000000..7bbd289859 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9505.yml @@ -0,0 +1,7 @@ +author: "Thalpy" +delete-after: True +changes: + - rscadd: "Added the ability to dispense smartdarts from the chemmaster." + - tweak: "Tweaks medolier amd chembags to allow quickpickups of smartdarts, lets the latter soak in beakers (on the floor)" + - bugfix: "fixed rounding errors with smartdart mixes." + - imageadd: "added modified smartdartgun icon." diff --git a/html/changelogs/AutoChangeLog-pr-9506.yml b/html/changelogs/AutoChangeLog-pr-9506.yml new file mode 100644 index 0000000000..e3a0e63b18 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9506.yml @@ -0,0 +1,4 @@ +author: "izzyinbox" +delete-after: True +changes: + - rscadd: "*bark emote" diff --git a/html/changelogs/AutoChangeLog-pr-9510.yml b/html/changelogs/AutoChangeLog-pr-9510.yml new file mode 100644 index 0000000000..b752fc06ea --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9510.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "Fixed tracking implant teleport issues." diff --git a/html/changelogs/AutoChangeLog-pr-9514.yml b/html/changelogs/AutoChangeLog-pr-9514.yml new file mode 100644 index 0000000000..ebf0735778 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9514.yml @@ -0,0 +1,6 @@ +author: "Linzolle" +delete-after: True +changes: + - rscadd: "Four colour variants of ankle coverings. Select them on the loadout screen." + - imageadd: "ankle coverings" + - tweak: "allows for shoes that don't cover your feet to be taken into account for footstep sound effects and glass shards" diff --git a/html/changelogs/AutoChangeLog-pr-9515.yml b/html/changelogs/AutoChangeLog-pr-9515.yml new file mode 100644 index 0000000000..ece9a57449 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9515.yml @@ -0,0 +1,7 @@ +author: "Ghommie (original PR by Skoglol)" +delete-after: True +changes: + - tweak: "Moved machine and computer frames below objects, parts are now always on top." + - tweak: "Moved structures (chairs, closets, windows, cult altars etc etc) below objects." + - tweak: "Moves mineral doors to airlock layers" + - tweak: "morgue/crematorium trays' layers shouldn't overlap bodybags' anymore." diff --git a/html/changelogs/AutoChangeLog-pr-9516.yml b/html/changelogs/AutoChangeLog-pr-9516.yml new file mode 100644 index 0000000000..f023b7eb14 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9516.yml @@ -0,0 +1,4 @@ +author: "Ghommie (original PR by MrDoomBringer)" +delete-after: True +changes: + - bugfix: "morgues have had their proton packs removed and as such no longer suck in ghosts on closing." diff --git a/html/changelogs/AutoChangeLog-pr-9517.yml b/html/changelogs/AutoChangeLog-pr-9517.yml new file mode 100644 index 0000000000..06442cae43 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9517.yml @@ -0,0 +1,4 @@ +author: "kappa-sama" +delete-after: True +changes: + - bugfix: "you can no longer have infinite ebows" diff --git a/html/changelogs/AutoChangeLog-pr-9520.yml b/html/changelogs/AutoChangeLog-pr-9520.yml new file mode 100644 index 0000000000..20188b7137 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9520.yml @@ -0,0 +1,4 @@ +author: "r4d6" +delete-after: True +changes: + - rscadd: "Added Decorative Wings for Humans, Felinids, Slimepersons and Lizardpeoples." diff --git a/html/changelogs/AutoChangeLog-pr-9522.yml b/html/changelogs/AutoChangeLog-pr-9522.yml new file mode 100644 index 0000000000..e4c51bf1e0 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9522.yml @@ -0,0 +1,6 @@ +author: "Linzolle" +delete-after: True +changes: + - rscadd: "Tend Wounds surgery. Heal in the field, with better healing the more damage the patient has." + - rscdel: "Reconstruction replaced by Tend Wounds" + - balance: "made Revival more accessible, more viable alternative to cloning." diff --git a/html/changelogs/AutoChangeLog-pr-9523.yml b/html/changelogs/AutoChangeLog-pr-9523.yml new file mode 100644 index 0000000000..da6864ace8 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9523.yml @@ -0,0 +1,4 @@ +author: "Linzolle" +delete-after: True +changes: + - bugfix: "advanced surgery tools can't perform lobectomy or coronary bypass" diff --git a/html/changelogs/AutoChangeLog-pr-9524.yml b/html/changelogs/AutoChangeLog-pr-9524.yml new file mode 100644 index 0000000000..df1ff4959a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9524.yml @@ -0,0 +1,7 @@ +author: "Linzolle" +delete-after: True +changes: + - rscadd: "Decorative and insect wings can now be coloured individually, similar to horns." + - bugfix: "people getting assigned wings if their savefile is old." + - rscdel: "wings that take the hair colour. Unnecessary if you can just set the colour." + - tweak: "Cannot make horns pure black. Trying to do so will set it to a default value." diff --git a/html/changelogs/AutoChangeLog-pr-9525.yml b/html/changelogs/AutoChangeLog-pr-9525.yml new file mode 100644 index 0000000000..a77b9e28b2 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9525.yml @@ -0,0 +1,4 @@ +author: "Linzolle" +delete-after: True +changes: + - bugfix: "decorative angel wings being invisible" diff --git a/html/changelogs/AutoChangeLog-pr-9534.yml b/html/changelogs/AutoChangeLog-pr-9534.yml new file mode 100644 index 0000000000..4654503f9b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9534.yml @@ -0,0 +1,5 @@ +author: "Linzolle" +delete-after: True +changes: + - bugfix: "abductors now actually work" + - tweak: "abductor scientist has their own greet message now" diff --git a/html/changelogs/AutoChangeLog-pr-9536.yml b/html/changelogs/AutoChangeLog-pr-9536.yml new file mode 100644 index 0000000000..ffac8e8f6f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9536.yml @@ -0,0 +1,4 @@ +author: "r4d6" +delete-after: True +changes: + - tweak: "Change the SEVA suit & Exo-suit's descriptions" diff --git a/html/changelogs/AutoChangeLog-pr-9537.yml b/html/changelogs/AutoChangeLog-pr-9537.yml new file mode 100644 index 0000000000..24318d4364 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9537.yml @@ -0,0 +1,4 @@ +author: "Hatterhat" +delete-after: True +changes: + - rscadd: "Magnetic pistols now fit in boot pockets - jackboots, workboots, etc." diff --git a/html/changelogs/AutoChangeLog-pr-9540.yml b/html/changelogs/AutoChangeLog-pr-9540.yml new file mode 100644 index 0000000000..8dd4e46bc6 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9540.yml @@ -0,0 +1,4 @@ +author: "YakumoChen" +delete-after: True +changes: + - rscdel: "Reverted laser miniguns." diff --git a/html/changelogs/AutoChangeLog-pr-9545.yml b/html/changelogs/AutoChangeLog-pr-9545.yml new file mode 100644 index 0000000000..970e463f41 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9545.yml @@ -0,0 +1,4 @@ +author: "Ghommie (original PR by Barhandar" +delete-after: True +changes: + - bugfix: "Pumpkin meteors on Halloween now replace catastrophic meteor waves, instead of ALL OF THEM." diff --git a/html/changelogs/AutoChangeLog-pr-9547.yml b/html/changelogs/AutoChangeLog-pr-9547.yml new file mode 100644 index 0000000000..7e0abca8f4 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9547.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "Silicons can now operate teleporter, medical and security records console from a distance again." diff --git a/html/oracle_ui/content/disposal_bin/index.html b/html/oracle_ui/content/disposal_bin/index.html new file mode 100644 index 0000000000..8f7713b53c --- /dev/null +++ b/html/oracle_ui/content/disposal_bin/index.html @@ -0,0 +1,27 @@ +
    +
    + State: +
    @{full_pressure}
    +
    +
    + Pressure: +
    +
    +
    +
    @{per}
    +
    +
    +
    +
    + Handle: +
    @{flush}
    +
    +
    + Eject: +
    @{contents}
    +
    +
    + Compressor: +
    @{pressure_charging}
    +
    +
    \ No newline at end of file diff --git a/html/oracle_ui/editor_tool.html b/html/oracle_ui/editor_tool.html new file mode 100644 index 0000000000..e0ce75bb29 --- /dev/null +++ b/html/oracle_ui/editor_tool.html @@ -0,0 +1,103 @@ + + + + + + OracleUI IDE + + + +
    +

    Content Template:

    + +
    +
    +

    Data:

    + +
    +
    +

    Output:

    + +
    + + + diff --git a/html/oracle_ui/themes/nano/index.html b/html/oracle_ui/themes/nano/index.html new file mode 100644 index 0000000000..388f6e4ce4 --- /dev/null +++ b/html/oracle_ui/themes/nano/index.html @@ -0,0 +1,19 @@ + + + + + + @{title} + + + + + +
    +
    @{title}
    +
    + @{body} +
    +
    + + diff --git a/html/oracle_ui/themes/nano/sui-nano-common.css b/html/oracle_ui/themes/nano/sui-nano-common.css new file mode 100644 index 0000000000..481b81c3e3 --- /dev/null +++ b/html/oracle_ui/themes/nano/sui-nano-common.css @@ -0,0 +1,353 @@ +body +{ + padding: 0; + margin: 0; + background-color: #272727; + font-size: 12px; + color: #ffffff; + line-height: 170%; + cursor: default; + -moz-user-select: none; + -ms-user-select: none; +} + +hr +{ + background-color: #40628a; + height: 1px; +} + +a, a:link, a:visited, a:active, .linkOn, .linkOff +{ + color: #ffffff; + text-decoration: none; + background: #40628a; + border: 1px solid #161616; + padding: 1px 4px 1px 4px; + margin: 0 2px 0 0; + cursor:default; +} + +a:hover +{ + color: #40628a; + background: #ffffff; +} + +a.white, a.white:link, a.white:visited, a.white:active +{ + color: #40628a; + text-decoration: none; + background: #ffffff; + border: 1px solid #161616; + padding: 1px 4px 1px 4px; + margin: 0 2px 0 0; + cursor:default; +} + +a.white:hover +{ + color: #ffffff; + background: #40628a; +} + +.active, a.active:link, a.active:visited, a.active:active, a.active:hover +{ + color: #ffffff; + background: #2f943c; + border-color: #24722e; +} + +.disabled, a.disabled:link, a.disabled:visited, a.disabled:active, a.disabled:hover +{ + color: #ffffff; + background: #999999; + border-color: #666666; +} + +a.icon, .linkOn.icon, .linkOff.icon +{ + position: relative; + padding: 1px 4px 2px 20px; +} + +a.icon img, .linkOn.icon img +{ + position: absolute; + top: 0; + left: 0; + width: 18px; + height: 18px; +} + +ul +{ + padding: 4px 0 0 10px; + margin: 0; + list-style-type: none; +} + +li +{ + padding: 0 0 2px 0; +} + +img, a img +{ + border-style:none; +} + +h1, h2, h3, h4, h5, h6 +{ + margin: 0; + padding: 16px 0 8px 0; + color: #517087; +} + +h1 +{ + font-size: 15px; +} + +h2 +{ + font-size: 14px; +} + +h3 +{ + font-size: 13px; +} + +h4 +{ + font-size: 12px; +} + +.uiWrapper +{ + + width: 100%; + height: 100%; +} + +.uiTitle +{ + clear: both; + padding: 6px 8px 6px 8px; + border-bottom: 2px solid #161616; + background: #383838; + color: #98B0C3; + font-size: 16px; +} + +.uiTitle.icon +{ + padding: 6px 8px 6px 42px; + background-position: 2px 50%; + background-repeat: no-repeat; +} + +.uiContent +{ + clear: both; + padding: 8px; + font-family: Verdana, Geneva, sans-serif; +} + +.good +{ + color: #00ff00; +} + +.average +{ + color: #d09000; +} + +.bad +{ + color: #ff0000; +} + +.highlight +{ + color: #8BA5C4; +} + +.dark +{ + color: #272727; +} + +.notice +{ + position: relative; + background: #E9C183; + color: #15345A; + font-size: 10px; + font-style: italic; + padding: 2px 4px 0 4px; + margin: 4px; +} + +.notice.icon +{ + padding: 2px 4px 0 20px; +} + +.notice img +{ + position: absolute; + top: 0; + left: 0; + width: 16px; + height: 16px; +} + +div.notice +{ + clear: both; +} + +.statusDisplay +{ + background: #000000; + color: #ffffff; + border: 1px solid #40628a; + padding: 4px; + margin: 3px 0; +} + +.statusLabel +{ + width: 138px; + float: left; + overflow: hidden; + color: #98B0C3; +} + +.statusValue +{ + float: left; +} + +.block +{ + padding: 8px; + margin: 10px 4px 4px 4px; + border: 1px solid #40628a; + background-color: #202020; +} + +.block h3 +{ + padding: 0; +} + +.progressBar +{ + position: relative; + width: 185px; + height: 14px; + border: 1px solid #666666; + float: left; + overflow: hidden; + padding: 1px; +} + +.progressLabel +{ + top: -2px; + height: 100%; + position: absolute; + right: 4px; + text-align: right; +} + +.progressFill +{ + width: 100%; + height: 100%; + background: #40628a; + overflow: hidden; + transition: width 2.2s linear; +} + +.progressFill.good +{ + color: #ffffff; + background: #00ff00; +} + +.progressFill.average +{ + color: #ffffff; + background: #d09000; +} + +.progressFill.bad +{ + color: #ffffff; + background: #ff0000; +} + +.progressFill.highlight +{ + color: #ffffff; + background: #8BA5C4; +} + +.clearBoth +{ + clear: both; +} + +.clearLeft +{ + clear: left; +} + +.clearRight +{ + clear: right; +} + +.line +{ + width: 100%; + clear: both; +} + +section .label, section .content +{ + display: table-cell; + margin: 0; + text-align: left; + vertical-align: middle; + padding: 3px 2px +} + +section .label +{ + width: 1%; + padding-right: 32px; + white-space: nowrap; + color: #8ba5c4; +} + +section +{ + display: table-row; + width: 100% +} + +.display { + width: calc(100% - 8px); + padding: 4px; + background-color: #000; + background-color: rgba(0, 0, 0, .33); + box-shadow: inset 0 0 5px rgba(0, 0, 0, .5); + -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr=#54000000,endColorStr=#54000000)"; + filter: progid: DXImageTransform.Microsoft.gradient(startColorStr=#54000000, endColorStr=#54000000); +} \ No newline at end of file diff --git a/html/oracle_ui/themes/nano/sui-nano-common.js b/html/oracle_ui/themes/nano/sui-nano-common.js new file mode 100644 index 0000000000..716891a53f --- /dev/null +++ b/html/oracle_ui/themes/nano/sui-nano-common.js @@ -0,0 +1,47 @@ +function replaceContent(body) { + var maincontent = document.getElementById('maincontent'); + if(maincontent) { + maincontent.innerHTML = body; + } +} + +function updateProgressLabels() { + var progressBars = document.getElementsByClassName("progressBar"); + for(var i = 0; i < progressBars.length; i++) { + var progressBar = progressBars[i]; + if(!progressBar) + continue; + var progressFill = progressBar.getElementsByClassName("progressFill")[0]; + if(!progressFill) + continue; + var width = parseInt(getComputedStyle(progressFill).width); + var maxWidth = parseInt(getComputedStyle(progressBar).width); + var progressLabel = progressBar.getElementsByClassName("progressLabel")[0]; + if(progressLabel) + progressLabel.innerHTML = Math.round((width / maxWidth) * 100) + '%'; + } +} + +if(getComputedStyle) { setInterval(updateProgressLabels, 50); } //Fallback + +function updateFields(json) { + var fields = JSON.parse(json); + for (var key in fields) { + let value = fields[key]; + var element = document.getElementById(key); + if(element == null) { + continue; + } else if(element.classList.contains('progressBar')) { + var progressFill = element.getElementsByClassName("progressFill")[0]; + if(progressFill) + progressFill.style["width"] = value; + if(!getComputedStyle) { //Fallback + var progressLabel = element.getElementsByClassName("progressLabel")[0]; + if(progressLabel) + progressLabel.innerHTML = value; + } + } else { + element.innerHTML = value; + } + } +} \ No newline at end of file diff --git a/html/oracle_ui/themes/nano/sui-nano-jquery.min.js b/html/oracle_ui/themes/nano/sui-nano-jquery.min.js new file mode 100644 index 0000000000..645c5adc18 --- /dev/null +++ b/html/oracle_ui/themes/nano/sui-nano-jquery.min.js @@ -0,0 +1,4 @@ +/*! jQuery v1.11.1 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */ +!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.1",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b){return b.toUpperCase()};m.fn=m.prototype={jquery:l,constructor:m,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b=a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+-new Date,v=a.document,w=0,x=0,y=gb(),z=gb(),A=gb(),B=function(a,b){return a===b&&(l=!0),0},C="undefined",D=1<<31,E={}.hasOwnProperty,F=[],G=F.pop,H=F.push,I=F.push,J=F.slice,K=F.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},L="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",N="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=N.replace("w","w#"),P="\\["+M+"*("+N+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+O+"))|)"+M+"*\\]",Q=":("+N+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+P+")*)|.*)\\)|)",R=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),S=new RegExp("^"+M+"*,"+M+"*"),T=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),V=new RegExp(Q),W=new RegExp("^"+O+"$"),X={ID:new RegExp("^#("+N+")"),CLASS:new RegExp("^\\.("+N+")"),TAG:new RegExp("^("+N.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+Q),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+L+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{I.apply(F=J.call(v.childNodes),v.childNodes),F[v.childNodes.length].nodeType}catch(eb){I={apply:F.length?function(a,b){H.apply(a,J.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],!a||"string"!=typeof a)return d;if(1!==(k=b.nodeType)&&9!==k)return[];if(p&&!e){if(f=_.exec(a))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return I.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return I.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=9===k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+qb(o[l]);w=ab.test(a)&&ob(b.parentNode)||b,x=o.join(",")}if(x)try{return I.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function gb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function hb(a){return a[u]=!0,a}function ib(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function jb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function kb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||D)-(~a.sourceIndex||D);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function lb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function nb(a){return hb(function(b){return b=+b,hb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function ob(a){return a&&typeof a.getElementsByTagName!==C&&a}c=fb.support={},f=fb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fb.setDocument=function(a){var b,e=a?a.ownerDocument||a:v,g=e.defaultView;return e!==n&&9===e.nodeType&&e.documentElement?(n=e,o=e.documentElement,p=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){m()},!1):g.attachEvent&&g.attachEvent("onunload",function(){m()})),c.attributes=ib(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ib(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(e.getElementsByClassName)&&ib(function(a){return a.innerHTML="
    ",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=ib(function(a){return o.appendChild(a).id=u,!e.getElementsByName||!e.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==C&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c=typeof a.getAttributeNode!==C&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==C?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==C&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(e.querySelectorAll))&&(ib(function(a){a.innerHTML="",a.querySelectorAll("[msallowclip^='']").length&&q.push("[*^$]="+M+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+M+"*(?:value|"+L+")"),a.querySelectorAll(":checked").length||q.push(":checked")}),ib(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+M+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ib(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",Q)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===v&&t(v,a)?-1:b===e||b.ownerDocument===v&&t(v,b)?1:k?K.call(k,a)-K.call(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],i=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:k?K.call(k,a)-K.call(k,b):0;if(f===g)return kb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?kb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},e):n},fb.matches=function(a,b){return fb(a,null,null,b)},fb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fb(b,n,null,[a]).length>0},fb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&E.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fb.selectors={cacheLength:50,createPseudo:hb,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+M+")"+a+"("+M+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==C&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?hb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=K.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:hb(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?hb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:hb(function(a){return function(b){return fb(a,b).length>0}}),contains:hb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:hb(function(a){return W.test(a||"")||fb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:nb(function(){return[0]}),last:nb(function(a,b){return[b-1]}),eq:nb(function(a,b,c){return[0>c?c+b:c]}),even:nb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:nb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:nb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:nb(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function rb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function sb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function tb(a,b,c){for(var d=0,e=b.length;e>d;d++)fb(a,b[d],c);return c}function ub(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function vb(a,b,c,d,e,f){return d&&!d[u]&&(d=vb(d)),e&&!e[u]&&(e=vb(e,f)),hb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||tb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ub(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ub(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?K.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ub(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):I.apply(g,r)})}function wb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=rb(function(a){return a===b},h,!0),l=rb(function(a){return K.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>i;i++)if(c=d.relative[a[i].type])m=[rb(sb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return vb(i>1&&sb(m),i>1&&qb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&wb(a.slice(i,e)),f>e&&wb(a=a.slice(e)),f>e&&qb(a))}m.push(c)}return sb(m)}function xb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=G.call(i));s=ub(s)}I.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&fb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?hb(f):f}return h=fb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xb(e,d)),f.selector=a}return f},i=fb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&ob(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qb(j),!a)return I.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&ob(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ib(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ib(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||jb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ib(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||jb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ib(function(a){return null==a.getAttribute("disabled")})||jb(L,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fb}(a);m.find=s,m.expr=s.selectors,m.expr[":"]=m.expr.pseudos,m.unique=s.uniqueSort,m.text=s.getText,m.isXMLDoc=s.isXML,m.contains=s.contains;var t=m.expr.match.needsContext,u=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,v=/^.[^:#\[\.,]*$/;function w(a,b,c){if(m.isFunction(b))return m.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return m.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(v.test(b))return m.filter(b,a,c);b=m.filter(b,a)}return m.grep(a,function(a){return m.inArray(a,b)>=0!==c})}m.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?m.find.matchesSelector(d,a)?[d]:[]:m.find.matches(a,m.grep(b,function(a){return 1===a.nodeType}))},m.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(m(a).filter(function(){for(b=0;e>b;b++)if(m.contains(d[b],this))return!0}));for(b=0;e>b;b++)m.find(a,d[b],c);return c=this.pushStack(e>1?m.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(w(this,a||[],!1))},not:function(a){return this.pushStack(w(this,a||[],!0))},is:function(a){return!!w(this,"string"==typeof a&&t.test(a)?m(a):a||[],!1).length}});var x,y=a.document,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=m.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||x).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof m?b[0]:b,m.merge(this,m.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:y,!0)),u.test(c[1])&&m.isPlainObject(b))for(c in b)m.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=y.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return x.find(a);this.length=1,this[0]=d}return this.context=y,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):m.isFunction(a)?"undefined"!=typeof x.ready?x.ready(a):a(m):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),m.makeArray(a,this))};A.prototype=m.fn,x=m(y);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};m.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!m(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),m.fn.extend({has:function(a){var b,c=m(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(m.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=t.test(a)||"string"!=typeof a?m(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&m.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?m.unique(f):f)},index:function(a){return a?"string"==typeof a?m.inArray(this[0],m(a)):m.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(m.unique(m.merge(this.get(),m(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}m.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return m.dir(a,"parentNode")},parentsUntil:function(a,b,c){return m.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return m.dir(a,"nextSibling")},prevAll:function(a){return m.dir(a,"previousSibling")},nextUntil:function(a,b,c){return m.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return m.dir(a,"previousSibling",c)},siblings:function(a){return m.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return m.sibling(a.firstChild)},contents:function(a){return m.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:m.merge([],a.childNodes)}},function(a,b){m.fn[a]=function(c,d){var e=m.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=m.filter(d,e)),this.length>1&&(C[a]||(e=m.unique(e)),B.test(a)&&(e=e.reverse())),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return m.each(a.match(E)||[],function(a,c){b[c]=!0}),b}m.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):m.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){m.each(b,function(b,c){var d=m.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&m.each(arguments,function(a,c){var d;while((d=m.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?m.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},m.extend({Deferred:function(a){var b=[["resolve","done",m.Callbacks("once memory"),"resolved"],["reject","fail",m.Callbacks("once memory"),"rejected"],["notify","progress",m.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return m.Deferred(function(c){m.each(b,function(b,f){var g=m.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&m.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?m.extend(a,d):d}},e={};return d.pipe=d.then,m.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&m.isFunction(a.promise)?e:0,g=1===f?a:m.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&m.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;m.fn.ready=function(a){return m.ready.promise().done(a),this},m.extend({isReady:!1,readyWait:1,holdReady:function(a){a?m.readyWait++:m.ready(!0)},ready:function(a){if(a===!0?!--m.readyWait:!m.isReady){if(!y.body)return setTimeout(m.ready);m.isReady=!0,a!==!0&&--m.readyWait>0||(H.resolveWith(y,[m]),m.fn.triggerHandler&&(m(y).triggerHandler("ready"),m(y).off("ready")))}}});function I(){y.addEventListener?(y.removeEventListener("DOMContentLoaded",J,!1),a.removeEventListener("load",J,!1)):(y.detachEvent("onreadystatechange",J),a.detachEvent("onload",J))}function J(){(y.addEventListener||"load"===event.type||"complete"===y.readyState)&&(I(),m.ready())}m.ready.promise=function(b){if(!H)if(H=m.Deferred(),"complete"===y.readyState)setTimeout(m.ready);else if(y.addEventListener)y.addEventListener("DOMContentLoaded",J,!1),a.addEventListener("load",J,!1);else{y.attachEvent("onreadystatechange",J),a.attachEvent("onload",J);var c=!1;try{c=null==a.frameElement&&y.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!m.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}I(),m.ready()}}()}return H.promise(b)};var K="undefined",L;for(L in m(k))break;k.ownLast="0"!==L,k.inlineBlockNeedsLayout=!1,m(function(){var a,b,c,d;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",k.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(d))}),function(){var a=y.createElement("div");if(null==k.deleteExpando){k.deleteExpando=!0;try{delete a.test}catch(b){k.deleteExpando=!1}}a=null}(),m.acceptData=function(a){var b=m.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var M=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,N=/([A-Z])/g;function O(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(N,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:M.test(c)?m.parseJSON(c):c}catch(e){}m.data(a,b,c)}else c=void 0}return c}function P(a){var b;for(b in a)if(("data"!==b||!m.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h; + if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML="
    a",k.leadingWhitespace=3===b.firstChild.nodeType,k.tbody=!b.getElementsByTagName("tbody").length,k.htmlSerialize=!!b.getElementsByTagName("link").length,k.html5Clone="<:nav>"!==y.createElement("nav").cloneNode(!0).outerHTML,a.type="checkbox",a.checked=!0,c.appendChild(a),k.appendChecked=a.checked,b.innerHTML="",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML="",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function ab(){return!0}function bb(){return!1}function cb(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=m.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(E)||[""],h=b.length;while(h--)f=_.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=m.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=m.event.special[o]||{},l=m.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&m.expr.match.needsContext.test(e),namespace:p.join(".")},i),(n=g[o])||(n=g[o]=[],n.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?n.splice(n.delegateCount++,0,l):n.push(l),m.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m.hasData(a)&&m._data(a);if(r&&(k=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=_.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=m.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,n=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=n.length;while(f--)g=n[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(n.splice(f,1),g.selector&&n.delegateCount--,l.remove&&l.remove.call(a,g));i&&!n.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||m.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)m.event.remove(a,o+b[j],c,d,!0);m.isEmptyObject(k)&&(delete r.handle,m._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,o=[d||y],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||y,3!==d.nodeType&&8!==d.nodeType&&!$.test(p+m.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[m.expando]?b:new m.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:m.makeArray(c,[b]),k=m.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!m.isWindow(d)){for(i=k.delegateType||p,$.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||y)&&o.push(l.defaultView||l.parentWindow||a)}n=0;while((h=o[n++])&&!b.isPropagationStopped())b.type=n>1?i:k.bindType||p,f=(m._data(h,"events")||{})[b.type]&&m._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&m.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&m.acceptData(d)&&g&&d[p]&&!m.isWindow(d)){l=d[g],l&&(d[g]=null),m.event.triggered=p;try{d[p]()}catch(r){}m.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=m.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(m._data(this,"events")||{})[a.type]||[],k=m.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=m.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((m.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?m(c,this).index(i)>=0:m.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h]","i"),hb=/^\s+/,ib=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,jb=/<([\w:]+)/,kb=/
","
"],tr:[2,"","
"],col:[2,"","
"],td:[3,"","
"],_default:k.htmlSerialize?[0,"",""]:[1,"X
","
"]},sb=db(y),tb=sb.appendChild(y.createElement("div"));rb.optgroup=rb.option,rb.tbody=rb.tfoot=rb.colgroup=rb.caption=rb.thead,rb.th=rb.td;function ub(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==K?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==K?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||m.nodeName(d,b)?f.push(d):m.merge(f,ub(d,b));return void 0===b||b&&m.nodeName(a,b)?m.merge([a],f):f}function vb(a){W.test(a.type)&&(a.defaultChecked=a.checked)}function wb(a,b){return m.nodeName(a,"table")&&m.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function xb(a){return a.type=(null!==m.find.attr(a,"type"))+"/"+a.type,a}function yb(a){var b=pb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function zb(a,b){for(var c,d=0;null!=(c=a[d]);d++)m._data(c,"globalEval",!b||m._data(b[d],"globalEval"))}function Ab(a,b){if(1===b.nodeType&&m.hasData(a)){var c,d,e,f=m._data(a),g=m._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)m.event.add(b,c,h[c][d])}g.data&&(g.data=m.extend({},g.data))}}function Bb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!k.noCloneEvent&&b[m.expando]){e=m._data(b);for(d in e.events)m.removeEvent(b,d,e.handle);b.removeAttribute(m.expando)}"script"===c&&b.text!==a.text?(xb(b).text=a.text,yb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),k.html5Clone&&a.innerHTML&&!m.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&W.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}m.extend({clone:function(a,b,c){var d,e,f,g,h,i=m.contains(a.ownerDocument,a);if(k.html5Clone||m.isXMLDoc(a)||!gb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(tb.innerHTML=a.outerHTML,tb.removeChild(f=tb.firstChild)),!(k.noCloneEvent&&k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||m.isXMLDoc(a)))for(d=ub(f),h=ub(a),g=0;null!=(e=h[g]);++g)d[g]&&Bb(e,d[g]);if(b)if(c)for(h=h||ub(a),d=d||ub(f),g=0;null!=(e=h[g]);g++)Ab(e,d[g]);else Ab(a,f);return d=ub(f,"script"),d.length>0&&zb(d,!i&&ub(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,l,n=a.length,o=db(b),p=[],q=0;n>q;q++)if(f=a[q],f||0===f)if("object"===m.type(f))m.merge(p,f.nodeType?[f]:f);else if(lb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(jb.exec(f)||["",""])[1].toLowerCase(),l=rb[i]||rb._default,h.innerHTML=l[1]+f.replace(ib,"<$1>")+l[2],e=l[0];while(e--)h=h.lastChild;if(!k.leadingWhitespace&&hb.test(f)&&p.push(b.createTextNode(hb.exec(f)[0])),!k.tbody){f="table"!==i||kb.test(f)?""!==l[1]||kb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)m.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}m.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),k.appendChecked||m.grep(ub(p,"input"),vb),q=0;while(f=p[q++])if((!d||-1===m.inArray(f,d))&&(g=m.contains(f.ownerDocument,f),h=ub(o.appendChild(f),"script"),g&&zb(h),c)){e=0;while(f=h[e++])ob.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=m.expando,j=m.cache,l=k.deleteExpando,n=m.event.special;null!=(d=a[h]);h++)if((b||m.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)n[e]?m.event.remove(d,e):m.removeEvent(d,e,g.handle);j[f]&&(delete j[f],l?delete d[i]:typeof d.removeAttribute!==K?d.removeAttribute(i):d[i]=null,c.push(f))}}}),m.fn.extend({text:function(a){return V(this,function(a){return void 0===a?m.text(this):this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?m.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||m.cleanData(ub(c)),c.parentNode&&(b&&m.contains(c.ownerDocument,c)&&zb(ub(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&m.cleanData(ub(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&m.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return m.clone(this,a,b)})},html:function(a){return V(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(fb,""):void 0;if(!("string"!=typeof a||mb.test(a)||!k.htmlSerialize&&gb.test(a)||!k.leadingWhitespace&&hb.test(a)||rb[(jb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(ib,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(m.cleanData(ub(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,m.cleanData(ub(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,n=this,o=l-1,p=a[0],q=m.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&nb.test(p))return this.each(function(c){var d=n.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(i=m.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=m.map(ub(i,"script"),xb),f=g.length;l>j;j++)d=i,j!==o&&(d=m.clone(d,!0,!0),f&&m.merge(g,ub(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,m.map(g,yb),j=0;f>j;j++)d=g[j],ob.test(d.type||"")&&!m._data(d,"globalEval")&&m.contains(h,d)&&(d.src?m._evalUrl&&m._evalUrl(d.src):m.globalEval((d.text||d.textContent||d.innerHTML||"").replace(qb,"")));i=c=null}return this}}),m.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){m.fn[a]=function(a){for(var c,d=0,e=[],g=m(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),m(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Cb,Db={};function Eb(b,c){var d,e=m(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:m.css(e[0],"display");return e.detach(),f}function Fb(a){var b=y,c=Db[a];return c||(c=Eb(a,b),"none"!==c&&c||(Cb=(Cb||m("