diff --git a/_maps/RandomRuins/AnywhereRuins/golem_ship.dmm b/_maps/RandomRuins/AnywhereRuins/golem_ship.dmm index 274c814cf5..e20fa042d7 100644 --- a/_maps/RandomRuins/AnywhereRuins/golem_ship.dmm +++ b/_maps/RandomRuins/AnywhereRuins/golem_ship.dmm @@ -139,6 +139,7 @@ dir = 4; name = "shrine of the liberator" }, +/obj/item/tcg_card/special/golem, /turf/open/floor/mineral/titanium/purple, /area/ruin/powered/golem_ship) "v" = ( diff --git a/_maps/RandomRuins/IceRuins/icemoon_surface_hotsprings.dmm b/_maps/RandomRuins/IceRuins/icemoon_surface_hotsprings.dmm index 93b221c446..a32c526ec4 100644 --- a/_maps/RandomRuins/IceRuins/icemoon_surface_hotsprings.dmm +++ b/_maps/RandomRuins/IceRuins/icemoon_surface_hotsprings.dmm @@ -14,6 +14,10 @@ }, /turf/open/floor/plating/beach/sand, /area/icemoon/surface/outdoors) +"l" = ( +/obj/item/tcg_card/special/morph, +/turf/open/floor/plating/beach/sand, +/area/icemoon/surface/outdoors) "I" = ( /turf/closed/indestructible/fakeglass, /area/icemoon/surface/outdoors) @@ -72,7 +76,7 @@ L c c c -U +l U a b diff --git a/_maps/RandomRuins/IceRuins/icemoon_surface_lust.dmm b/_maps/RandomRuins/IceRuins/icemoon_surface_lust.dmm index 704ac63a7d..7a41256478 100644 --- a/_maps/RandomRuins/IceRuins/icemoon_surface_lust.dmm +++ b/_maps/RandomRuins/IceRuins/icemoon_surface_lust.dmm @@ -20,6 +20,10 @@ }, /turf/open/floor/mineral/diamond, /area/icemoon/surface/outdoors) +"f" = ( +/obj/item/tcg_card/special/xenomaid, +/turf/open/floor/mineral/diamond, +/area/icemoon/surface/outdoors) (1,1,1) = {" a @@ -65,7 +69,7 @@ a a a b -c +f c c b diff --git a/_maps/RandomRuins/IceRuins/icemoon_surface_mining_site.dmm b/_maps/RandomRuins/IceRuins/icemoon_surface_mining_site.dmm index 23abc4b731..9ea8747846 100644 --- a/_maps/RandomRuins/IceRuins/icemoon_surface_mining_site.dmm +++ b/_maps/RandomRuins/IceRuins/icemoon_surface_mining_site.dmm @@ -49,6 +49,7 @@ /area/ruin/unpowered) "k" = ( /obj/structure/closet/crate/freezer, +/obj/item/tcg_card/special/demonic_miner, /turf/open/floor/wood, /area/ruin/unpowered) "l" = ( diff --git a/_maps/RandomRuins/IceRuins/icemoon_underground_wendigo_cave.dmm b/_maps/RandomRuins/IceRuins/icemoon_underground_wendigo_cave.dmm index a383c2e8c4..5861309eff 100644 --- a/_maps/RandomRuins/IceRuins/icemoon_underground_wendigo_cave.dmm +++ b/_maps/RandomRuins/IceRuins/icemoon_underground_wendigo_cave.dmm @@ -31,6 +31,10 @@ "N" = ( /turf/open/indestructible/necropolis/ice, /area/icemoon/underground/explored) +"S" = ( +/obj/item/tcg_card/special/wendigo, +/turf/open/indestructible/necropolis/ice, +/area/icemoon/underground/explored) "U" = ( /obj/item/paper/crumpled/bloody{ info = "for your own sake, do not enter" @@ -451,7 +455,7 @@ a N N N -N +S N N N diff --git a/_maps/RandomRuins/LavaRuins/lavaland_biodome_clown_planet.dmm b/_maps/RandomRuins/LavaRuins/lavaland_biodome_clown_planet.dmm index 639d63772c..cd512e44b6 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_biodome_clown_planet.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_biodome_clown_planet.dmm @@ -862,6 +862,7 @@ /obj/structure/disposalpipe/segment{ dir = 10 }, +/obj/item/tcg_card/special/honk, /turf/open/floor/plating, /area/ruin/powered/clownplanet) "bF" = ( diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_dead_ratvar.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_dead_ratvar.dmm index d8713fd40a..134a692e41 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_dead_ratvar.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_dead_ratvar.dmm @@ -155,6 +155,12 @@ /obj/item/stack/tile/brass/fifty, /turf/open/floor/plating/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors/unexplored) +"Y" = ( +/obj/item/tcg_card/special/ratvar, +/turf/open/floor/clockwork{ + initial_gas_mix = "o2=14;n2=23;TEMP=300" + }, +/area/lavaland/surface/outdoors/unexplored) (1,1,1) = {" a @@ -484,7 +490,7 @@ h h h h -h +Y h l l @@ -709,7 +715,7 @@ b l l b -h +Y h t b diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_hierophant.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_hierophant.dmm index cad120c3f2..c307c2caae 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_hierophant.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_hierophant.dmm @@ -26,6 +26,10 @@ }, /turf/open/indestructible/hierophant/two, /area/ruin/unpowered/hierophant) +"s" = ( +/obj/item/tcg_card/special/hierophant, +/turf/open/indestructible/hierophant, +/area/ruin/unpowered/hierophant) (1,1,1) = {" a @@ -494,7 +498,7 @@ b b b c -b +s a a b diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_ufo_crash.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_ufo_crash.dmm index f4c8c7ea0e..7ac6d32b80 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_ufo_crash.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_ufo_crash.dmm @@ -11,6 +11,13 @@ "d" = ( /turf/closed/wall/mineral/abductor, /area/ruin/unpowered) +"h" = ( +/obj/structure/closet/abductor, +/obj/item/tcg_card/special/abductor, +/turf/open/floor/plating/abductor{ + initial_gas_mix = "o2=14;n2=23;TEMP=300" + }, +/area/ruin/unpowered) "j" = ( /obj/machinery/abductor/experiment{ team_number = 100 @@ -188,7 +195,7 @@ a a c d -q +h t q d diff --git a/_maps/RandomRuins/SpaceRuins/abandonedzoo.dmm b/_maps/RandomRuins/SpaceRuins/abandonedzoo.dmm index d83b4cf2c3..d4b0e65f2d 100644 --- a/_maps/RandomRuins/SpaceRuins/abandonedzoo.dmm +++ b/_maps/RandomRuins/SpaceRuins/abandonedzoo.dmm @@ -567,6 +567,7 @@ "bm" = ( /obj/structure/closet/wardrobe/science_white, /obj/structure/disposalpipe/segment, +/obj/item/tcg_card/special/space_carp, /turf/open/floor/plasteel{ icon_state = "dark" }, diff --git a/_maps/RandomRuins/SpaceRuins/caravanambush.dmm b/_maps/RandomRuins/SpaceRuins/caravanambush.dmm index a1171400e6..bba36470dd 100644 --- a/_maps/RandomRuins/SpaceRuins/caravanambush.dmm +++ b/_maps/RandomRuins/SpaceRuins/caravanambush.dmm @@ -16,8 +16,8 @@ /area/template_noop) "ae" = ( /obj/structure/fluff/broken_flooring{ - icon_state = "plating"; - dir = 4 + dir = 4; + icon_state = "plating" }, /turf/template_noop, /area/template_noop) @@ -66,8 +66,8 @@ "an" = ( /obj/structure/lattice, /obj/structure/fluff/broken_flooring{ - icon_state = "plating"; - dir = 4 + dir = 4; + icon_state = "plating" }, /turf/template_noop, /area/template_noop) @@ -78,8 +78,8 @@ "ap" = ( /obj/structure/lattice, /obj/structure/fluff/broken_flooring{ - icon_state = "pile"; - dir = 8 + dir = 8; + icon_state = "pile" }, /turf/template_noop, /area/template_noop) @@ -133,8 +133,8 @@ /area/template_noop) "aE" = ( /obj/structure/fluff/broken_flooring{ - icon_state = "pile"; - dir = 4 + dir = 4; + icon_state = "pile" }, /turf/template_noop, /area/template_noop) @@ -1054,6 +1054,7 @@ /obj/effect/decal/cleanable/dirt, /obj/structure/closet/crate/secure/weapon, /obj/item/gun/ballistic/automatic/pistol/APS, +/obj/item/tcg_card/special/spess_pirate, /turf/open/floor/plasteel/airless/dark, /area/shuttle/caravan/freighter2) "js" = ( diff --git a/_maps/RandomRuins/SpaceRuins/gondolaasteroid.dmm b/_maps/RandomRuins/SpaceRuins/gondolaasteroid.dmm index e3b105d06e..ab5086e534 100644 --- a/_maps/RandomRuins/SpaceRuins/gondolaasteroid.dmm +++ b/_maps/RandomRuins/SpaceRuins/gondolaasteroid.dmm @@ -91,6 +91,10 @@ }, /turf/open/floor/plating/asteroid/airless, /area/ruin/space/has_grav) +"Y" = ( +/obj/item/tcg_card/special/gondola, +/turf/open/floor/plating/asteroid/airless, +/area/ruin/space/has_grav) (1,1,1) = {" a @@ -339,7 +343,7 @@ b c c c -c +Y o c r diff --git a/_maps/RandomRuins/SpaceRuins/mechtransport.dmm b/_maps/RandomRuins/SpaceRuins/mechtransport.dmm index 6e35de07be..a9beb9540e 100644 --- a/_maps/RandomRuins/SpaceRuins/mechtransport.dmm +++ b/_maps/RandomRuins/SpaceRuins/mechtransport.dmm @@ -19,6 +19,7 @@ /area/ruin/space/has_grav/powered/mechtransport) "g" = ( /obj/structure/closet/crate/secure/loot, +/obj/item/tcg_card/special/phazon, /turf/open/floor/mineral/titanium/blue, /area/ruin/space/has_grav/powered/mechtransport) "h" = ( diff --git a/_maps/RandomZLevels/away_mission/SnowCabin.dmm b/_maps/RandomZLevels/away_mission/SnowCabin.dmm index fbb83899fd..dda382c4b7 100644 --- a/_maps/RandomZLevels/away_mission/SnowCabin.dmm +++ b/_maps/RandomZLevels/away_mission/SnowCabin.dmm @@ -881,7 +881,7 @@ /turf/open/floor/plating, /area/awaymission/cabin) "cT" = ( -/obj/vehicle/ridden/atv, +/obj/vehicle/ridden/atv/snowmobile, /turf/open/floor/plating{ icon_state = "platingdmg3" }, @@ -893,7 +893,7 @@ /turf/open/floor/plating, /area/awaymission/cabin) "cV" = ( -/obj/vehicle/ridden/atv, +/obj/vehicle/ridden/atv/snowmobile, /turf/open/floor/plating, /area/awaymission/cabin) "cW" = ( diff --git a/_maps/RandomZLevels/away_mission/jungleresort.dmm b/_maps/RandomZLevels/away_mission/jungleresort.dmm index d4698fec9a..9ff92b619a 100644 --- a/_maps/RandomZLevels/away_mission/jungleresort.dmm +++ b/_maps/RandomZLevels/away_mission/jungleresort.dmm @@ -14,7 +14,7 @@ "ai" = ( /obj/effect/turf_decal/sand/plating, /obj/structure/closet/crate/secure/loot, -/obj/item/clothing/head/collectable/paper, +/obj/item/clothing/head/sombrero/shamebrero, /turf/open/floor/plating, /area/awaymission/jungleresort) "ak" = ( @@ -51,6 +51,10 @@ /obj/machinery/jukebox, /turf/open/floor/wood, /area/awaymission/jungleresort) +"az" = ( +/obj/structure/stone_tile/center, +/turf/open/floor/plating/dirt/jungle, +/area/awaymission/jungleresort) "aA" = ( /obj/machinery/light, /obj/structure/chair/wood{ @@ -199,7 +203,7 @@ /area/awaymission/jungleresort) "cK" = ( /obj/structure/closet/crate, -/obj/item/clothing/head/collectable/tophat, +/obj/item/clothing/head/collectable/petehat/gang, /turf/open/floor/plating/rust, /area/awaymission/jungleresort) "cT" = ( @@ -217,6 +221,11 @@ /obj/structure/flora/rock, /turf/open/floor/plating/dirt/jungle, /area/awaymission/jungleresort) +"cY" = ( +/obj/structure/flora/grass/jungle/b, +/mob/living/simple_animal/hostile/gorilla/jungle, +/turf/open/floor/grass, +/area/awaymission/jungleresort) "dm" = ( /obj/structure/table/wood, /obj/item/reagent_containers/food/drinks/beer, @@ -274,7 +283,6 @@ dir = 9 }, /obj/structure/stone_tile/center/cracked, -/obj/item/ammo_casing/shotgun/buckshot, /turf/open/floor/plating/dirt/jungle, /area/awaymission/jungleresort) "eB" = ( @@ -407,8 +415,8 @@ /area/awaymission/jungleresort) "gK" = ( /obj/structure/table/wood, -/obj/item/gun/ballistic/automatic/l6_saw/toy/unrestricted/riot, -/obj/item/ammo_box/magazine/toy/m762/riot, +/obj/item/gun/ballistic/automatic/c20r/toy/unrestricted, +/obj/item/ammo_box/magazine/toy/smgm45, /turf/open/floor/wood, /area/awaymission/jungleresort) "gL" = ( @@ -580,6 +588,9 @@ dir = 1 }, /obj/structure/stone_tile/center/burnt, +/obj/structure/stone_tile/surrounding_tile/cracked{ + dir = 6 + }, /turf/open/floor/plating/dirt/jungle, /area/awaymission/jungleresort) "iE" = ( @@ -660,6 +671,11 @@ }, /turf/open/floor/grass, /area/awaymission/jungleresort) +"jw" = ( +/obj/structure/stone_tile/surrounding/cracked, +/obj/structure/stone_tile/center/burnt, +/turf/open/floor/plating/dirt/jungle, +/area/awaymission/jungleresort) "jy" = ( /obj/structure/flora/grass/jungle/b, /obj/effect/turf_decal/weather/dirt{ @@ -674,6 +690,16 @@ }, /turf/open/floor/grass, /area/awaymission/jungleresort) +"jD" = ( +/obj/structure/stone_tile/surrounding_tile/cracked, +/obj/structure/stone_tile/surrounding_tile/cracked{ + dir = 9 + }, +/obj/structure/stone_tile/surrounding_tile/cracked{ + dir = 6 + }, +/turf/open/floor/plating/dirt/jungle, +/area/awaymission/jungleresort) "jF" = ( /obj/structure/flora/tree/jungle, /obj/machinery/light, @@ -798,6 +824,11 @@ }, /turf/open/floor/wood, /area/awaymission/jungleresort) +"lF" = ( +/obj/structure/flora/junglebush, +/mob/living/simple_animal/hostile/gorilla/jungle, +/turf/open/floor/grass, +/area/awaymission/jungleresort) "lJ" = ( /obj/structure/flora/junglebush/c, /obj/machinery/light{ @@ -869,6 +900,8 @@ /obj/structure/cable{ icon_state = "2-4" }, +/obj/item/clothing/glasses/meson/engine, +/obj/item/storage/belt/utility, /turf/open/floor/plating, /area/awaymission/jungleresort) "mE" = ( @@ -986,6 +1019,10 @@ /obj/item/toy/crayon/spraycan, /turf/open/floor/plating/dirt/jungle, /area/awaymission/jungleresort) +"ou" = ( +/obj/item/clothing/glasses/meson, +/turf/open/floor/plating/asteroid, +/area/awaymission/jungleresort) "ow" = ( /obj/structure/flora/tree/jungle, /obj/effect/turf_decal/weather/dirt, @@ -993,7 +1030,7 @@ /area/awaymission/jungleresort) "oW" = ( /obj/effect/decal/remains/human, -/obj/item/clothing/head/collectable/petehat/gang, +/obj/item/clothing/head/collectable/tophat, /turf/open/floor/plating, /area/awaymission/jungleresort) "oX" = ( @@ -1075,7 +1112,7 @@ "qi" = ( /obj/effect/turf_decal/sand/plating, /obj/structure/closet/crate/secure/loot, -/obj/item/clothing/head/collectable/beret, +/obj/item/clothing/head/rice_hat/cursed, /turf/open/floor/plating, /area/awaymission/jungleresort) "qr" = ( @@ -1255,6 +1292,15 @@ /obj/effect/turf_decal/sand/plating, /turf/open/floor/plating, /area/awaymission/jungleresort) +"tm" = ( +/obj/structure/stone_tile/surrounding_tile/cracked{ + dir = 9 + }, +/obj/structure/stone_tile/surrounding_tile/cracked{ + dir = 1 + }, +/turf/open/floor/plating/dirt/jungle, +/area/awaymission/jungleresort) "tn" = ( /obj/structure/flora/rock/pile, /obj/machinery/light{ @@ -1478,6 +1524,15 @@ /obj/effect/turf_decal/weather/dirt, /turf/open/floor/grass, /area/awaymission/jungleresort) +"vz" = ( +/obj/structure/stone_tile/surrounding_tile/cracked{ + dir = 6 + }, +/obj/structure/stone_tile/surrounding/cracked{ + dir = 1 + }, +/turf/open/floor/plating/dirt/jungle, +/area/awaymission/jungleresort) "vK" = ( /obj/structure/flora/ausbushes/stalkybush, /turf/open/floor/grass, @@ -1497,6 +1552,10 @@ }, /turf/open/floor/wood, /area/awaymission/jungleresort) +"wd" = ( +/obj/item/storage/bag/ore, +/turf/open/floor/plating/asteroid, +/area/awaymission/jungleresort) "wj" = ( /obj/machinery/light{ dir = 1 @@ -1535,7 +1594,7 @@ /area/awaymission/jungleresort) "ww" = ( /obj/structure/closet/secure_closet/personal/cabinet, -/obj/item/clothing/suit/hooded/wintercoat/captain, +/obj/item/clothing/suit/hooded/wintercoat/captain/jungle, /turf/open/floor/carpet/blue, /area/awaymission/jungleresort) "wF" = ( @@ -1655,6 +1714,10 @@ }, /turf/open/floor/grass, /area/awaymission/jungleresort) +"yw" = ( +/obj/item/pickaxe/mini, +/turf/open/floor/plating/asteroid, +/area/awaymission/jungleresort) "yx" = ( /obj/structure/flora/ausbushes/fullgrass, /obj/effect/turf_decal/weather/dirt{ @@ -1814,6 +1877,13 @@ /obj/structure/flora/ausbushes/sparsegrass, /turf/open/floor/grass, /area/awaymission/jungleresort) +"Ad" = ( +/obj/structure/stone_tile/surrounding_tile/cracked{ + dir = 1 + }, +/obj/structure/stone_tile/surrounding_tile/cracked, +/turf/open/floor/plating/dirt/jungle, +/area/awaymission/jungleresort) "Ag" = ( /obj/machinery/door/airlock/wood{ name = "Resort Office" @@ -2016,6 +2086,7 @@ /obj/structure/window/reinforced{ dir = 4 }, +/obj/structure/window/reinforced, /turf/open/floor/carpet, /area/awaymission/jungleresort) "CV" = ( @@ -2329,6 +2400,9 @@ /obj/structure/stone_tile/surrounding_tile/cracked{ dir = 9 }, +/obj/structure/stone_tile/surrounding/cracked{ + dir = 1 + }, /turf/open/floor/plating/dirt/jungle, /area/awaymission/jungleresort) "GN" = ( @@ -2368,6 +2442,10 @@ }, /turf/open/floor/grass, /area/awaymission/jungleresort) +"Hr" = ( +/obj/structure/stone_tile/surrounding/cracked, +/turf/open/floor/plating/dirt/jungle, +/area/awaymission/jungleresort) "Hs" = ( /obj/structure/flora/ausbushes/stalkybush, /obj/machinery/light, @@ -2410,6 +2488,10 @@ }, /turf/open/floor/grass, /area/awaymission/jungleresort) +"HT" = ( +/mob/living/simple_animal/hostile/gorilla/jungle, +/turf/open/floor/grass, +/area/awaymission/jungleresort) "Ih" = ( /turf/open/floor/plating, /area/awaymission/jungleresort) @@ -2897,6 +2979,15 @@ /obj/item/storage/book/bible, /turf/open/floor/carpet, /area/awaymission/jungleresort) +"ON" = ( +/obj/effect/decal/cleanable/blood/splatter, +/obj/effect/decal/remains/human, +/obj/structure/stone_tile/burnt, +/obj/structure/stone_tile/surrounding_tile/cracked{ + dir = 1 + }, +/turf/open/floor/plating/dirt/jungle, +/area/awaymission/jungleresort) "OU" = ( /obj/effect/turf_decal/weather/dirt, /turf/open/floor/grass, @@ -3030,7 +3121,7 @@ /obj/effect/decal/cleanable/blood/tracks{ dir = 8 }, -/obj/structure/stone_tile/surrounding/cracked, +/obj/structure/stone_tile/center/burnt, /turf/open/floor/plating/dirt/jungle, /area/awaymission/jungleresort) "QA" = ( @@ -3091,6 +3182,7 @@ /obj/item/stack/sheet/mineral/uranium, /obj/item/stack/sheet/mineral/uranium, /obj/item/clothing/glasses/meson/engine, +/obj/item/storage/belt/utility, /turf/open/floor/plating, /area/awaymission/jungleresort) "Rm" = ( @@ -3224,11 +3316,8 @@ /obj/effect/decal/remains/human, /obj/effect/decal/cleanable/blood/old, /obj/structure/stone_tile/surrounding/cracked, -/obj/item/gun/ballistic/shotgun/sc_pump, /obj/item/clothing/suit/armor/vest, /obj/item/clothing/head/helmet, -/obj/item/ammo_casing/shotgun/buckshot, -/obj/item/ammo_casing/shotgun/buckshot, /turf/open/floor/plating/dirt/jungle, /area/awaymission/jungleresort) "SV" = ( @@ -3246,6 +3335,7 @@ /obj/structure/stone_tile/surrounding_tile/cracked{ dir = 5 }, +/obj/structure/stone_tile/burnt, /turf/open/floor/plating/dirt/jungle, /area/awaymission/jungleresort) "Ta" = ( @@ -3290,6 +3380,7 @@ /obj/structure/stone_tile/surrounding_tile/cracked{ dir = 9 }, +/obj/structure/stone_tile/center, /turf/open/floor/plating/dirt/jungle, /area/awaymission/jungleresort) "TG" = ( @@ -3508,7 +3599,7 @@ /area/awaymission/jungleresort) "WD" = ( /obj/effect/decal/remains/human, -/obj/item/clothing/head/collectable/slime, +/obj/item/clothing/head/collectable/beret, /turf/open/floor/plating/rust, /area/awaymission/jungleresort) "WE" = ( @@ -3573,6 +3664,11 @@ }, /turf/open/floor/plating/dirt/jungle, /area/awaymission/jungleresort) +"Xu" = ( +/obj/structure/flora/junglebush/c, +/mob/living/simple_animal/hostile/gorilla/jungle, +/turf/open/floor/grass, +/area/awaymission/jungleresort) "Xz" = ( /turf/open/floor/carpet/red, /area/awaymission/jungleresort) @@ -3639,6 +3735,7 @@ "Ye" = ( /obj/structure/closet/secure_closet/personal/cabinet, /obj/item/toy/figure/syndie, +/obj/item/gun/ballistic/automatic/toy/pistol/unrestricted, /turf/open/floor/carpet/red, /area/awaymission/jungleresort) "Yf" = ( @@ -3748,6 +3845,9 @@ dir = 8 }, /obj/structure/stone_tile/surrounding_tile/burnt, +/obj/structure/stone_tile/surrounding_tile/cracked{ + dir = 9 + }, /turf/open/floor/plating/dirt/jungle, /area/awaymission/jungleresort) "ZH" = ( @@ -6362,8 +6462,8 @@ AR AR AR AR -AR oZ +jD aL fy Dr @@ -6513,8 +6613,8 @@ AR AR AR AR -AR -AR +oZ +Gk AC GD oZ @@ -6668,8 +6768,8 @@ AR oZ iv Qz -AR -AR +tm +oZ AR AR AR @@ -6819,6 +6919,7 @@ AR oZ wS SZ +Hr oZ AR AR @@ -6834,7 +6935,6 @@ AR AR AR AR -AR rd AF YQ @@ -6967,11 +7067,11 @@ AR AR AR AR -AR -AR -yJ oZ -AR +aL +yJ +TD +oZ AR AR AR @@ -7122,6 +7222,8 @@ AR AR oZ Yp +az +ON oZ AR AR @@ -7137,8 +7239,6 @@ AR AR AR AR -AR -AR YQ YM cn @@ -7166,7 +7266,7 @@ YQ YQ CN YQ -YQ +HT rd YQ YQ @@ -7274,6 +7374,8 @@ AR AR oZ TD +Ad +jw oZ AR AR @@ -7289,8 +7391,6 @@ AR AR AR AR -AR -AR YQ aP Wl @@ -7427,7 +7527,7 @@ AR oZ aL Xs -AR +oZ AR AR AR @@ -7579,7 +7679,7 @@ AR AR oZ tH -AR +vz AR AR AR @@ -8261,7 +8361,7 @@ YQ YQ MW CN -AF +lF Wl YQ YQ @@ -9006,7 +9106,7 @@ YQ CN YQ YQ -YQ +HT Wl aP YQ @@ -9807,7 +9907,7 @@ YQ YQ YQ YQ -YQ +HT YQ YQ YQ @@ -10950,7 +11050,7 @@ YQ YQ Fz wH -YQ +HT YQ YQ VU @@ -11390,9 +11490,9 @@ AR AR AR io -uh -pQ -pQ +VJ +AV +AV QA dF io @@ -11544,8 +11644,8 @@ AR AR AR AR -AR -pQ +io +VJ AV QA QA @@ -14218,7 +14318,7 @@ YQ cn ZV MW -YQ +HT rd aP vK @@ -15051,7 +15151,7 @@ Wl YQ YQ YQ -YQ +HT rd YQ YQ @@ -18177,8 +18277,8 @@ YQ YQ YQ AF -AR -AR +yw +ou AR AR AR @@ -18329,9 +18429,9 @@ YQ YM Wl Pg -AR -AR -AR +wd +Qp +Qp AR AR AR @@ -20699,7 +20799,7 @@ YQ YQ YQ MW -rd +cY Wl YQ YQ @@ -22732,7 +22832,7 @@ AF ZV YQ YQ -cn +Xu YQ YQ YQ @@ -23322,7 +23422,7 @@ YQ CN VU dY -YQ +HT YQ aP YQ @@ -23577,7 +23677,7 @@ YQ YQ YQ vK -YQ +HT kr YQ AF diff --git a/_maps/map_files/BoxStation/BoxStation.dmm b/_maps/map_files/BoxStation/BoxStation.dmm index 888b7b7ed6..031b7b4d16 100644 --- a/_maps/map_files/BoxStation/BoxStation.dmm +++ b/_maps/map_files/BoxStation/BoxStation.dmm @@ -13605,13 +13605,10 @@ /obj/structure/cable{ icon_state = "1-2" }, -/obj/structure/disposalpipe/sorting/mail{ - dir = 2; - sortType = 18 - }, /obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{ dir = 4 }, +/obj/structure/disposalpipe/segment, /turf/open/floor/plating, /area/maintenance/starboard/fore) "aEB" = ( @@ -56987,6 +56984,17 @@ icon_state = "wood-broken6" }, /area/maintenance/bar) +"lqO" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden, +/obj/structure/disposalpipe/sorting/mail/flip{ + dir = 1; + sortType = 18 + }, +/turf/open/floor/plating, +/area/maintenance/fore) "lre" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden, /obj/structure/table/wood/poker, @@ -57108,6 +57116,12 @@ }, /turf/closed/wall, /area/maintenance/disposal/incinerator) +"lLf" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/closed/wall/r_wall, +/area/maintenance/fore) "lMg" = ( /obj/effect/turf_decal/stripes/line{ dir = 9 @@ -58655,8 +58669,11 @@ /obj/structure/cable{ icon_state = "1-2" }, -/obj/machinery/door/airlock/vault, /obj/effect/mapping_helpers/airlock/locked, +/obj/machinery/door/airlock/vault{ + name = "Vault Door"; + req_access_txt = "53" + }, /turf/open/floor/plasteel/dark, /area/ai_monitored/nuke_storage) "puh" = ( @@ -58822,6 +58839,14 @@ }, /turf/open/floor/plating, /area/maintenance/disposal) +"pMQ" = ( +/obj/structure/window/reinforced, +/obj/machinery/disposal/bin, +/obj/structure/disposalpipe/trunk{ + dir = 4 + }, +/turf/open/floor/wood, +/area/crew_quarters/theatre) "pPi" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 4 @@ -60860,11 +60885,13 @@ /obj/structure/cable{ icon_state = "2-8" }, -/obj/structure/disposalpipe/junction, /obj/effect/turf_decal/tile/neutral{ dir = 8 }, /obj/effect/turf_decal/tile/neutral, +/obj/structure/disposalpipe/sorting/mail{ + sortType = 26 + }, /turf/open/floor/plasteel, /area/crew_quarters/dorms) "uys" = ( @@ -61051,7 +61078,6 @@ /area/science/circuit) "uOJ" = ( /obj/effect/mapping_helpers/airlock/locked, -/obj/machinery/door/airlock/vault, /obj/structure/cable{ icon_state = "1-2" }, @@ -61065,6 +61091,10 @@ /obj/effect/turf_decal/tile/neutral{ dir = 8 }, +/obj/machinery/door/airlock/vault{ + name = "Vault Door"; + req_access_txt = "53" + }, /turf/open/floor/plasteel/dark, /area/ai_monitored/nuke_storage) "uQR" = ( @@ -84618,7 +84648,7 @@ ayD nez ngV xPY -aOH +pMQ hcb hcb syJ @@ -84875,7 +84905,7 @@ ayE ayE ayE ayE -ayE +lLf ayE ayE ayE @@ -85132,7 +85162,7 @@ ayH ayH ayH ayH -ayH +lqO ayH aFV ayH diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index 79193b3186..1f7bf25feb 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -47138,13 +47138,9 @@ /turf/open/floor/plasteel, /area/engine/gravity_generator) "bEx" = ( -/obj/structure/closet/radiation, /obj/machinery/light/small{ dir = 1 }, -/obj/structure/extinguisher_cabinet{ - pixel_x = 26 - }, /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 4 }, @@ -48383,7 +48379,10 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 4 }, -/obj/machinery/light/small, +/obj/structure/extinguisher_cabinet{ + pixel_x = 26 + }, +/obj/structure/closet/radiation, /turf/open/floor/plasteel, /area/engine/gravity_generator) "bGg" = ( @@ -49543,6 +49542,9 @@ /obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{ dir = 4 }, +/obj/machinery/light/small{ + dir = 4 + }, /turf/open/floor/plasteel, /area/engine/gravity_generator) "bHV" = ( diff --git a/code/__DEFINES/configuration.dm b/code/__DEFINES/configuration.dm index 0428a16828..9915563cab 100644 --- a/code/__DEFINES/configuration.dm +++ b/code/__DEFINES/configuration.dm @@ -22,3 +22,5 @@ #define POLICYCONFIG_ON_DEFIB_LATE "ON_DEFIB_LATE" /// Displayed to pyroclastic slimes on spawn #define POLICYCONFIG_ON_PYROCLASTIC_SENTIENT "PYROCLASTIC_SLIME" +/// Displayed to pAIs on spawn +#define POLICYCONFIG_PAI "PAI_SPAWN" diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index a1bb4122a8..42199174e7 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -290,7 +290,7 @@ #define COMSIG_LIVING_ACTIVE_BLOCK_START "active_block_start" //from base of mob/living/keybind_start_active_blocking(): (obj/item/blocking_item, list/backup_items) #define COMPONENT_PREVENT_BLOCK_START 1 -#define COMSIG_LIVING_ACTIVE_PARRY_START "active_parry_start" //from base of mob/living/initiate_parry_sequence(): (parrying_method, datum/parrying_item_mob_or_art, list/backup_items) +#define COMSIG_LIVING_ACTIVE_PARRY_START "active_parry_start" //from base of mob/living/initiate_parry_sequence(): (parrying_method, datum/parrying_item_mob_or_art, list/backup_items, list/override) #define COMPONENT_PREVENT_PARRY_START 1 //ALL OF THESE DO NOT TAKE INTO ACCOUNT WHETHER AMOUNT IS 0 OR LOWER AND ARE SENT REGARDLESS! diff --git a/code/__DEFINES/instruments.dm b/code/__DEFINES/instruments.dm index 3c414f87f4..69d2a60e51 100644 --- a/code/__DEFINES/instruments.dm +++ b/code/__DEFINES/instruments.dm @@ -19,7 +19,7 @@ #define INSTRUMENT_EXP_FALLOFF_MAX 10 /// Minimum volume for when the sound is considered dead. -#define INSTRUMENT_MIN_SUSTAIN_DROPOFF 0 +#define INSTRUMENT_MIN_SUSTAIN_DROPOFF 1 #define SUSTAIN_LINEAR 1 #define SUSTAIN_EXPONENTIAL 2 diff --git a/code/__DEFINES/language.dm b/code/__DEFINES/language.dm index add4a8e277..798ea478c2 100644 --- a/code/__DEFINES/language.dm +++ b/code/__DEFINES/language.dm @@ -24,3 +24,4 @@ #define LANGUAGE_STONER "stoner" #define LANGUAGE_VASSAL "vassal" #define LANGUAGE_VOICECHANGE "voicechange" +#define LANGUAGE_MULTILINGUAL "multilingual" diff --git a/code/__DEFINES/robots.dm b/code/__DEFINES/robots.dm index a0fded3798..dda9cfd430 100644 --- a/code/__DEFINES/robots.dm +++ b/code/__DEFINES/robots.dm @@ -69,8 +69,8 @@ //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)) -//silicon_priviledges flags -#define PRIVILEDGES_SILICON (1<<0) -#define PRIVILEDGES_PAI (1<<1) -#define PRIVILEDGES_BOT (1<<2) -#define PRIVILEDGES_DRONE (1<<3) +//silicon_privileges flags +#define PRIVILEGES_SILICON (1<<0) +#define PRIVILEGES_PAI (1<<1) +#define PRIVILEGES_BOT (1<<2) +#define PRIVILEGES_DRONE (1<<3) diff --git a/code/__DEFINES/say.dm b/code/__DEFINES/say.dm index 57484ae85b..9403eca2da 100644 --- a/code/__DEFINES/say.dm +++ b/code/__DEFINES/say.dm @@ -86,8 +86,8 @@ #define EMOTE_OMNI 4 //Don't set this very much higher then 1024 unless you like inviting people in to dos your server with message spam -#define MAX_MESSAGE_LEN 2048 //Citadel edit: What's the WORST that could happen? -#define MAX_FLAVOR_LEN 4096 //double the maximum message length. +#define MAX_MESSAGE_LEN 4096 //Citadel edit: What's the WORST that could happen? +#define MAX_FLAVOR_LEN 4096 #define MAX_TASTE_LEN 40 //lick... vore... ew... #define MAX_NAME_LEN 42 #define MAX_BROADCAST_LEN 512 diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 642c80109a..66c4f808ff 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -219,7 +219,7 @@ ///Compile all the overlays for an atom from the cache lists // |= on overlays is not actually guaranteed to not add same appearances but we're optimistically using it anyway. #define COMPILE_OVERLAYS(A)\ - if (TRUE) {\ + do {\ var/list/ad = A.add_overlays;\ var/list/rm = A.remove_overlays;\ if(LAZYLEN(rm)){\ @@ -231,7 +231,7 @@ ad.Cut();\ }\ A.flags_1 &= ~OVERLAY_QUEUED_1;\ - } + } while(FALSE) /** diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index b7750556d5..8e0886a30d 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -191,12 +191,14 @@ #define TRAIT_MUSICIAN "musician" #define TRAIT_PERMABONER "permanent_arousal" #define TRAIT_NEVERBONER "never_aroused" +#define TRAIT_NYMPHO "nymphomaniac" #define TRAIT_MASO "masochism" #define TRAIT_HIGH_BLOOD "high_blood" #define TRAIT_PARA "paraplegic" #define TRAIT_EMPATH "empath" #define TRAIT_FRIENDLY "friendly" #define TRAIT_SNOB "snob" +#define TRAIT_MULTILINGUAL "multilingual" #define TRAIT_CULT_EYES "cult_eyes" #define TRAIT_AUTO_CATCH_ITEM "auto_catch_item" #define TRAIT_CLOWN_MENTALITY "clown_mentality" // The future is now, clownman. diff --git a/code/__HELPERS/_lists.dm b/code/__HELPERS/_lists.dm index 47a4387233..31f34c5d4c 100644 --- a/code/__HELPERS/_lists.dm +++ b/code/__HELPERS/_lists.dm @@ -66,7 +66,7 @@ } while(FALSE) //Returns a list in plain english as a string -/proc/english_list(list/input, nothing_text = "nothing", and_text = " and ", comma_text = ", ", final_comma_text = "" ) +/proc/english_list(list/input, nothing_text = "nothing", and_text = " and ", comma_text = ", ", final_comma_text = "") var/total = length(input) switch(total) if (0) @@ -87,6 +87,34 @@ return "[output][and_text][input[index]]" +/** + * English_list but associative supporting. Higher overhead. + */ +/proc/english_list_assoc(list/input, nothing_text = "nothing", and_text = " and ", comma_text = ", ", final_comma_text = "") + var/total = length(input) + switch(total) + if (0) + return "[nothing_text]" + if (1) + var/assoc = input[input[1]] == null? "" : " = [input[input[1]]]" + return "[input[1]][assoc]" + if (2) + var/assoc = input[input[1]] == null? "" : " = [input[input[1]]]" + var/assoc2 = input[input[2]] == null? "" : " = [input[input[2]]]" + return "[input[1]][assoc][and_text][input[2]][assoc2]" + else + var/output = "" + var/index = 1 + var/assoc + while (index < total) + if (index == total - 1) + comma_text = final_comma_text + assoc = input[input[index]] == null? "" : " = [input[input[index]]]" + output += "[input[index]][assoc][comma_text]" + ++index + assoc = input[input[index]] == null? "" : " = [input[input[index]]]" + return "[output][and_text][input[index]]" + //Returns list element or null. Should prevent "index out of bounds" error. /proc/listgetindex(list/L, index) if(LAZYLEN(L)) diff --git a/code/__HELPERS/_logging.dm b/code/__HELPERS/_logging.dm index 18d02229dd..8464e373d5 100644 --- a/code/__HELPERS/_logging.dm +++ b/code/__HELPERS/_logging.dm @@ -231,10 +231,10 @@ src_object = window.locked_by.src_object // Insert src_object info if(src_object) - entry += "\nUsing: [src_object.type] [REF(src_object)]" + entry += "Using: [src_object.type] [REF(src_object)]" // Insert message if(message) - entry += "\n[message]" + entry += "[message]" WRITE_LOG(GLOB.tgui_log, entry) /* Close open log handles. This should be called as late as possible, and no logging should hapen after. */ diff --git a/code/__HELPERS/priority_announce.dm b/code/__HELPERS/priority_announce.dm index d06912b701..374e89f715 100644 --- a/code/__HELPERS/priority_announce.dm +++ b/code/__HELPERS/priority_announce.dm @@ -10,7 +10,7 @@ announcement += "

[html_encode(title)]

" else if(type == "Captain") announcement += "

Captain Announces

" - GLOB.news_network.SubmitArticle(text, "Captain's Announcement", "Station Announcements", null) + GLOB.news_network.SubmitArticle(html_encode(text), "Captain's Announcement", "Station Announcements", null) else if(!sender_override) diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm index a860a8cd3f..6f7eeb95c3 100644 --- a/code/__HELPERS/roundend.dm +++ b/code/__HELPERS/roundend.dm @@ -242,6 +242,8 @@ SSpersistence.station_was_destroyed = TRUE if(!mode.allow_persistence_save) SSpersistence.station_persistence_save_disabled = TRUE + else + SSpersistence.SaveTCGCards() SSpersistence.CollectData() //stop collecting feedback during grifftime diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 9f89920b46..71bbfe64fe 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -263,7 +263,7 @@ Turf and target are separate in case you want to teleport some distance from a t return . //Returns a list of all items of interest with their name -/proc/getpois(mobs_only=0,skip_mindless=0) +/proc/getpois(mobs_only = FALSE, skip_mindless = FALSE, specify_dead_role = TRUE) var/list/mobs = sortmobs() var/list/namecounts = list() var/list/pois = list() @@ -277,7 +277,7 @@ Turf and target are separate in case you want to teleport some distance from a t if(M.real_name && M.real_name != M.name) name += " \[[M.real_name]\]" - if(M.stat == DEAD) + if(M.stat == DEAD && specify_dead_role) if(isobserver(M)) name += " \[ghost\]" else diff --git a/code/_globalvars/traits.dm b/code/_globalvars/traits.dm index f376ba50d7..ac6ea4e25c 100644 --- a/code/_globalvars/traits.dm +++ b/code/_globalvars/traits.dm @@ -132,6 +132,9 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_NODROP" = TRAIT_NODROP, "TRAIT_NO_TELEPORT" = TRAIT_NO_TELEPORT, "TRAIT_SPOOKY_THROW" = TRAIT_SPOOKY_THROW + ), + /datum/mind = list( + "TRAIT_CLOWN_MENTALITY" = TRAIT_CLOWN_MENTALITY ) )) diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm index 04141becf2..841a3e8303 100644 --- a/code/_onclick/hud/human.dm +++ b/code/_onclick/hud/human.dm @@ -118,27 +118,7 @@ action_intent.hud = src static_inventory += action_intent - using = new /obj/screen/mov_intent - using.icon = tg_ui_icon_to_cit_ui(ui_style) // CIT CHANGE - overrides mov intent icon - using.icon_state = (mymob.m_intent == MOVE_INTENT_RUN ? "running" : "walking") - using.screen_loc = ui_movi - using.hud = src - static_inventory += using - - //CITADEL CHANGES - sprint button - using = new /obj/screen/sprintbutton - using.icon = tg_ui_icon_to_cit_ui(ui_style) - using.icon_state = ((owner.combat_flags & COMBAT_FLAG_SPRINT_ACTIVE) ? "act_sprint_on" : "act_sprint") - using.screen_loc = ui_movi - using.hud = src - static_inventory += using - //END OF CITADEL CHANGES - - //same as above but buffer. - sprint_buffer = new /obj/screen/sprint_buffer - sprint_buffer.screen_loc = ui_sprintbufferloc - sprint_buffer.hud = src - static_inventory += sprint_buffer + assert_move_intent_ui(owner, TRUE) // clickdelay clickdelay = new @@ -393,6 +373,51 @@ update_locked_slots() +/datum/hud/human/proc/assert_move_intent_ui(mob/living/carbon/human/owner = mymob, on_new = FALSE) + var/obj/screen/using + // delete old ones + var/list/obj/screen/victims = list() + victims += locate(/obj/screen/mov_intent) in static_inventory + victims += locate(/obj/screen/sprintbutton) in static_inventory + victims += locate(/obj/screen/sprint_buffer) in static_inventory + if(victims) + static_inventory -= victims + if(mymob?.client) + mymob.client.screen -= victims + QDEL_LIST(victims) + + // make new ones + // walk/run + using = new /obj/screen/mov_intent + using.icon = tg_ui_icon_to_cit_ui(ui_style) // CIT CHANGE - overrides mov intent icon + using.screen_loc = ui_movi + using.hud = src + using.update_icon() + static_inventory += using + if(!on_new) + owner?.client?.screen += using + + if(!CONFIG_GET(flag/sprint_enabled)) + return + + // sprint button + using = new /obj/screen/sprintbutton + using.icon = tg_ui_icon_to_cit_ui(ui_style) + using.icon_state = ((owner.combat_flags & COMBAT_FLAG_SPRINT_ACTIVE) ? "act_sprint_on" : "act_sprint") + using.screen_loc = ui_movi + using.hud = src + static_inventory += using + if(!on_new) + owner?.client?.screen += using + + // same as above but buffer. + sprint_buffer = new /obj/screen/sprint_buffer + sprint_buffer.screen_loc = ui_sprintbufferloc + sprint_buffer.hud = src + static_inventory += sprint_buffer + if(!on_new) + owner?.client?.screen += using + /datum/hud/human/update_locked_slots() if(!mymob) return diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index 53915ff42b..64515260ec 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -351,6 +351,10 @@ icon = 'icons/mob/screen_midnight.dmi' icon_state = "running" +/obj/screen/mov_intent/Initialize(mapload) + . = ..() + update_icon() + /obj/screen/mov_intent/Click() toggle(usr) @@ -359,7 +363,7 @@ if(MOVE_INTENT_WALK) icon_state = "walking" if(MOVE_INTENT_RUN) - icon_state = "running" + icon_state = CONFIG_GET(flag/sprint_enabled)? "running" : "running_nosprint" /obj/screen/mov_intent/proc/toggle(mob/user) if(isobserver(user)) diff --git a/code/controllers/configuration/entries/game_options.dm b/code/controllers/configuration/entries/game_options.dm index dc8e9e1859..4034722417 100644 --- a/code/controllers/configuration/entries/game_options.dm +++ b/code/controllers/configuration/entries/game_options.dm @@ -290,6 +290,17 @@ var/datum/movespeed_modifier/config_walk_run/M = get_cached_movespeed_modifier(/datum/movespeed_modifier/config_walk_run/walk) M.sync() +/datum/config_entry/flag/sprint_enabled + config_entry_value = TRUE + +/datum/config_entry/flag/sprint_enabled/ValidateAndSet(str_val) + . = ..() + for(var/datum/hud/human/H) + H.assert_move_intent_ui() + if(!config_entry_value) // disabled + for(var/mob/living/L in world) + L.disable_intentional_sprint_mode() + /datum/config_entry/number/movedelay/sprint_speed_increase config_entry_value = 1 @@ -484,6 +495,8 @@ /datum/config_entry/flag/modetier_voting +/datum/config_entry/flag/must_be_readied_to_vote_gamemode + /datum/config_entry/number/dropped_modes config_entry_value = 3 diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm index 3c93952b65..4d985c7234 100644 --- a/code/controllers/configuration/entries/general.dm +++ b/code/controllers/configuration/entries/general.dm @@ -26,50 +26,6 @@ /datum/config_entry/flag/hub // if the game appears on the hub or not -/datum/config_entry/flag/log_ooc // log OOC channel - -/datum/config_entry/flag/log_access // log login/logout - -/datum/config_entry/flag/log_say // log client say - -/datum/config_entry/flag/log_admin // log admin actions - protection = CONFIG_ENTRY_LOCKED - -/datum/config_entry/flag/log_prayer // log prayers - -/datum/config_entry/flag/log_law // log lawchanges - -/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_craft // log crafting - -/datum/config_entry/flag/log_whisper // log client whisper - -/datum/config_entry/flag/log_attack // log attack messages - -/datum/config_entry/flag/log_emote // log emotes - -/datum/config_entry/flag/log_adminchat // log admin chat messages - protection = CONFIG_ENTRY_LOCKED - -/datum/config_entry/flag/log_shuttle // log shuttle related actions, ie shuttle computers, shuttle manipulator, emergency console - -/datum/config_entry/flag/log_pda // log pda messages - -/datum/config_entry/flag/log_telecomms // log telecomms messages - -/datum/config_entry/flag/log_twitter // log certain expliotable parrots and other such fun things in a JSON file of twitter valid phrases. - -/datum/config_entry/flag/log_world_topic // log all world.Topic() calls - -/datum/config_entry/flag/log_manifest // log crew manifest to seperate file - -/datum/config_entry/flag/log_job_debug // log roundstart divide occupations debug information to a file - /datum/config_entry/flag/allow_admin_ooccolor // Allows admins with relevant permissions to have their own ooc colour /datum/config_entry/flag/allow_vote_restart // allow votes to restart @@ -472,10 +428,6 @@ /datum/config_entry/string/default_view_square config_entry_value = "15x15" -/datum/config_entry/flag/log_pictures - -/datum/config_entry/flag/picture_logging_camera - /datum/config_entry/number/max_bunker_days config_entry_value = 7 min_val = 1 diff --git a/code/controllers/configuration/entries/logging.dm b/code/controllers/configuration/entries/logging.dm new file mode 100644 index 0000000000..1cb47d6ab7 --- /dev/null +++ b/code/controllers/configuration/entries/logging.dm @@ -0,0 +1,70 @@ +/datum/config_entry/flag/log_ooc // log OOC channel + config_entry_value = TRUE + +/datum/config_entry/flag/log_access // log login/logout + config_entry_value = TRUE + +/datum/config_entry/flag/log_say // log client say + config_entry_value = TRUE + +/datum/config_entry/flag/log_admin // log admin actions + protection = CONFIG_ENTRY_LOCKED + +/datum/config_entry/flag/log_prayer // log prayers + config_entry_value = TRUE + +/datum/config_entry/flag/log_law // log lawchanges + config_entry_value = TRUE + +/datum/config_entry/flag/log_game // log game events + config_entry_value = TRUE + +/datum/config_entry/flag/log_virus // log virology data + config_entry_value = TRUE + +/datum/config_entry/flag/log_vote // log voting + config_entry_value = TRUE + +/datum/config_entry/flag/log_craft // log crafting + config_entry_value = TRUE + +/datum/config_entry/flag/log_whisper // log client whisper + config_entry_value = TRUE + +/datum/config_entry/flag/log_attack // log attack messages + config_entry_value = TRUE + +/datum/config_entry/flag/log_emote // log emotes + config_entry_value = TRUE + +/datum/config_entry/flag/log_adminchat // log admin chat messages + protection = CONFIG_ENTRY_LOCKED + +/datum/config_entry/flag/log_shuttle // log shuttle related actions, ie shuttle computers, shuttle manipulator, emergency console + config_entry_value = TRUE + +/datum/config_entry/flag/log_pda // log pda messages + config_entry_value = TRUE + +/datum/config_entry/flag/log_telecomms // log telecomms messages + config_entry_value = TRUE + +/datum/config_entry/flag/log_twitter // log certain expliotable parrots and other such fun things in a JSON file of twitter valid phrases. + config_entry_value = TRUE + +/datum/config_entry/flag/log_world_topic // log all world.Topic() calls + config_entry_value = TRUE + +/datum/config_entry/flag/log_manifest // log crew manifest to seperate file + config_entry_value = TRUE + +/datum/config_entry/flag/log_job_debug // log roundstart divide occupations debug information to a file + config_entry_value = TRUE + +/datum/config_entry/flag/log_pictures + +/datum/config_entry/flag/picture_logging_camera + +/// forces log_href for tgui +/datum/config_entry/flag/emergency_tgui_logging + config_entry_value = FALSE diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm index 165f6e9d81..c090d7367c 100644 --- a/code/controllers/subsystem/job.dm +++ b/code/controllers/subsystem/job.dm @@ -490,6 +490,43 @@ SUBSYSTEM_DEF(job) job.after_spawn(H, M, joined_late) // note: this happens before the mob has a key! M will always have a client, H might not. equip_loadout(N, H, TRUE)//CIT CHANGE - makes players spawn with in-backpack loadout items properly. A little hacky but it works + if(ishuman(H) && H.client && N) + if(H.client && H.client.prefs && length(H.client.prefs.tcg_cards)) + var/obj/item/tcgcard_binder/binder = new(get_turf(H)) + H.equip_to_slot_if_possible(binder, SLOT_IN_BACKPACK, disable_warning = TRUE, bypass_equip_delay_self = TRUE) + for(var/card_type in H.client.prefs.tcg_cards) + if(card_type) + if(islist(H.client.prefs.tcg_cards[card_type])) + for(var/duplicate in H.client.prefs.tcg_cards[card_type]) + var/obj/item/tcg_card/card = new(get_turf(H), card_type, duplicate) + card.forceMove(binder) + binder.cards.Add(card) + else + var/obj/item/tcg_card/card = new(get_turf(H), card_type, H.client.prefs.tcg_cards[card_type]) + card.forceMove(binder) + binder.cards.Add(card) + binder.check_for_exodia() + if(length(H.client.prefs.tcg_decks)) + binder.decks = H.client.prefs.tcg_decks + else + if(H && N.client.prefs && length(N.client.prefs.tcg_cards)) + var/obj/item/tcgcard_binder/binder = new(get_turf(H)) + H.equip_to_slot_if_possible(binder, SLOT_IN_BACKPACK, disable_warning = TRUE, bypass_equip_delay_self = TRUE) + for(var/card_type in N.client.prefs.tcg_cards) + if(card_type) + if(islist(H.client.prefs.tcg_cards[card_type])) + for(var/duplicate in N.client.prefs.tcg_cards[card_type]) + var/obj/item/tcg_card/card = new(get_turf(H), card_type, duplicate) + card.forceMove(binder) + binder.cards.Add(card) + else + var/obj/item/tcg_card/card = new(get_turf(H), card_type, N.client.prefs.tcg_cards[card_type]) + card.forceMove(binder) + binder.cards.Add(card) + binder.check_for_exodia() + if(length(N.client.prefs.tcg_decks)) + binder.decks = N.client.prefs.tcg_decks + return H /* /datum/controller/subsystem/job/proc/handle_auto_deadmin_roles(client/C, rank) diff --git a/code/controllers/subsystem/persistence/_persistence.dm b/code/controllers/subsystem/persistence/_persistence.dm index e8faf80e5d..d494561d0f 100644 --- a/code/controllers/subsystem/persistence/_persistence.dm +++ b/code/controllers/subsystem/persistence/_persistence.dm @@ -349,3 +349,15 @@ SUBSYSTEM_DEF(persistence) if(!ending_human.client) return ending_human.client.prefs.save_character() + +/datum/controller/subsystem/persistence/proc/SaveTCGCards() + for(var/i in GLOB.joined_player_list) + var/mob/living/carbon/human/ending_human = get_mob_by_ckey(i) + if(!istype(ending_human) || !ending_human.mind || !ending_human.client || !ending_human.client.prefs || !ending_human.client.prefs.tcg_cards) + continue + + var/mob/living/carbon/human/original_human = ending_human.mind.original_character + if(!original_human || original_human.stat == DEAD || !(original_human == ending_human)) + continue + + ending_human.SaveTCGCards() diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index fb8299d108..2474a6f272 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -68,6 +68,10 @@ SUBSYSTEM_DEF(vote) //get the highest number of votes var/greatest_votes = 0 var/total_votes = 0 + if(mode == "gamemode" && CONFIG_GET(flag/must_be_readied_to_vote_gamemode)) + for(var/mob/dead/new_player/P in GLOB.player_list) + if(P.ready != PLAYER_READY_TO_PLAY && voted[P.ckey]) + choices[choices[voted[P.ckey]]]-- for(var/option in choices) var/votes = choices[option] total_votes += votes @@ -101,6 +105,10 @@ SUBSYSTEM_DEF(vote) /datum/controller/subsystem/vote/proc/calculate_condorcet_votes(var/blackbox_text) // https://en.wikipedia.org/wiki/Schulze_method#Implementation + if((mode == "gamemode" || mode == "dynamic") && CONFIG_GET(flag/must_be_readied_to_vote_gamemode)) + for(var/mob/dead/new_player/P in GLOB.player_list) + if(P.ready != PLAYER_READY_TO_PLAY && voted[P.ckey]) + voted -= P.ckey var/list/d[][] = new/list(choices.len,choices.len) // the basic vote matrix, how many times a beats b for(var/ckey in voted) var/list/this_vote = voted[ckey] @@ -147,6 +155,10 @@ SUBSYSTEM_DEF(vote) for(var/choice in choices) scores_by_choice += "[choice]" scores_by_choice["[choice]"] = list() + if((mode == "gamemode" || mode == "dynamic") && CONFIG_GET(flag/must_be_readied_to_vote_gamemode)) + for(var/mob/dead/new_player/P in GLOB.player_list) + if(P.ready != PLAYER_READY_TO_PLAY && voted[P.ckey]) + voted -= P.ckey for(var/ckey in voted) var/list/this_vote = voted[ckey] var/list/pretty_vote = list() diff --git a/code/datums/components/crafting/recipes/recipes_misc.dm b/code/datums/components/crafting/recipes/recipes_misc.dm index 1f4a47c474..d85df8c010 100644 --- a/code/datums/components/crafting/recipes/recipes_misc.dm +++ b/code/datums/components/crafting/recipes/recipes_misc.dm @@ -45,8 +45,8 @@ /datum/crafting_recipe/bloodsucker/blackcoffin name = "Black Coffin" result = /obj/structure/closet/crate/coffin/blackcoffin - tools = list(/obj/item/weldingtool, - /obj/item/screwdriver) + tools = list(TOOL_WELDER, + TOOL_SCREWDRIVER) reqs = list(/obj/item/stack/sheet/cloth = 1, /obj/item/stack/sheet/mineral/wood = 5, /obj/item/stack/sheet/metal = 1) @@ -72,8 +72,8 @@ /datum/crafting_recipe/bloodsucker/metalcoffin name = "Metal Coffin" result =/obj/structure/closet/crate/coffin/metalcoffin - tools = list(/obj/item/weldingtool, - /obj/item/screwdriver) + tools = list(TOOL_WELDER, + TOOL_SCREWDRIVER) reqs = list(/obj/item/stack/sheet/metal = 5) time = 100 subcategory = CAT_FURNITURE @@ -84,9 +84,9 @@ name = "Persuasion Rack" //desc = "For converting crewmembers into loyal Vassals." result = /obj/structure/bloodsucker/vassalrack - tools = list(/obj/item/weldingtool, - //obj/item/screwdriver, - /obj/item/wrench + tools = list(TOOL_WELDER, + //TOOL_SCREWDRIVER, + TOOL_WRENCH ) reqs = list(/obj/item/stack/sheet/mineral/wood = 3, /obj/item/stack/sheet/metal = 2, @@ -108,8 +108,8 @@ name = "Candelabrum" //desc = "For converting crewmembers into loyal Vassals." result = /obj/structure/bloodsucker/candelabrum - tools = list(/obj/item/weldingtool, - /obj/item/wrench + tools = list(TOOL_WELDER, + TOOL_WRENCH ) reqs = list(/obj/item/stack/sheet/metal = 3, /obj/item/stack/rods = 1, diff --git a/code/datums/components/gps.dm b/code/datums/components/gps.dm index 61098c8b66..f3ff912321 100644 --- a/code/datums/components/gps.dm +++ b/code/datums/components/gps.dm @@ -26,15 +26,16 @@ GLOBAL_LIST_EMPTY(GPS_list) if(. == COMPONENT_INCOMPATIBLE || !isitem(parent)) return COMPONENT_INCOMPATIBLE var/atom/A = parent - A.add_overlay("working") + if(starton) + A.add_overlay("working") + else + tracking = FALSE A.name = "[initial(A.name)] ([gpstag])" RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF, .proc/interact) if(!emp_proof) RegisterSignal(parent, COMSIG_ATOM_EMP_ACT, .proc/on_emp_act) RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/on_examine) RegisterSignal(parent, COMSIG_CLICK_ALT, .proc/on_AltClick) - if(!starton) - tracking = FALSE ///Called on COMSIG_ITEM_ATTACK_SELF /datum/component/gps/item/proc/interact(datum/source, mob/user) diff --git a/code/datums/components/orbiter.dm b/code/datums/components/orbiter.dm index 49b19f767c..26f52f6ba5 100644 --- a/code/datums/components/orbiter.dm +++ b/code/datums/components/orbiter.dm @@ -146,9 +146,11 @@ if(!istype(A) || !get_turf(A) || A == src) return + orbit_target = A return A.AddComponent(/datum/component/orbiter, src, radius, clockwise, rotation_speed, rotation_segments, pre_rotation) /atom/movable/proc/stop_orbit(datum/component/orbiter/orbits) + orbit_target = null return // We're just a simple hook /atom/proc/transfer_observers_to(atom/target) diff --git a/code/datums/components/remote_materials.dm b/code/datums/components/remote_materials.dm index ca62a70ee5..01038c11d3 100644 --- a/code/datums/components/remote_materials.dm +++ b/code/datums/components/remote_materials.dm @@ -84,38 +84,37 @@ handles linking back and forth. _MakeLocal() /datum/component/remote_materials/proc/OnAttackBy(datum/source, obj/item/I, mob/user) - if (istype(I, /obj/item/multitool)) - var/obj/item/multitool/M = I - if (!QDELETED(M.buffer) && istype(M.buffer, /obj/machinery/ore_silo)) - if (silo == M.buffer) + if(I.tool_behaviour == TOOL_MULTITOOL) + if((I.buffer) && istype(I.buffer, /obj/machinery/ore_silo)) + if(silo == I.buffer) to_chat(user, "[parent] is already connected to [silo].") return COMPONENT_NO_AFTERATTACK - if (silo) + if(silo) silo.connected -= src silo.updateUsrDialog() - else if (mat_container) + else if(mat_container) mat_container.retrieve_all() qdel(mat_container) - silo = M.buffer + silo = I.buffer silo.connected += src silo.updateUsrDialog() mat_container = silo.GetComponent(/datum/component/material_container) to_chat(user, "You connect [parent] to [silo] from the multitool's buffer.") return COMPONENT_NO_AFTERATTACK - else if (silo && istype(I, /obj/item/stack)) - if (silo.remote_attackby(parent, user, I)) + else if(silo && istype(I, /obj/item/stack)) + if(silo.remote_attackby(parent, user, I)) return COMPONENT_NO_AFTERATTACK /datum/component/remote_materials/proc/on_hold() return silo && silo.holds["[get_area(parent)]/[category]"] /datum/component/remote_materials/proc/silo_log(obj/machinery/M, action, amount, noun, list/mats) - if (silo) + if(silo) silo.silo_log(M || parent, action, amount, noun, mats) /datum/component/remote_materials/proc/format_amount() - if (mat_container) + if(mat_container) return "[mat_container.total_amount] / [mat_container.max_amount == INFINITY ? "Unlimited" : mat_container.max_amount] ([silo ? "remote" : "local"])" else return "0 / 0" diff --git a/code/datums/components/riding.dm b/code/datums/components/riding.dm index e9aa5afe92..e11eca2975 100644 --- a/code/datums/components/riding.dm +++ b/code/datums/components/riding.dm @@ -37,7 +37,7 @@ qdel(src) /datum/component/riding/proc/vehicle_mob_buckle(datum/source, mob/living/M, force) - handle_vehicle_offsets() + handle_vehicle_offsets(M.buckled?.dir) /datum/component/riding/proc/handle_vehicle_layer(dir) var/atom/movable/AM = parent diff --git a/code/datums/components/rotation.dm b/code/datums/components/rotation.dm index 129faabdb7..b8d629273b 100644 --- a/code/datums/components/rotation.dm +++ b/code/datums/components/rotation.dm @@ -125,7 +125,7 @@ else if(!default_can_user_rotate(user, default_rotation_direction)) return - if(istype(I,/obj/item/wrench)) + if(I.tool_behaviour == TOOL_WRENCH) BaseRot(user,default_rotation_direction) return COMPONENT_NO_AFTERATTACK diff --git a/code/datums/components/storage/concrete/tcg.dm b/code/datums/components/storage/concrete/tcg.dm new file mode 100644 index 0000000000..a9d8012a4b --- /dev/null +++ b/code/datums/components/storage/concrete/tcg.dm @@ -0,0 +1,49 @@ +/** + *A storage component to be used on card piles, for use as hands/decks/discard piles. Don't use on something that's not a card pile! + */ +/datum/component/storage/concrete/tcg + display_numerical_stacking = FALSE + max_w_class = WEIGHT_CLASS_TINY + max_items = 30 + max_combined_w_class = WEIGHT_CLASS_TINY * 30 + ///The deck that the card pile is using for FAIR PLAY. + +/datum/component/storage/concrete/tcg/can_be_inserted(obj/item/I, stop_messages, mob/M) + . = ..() + return istype(I, /obj/item/tcg_card) + +/datum/component/storage/concrete/tcg/PostTransfer() + . = ..() + handle_empty_deck() + +/datum/component/storage/concrete/tcg/remove_from_storage(atom/movable/AM, atom/new_location) + . = ..() + handle_empty_deck() + +/datum/component/storage/concrete/tcg/ui_show(mob/M) + . = ..() + M.visible_message("[M] starts to look through the contents of \the [parent]!", \ + "You begin looking into the contents of \the [parent]!") + +/datum/component/storage/concrete/tcg/close(mob/M) + . = ..() + var/list/card_contents = contents() + var/obj/temp_parent = parent + temp_parent.visible_message("\the [parent] is shuffled after looking through it.") + card_contents = shuffle(card_contents) + +/datum/component/storage/concrete/tcg/mass_remove_from_storage(atom/target, list/things, datum/progressbar/progress, trigger_on_found) + . = ..() + if(!things.len) + qdel(parent) + +/datum/component/storage/concrete/tcg/proc/handle_empty_deck() + var/list/contents = contents() + //You can't have a deck of one card! + if(contents.len == 1) + var/obj/item/tcgcard_deck/deck = parent + var/obj/item/tcg_card/card = contents[1] + remove_from_storage(card, card.drop_location()) + card.flipped = deck.flipped + card.update_icon_state() + qdel(parent) diff --git a/code/datums/traits/_quirk.dm b/code/datums/traits/_quirk.dm index c6466fdd96..22a851da1d 100644 --- a/code/datums/traits/_quirk.dm +++ b/code/datums/traits/_quirk.dm @@ -11,6 +11,8 @@ var/antag_removal_text // Text will be given to the quirk holder if they get an antag that has it blacklisted. var/mood_quirk = FALSE //if true, this quirk affects mood and is unavailable if moodlets are disabled var/mob_trait //if applicable, apply and remove this mob trait + /// should we immediately call on_spawn or add a timer to trigger + var/on_spawn_immediate = TRUE var/mob/living/quirk_holder /datum/quirk/New(mob/living/quirk_mob, spawn_effects) @@ -26,7 +28,10 @@ START_PROCESSING(SSquirks, src) add() if(spawn_effects) - on_spawn() + if(on_spawn_immediate) + on_spawn() + else + addtimer(CALLBACK(src, .proc/on_spawn), 0) addtimer(CALLBACK(src, .proc/post_add), 30) /datum/quirk/Destroy() diff --git a/code/datums/traits/good.dm b/code/datums/traits/good.dm index 23fd75f982..659149a123 100644 --- a/code/datums/traits/good.dm +++ b/code/datums/traits/good.dm @@ -219,3 +219,19 @@ /datum/quirk/night_vision/on_spawn() var/mob/living/carbon/human/H = quirk_holder H.update_sight() + +/datum/quirk/multilingual + name = "Multi-Lingual" + desc = "You spent a portion of your life learning to understand an additional language. You may or may not be able to speak it based on your anatomy." + value = 1 + mob_trait = TRAIT_MULTILINGUAL + gain_text = "You've learned an extra language!" + lose_text = "You've forgotten your extra language." + +/datum/quirk/multilingual/post_add() + var/mob/living/carbon/human/H = quirk_holder + H.grant_language(H.client.prefs.language, TRUE, TRUE, LANGUAGE_MULTILINGUAL) + +/datum/quirk/multilingual/remove() + var/mob/living/carbon/human/H = quirk_holder + H.remove_language(H.client.prefs.language, TRUE, TRUE, LANGUAGE_MULTILINGUAL) diff --git a/code/datums/traits/negative.dm b/code/datums/traits/negative.dm index 3cbf4b3cd2..cce138e82c 100644 --- a/code/datums/traits/negative.dm +++ b/code/datums/traits/negative.dm @@ -184,6 +184,7 @@ GLOBAL_LIST_EMPTY(family_heirlooms) gain_text = null // Handled by trauma. lose_text = null medical_record_text = "Patient has an untreatable impairment in motor function in the lower extremities." + on_spawn_immediate = FALSE /datum/quirk/paraplegic/add() var/datum/brain_trauma/severe/paralysis/paraplegic/T = new() diff --git a/code/datums/traits/neutral.dm b/code/datums/traits/neutral.dm index 73813fd253..18d565ed5a 100644 --- a/code/datums/traits/neutral.dm +++ b/code/datums/traits/neutral.dm @@ -105,6 +105,22 @@ gain_text = "You desire to be hurt." lose_text = "Pain has become less exciting for you." +/datum/quirk/libido + name = "Nymphomaniac" + desc = "You are much more sensitive to arousal." + value = 0 + mob_trait = TRAIT_NYMPHO + gain_text = "You are feeling extra wild." + lose_text = "You don't feel that burning sensation anymore." + +/datum/quirk/libido/add() + var/mob/living/carbon/human/H = quirk_holder + H.arousal_rate = 3 * initial(H.arousal_rate) + +/datum/quirk/libido/remove() + var/mob/living/carbon/human/H = quirk_holder + H.arousal_rate = initial(H.arousal_rate) + /datum/quirk/alcohol_intolerance name = "Alcohol Intolerance" desc = "You take toxin damage from alcohol rather than getting drunk." diff --git a/code/datums/wires/_wires.dm b/code/datums/wires/_wires.dm index 68c475f67b..1c9c14ee3e 100644 --- a/code/datums/wires/_wires.dm +++ b/code/datums/wires/_wires.dm @@ -265,11 +265,10 @@ reveal_wires = TRUE // 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 + else if(user.is_holding_tool_quality(TOOL_MULTITOOL)) + var/obj/item/tool = user.is_holding_tool_quality(TOOL_MULTITOOL) + if(tool.show_wires) + 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/datums/wounds/_wounds.dm b/code/datums/wounds/_wounds.dm index 02421b1e52..9c5a41de5d 100644 --- a/code/datums/wounds/_wounds.dm +++ b/code/datums/wounds/_wounds.dm @@ -134,6 +134,7 @@ if(status_effect_type) linked_status_effect = victim.apply_status_effect(status_effect_type, src) SEND_SIGNAL(victim, COMSIG_CARBON_GAIN_WOUND, src, limb) + victim.emote("pain") if(!victim.alerts["wound"]) // only one alert is shared between all of the wounds victim.throw_alert("wound", /obj/screen/alert/status_effect/wound) diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 2514f41c44..f5ab29d07a 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -99,6 +99,9 @@ ///Mobs that are currently do_after'ing this atom, to be cleared from on Destroy() var/list/targeted_by + ///Reference to atom being orbited + var/atom/orbit_target + /** * Called when an atom is created in byond (built in engine proc) * @@ -982,7 +985,7 @@ return /atom/proc/multitool_check_buffer(user, obj/item/I, silent = FALSE) - if(!istype(I, /obj/item/multitool)) + if(!I.tool_behaviour == TOOL_MULTITOOL) if(user && !silent) to_chat(user, "[I] has no data buffer!") return FALSE diff --git a/code/game/gamemodes/objective_sabotage.dm b/code/game/gamemodes/objective_sabotage.dm index c8f1ef4713..1fbebfdac4 100644 --- a/code/game/gamemodes/objective_sabotage.dm +++ b/code/game/gamemodes/objective_sabotage.dm @@ -33,6 +33,7 @@ /datum/sabotage_objective/processing/check_conditions() return won +/* /datum/sabotage_objective/processing/power_sink name = "Drain at least 100 megajoules of power using a power sink." sabotage_type = "powersink" @@ -44,6 +45,7 @@ for(var/s in GLOB.power_sinks) var/obj/item/powersink/sink = s won = max(won,sink.power_drained/1e8) +*/ /obj/item/paper/guides/antag/supermatter_sabotage info = "Ways to sabotage a supermatter:
\ diff --git a/code/game/machinery/PDApainter.dm b/code/game/machinery/PDApainter.dm index 6bac63dff0..82209221ce 100644 --- a/code/game/machinery/PDApainter.dm +++ b/code/game/machinery/PDApainter.dm @@ -82,7 +82,7 @@ O.add_fingerprint(user) update_icon() - else if(istype(O, /obj/item/weldingtool) && user.a_intent != INTENT_HARM) + else if(O.tool_behaviour == TOOL_WELDER && user.a_intent != INTENT_HARM) if(stat & BROKEN) if(!O.tool_start_check(user, amount=0)) return diff --git a/code/game/machinery/aug_manipulator.dm b/code/game/machinery/aug_manipulator.dm index 50b6180d62..6fdeae61a1 100644 --- a/code/game/machinery/aug_manipulator.dm +++ b/code/game/machinery/aug_manipulator.dm @@ -73,7 +73,7 @@ O.add_fingerprint(user) update_icon() - else if(istype(O, /obj/item/weldingtool) && user.a_intent != INTENT_HARM) + else if(O.tool_behaviour == TOOL_WELDER && user.a_intent != INTENT_HARM) if(obj_integrity < max_integrity) if(!O.tool_start_check(user, amount=0)) return diff --git a/code/game/machinery/buttons.dm b/code/game/machinery/buttons.dm index b5031b68a1..0de76694c0 100644 --- a/code/game/machinery/buttons.dm +++ b/code/game/machinery/buttons.dm @@ -65,7 +65,7 @@ . += "button-board" /obj/machinery/button/attackby(obj/item/W, mob/user, params) - if(istype(W, /obj/item/screwdriver)) + if(W.tool_behaviour == TOOL_SCREWDRIVER) if(panel_open || allowed(user)) default_deconstruction_screwdriver(user, "button-open", "[skin]",W) update_icon() @@ -93,7 +93,7 @@ req_access = board.accesses to_chat(user, "You add [W] to the button.") - if(!device && !board && istype(W, /obj/item/wrench)) + if(!device && !board && W.tool_behaviour == TOOL_WRENCH) to_chat(user, "You start unsecuring the button frame...") W.play_tool_sound(src) if(W.use_tool(src, user, 40)) diff --git a/code/game/machinery/camera/camera_assembly.dm b/code/game/machinery/camera/camera_assembly.dm index b6af0600e4..ba54822140 100644 --- a/code/game/machinery/camera/camera_assembly.dm +++ b/code/game/machinery/camera/camera_assembly.dm @@ -39,7 +39,7 @@ switch(state) if(1) // State 1 - if(istype(W, /obj/item/weldingtool)) + if(W.tool_behaviour == TOOL_WELDER) if(weld(W, user)) to_chat(user, "You weld the assembly securely into place.") setAnchored(TRUE) @@ -56,7 +56,7 @@ return return - else if(istype(W, /obj/item/weldingtool)) + else if(W.tool_behaviour == TOOL_WELDER) if(weld(W, user)) to_chat(user, "You unweld the assembly from its place.") @@ -133,7 +133,9 @@ qdel(src) return TRUE -/obj/structure/camera_assembly/proc/weld(obj/item/weldingtool/W, mob/living/user) +/obj/structure/camera_assembly/proc/weld(obj/item/W, mob/living/user) + if(!W.tool_behaviour == TOOL_WELDER) + return if(!W.tool_start_check(user, amount=0)) return FALSE to_chat(user, "You start to weld \the [src]...") diff --git a/code/game/machinery/cell_charger.dm b/code/game/machinery/cell_charger.dm index effd70e9ab..25445f0d1c 100644 --- a/code/game/machinery/cell_charger.dm +++ b/code/game/machinery/cell_charger.dm @@ -10,7 +10,7 @@ circuit = /obj/item/circuitboard/machine/cell_charger pass_flags = PASSTABLE var/obj/item/stock_parts/cell/charging = null - var/charge_rate = 500 + var/recharge_coeff = 1 /obj/machinery/cell_charger/update_overlays() . += ..() @@ -28,9 +28,10 @@ . = ..() . += "There's [charging ? "a" : "no"] cell in the charger." if(charging) - . += "Current charge: [round(charging.percent(), 1)]%." + var/obj/item/stock_parts/cell/C = charging.get_cell() + . += "Current charge: [C.percent()]%." if(in_range(user, src) || isobserver(user)) - . += "The status display reads: Charge rate at [charge_rate]J per cycle." + . += "The status display reads: Charge rate at [recharge_coeff*10]J per cycle." /obj/machinery/cell_charger/attackby(obj/item/W, mob/user, params) if(istype(W, /obj/item/stock_parts/cell) && !panel_open) @@ -122,17 +123,18 @@ charging.emp_act(severity) /obj/machinery/cell_charger/RefreshParts() - charge_rate = 500 for(var/obj/item/stock_parts/capacitor/C in component_parts) - charge_rate *= C.rating + recharge_coeff = C.rating /obj/machinery/cell_charger/process() if(!charging || !anchored || (stat & (BROKEN|NOPOWER))) return - if(charging.percent() >= 100) - return - use_power(charge_rate) - charging.give(charge_rate) //this is 2558, efficient batteries exist + if(charging) + var/obj/item/stock_parts/cell/C = charging.get_cell() + if(C) + if(C.charge < C.maxcharge) + C.give(C.chargerate * recharge_coeff) + use_power(250 * recharge_coeff) update_icon() diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm index 60a310e9d5..e95543cffb 100644 --- a/code/game/machinery/cloning.dm +++ b/code/game/machinery/cloning.dm @@ -297,22 +297,20 @@ if(default_deconstruction_crowbar(W)) return - if(istype(W, /obj/item/multitool)) - var/obj/item/multitool/P = W - - if(istype(P.buffer, /obj/machinery/computer/cloning)) - if(get_area(P.buffer) != get_area(src)) + if(W.tool_behaviour == TOOL_MULTITOOL) + if(istype(W.buffer, /obj/machinery/computer/cloning)) + if(get_area(W.buffer) != get_area(src)) to_chat(user, "-% Cannot link machines across power zones. Buffer cleared %-") - P.buffer = null + W.buffer = null return - to_chat(user, "-% Successfully linked [P.buffer] with [src] %-") - var/obj/machinery/computer/cloning/comp = P.buffer + to_chat(user, "-% Successfully linked [W.buffer] with [src] %-") + var/obj/machinery/computer/cloning/comp = W.buffer if(connected) connected.DetachCloner(src) comp.AttachCloner(src) else - P.buffer = src - to_chat(user, "-% Successfully stored [REF(P.buffer)] [P.buffer.name] in buffer %-") + W.buffer = src + to_chat(user, "-% Successfully stored [REF(W.buffer)] [W.buffer] in buffer %-") return var/mob/living/mob_occupant = occupant diff --git a/code/game/machinery/colormate.dm b/code/game/machinery/colormate.dm index 1f1c16248c..d059d492ae 100644 --- a/code/game/machinery/colormate.dm +++ b/code/game/machinery/colormate.dm @@ -44,7 +44,8 @@ icon_state = "colormate" /obj/machinery/gear_painter/Destroy() - inserted.forceMove(drop_location()) + if(inserted) //please i beg you do not drop nulls + inserted.forceMove(drop_location()) return ..() /obj/machinery/gear_painter/attackby(obj/item/I, mob/living/user) diff --git a/code/game/machinery/computer/aifixer.dm b/code/game/machinery/computer/aifixer.dm index 8ebb64097d..bd7ae64e16 100644 --- a/code/game/machinery/computer/aifixer.dm +++ b/code/game/machinery/computer/aifixer.dm @@ -10,8 +10,8 @@ var/mob/living/silicon/ai/occupier = null var/active = FALSE -/obj/machinery/computer/aifixer/attackby(obj/I, mob/user, params) - if(occupier && istype(I, /obj/item/screwdriver)) +/obj/machinery/computer/aifixer/attackby(obj/item/I, mob/user, params) + if(occupier && I.tool_behaviour == TOOL_SCREWDRIVER) if(stat & (NOPOWER|BROKEN)) to_chat(user, "The screws on [name]'s screen won't budge.") else diff --git a/code/game/machinery/computer/apc_control.dm b/code/game/machinery/computer/apc_control.dm index c14837b8e3..804025961b 100644 --- a/code/game/machinery/computer/apc_control.dm +++ b/code/game/machinery/computer/apc_control.dm @@ -151,7 +151,14 @@ var/obj/machinery/power/apc/target = locate(ref) in GLOB.apcs_list if(!target) return - target.vars[type] = target.setsubsystem(text2num(value)) + value = target.setsubsystem(text2num(value)) + switch(type) // Sanity check + if("equipment", "lighting", "environ") + target.vars[type] = value + else + message_admins("Warning: possible href exploit by [key_name(usr)] - attempted to set [type] on [target] to [value]") + log_game("Warning: possible href exploit by [key_name(usr)] - attempted to set [type] on [target] to [value]") + return target.update_icon() target.update() var/setTo = "" diff --git a/code/game/machinery/computer/buildandrepair.dm b/code/game/machinery/computer/buildandrepair.dm index a21ebbeccf..00ba621550 100644 --- a/code/game/machinery/computer/buildandrepair.dm +++ b/code/game/machinery/computer/buildandrepair.dm @@ -7,14 +7,14 @@ add_fingerprint(user) switch(state) if(0) - if(istype(P, /obj/item/wrench)) + if(P.tool_behaviour == TOOL_WRENCH) to_chat(user, "You start wrenching the frame into place...") if(P.use_tool(src, user, 20, volume=50)) to_chat(user, "You wrench the frame into place.") setAnchored(TRUE) state = 1 return - if(istype(P, /obj/item/weldingtool)) + if(P.tool_behaviour == TOOL_WELDER) if(!P.tool_start_check(user, amount=0)) return @@ -26,7 +26,7 @@ qdel(src) return if(1) - if(istype(P, /obj/item/wrench)) + if(P.tool_behaviour == TOOL_WRENCH) to_chat(user, "You start to unfasten the frame...") if(P.use_tool(src, user, 20, volume=50) && state == 1) to_chat(user, "You unfasten the frame.") @@ -46,13 +46,13 @@ else if(istype(P, /obj/item/circuitboard) && !circuit) to_chat(user, "This frame does not accept circuit boards of this type!") return - if(istype(P, /obj/item/screwdriver) && circuit) + if(P.tool_behaviour == TOOL_SCREWDRIVER && circuit) P.play_tool_sound(src) to_chat(user, "You screw [circuit] into place.") state = 2 icon_state = "2" return - if(istype(P, /obj/item/crowbar) && circuit) + if(P.tool_behaviour == TOOL_CROWBAR && circuit) P.play_tool_sound(src) to_chat(user, "You remove [circuit].") state = 1 @@ -62,7 +62,7 @@ circuit = null return if(2) - if(istype(P, /obj/item/screwdriver) && circuit) + if(P.tool_behaviour == TOOL_SCREWDRIVER && circuit) P.play_tool_sound(src) to_chat(user, "You unfasten the circuit board.") state = 1 @@ -78,7 +78,7 @@ icon_state = "3" return if(3) - if(istype(P, /obj/item/wirecutters)) + if(P.tool_behaviour == TOOL_WIRECUTTER) P.play_tool_sound(src) to_chat(user, "You remove the cables.") state = 2 @@ -98,7 +98,7 @@ src.icon_state = "4" return if(4) - if(istype(P, /obj/item/crowbar)) + if(P.tool_behaviour == TOOL_CROWBAR) P.play_tool_sound(src) to_chat(user, "You remove the glass panel.") state = 3 @@ -106,7 +106,7 @@ var/obj/item/stack/sheet/glass/G = new(drop_location(), 2) G.add_fingerprint(user) return - if(istype(P, /obj/item/screwdriver)) + if(P.tool_behaviour == TOOL_SCREWDRIVER) P.play_tool_sound(src) to_chat(user, "You connect the monitor.") var/obj/B = new circuit.build_path (loc, circuit) @@ -117,12 +117,6 @@ if(user.a_intent == INTENT_HARM) return ..() -//callback proc used on stacks use_tool to stop unnecessary amounts being wasted from spam clicking. -/obj/structure/frame/computer/proc/check_state(target_state) - if(state == target_state) - return TRUE - return FALSE - /obj/structure/frame/computer/deconstruct(disassembled = TRUE) if(!(flags_1 & NODECONSTRUCT_1)) if(state == 4) diff --git a/code/game/machinery/computer/cloning.dm b/code/game/machinery/computer/cloning.dm index 7057b8b02d..adadb40bc9 100644 --- a/code/game/machinery/computer/cloning.dm +++ b/code/game/machinery/computer/cloning.dm @@ -133,22 +133,20 @@ to_chat(user, "You insert [W].") playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0) src.updateUsrDialog() - else if(istype(W, /obj/item/multitool)) - var/obj/item/multitool/P = W - - if(istype(P.buffer, clonepod_type)) - if(get_area(P.buffer) != get_area(src)) + else if(W.tool_behaviour == TOOL_MULTITOOL) + if(istype(W.buffer, clonepod_type)) + if(get_area(W.buffer) != get_area(src)) to_chat(user, "-% Cannot link machines across power zones. Buffer cleared %-") - P.buffer = null + W.buffer = null return - to_chat(user, "-% Successfully linked [P.buffer] with [src] %-") - var/obj/machinery/clonepod/pod = P.buffer + to_chat(user, "-% Successfully linked [W.buffer] with [src] %-") + var/obj/machinery/clonepod/pod = W.buffer if(pod.connected) pod.connected.DetachCloner(pod) AttachCloner(pod) else - P.buffer = src - to_chat(user, "-% Successfully stored [REF(P.buffer)] [P.buffer.name] in buffer %-") + W.buffer = src + to_chat(user, "-% Successfully stored [REF(W.buffer)] [W.buffer] in buffer %-") return else return ..() @@ -473,7 +471,7 @@ scanner.locked = prev_locked src.updateUsrDialog() playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0) - + /obj/machinery/computer/cloning/proc/scan_occupant(occupant) var/mob/living/mob_occupant = get_mob_or_brainmob(occupant) diff --git a/code/game/machinery/computer/launchpad_control.dm b/code/game/machinery/computer/launchpad_control.dm index b2f7ae73a1..18a0aeb221 100644 --- a/code/game/machinery/computer/launchpad_control.dm +++ b/code/game/machinery/computer/launchpad_control.dm @@ -23,11 +23,10 @@ if(W.tool_behaviour == TOOL_MULTITOOL) if(!multitool_check_buffer(user, W)) return - var/obj/item/multitool/M = W - if(M.buffer && istype(M.buffer, /obj/machinery/launchpad)) + if(W.buffer && istype(W.buffer, /obj/machinery/launchpad)) if(LAZYLEN(launchpads) < maximum_pads) - launchpads |= M.buffer - M.buffer = null + launchpads |= W.buffer + W.buffer = null to_chat(user, "You upload the data from the [W.name]'s buffer.") else to_chat(user, "[src] cannot handle any more connections!") diff --git a/code/game/machinery/computer/mechlaunchpad.dm b/code/game/machinery/computer/mechlaunchpad.dm index 88d3c765cb..3489ee5d35 100644 --- a/code/game/machinery/computer/mechlaunchpad.dm +++ b/code/game/machinery/computer/mechlaunchpad.dm @@ -55,11 +55,12 @@ return connected_mechpad /obj/machinery/computer/mechpad/multitool_act(mob/living/user, obj/item/tool) + if(!tool.tool_behaviour == TOOL_MULTITOOL) + return if(!multitool_check_buffer(user, tool)) return - var/obj/item/multitool/multitool = tool - if(istype(multitool.buffer, /obj/machinery/mechpad)) - var/obj/machinery/mechpad/buffered_console = multitool.buffer + if(istype(tool.buffer, /obj/machinery/mechpad)) + var/obj/machinery/mechpad/buffered_console = tool.buffer if(!(mechpads.len < maximum_pads)) to_chat(user, "[src] cannot handle any more connections!") return @@ -69,13 +70,13 @@ connected_mechpad = buffered_console connected_mechpad.connected_console = src connected_mechpad.id = id - multitool.buffer = null - to_chat(user, "You connect the console to the pad with data from the [multitool.name]'s buffer.") + tool.buffer = null + to_chat(user, "You connect the console to the pad with data from the [tool.name]'s buffer.") else mechpads += buffered_console LAZYADD(buffered_console.consoles, src) - multitool.buffer = null - to_chat(user, "You upload the data from the [multitool.name]'s buffer.") + tool.buffer = null + to_chat(user, "You upload the data from the [tool.name]'s buffer.") /** * Tries to call the launch proc on the connected mechpad, returns if there is no connected mechpad or there is no mecha on the pad diff --git a/code/game/machinery/computer/security.dm b/code/game/machinery/computer/security.dm index 0157f4ca87..45bb9bd327 100644 --- a/code/game/machinery/computer/security.dm +++ b/code/game/machinery/computer/security.dm @@ -264,6 +264,8 @@ What a mess.*/ active1 = null if(!( GLOB.data_core.security.Find(active2) )) active2 = null + if(!authenticated && href_list["choice"] != "Log In") // logging in is the only action you can do if not logged in + return if(usr.contents.Find(src) || (in_range(src, usr) && isturf(loc)) || hasSiliconAccessInArea(usr) || IsAdminGhost(usr)) usr.set_machine(src) switch(href_list["choice"]) diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm index 5ee8223625..d5bbcb0adc 100644 --- a/code/game/machinery/constructable_frame.dm +++ b/code/game/machinery/constructable_frame.dm @@ -21,6 +21,11 @@ circuit = null qdel(src) +//callback proc used on stacks use_tool to stop unnecessary amounts being wasted from spam clicking. +/obj/structure/frame/proc/check_state(target_state) + if(state == target_state) + return TRUE + return FALSE /obj/structure/frame/machine name = "machine frame" @@ -84,34 +89,32 @@ if(!P.tool_start_check(user, amount=5)) return to_chat(user, "You start to add cables to the frame...") - if(P.use_tool(src, user, 20, volume=50, amount=5)) + if(P.use_tool(src, user, 20, volume=50, amount=5, extra_checks = CALLBACK(src, .proc/check_state, 1))) to_chat(user, "You add cables to the frame.") state = 2 icon_state = "box_1" return - if(istype(P, /obj/item/screwdriver) && !anchored) + if(P.tool_behaviour == TOOL_SCREWDRIVER && !anchored) user.visible_message("[user] disassembles the frame.", \ "You start to disassemble the frame...", "You hear banging and clanking.") - if(P.use_tool(src, user, 40, volume=50)) - if(state == 1) - to_chat(user, "You disassemble the frame.") - var/obj/item/stack/sheet/metal/M = new (loc, 5) - M.add_fingerprint(user) - qdel(src) + if(P.use_tool(src, user, 40, volume=50, extra_checks = CALLBACK(src, .proc/check_state, 1))) + to_chat(user, "You disassemble the frame.") + var/obj/item/stack/sheet/metal/M = new (loc, 5) + M.add_fingerprint(user) + qdel(src) return - if(istype(P, /obj/item/wrench)) + if(P.tool_behaviour == TOOL_WRENCH) to_chat(user, "You start [anchored ? "un" : ""]securing [name]...") - if(P.use_tool(src, user, 40, volume=75)) - if(state == 1) - to_chat(user, "You [anchored ? "un" : ""]secure [name].") - setAnchored(!anchored) + if(P.use_tool(src, user, 40, volume=75, extra_checks = CALLBACK(src, .proc/check_state, 1))) + to_chat(user, "You [anchored ? "un" : ""]secure [name].") + setAnchored(!anchored) return if(2) - if(istype(P, /obj/item/wrench)) + if(P.tool_behaviour == TOOL_WRENCH) to_chat(user, "You start [anchored ? "un" : ""]securing [name]...") - if(P.use_tool(src, user, 40, volume=75)) + if(P.use_tool(src, user, 40, volume=75, extra_checks = CALLBACK(src, .proc/check_state, 2))) to_chat(user, "You [anchored ? "un" : ""]secure [name].") setAnchored(!anchored) return @@ -140,7 +143,7 @@ to_chat(user, "This frame does not accept circuit boards of this type!") return - if(istype(P, /obj/item/wirecutters)) + if(P.tool_behaviour == TOOL_WIRECUTTER) P.play_tool_sound(src) to_chat(user, "You remove the cables.") state = 1 @@ -149,7 +152,7 @@ return if(3) - if(istype(P, /obj/item/crowbar)) + if(P.tool_behaviour == TOOL_CROWBAR) P.play_tool_sound(src) state = 2 circuit.forceMove(drop_location()) @@ -167,14 +170,14 @@ icon_state = "box_1" return - if(istype(P, /obj/item/wrench) && !circuit.needs_anchored) + if(P.tool_behaviour == TOOL_WRENCH && !circuit.needs_anchored) to_chat(user, "You start [anchored ? "un" : ""]securing [name]...") - if(P.use_tool(src, user, 40, volume=75)) + if(P.use_tool(src, user, 40, volume=75, extra_checks = CALLBACK(src, .proc/check_state, 3))) to_chat(user, "You [anchored ? "un" : ""]secure [name].") setAnchored(!anchored) return - if(istype(P, /obj/item/screwdriver)) + if(P.tool_behaviour == TOOL_SCREWDRIVER) var/component_check = 1 for(var/R in req_components) if(req_components[R] > 0) diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm index ea41d77e2a..5be3e2a3a5 100644 --- a/code/game/machinery/cryopod.dm +++ b/code/game/machinery/cryopod.dm @@ -296,6 +296,12 @@ AM.forceMove(src) R.module.remove_module(I, TRUE) else + + if(ishuman(mob_occupant)) + var/mob/living/carbon/human/H = mob_occupant + if(H.mind && H.client && H.client.prefs && H == H.mind.original_character) + H.SaveTCGCards() + var/list/gear = list() if(iscarbon(mob_occupant)) // sorry simp-le-mobs deserve no mercy var/mob/living/carbon/C = mob_occupant diff --git a/code/game/machinery/dance_machine.dm b/code/game/machinery/dance_machine.dm index 756f924cfa..8b24a3804f 100644 --- a/code/game/machinery/dance_machine.dm +++ b/code/game/machinery/dance_machine.dm @@ -35,7 +35,7 @@ /obj/machinery/jukebox/attackby(obj/item/O, mob/user, params) if(!active && !(flags_1 & NODECONSTRUCT_1)) - if(istype(O, /obj/item/wrench)) + if(O.tool_behaviour == TOOL_WRENCH) if(!anchored && !isinspace()) to_chat(user,"You secure [src] to the floor.") setAnchored(TRUE) diff --git a/code/game/machinery/defibrillator_mount.dm b/code/game/machinery/defibrillator_mount.dm index 677cbe1208..bc6cc4b60e 100644 --- a/code/game/machinery/defibrillator_mount.dm +++ b/code/game/machinery/defibrillator_mount.dm @@ -99,19 +99,21 @@ return ..() -/obj/machinery/defibrillator_mount/multitool_act(mob/living/user, obj/item/multitool) +/obj/machinery/defibrillator_mount/multitool_act(mob/living/user, obj/item/W) + if(!W.tool_behaviour == TOOL_MULTITOOL) + return if(!defib) to_chat(user, "There isn't any defibrillator to clamp in!") return TRUE if(!clamps_locked) to_chat(user, "[src]'s clamps are disengaged!") return TRUE - user.visible_message("[user] presses [multitool] into [src]'s ID slot...", \ + user.visible_message("[user] presses [W] into [src]'s ID slot...", \ "You begin overriding the clamps on [src]...") playsound(src, 'sound/machines/click.ogg', 50, TRUE) if(!do_after(user, 100, target = src) || !clamps_locked) return - user.visible_message("[user] pulses [multitool], and [src]'s clamps slide up.", \ + user.visible_message("[user] pulses [W], and [src]'s clamps slide up.", \ "You override the locking clamps on [src]!") playsound(src, 'sound/machines/locktoggle.ogg', 50, TRUE) clamps_locked = FALSE diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm index 252e6cf6b3..ca4b392efa 100644 --- a/code/game/machinery/deployable.dm +++ b/code/game/machinery/deployable.dm @@ -26,7 +26,7 @@ return /obj/structure/barricade/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/weldingtool) && user.a_intent != INTENT_HARM && bar_material == METAL) + if(I.tool_behaviour == TOOL_WELDER && user.a_intent != INTENT_HARM && bar_material == METAL) if(obj_integrity < max_integrity) if(!I.tool_start_check(user, amount=0)) return diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 9ef34390f6..f4a65ce984 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -864,7 +864,7 @@ update_icon() return if(AIRLOCK_SECURITY_METAL) - if(istype(C, /obj/item/weldingtool)) + if(C.tool_behaviour == TOOL_WELDER) if(!C.tool_start_check(user, amount=2)) return to_chat(user, "You begin cutting the panel's shielding...") @@ -879,10 +879,9 @@ update_icon() return if(AIRLOCK_SECURITY_PLASTEEL_I_S) - if(istype(C, /obj/item/crowbar)) - var/obj/item/crowbar/W = C + if(C.tool_behaviour == TOOL_CROWBAR) to_chat(user, "You start removing the inner layer of shielding...") - if(W.use_tool(src, user, 40, volume=100)) + if(C.use_tool(src, user, 40, volume=100)) if(!panel_open) return if(security_level != AIRLOCK_SECURITY_PLASTEEL_I_S) @@ -896,7 +895,7 @@ update_icon() return if(AIRLOCK_SECURITY_PLASTEEL_I) - if(istype(C, /obj/item/weldingtool)) + if(C.tool_behaviour == TOOL_WELDER) if(!C.tool_start_check(user, amount=2)) return to_chat(user, "You begin cutting the inner layer of shielding...") @@ -909,7 +908,7 @@ security_level = AIRLOCK_SECURITY_PLASTEEL_I_S return if(AIRLOCK_SECURITY_PLASTEEL_O_S) - if(istype(C, /obj/item/crowbar)) + if(C.tool_behaviour == TOOL_CROWBAR) to_chat(user, "You start removing outer layer of shielding...") if(C.use_tool(src, user, 40, volume=100)) if(!panel_open) @@ -922,7 +921,7 @@ spawn_atom_to_turf(/obj/item/stack/sheet/plasteel, user.loc, 1) return if(AIRLOCK_SECURITY_PLASTEEL_O) - if(istype(C, /obj/item/weldingtool)) + if(C.tool_behaviour == TOOL_WELDER) if(!C.tool_start_check(user, amount=2)) return to_chat(user, "You begin cutting the outer layer of shielding...") @@ -935,7 +934,7 @@ security_level = AIRLOCK_SECURITY_PLASTEEL_O_S return if(AIRLOCK_SECURITY_PLASTEEL) - if(istype(C, /obj/item/wirecutters)) + if(C.tool_behaviour == TOOL_WIRECUTTER) if(src.hasPower() && src.shock(user, 60)) // Protective grille of wiring is electrified return to_chat(user, "You start cutting through the outer grille.") @@ -946,7 +945,7 @@ "You cut through \the [src]'s outer grille.") security_level = AIRLOCK_SECURITY_PLASTEEL_O return - if(istype(C, /obj/item/screwdriver)) + if(C.tool_behaviour == TOOL_SCREWDRIVER) if(panel_open && detonated) to_chat(user, "[src] has no maintenance panel!") return @@ -954,7 +953,7 @@ to_chat(user, "You [panel_open ? "open":"close"] the maintenance panel of the airlock.") C.play_tool_sound(src) src.update_icon() - else if(istype(C, /obj/item/wirecutters) && note) + else if(C.tool_behaviour == TOOL_WIRECUTTER && note) user.visible_message("[user] cuts down [note] from [src].", "You remove [note] from [src].") C.play_tool_sound(src) note.forceMove(get_turf(user)) @@ -999,7 +998,9 @@ return ..() -/obj/machinery/door/airlock/try_to_weld(obj/item/weldingtool/W, mob/user) +/obj/machinery/door/airlock/try_to_weld(obj/item/W, mob/user) + if(!W.tool_behaviour == TOOL_WELDER) + return if(!operating && density) if(user.a_intent != INTENT_HELP) if(!W.tool_start_check(user, amount=0)) @@ -1028,12 +1029,14 @@ else to_chat(user, "The airlock doesn't need repairing.") -/obj/machinery/door/airlock/proc/weld_checks(obj/item/weldingtool/W, mob/user) +/obj/machinery/door/airlock/proc/weld_checks(obj/item/W, mob/user) + if(!W.tool_behaviour == TOOL_WELDER) + return return !operating && density /obj/machinery/door/airlock/try_to_crowbar(obj/item/I, mob/living/user) var/beingcrowbarred = null - if(istype(I, /obj/item/crowbar) ) + if(I.tool_behaviour == TOOL_CROWBAR) beingcrowbarred = 1 else beingcrowbarred = 0 @@ -1059,7 +1062,7 @@ to_chat(user, "The airlock's motors resist your efforts to force it!") else if(locked) to_chat(user, "The airlock's bolts prevent it from being forced!") - else if( !welded && !operating) + else if(!welded && !operating) if(!beingcrowbarred) //being fireaxe'd var/obj/item/fireaxe/axe = I if(!axe.wielded) @@ -1069,7 +1072,9 @@ else INVOKE_ASYNC(src, (density ? .proc/open : .proc/close), 2) - if(istype(I, /obj/item/crowbar/power)) + if(I.tool_behaviour == TOOL_CROWBAR) + if(!I.can_force_powered) + return if(hasPower() && isElectrified()) shock(user,100)//it's like sticking a forck in a power socket return diff --git a/code/game/machinery/doors/airlock_types.dm b/code/game/machinery/doors/airlock_types.dm index d1f9fc5e83..5215baf87f 100644 --- a/code/game/machinery/doors/airlock_types.dm +++ b/code/game/machinery/doors/airlock_types.dm @@ -658,7 +658,7 @@ /obj/machinery/door/airlock/clockwork/proc/attempt_construction(obj/item/I, mob/living/user) if(!I || !user || !user.canUseTopic(src)) return 0 - else if(istype(I, /obj/item/wrench)) + else if(I.tool_behaviour == TOOL_WRENCH) if(construction_state == GEAR_SECURE) user.visible_message("[user] begins loosening [src]'s cogwheel...", "You begin loosening [src]'s cogwheel...") if(!I.use_tool(src, user, 75, volume=50) || construction_state != GEAR_SECURE) @@ -674,7 +674,7 @@ playsound(src, 'sound/items/deconstruct.ogg', 50, 1) construction_state = GEAR_SECURE return 1 - else if(istype(I, /obj/item/crowbar)) + else if(I.tool_behaviour == TOOL_CROWBAR) if(construction_state == GEAR_SECURE) to_chat(user, "[src]'s cogwheel is too tightly secured! Your [I.name] can't reach under it!") return 1 diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 221f11c698..796a91af66 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -173,7 +173,9 @@ /obj/machinery/door/proc/unrestricted_side(mob/M) //Allows for specific side of airlocks to be unrestrected (IE, can exit maint freely, but need access to enter) return get_dir(src, M) & unres_sides -/obj/machinery/door/proc/try_to_weld(obj/item/weldingtool/W, mob/user) +/obj/machinery/door/proc/try_to_weld(obj/item/W, mob/user) + if(!W.tool_behaviour == TOOL_WELDER) + return return /obj/machinery/door/proc/try_to_crowbar(obj/item/I, mob/user) diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm index d88a9c9072..d84b994b92 100644 --- a/code/game/machinery/doors/firedoor.dm +++ b/code/game/machinery/doors/firedoor.dm @@ -123,7 +123,9 @@ /obj/machinery/door/firedoor/try_to_activate_door(mob/user) return -/obj/machinery/door/firedoor/try_to_weld(obj/item/weldingtool/W, mob/user) +/obj/machinery/door/firedoor/try_to_weld(obj/item/W, mob/user) + if(!W.tool_behaviour == TOOL_WELDER) + return if(!W.tool_start_check(user, amount=0)) return user.visible_message("[user] starts [welded ? "unwelding" : "welding"] [src].", "You start welding [src].") diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm index 7847c3757e..dd885542c9 100644 --- a/code/game/machinery/doors/windowdoor.dm +++ b/code/game/machinery/doors/windowdoor.dm @@ -243,7 +243,7 @@ add_fingerprint(user) if(!(flags_1&NODECONSTRUCT_1)) - if(istype(I, /obj/item/screwdriver)) + if(I.tool_behaviour == TOOL_SCREWDRIVER) if(density || operating) to_chat(user, "You need to open the door to access the maintenance panel!") return @@ -252,7 +252,7 @@ to_chat(user, "You [panel_open ? "open":"close"] the maintenance panel of the [src.name].") return - if(istype(I, /obj/item/crowbar)) + if(I.tool_behaviour == TOOL_CROWBAR) if(panel_open && !density && !operating) user.visible_message("[user] removes the electronics from the [src.name].", \ "You start to remove electronics from the [src.name]...") diff --git a/code/game/machinery/doppler_array.dm b/code/game/machinery/doppler_array.dm index 4f27e38a14..1cdb81ee1d 100644 --- a/code/game/machinery/doppler_array.dm +++ b/code/game/machinery/doppler_array.dm @@ -54,7 +54,7 @@ GLOBAL_LIST_EMPTY(doppler_arrays) return /obj/machinery/doppler_array/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/wrench)) + if(I.tool_behaviour == TOOL_WRENCH) if(!anchored && !isinspace()) anchored = TRUE power_change() diff --git a/code/game/machinery/droneDispenser.dm b/code/game/machinery/droneDispenser.dm index 33ea273e9d..74df30ebfe 100644 --- a/code/game/machinery/droneDispenser.dm +++ b/code/game/machinery/droneDispenser.dm @@ -210,13 +210,13 @@ icon_state = icon_on /obj/machinery/droneDispenser/attackby(obj/item/I, mob/living/user) - if(istype(I, /obj/item/crowbar)) + if(I.tool_behaviour == TOOL_CROWBAR) var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) materials.retrieve_all() I.play_tool_sound(src) to_chat(user, "You retrieve the materials from [src].") - else if(istype(I, /obj/item/weldingtool)) + else if(I.tool_behaviour == TOOL_WELDER) if(!(stat & BROKEN)) to_chat(user, "[src] doesn't need repairs.") return diff --git a/code/game/machinery/firealarm.dm b/code/game/machinery/firealarm.dm index ca9ce09ced..c6b29cf54c 100644 --- a/code/game/machinery/firealarm.dm +++ b/code/game/machinery/firealarm.dm @@ -160,7 +160,7 @@ /obj/machinery/firealarm/attackby(obj/item/W, mob/user, params) add_fingerprint(user) - if(istype(W, /obj/item/screwdriver) && buildstage == 2) + if(W.tool_behaviour == TOOL_SCREWDRIVER && buildstage == 2) W.play_tool_sound(src) panel_open = !panel_open to_chat(user, "The wires have been [panel_open ? "exposed" : "unexposed"].") @@ -169,7 +169,7 @@ if(panel_open) - if(istype(W, /obj/item/weldingtool) && user.a_intent == INTENT_HELP) + if((W.tool_behaviour == TOOL_WELDER) && user.a_intent == INTENT_HELP) if(obj_integrity < max_integrity) if(!W.tool_start_check(user, amount=0)) return @@ -184,7 +184,7 @@ switch(buildstage) if(2) - if(istype(W, /obj/item/multitool)) + if(W.tool_behaviour == TOOL_MULTITOOL) detecting = !detecting if (src.detecting) user.visible_message("[user] has reconnected [src]'s detecting unit!", "You reconnect [src]'s detecting unit.") @@ -192,7 +192,7 @@ user.visible_message("[user] has disconnected [src]'s detecting unit!", "You disconnect [src]'s detecting unit.") return - else if (istype(W, /obj/item/wirecutters)) + else if(W.tool_behaviour == TOOL_WIRECUTTER) buildstage = 1 W.play_tool_sound(src) new /obj/item/stack/cable_coil(user.loc, 5) @@ -215,7 +215,7 @@ update_icon() return - else if(istype(W, /obj/item/crowbar)) + else if(W.tool_behaviour == TOOL_CROWBAR) user.visible_message("[user.name] removes the electronics from [src.name].", \ "You start prying out the circuit...") if(W.use_tool(src, user, 20, volume=50)) @@ -247,7 +247,7 @@ update_icon() return - else if(istype(W, /obj/item/wrench)) + else if(W.tool_behaviour == TOOL_WRENCH) user.visible_message("[user] removes the fire alarm assembly from the wall.", \ "You remove the fire alarm assembly from the wall.") var/obj/item/wallframe/firealarm/frame = new /obj/item/wallframe/firealarm() diff --git a/code/game/machinery/flasher.dm b/code/game/machinery/flasher.dm index c0e1122140..20aac89743 100644 --- a/code/game/machinery/flasher.dm +++ b/code/game/machinery/flasher.dm @@ -57,8 +57,8 @@ //Don't want to render prison breaks impossible /obj/machinery/flasher/attackby(obj/item/W, mob/user, params) add_fingerprint(user) - if (istype(W, /obj/item/wirecutters)) - if (bulb) + if(W.tool_behaviour == TOOL_WIRECUTTER) + if(bulb) user.visible_message("[user] begins to disconnect [src]'s flashbulb.", "You begin to disconnect [src]'s flashbulb...") if(W.use_tool(src, user, 30, volume=50) && bulb) user.visible_message("[user] has disconnected [src]'s flashbulb!", "You disconnect [src]'s flashbulb.") @@ -66,7 +66,7 @@ bulb = null power_change() - else if (istype(W, /obj/item/assembly/flash/handheld)) + else if(istype(W, /obj/item/assembly/flash/handheld)) if (!bulb) if(!user.transferItemToLoc(W, src)) return @@ -76,7 +76,7 @@ else to_chat(user, "A flashbulb is already installed in [src]!") - else if (istype(W, /obj/item/wrench)) + else if(W.tool_behaviour == TOOL_WRENCH) if(!bulb) to_chat(user, "You start unsecuring the flasher frame...") if(W.use_tool(src, user, 40, volume=50)) @@ -173,10 +173,10 @@ flash() /obj/machinery/flasher/portable/attackby(obj/item/W, mob/user, params) - if (istype(W, /obj/item/wrench)) + if(W.tool_behaviour == TOOL_WRENCH) W.play_tool_sound(src, 100) - if (!anchored && !isinspace()) + if(!anchored && !isinspace()) to_chat(user, "[src] is now secured.") add_overlay("[base_state]-s") setAnchored(TRUE) diff --git a/code/game/machinery/igniter.dm b/code/game/machinery/igniter.dm index ba4d01cfe5..bb047a6a5e 100644 --- a/code/game/machinery/igniter.dm +++ b/code/game/machinery/igniter.dm @@ -91,7 +91,7 @@ // src.sd_SetLuminosity(0) /obj/machinery/sparker/attackby(obj/item/W, mob/user, params) - if (istype(W, /obj/item/screwdriver)) + if(W.tool_behaviour == TOOL_SCREWDRIVER) add_fingerprint(user) src.disable = !src.disable if (src.disable) diff --git a/code/game/machinery/launch_pad.dm b/code/game/machinery/launch_pad.dm index e3df79e291..87989b18ec 100644 --- a/code/game/machinery/launch_pad.dm +++ b/code/game/machinery/launch_pad.dm @@ -38,8 +38,7 @@ if(I.tool_behaviour == TOOL_MULTITOOL) if(!multitool_check_buffer(user, I)) return - var/obj/item/multitool/M = I - M.buffer = src + I.buffer = src to_chat(user, "You save the data in the [I.name]'s buffer.") return TRUE diff --git a/code/game/machinery/mechlaunchpad.dm b/code/game/machinery/mechlaunchpad.dm index 049f3e7d3e..f32fe0bc4f 100644 --- a/code/game/machinery/mechlaunchpad.dm +++ b/code/game/machinery/mechlaunchpad.dm @@ -37,13 +37,14 @@ return TRUE /obj/machinery/mechpad/multitool_act(mob/living/user, obj/item/tool) + if(!tool.tool_behaviour == TOOL_MULTITOOL) + return if(!panel_open) return if(!multitool_check_buffer(user, tool)) return - var/obj/item/multitool/multitool = tool - multitool.buffer = src - to_chat(user, "You save the data in the [multitool.name]'s buffer.") + tool.buffer = src + to_chat(user, "You save the data in the [tool.name]'s buffer.") return TRUE /** diff --git a/code/game/machinery/navbeacon.dm b/code/game/machinery/navbeacon.dm index 766943de36..752ba1b732 100644 --- a/code/game/machinery/navbeacon.dm +++ b/code/game/machinery/navbeacon.dm @@ -89,7 +89,7 @@ if(T.intact) return // prevent intraction when T-scanner revealed - if(istype(I, /obj/item/screwdriver)) + if(I.tool_behaviour == TOOL_SCREWDRIVER) open = !open user.visible_message("[user] [open ? "opens" : "closes"] the beacon's cover.", "You [open ? "open" : "close"] the beacon's cover.") diff --git a/code/game/machinery/pipe/construction.dm b/code/game/machinery/pipe/construction.dm index 3acbaba4fd..141afa53e7 100644 --- a/code/game/machinery/pipe/construction.dm +++ b/code/game/machinery/pipe/construction.dm @@ -127,7 +127,9 @@ Buildable meters /obj/item/pipe/attack_self(mob/user) setDir(turn(dir,-90)) -/obj/item/pipe/wrench_act(mob/living/user, obj/item/wrench/W) +/obj/item/pipe/wrench_act(mob/living/user, obj/item/W) + if(!W.tool_behaviour == TOOL_WRENCH) + return if(!isturf(loc)) return TRUE @@ -196,8 +198,9 @@ Buildable meters w_class = WEIGHT_CLASS_BULKY var/piping_layer = PIPING_LAYER_DEFAULT -/obj/item/pipe_meter/wrench_act(mob/living/user, obj/item/wrench/W) - +/obj/item/pipe_meter/wrench_act(mob/living/user, obj/item/W) + if(!W.tool_behaviour == TOOL_WRENCH) + return var/obj/machinery/atmospherics/pipe/pipe for(var/obj/machinery/atmospherics/pipe/P in loc) if(P.piping_layer == piping_layer) diff --git a/code/game/machinery/porta_turret/portable_turret.dm b/code/game/machinery/porta_turret/portable_turret.dm index 29883a073a..aad64df6d9 100644 --- a/code/game/machinery/porta_turret/portable_turret.dm +++ b/code/game/machinery/porta_turret/portable_turret.dm @@ -283,9 +283,9 @@ /obj/machinery/porta_turret/attackby(obj/item/I, mob/user, params) if(stat & BROKEN) - if(istype(I, /obj/item/crowbar)) - //If the turret is destroyed, you can remove it with a crowbar to - //try and salvage its components + if(I.tool_behaviour == TOOL_CROWBAR) + //If the turret is destroyed, you can remove it with something + //that acts like a crowbar to try and salvage its components to_chat(user, "You begin prying the metal coverings off...") if(I.use_tool(src, user, 20)) if(prob(70)) @@ -302,7 +302,7 @@ qdel(src) return - else if((istype(I, /obj/item/wrench)) && (!on)) + else if((I.tool_behaviour == TOOL_WRENCH) && (!on)) if(raised) return @@ -329,12 +329,11 @@ to_chat(user, "Controls are now [locked ? "locked" : "unlocked"].") else to_chat(user, "Access denied.") - else if(istype(I, /obj/item/multitool) && !locked) + else if(I.tool_behaviour == TOOL_MULTITOOL && !locked) if(!multitool_check_buffer(user, I)) return - var/obj/item/multitool/M = I - M.buffer = src - to_chat(user, "You add [src] to multitool buffer.") + I.buffer = src + to_chat(user, "You add [src] to [I]'s buffer.") else return ..() @@ -393,6 +392,27 @@ spark_system.start() //creates some sparks because they look cool qdel(cover) //deletes the cover - no need on keeping it there! +//turret healing +/obj/machinery/porta_turret/examine(mob/user) + . = ..() + if(obj_integrity < max_integrity) + . += "[src] is damaged, use a lit welder to fix it." + +/obj/machinery/porta_turret/welder_act(mob/living/user, obj/item/I) + . = TRUE + if(cover && obj_integrity < max_integrity) + if(!I.tool_start_check(user, amount=0)) + return + user.visible_message("[user] is welding the turret.", \ + "You begin repairing the turret...", \ + "You hear welding.") + if(I.use_tool(src, user, 40, volume=50)) + obj_integrity = max_integrity + user.visible_message("[user.name] has repaired [src].", \ + "You finish repairing the turret.") + else + to_chat(user, "The turret doesn't need repairing.") + /obj/machinery/porta_turret/process() //the main machinery process if(cover == null && anchored) //if it has no cover and is anchored @@ -927,20 +947,19 @@ if(stat & BROKEN) return - if (istype(I, /obj/item/multitool)) + if(I.tool_behaviour == TOOL_MULTITOOL) if(!multitool_check_buffer(user, I)) return - var/obj/item/multitool/M = I - if(M.buffer && istype(M.buffer, /obj/machinery/porta_turret)) - turrets |= M.buffer - to_chat(user, "You link \the [M.buffer] with \the [src].") + if(I.buffer && istype(I.buffer, /obj/machinery/porta_turret)) + turrets |= I.buffer + to_chat(user, "You link \the [I.buffer] with \the [src].") return - if (issilicon(user)) + if(issilicon(user)) return attack_hand(user) - if ( get_dist(src, user) == 0 ) // trying to unlock the interface - if (allowed(usr)) + if(get_dist(src, user) == 0 ) // trying to unlock the interface + if(allowed(usr)) if(obj_flags & EMAGGED) to_chat(user, "The turret control is unresponsive!") return diff --git a/code/game/machinery/porta_turret/portable_turret_construct.dm b/code/game/machinery/porta_turret/portable_turret_construct.dm index 2a73ee8d89..3b9e6ff45f 100644 --- a/code/game/machinery/porta_turret/portable_turret_construct.dm +++ b/code/game/machinery/porta_turret/portable_turret_construct.dm @@ -23,14 +23,14 @@ //this is a bit unwieldy but self-explanatory switch(build_step) if(PTURRET_UNSECURED) //first step - if(istype(I, /obj/item/wrench) && !anchored) + if(I.tool_behaviour == TOOL_WRENCH && !anchored) I.play_tool_sound(src, 100) to_chat(user, "You secure the external bolts.") setAnchored(TRUE) build_step = PTURRET_BOLTED return - else if(istype(I, /obj/item/crowbar) && !anchored) + else if(I.tool_behaviour == TOOL_CROWBAR && !anchored) I.play_tool_sound(src, 75) to_chat(user, "You dismantle the turret construction.") new /obj/item/stack/sheet/metal( loc, 5) @@ -48,7 +48,7 @@ to_chat(user, "You need two sheets of metal to continue construction!") return - else if(istype(I, /obj/item/wrench)) + else if(I.tool_behaviour == TOOL_WRENCH) I.play_tool_sound(src, 75) to_chat(user, "You unfasten the external bolts.") setAnchored(FALSE) @@ -57,13 +57,13 @@ if(PTURRET_START_INTERNAL_ARMOUR) - if(istype(I, /obj/item/wrench)) + if(I.tool_behaviour == TOOL_WRENCH) I.play_tool_sound(src, 100) to_chat(user, "You bolt the metal armor into place.") build_step = PTURRET_INTERNAL_ARMOUR_ON return - else if(istype(I, /obj/item/weldingtool)) + else if(I.tool_behaviour == TOOL_WELDER) if(!I.tool_start_check(user, amount=5)) //uses up 5 fuel return @@ -89,7 +89,7 @@ build_step = PTURRET_GUN_EQUIPPED return - else if(istype(I, /obj/item/wrench)) + else if(I.tool_behaviour == TOOL_WRENCH) I.play_tool_sound(src, 100) to_chat(user, "You remove the turret's metal armor bolts.") build_step = PTURRET_START_INTERNAL_ARMOUR @@ -106,7 +106,7 @@ if(PTURRET_SENSORS_ON) - if(istype(I, /obj/item/screwdriver)) + if(I.tool_behaviour == TOOL_SCREWDRIVER) I.play_tool_sound(src, 100) build_step = PTURRET_CLOSED to_chat(user, "You close the internal access hatch.") @@ -123,14 +123,14 @@ to_chat(user, "You need two sheets of metal to continue construction!") return - else if(istype(I, /obj/item/screwdriver)) + else if(I.tool_behaviour == TOOL_SCREWDRIVER) I.play_tool_sound(src, 100) build_step = PTURRET_SENSORS_ON to_chat(user, "You open the internal access hatch.") return if(PTURRET_START_EXTERNAL_ARMOUR) - if(istype(I, /obj/item/weldingtool)) + if(I.tool_behaviour == TOOL_WELDER) if(!I.tool_start_check(user, amount=5)) return @@ -153,7 +153,7 @@ qdel(src) return - else if(istype(I, /obj/item/crowbar)) + else if(I.tool_behaviour == TOOL_CROWBAR) I.play_tool_sound(src, 75) to_chat(user, "You pry off the turret's exterior armor.") new /obj/item/stack/sheet/metal(loc, 2) diff --git a/code/game/machinery/porta_turret/portable_turret_cover.dm b/code/game/machinery/porta_turret/portable_turret_cover.dm index e0746bda78..33a7a44e63 100644 --- a/code/game/machinery/porta_turret/portable_turret_cover.dm +++ b/code/game/machinery/porta_turret/portable_turret_cover.dm @@ -37,7 +37,7 @@ /obj/machinery/porta_turret_cover/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/wrench) && !parent_turret.on) + if(I.tool_behaviour == TOOL_WRENCH && !parent_turret.on) if(parent_turret.raised) return @@ -60,10 +60,9 @@ updateUsrDialog() else to_chat(user, "Access denied.") - else if(istype(I, /obj/item/multitool) && !parent_turret.locked) - var/obj/item/multitool/M = I - M.buffer = parent_turret - to_chat(user, "You add [parent_turret] to multitool buffer.") + else if(I.tool_behaviour == TOOL_MULTITOOL && !parent_turret.locked) + I.buffer = parent_turret + to_chat(user, "You add [parent_turret] to [I]'s buffer.") else return ..() diff --git a/code/game/machinery/poweredfans/fan_assembly.dm b/code/game/machinery/poweredfans/fan_assembly.dm index 651b3342ac..59dbe84def 100644 --- a/code/game/machinery/poweredfans/fan_assembly.dm +++ b/code/game/machinery/poweredfans/fan_assembly.dm @@ -25,7 +25,7 @@ switch(stat) if(1) // Stat 1 - if(istype(W, /obj/item/weldingtool)) + if(W.tool_behaviour == TOOL_WELDER) if(weld(W, user)) to_chat(user, "You weld the fan assembly securely into place.") setAnchored(TRUE) @@ -46,7 +46,7 @@ forceMove(F) F.setDir(src.dir) return - else if(istype(W, /obj/item/weldingtool)) + else if(W.tool_behaviour == TOOL_WELDER) if(weld(W, user)) to_chat(user, "You unweld the fan assembly from its place.") stat = 1 @@ -64,7 +64,9 @@ deconstruct() return TRUE -/obj/machinery/fan_assembly/proc/weld(obj/item/weldingtool/W, mob/living/user) +/obj/machinery/fan_assembly/proc/weld(obj/item/W, mob/living/user) + if(!W.tool_behaviour == TOOL_WELDER) + return if(!W.tool_start_check(user, amount=0)) return FALSE switch(stat) diff --git a/code/game/machinery/quantum_pad.dm b/code/game/machinery/quantum_pad.dm index 4f706954a6..5c1a2195a4 100644 --- a/code/game/machinery/quantum_pad.dm +++ b/code/game/machinery/quantum_pad.dm @@ -55,19 +55,17 @@ return if(panel_open) - if(istype(I, /obj/item/multitool)) - var/obj/item/multitool/M = I - M.buffer = src + if(I.tool_behaviour == TOOL_MULTITOOL) + I.buffer = src to_chat(user, "You save the data in [I]'s buffer. It can now be saved to pads with closed panels.") return TRUE - else if(istype(I, /obj/item/multitool)) - var/obj/item/multitool/M = I - if(istype(M.buffer, /obj/machinery/quantumpad)) - if(M.buffer == src) + else if(I.tool_behaviour == TOOL_MULTITOOL) + if(istype(I.buffer, /obj/machinery/quantumpad)) + if(I.buffer == src) to_chat(user, "You cannot link a pad to itself!") return TRUE else - linked_pad = M.buffer + linked_pad = I.buffer to_chat(user, "You link [src] to the one in [I]'s buffer.") return TRUE else diff --git a/code/game/machinery/recharger.dm b/code/game/machinery/recharger.dm index 1d118023c9..aad011119f 100755 --- a/code/game/machinery/recharger.dm +++ b/code/game/machinery/recharger.dm @@ -61,7 +61,7 @@ setCharging() /obj/machinery/recharger/attackby(obj/item/G, mob/user, params) - if(istype(G, /obj/item/wrench)) + if(G.tool_behaviour == TOOL_WRENCH) if(charging) to_chat(user, "Remove the charging item first!") return @@ -102,7 +102,7 @@ if(default_deconstruction_screwdriver(user, "rechargeropen", "recharger0", G)) return - if(panel_open && istype(G, /obj/item/crowbar)) + if(panel_open && G.tool_behaviour == TOOL_CROWBAR) default_deconstruction_crowbar(G) return diff --git a/code/game/machinery/requests_console.dm b/code/game/machinery/requests_console.dm index 2915c2f34b..5d1b30741b 100644 --- a/code/game/machinery/requests_console.dm +++ b/code/game/machinery/requests_console.dm @@ -502,7 +502,7 @@ GLOBAL_LIST_EMPTY(allConsoles) messages += "From: [linkedsender]
[message]" /obj/machinery/requests_console/attackby(obj/item/O, mob/user, params) - if(istype(O, /obj/item/crowbar)) + if(O.tool_behaviour == TOOL_CROWBAR) if(open) to_chat(user, "You close the maintenance panel.") open = FALSE @@ -511,7 +511,7 @@ GLOBAL_LIST_EMPTY(allConsoles) open = TRUE update_icon() return - if(istype(O, /obj/item/screwdriver)) + if(O.tool_behaviour == TOOL_SCREWDRIVER) if(open) hackState = !hackState if(hackState) diff --git a/code/game/machinery/shieldgen.dm b/code/game/machinery/shieldgen.dm index 8a0f376b0f..2ebb137839 100644 --- a/code/game/machinery/shieldgen.dm +++ b/code/game/machinery/shieldgen.dm @@ -146,7 +146,7 @@ return /obj/machinery/shieldgen/attackby(obj/item/W, mob/user, params) - if(istype(W, /obj/item/screwdriver)) + if(W.tool_behaviour == TOOL_SCREWDRIVER) W.play_tool_sound(src, 100) panel_open = !panel_open if(panel_open) @@ -165,7 +165,7 @@ to_chat(user, "You repair \the [src].") update_icon() - else if(istype(W, /obj/item/wrench)) + else if(W.tool_behaviour == TOOL_WRENCH) if(locked) to_chat(user, "The bolts are covered! Unlocking this would retract the covers.") return @@ -343,7 +343,7 @@ return ..() /obj/machinery/shieldwallgen/attackby(obj/item/W, mob/user, params) - if(istype(W, /obj/item/wrench)) + if(W.tool_behaviour == TOOL_WRENCH) default_unfasten_wrench(user, W, 0) else if(W.GetID()) diff --git a/code/game/machinery/spaceheater.dm b/code/game/machinery/spaceheater.dm index 056902801f..d6478f2e58 100644 --- a/code/game/machinery/spaceheater.dm +++ b/code/game/machinery/spaceheater.dm @@ -164,7 +164,7 @@ else to_chat(user, "The hatch must be open to insert a power cell!") return - else if(istype(I, /obj/item/screwdriver)) + else if(I.tool_behaviour == TOOL_SCREWDRIVER) panel_open = !panel_open user.visible_message("\The [user] [panel_open ? "opens" : "closes"] the hatch on \the [src].", "You [panel_open ? "open" : "close"] the hatch on \the [src].") update_icon() diff --git a/code/game/machinery/syndicatebeacon.dm b/code/game/machinery/syndicatebeacon.dm index 1b3f942c51..fc5af59dcb 100644 --- a/code/game/machinery/syndicatebeacon.dm +++ b/code/game/machinery/syndicatebeacon.dm @@ -75,7 +75,7 @@ GLOBAL_VAR_INIT(singularity_counter, 0) to_chat(user, "You need to screw the beacon to the floor first!") /obj/machinery/power/singularity_beacon/attackby(obj/item/W, mob/user, params) - if(istype(W, /obj/item/screwdriver)) + if(W.tool_behaviour == TOOL_SCREWDRIVER) if(active) to_chat(user, "You need to deactivate the beacon first!") return diff --git a/code/game/machinery/syndicatebomb.dm b/code/game/machinery/syndicatebomb.dm index 50984c43b8..561daf433d 100644 --- a/code/game/machinery/syndicatebomb.dm +++ b/code/game/machinery/syndicatebomb.dm @@ -112,7 +112,7 @@ . = timer_set /obj/machinery/syndicatebomb/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/wrench) && can_unanchor) + if(I.tool_behaviour == TOOL_WRENCH && can_unanchor) if(!anchored) if(!isturf(loc) || isspaceturf(loc)) to_chat(user, "The bomb must be placed on solid ground to attach it.") @@ -130,7 +130,7 @@ else to_chat(user, "The bolts are locked down!") - else if(istype(I, /obj/item/screwdriver)) + else if(I.tool_behaviour == TOOL_SCREWDRIVER) open_panel = !open_panel update_icon() to_chat(user, "You [open_panel ? "open" : "close"] the wire panel.") @@ -138,7 +138,7 @@ else if(is_wire_tool(I) && open_panel) wires.interact(user) - else if(istype(I, /obj/item/crowbar)) + else if(I.tool_behaviour == TOOL_CROWBAR) if(open_panel && wires.is_all_cut()) if(payload) to_chat(user, "You carefully pry out [payload].") @@ -158,7 +158,7 @@ to_chat(user, "You place [payload] into [src].") else to_chat(user, "[payload] is already loaded into [src]! You'll have to remove it first.") - else if(istype(I, /obj/item/weldingtool)) + else if(I.tool_behaviour == TOOL_WELDER) if(payload || !wires.is_all_cut() || !open_panel) return @@ -436,7 +436,7 @@ qdel(src) /obj/item/bombcore/chemical/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/crowbar) && beakers.len > 0) + if(I.tool_behaviour == TOOL_CROWBAR && beakers.len > 0) I.play_tool_sound(src) for (var/obj/item/B in beakers) B.forceMove(drop_location()) diff --git a/code/game/machinery/telecomms/computers/message.dm b/code/game/machinery/telecomms/computers/message.dm index 539025e4d5..a674bb6489 100644 --- a/code/game/machinery/telecomms/computers/message.dm +++ b/code/game/machinery/telecomms/computers/message.dm @@ -80,7 +80,7 @@ ref = REF(pda) ) data_out["message_logs"] += list(data) - + return data_out /obj/machinery/computer/message_monitor/ui_data(mob/user) @@ -119,7 +119,7 @@ if(!linkedServer) data_out["selected"] = null return data_out - + data_out["selected"] = list( name = linkedServer.name, id = linkedServer.id, @@ -156,7 +156,7 @@ if(LAZYLEN(machinelist) > 0) message = "FAILED: Cannot probe when buffer full" return - + for(var/obj/machinery/telecomms/message_server/T in GLOB.telecomms_list) if(T.network == network) LAZYADD(machinelist, T) @@ -206,7 +206,7 @@ message = "NOTICE: Decryption key set." return message = incorrectkey - + if("hack") if(!(linkedServer.on && (linkedServer.toggled != FALSE))) message = noserver @@ -225,7 +225,7 @@ else if(!(linkedServer.on && (linkedServer.toggled != FALSE))) message = noserver return - + var/datum/data_ref = locate(params["ref"]) if(istype(data_ref, /datum/data_rc_msg)) LAZYREMOVE(linkedServer.rc_msgs, data_ref) @@ -258,7 +258,7 @@ else if(!(linkedServer.on && (linkedServer.toggled != FALSE))) message = noserver return - + if("reset" in params) ResetMessage() return @@ -311,7 +311,7 @@ return custommessage = M return - + if("recepient" in params) // Get out list of viable PDAs var/list/obj/item/pda/sendPDAs = get_viewable_pdas() @@ -324,8 +324,8 @@ update_static_data(usr) /obj/machinery/computer/message_monitor/attackby(obj/item/O, mob/living/user, params) - if(istype(O, /obj/item/screwdriver) && CHECK_BITFIELD(obj_flags, EMAGGED)) - //Stops people from just unscrewing the monitor and putting it back to get the console working again. + if(O.tool_behaviour == TOOL_SCREWDRIVER && CHECK_BITFIELD(obj_flags, EMAGGED)) + //Stops people from just unscrewing the monitor and putting it back to get the console working again. //Why this though, you should make it emag to a board level. (i wont do it) to_chat(user, "It is too hot to mess with!") else diff --git a/code/game/machinery/telecomms/machine_interactions.dm b/code/game/machinery/telecomms/machine_interactions.dm index cc8784c5b8..d1c7222485 100644 --- a/code/game/machinery/telecomms/machine_interactions.dm +++ b/code/game/machinery/telecomms/machine_interactions.dm @@ -11,7 +11,7 @@ /obj/machinery/telecomms/attackby(obj/item/P, mob/user, params) var/icon_closed = initial(icon_state) var/icon_open = "[initial(icon_state)]_o" - + if(!on) icon_closed = "[initial(icon_state)]_off" icon_open = "[initial(icon_state)]_o_off" @@ -19,7 +19,7 @@ if(default_deconstruction_screwdriver(user, icon_open, icon_closed, P)) return // Using a multitool lets you access the receiver's interface - else if(istype(P, /obj/item/multitool)) + else if(P.tool_behaviour == TOOL_MULTITOOL) attack_hand(user) else if(default_deconstruction_crowbar(P)) @@ -42,7 +42,7 @@ . = list() //cpypaste from the vending bus .["notice"] = temp .["multitool"] = FALSE - var/obj/item/multitool/P = get_multitool(user) + var/obj/item/P = get_multitool(user) if(P) .["multitool"] = TRUE .["multitool_buf"] = null //to clean the list! @@ -113,7 +113,7 @@ if("network" in params) if(!canAccess(usr)) return - var/newnet = sanitize(sanitize_text(params["network"], network)) + var/newnet = sanitize(sanitize_text(params["network"], network)) if(length(newnet) > 15) temp = "-% Too many characters in new network tag. %-" return @@ -122,19 +122,19 @@ temp = "-% New network tag assigned: \"[network]\" %-" return if("multitool") - var/obj/item/multitool/P = get_multitool(usr) + var/obj/item/P = get_multitool(usr) if("Link" in params) if(!canAccess(usr)) return - if(!istype(P)) + if(!P.tool_behaviour == TOOL_MULTITOOL) temp = "-% Unable to acquire buffer %-" return - + var/obj/machinery/telecomms/T = P.buffer if(!istype(T) || T == src) temp = "-% Unable to acquire buffer %-" return - + if(!(src in T.links)) LAZYADD(T.links, src) @@ -158,7 +158,7 @@ return P.buffer = src - temp = "% Successfully stored [REF(P.buffer)] [P.buffer.name] in buffer %-" + temp = "% Successfully stored [REF(P.buffer)] [P.buffer] in buffer %-" if("unlink") var/obj/machinery/telecomms/T = locate(params["value"]) @@ -167,7 +167,7 @@ if(!istype(T)) temp = "-% Unable to locate machine to unlink from, try again. %-" return - + temp = "-% Removed [REF(T)] [T.name] from linked entities. %-" if(T.links) //lazyrem makes blank list null, which is good but some might cause runtime ee's T.links.Remove(src) @@ -198,7 +198,7 @@ var/x = text2num(params["remove"]) temp = "-% Removed frequency filter [x] %-" freq_listening.Remove(x) - + /obj/machinery/telecomms/relay/ui_act(action, params) ..() switch(action) @@ -243,7 +243,11 @@ // Check if the user can use it. /obj/machinery/telecomms/proc/canInteract(mob/user) - if(hasSiliconAccessInArea(user) || istype(user.get_active_held_item(), /obj/item/multitool)) + var/get = user.get_active_held_item() + var/obj/item/I = get + if(I.tool_behaviour == TOOL_MULTITOOL) + return TRUE + if(hasSiliconAccessInArea(user)) return TRUE return FALSE // Check if the user is nearby and has a multitool. @@ -256,14 +260,16 @@ /obj/machinery/telecomms/proc/get_multitool(mob/user) if(!canInteract(user)) return null - var/obj/item/multitool/P = user.get_active_held_item() + var/obj/item/P = user.get_active_held_item() // Is the ref not a null? and is it the actual type? - if(istype(P)) + if(P.tool_behaviour == TOOL_MULTITOOL) return P else if(isAI(user)) var/mob/living/silicon/ai/U = user P = U.aiMulti else if(iscyborg(user) && in_range(user, src)) - if(istype(user.get_active_held_item(), /obj/item/multitool)) - P = user.get_active_held_item() + var/get = user.get_active_held_item() + var/obj/item/I = get + if(I.tool_behaviour == TOOL_MULTITOOL) + I = user.get_active_held_item() return P diff --git a/code/game/machinery/telecomms/machines/allinone.dm b/code/game/machinery/telecomms/machines/allinone.dm index fbb5505586..7cc421ef15 100644 --- a/code/game/machinery/telecomms/machines/allinone.dm +++ b/code/game/machinery/telecomms/machines/allinone.dm @@ -38,5 +38,5 @@ signal.broadcast() /obj/machinery/telecomms/allinone/attackby(obj/item/P, mob/user, params) - if(istype(P, /obj/item/multitool)) + if(P.tool_behaviour == TOOL_MULTITOOL) return attack_hand(user) diff --git a/code/game/machinery/teleporter.dm b/code/game/machinery/teleporter.dm index 16ae158ea7..daadbf4f72 100644 --- a/code/game/machinery/teleporter.dm +++ b/code/game/machinery/teleporter.dm @@ -164,16 +164,15 @@ return ..() /obj/machinery/teleport/station/attackby(obj/item/W, mob/user, params) - if(istype(W, /obj/item/multitool)) - var/obj/item/multitool/M = W + if(W.tool_behaviour == TOOL_MULTITOOL) if(panel_open) - M.buffer = src + W.buffer = src to_chat(user, "You download the data to the [W.name]'s buffer.") else - if(M.buffer && istype(M.buffer, /obj/machinery/teleport/station) && M.buffer != src) + if(W.buffer && istype(W.buffer, /obj/machinery/teleport/station) && W.buffer != src) if(linked_stations.len < efficiency) - linked_stations.Add(M.buffer) - M.buffer = null + linked_stations.Add(W.buffer) + W.buffer = null to_chat(user, "You upload the data from the [W.name]'s buffer.") else to_chat(user, "This station can't hold more information, try to use better parts.") @@ -185,7 +184,7 @@ else if(default_deconstruction_crowbar(W)) return - else if(istype(W, /obj/item/wirecutters)) + else if(W.tool_behaviour == TOOL_WIRECUTTER) if(panel_open) link_console_and_hub() to_chat(user, "You reconnect the station to nearby machinery.") diff --git a/code/game/mecha/equipment/weapons/weapons.dm b/code/game/mecha/equipment/weapons/weapons.dm index f2bced4aa8..30bf06b475 100644 --- a/code/game/mecha/equipment/weapons/weapons.dm +++ b/code/game/mecha/equipment/weapons/weapons.dm @@ -97,7 +97,7 @@ icon_state = "mecha_ion" energy_drain = 120 projectile = /obj/item/projectile/ion - fire_sound = 'sound/weapons/laser.ogg' + fire_sound = 'sound/weapons/IonRifle.ogg' /obj/item/mecha_parts/mecha_equipment/weapon/energy/tesla equip_cooldown = 35 @@ -195,7 +195,7 @@ //Base ballistic weapon type /obj/item/mecha_parts/mecha_equipment/weapon/ballistic name = "general ballistic weapon" - fire_sound = 'sound/weapons/gunshot.ogg' + fire_sound = 'sound/weapons/lmgshot.ogg' var/projectiles var/projectiles_cache //ammo to be loaded in, if possible. var/projectiles_cache_max @@ -285,6 +285,7 @@ /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/scattershot name = "\improper LBX AC 10 \"Scattershot\"" desc = "A weapon for combat exosuits. Shoots a spread of pellets." + fire_sound = 'sound/weapons/gunshotshotgunshot.ogg' icon_state = "mecha_scatter" equip_cooldown = 20 projectile = /obj/item/projectile/bullet/scattershot @@ -299,6 +300,7 @@ /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/seedscatter name = "\improper Melon Seed \"Scattershot\"" desc = "A weapon for combat exosuits. Shoots a spread of pellets, shaped as seed." + fire_sound = 'sound/weapons/gunshotshotgunshot.ogg' icon_state = "mecha_scatter" equip_cooldown = 20 projectile = /obj/item/projectile/bullet/seed @@ -331,7 +333,7 @@ desc = "A weapon for combat exosuits. Launches light explosive missiles." icon_state = "mecha_missilerack" projectile = /obj/item/projectile/bullet/a84mm_he - fire_sound = 'sound/weapons/grenadelaunch.ogg' + fire_sound = 'sound/weapons/rocketlaunch.ogg' projectiles = 8 projectiles_cache = 0 projectiles_cache_max = 0 @@ -345,7 +347,7 @@ desc = "A weapon for combat exosuits. Launches low-explosive breaching missiles designed to explode only when striking a sturdy target." icon_state = "mecha_missilerack_six" projectile = /obj/item/projectile/bullet/a84mm_br - fire_sound = 'sound/weapons/grenadelaunch.ogg' + fire_sound = 'sound/weapons/rocketlaunch.ogg' projectiles = 6 projectiles_cache = 0 projectiles_cache_max = 0 diff --git a/code/game/mecha/mecha_defense.dm b/code/game/mecha/mecha_defense.dm index d5b27a9636..ed26ff6185 100644 --- a/code/game/mecha/mecha_defense.dm +++ b/code/game/mecha/mecha_defense.dm @@ -196,7 +196,7 @@ to_chat(user, "Invalid ID: Access denied.") else to_chat(user, "Maintenance protocols disabled by operator.") - else if(istype(W, /obj/item/wrench)) + else if(W.tool_behaviour == TOOL_WRENCH) if(state==1) state = 2 to_chat(user, "You undo the securing bolts.") @@ -204,7 +204,7 @@ state = 1 to_chat(user, "You tighten the securing bolts.") return - else if(istype(W, /obj/item/crowbar)) + else if(W.tool_behaviour == TOOL_CROWBAR) if(state==2) state = 3 to_chat(user, "You open the hatch to the power unit.") @@ -220,7 +220,7 @@ else to_chat(user, "You need two lengths of cable to fix this mech!") return - else if(istype(W, /obj/item/screwdriver) && user.a_intent != INTENT_HARM) + else if(W.tool_behaviour == TOOL_SCREWDRIVER && user.a_intent != INTENT_HARM) if(internal_damage & MECHA_INT_TEMP_CONTROL) clearInternalDamage(MECHA_INT_TEMP_CONTROL) to_chat(user, "You repair the damaged temperature controller.") @@ -248,7 +248,7 @@ to_chat(user, "There's already a powercell installed.") return - else if(istype(W, /obj/item/weldingtool) && user.a_intent != INTENT_HARM) + else if(W.tool_behaviour == TOOL_WELDER && user.a_intent != INTENT_HARM) user.DelayNextAction(CLICK_CD_MELEE) if(obj_integrity < max_integrity) if(W.use_tool(src, user, 0, volume=50, amount=1)) diff --git a/code/game/mecha/mecha_wreckage.dm b/code/game/mecha/mecha_wreckage.dm index 9175489c89..36584b85ec 100644 --- a/code/game/mecha/mecha_wreckage.dm +++ b/code/game/mecha/mecha_wreckage.dm @@ -35,7 +35,7 @@ . += "The AI recovery beacon is active." /obj/structure/mecha_wreckage/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/weldingtool)) + if(I.tool_behaviour == TOOL_WELDER) if(salvage_num <= 0 || !length(welder_salvage)) to_chat(user, "You don't see anything that can be cut with [I]!") return @@ -54,7 +54,7 @@ to_chat(user, "You fail to salvage anything valuable from [src]!") return - else if(istype(I, /obj/item/wirecutters)) + else if(I.tool_behaviour == TOOL_WIRECUTTER) if(salvage_num <= 0) to_chat(user, "You don't see anything that can be cut with [I]!") return @@ -67,7 +67,7 @@ else to_chat(user, "You fail to salvage anything valuable from [src]!") - else if(istype(I, /obj/item/crowbar)) + else if(I.tool_behaviour == TOOL_CROWBAR) if(crowbar_salvage && crowbar_salvage.len) var/obj/S = pick(crowbar_salvage) if(S) diff --git a/code/game/objects/effects/contraband.dm b/code/game/objects/effects/contraband.dm index 8e2f39d0df..846132a2fc 100644 --- a/code/game/objects/effects/contraband.dm +++ b/code/game/objects/effects/contraband.dm @@ -92,7 +92,7 @@ /obj/structure/sign/poster/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/wirecutters)) + if(I.tool_behaviour == TOOL_WIRECUTTER) I.play_tool_sound(src, 100) if(ruined) to_chat(user, "You remove the remnants of the poster.") diff --git a/code/game/objects/effects/decals/cleanable/humans.dm b/code/game/objects/effects/decals/cleanable/humans.dm index 6d051b6c8c..bd32ddadf3 100644 --- a/code/game/objects/effects/decals/cleanable/humans.dm +++ b/code/game/objects/effects/decals/cleanable/humans.dm @@ -81,6 +81,7 @@ /obj/effect/decal/cleanable/trail_holder //not a child of blood on purpose name = "blood" + icon = 'icons/effects/blood.dmi' icon_state = "ltrails_1" desc = "Your instincts say you shouldn't be following these." random_icon_states = null diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 608768a0c7..8a09bca0bf 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -112,6 +112,12 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb var/tool_behaviour = NONE var/toolspeed = 1 + //Special multitools + var/buffer = null + var/show_wires = FALSE + var/datum/integrated_io/selected_io = null //functional for integrated circuits. + //Special crowbar + var/can_force_powered = FALSE var/reach = 1 //In tiles, how far this weapon can reach; 1 for adjacent, which is default diff --git a/code/game/objects/items/RCL.dm b/code/game/objects/items/RCL.dm index e0ac4b43c6..019231b8b4 100644 --- a/code/game/objects/items/RCL.dm +++ b/code/game/objects/items/RCL.dm @@ -63,7 +63,7 @@ return update_icon() to_chat(user, "You add the cables to [src]. It now contains [loaded.amount].") - else if(istype(W, /obj/item/screwdriver)) + else if(W.tool_behaviour == TOOL_SCREWDRIVER) if(!loaded) return if(ghetto && prob(10)) //Is it a ghetto RCL? If so, give it a 10% chance to fall apart diff --git a/code/game/objects/items/armor_kits.dm b/code/game/objects/items/armor_kits.dm index fa88b77600..906d7c5f81 100644 --- a/code/game/objects/items/armor_kits.dm +++ b/code/game/objects/items/armor_kits.dm @@ -10,35 +10,41 @@ /obj/item/armorkit/afterattack(atom/target, mob/user, proximity_flag, click_parameters) // yeah have fun making subtypes and modifying the afterattack if you want to make variants // idiot - // - hatter var/used = FALSE if(isobj(target) && istype(target, /obj/item/clothing/under)) var/obj/item/clothing/under/C = target - if(C.armor.melee < 10) - C.armor.melee = 10 + if(C.damaged_clothes) + to_chat(user,"You should repair the damage done to [C] first.") + return + if(C.attached_accessory) + to_chat(user,"Kind of hard to sew around [C.attached_accessory].") + return + if(C.armor.getRating("melee") < 10) + C.armor = C.armor.setRating("melee" = 10) used = TRUE - if(C.armor.laser < 10) - C.armor.laser = 10 + if(C.armor.getRating("laser") < 10) + C.armor = C.armor.setRating("laser" = 10) used = TRUE - if(C.armor.fire < 40) - C.armor.fire = 40 + if(C.armor.getRating("fire") < 40) + C.armor = C.armor.setRating("fire" = 40) used = TRUE - if(C.armor.acid < 10) - C.armor.acid = 10 + if(C.armor.getRating("acid") < 10) + C.armor = C.armor.setRating("acid" = 10) used = TRUE - if(C.armor.bomb < 5) - C.armor.bomb = 5 + if(C.armor.getRating("bomb") < 5) + C.armor = C.armor.setRating("bomb" = 5) used = TRUE if(used) - user.visible_message("[user] uses [src] on [C], reinforcing it and tossing the empty case away afterwards.", \ - "You reinforce [C] with [src], making it a little more protective! You toss the empty casing away afterwards.") - C.name = "durathread [C.name]" // this disappears if it gets repaired, which is annoying + user.visible_message("[user] reinforces [C] with [src].", \ + "You reinforce [C] with [src], making it as protective as a durathread jumpsuit.") + C.name = "durathread [C.name]" + C.upgrade_prefix = "durathread" // god i hope this works qdel(src) return else - to_chat(user, "You stare at [src] and [C], coming to the conclusion that you probably don't need to reinforce it any further.") + to_chat(user, "You don't need to reinforce [C] any further.") return else return diff --git a/code/game/objects/items/charter.dm b/code/game/objects/items/charter.dm index 9b658bc5f1..3f5296a1ef 100644 --- a/code/game/objects/items/charter.dm +++ b/code/game/objects/items/charter.dm @@ -63,7 +63,7 @@ to_chat(user, "Your name has been sent to your employers for approval.") // Autoapproves after a certain time response_timer_id = addtimer(CALLBACK(src, .proc/rename_station, new_name, user.name, user.real_name, key_name(user)), approval_time, TIMER_STOPPABLE) - to_chat(GLOB.admins, "CUSTOM STATION RENAME:[ADMIN_LOOKUPFLW(user)] proposes to rename the [name_type] to [new_name] (will autoapprove in [DisplayTimeText(approval_time)]). [ADMIN_SMITE(user)] (REJECT) [ADMIN_CENTCOM_REPLY(user)]") + to_chat(GLOB.admins, "CUSTOM STATION RENAME:[ADMIN_LOOKUPFLW(user)] proposes to rename the [name_type] to [html_encode(new_name)] (will autoapprove in [DisplayTimeText(approval_time)]). [ADMIN_SMITE(user)] (REJECT) [ADMIN_CENTCOM_REPLY(user)]") /obj/item/station_charter/proc/reject_proposed(user) if(!user) diff --git a/code/game/objects/items/circuitboards/computer_circuitboards.dm b/code/game/objects/items/circuitboards/computer_circuitboards.dm index 9a1c770417..8387c2704e 100644 --- a/code/game/objects/items/circuitboards/computer_circuitboards.dm +++ b/code/game/objects/items/circuitboards/computer_circuitboards.dm @@ -66,7 +66,7 @@ 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)) + if(I.tool_behaviour == TOOL_SCREWDRIVER) target_dept = (target_dept == dept_list.len) ? 1 : (target_dept + 1) to_chat(user, "You set the board to \"[dept_list[target_dept]]\".") else @@ -181,7 +181,7 @@ build_path = /obj/machinery/computer/rdconsole/core /obj/item/circuitboard/computer/rdconsole/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/screwdriver)) + if(I.tool_behaviour == TOOL_SCREWDRIVER) if(build_path == /obj/machinery/computer/rdconsole/core) name = "R&D Console - Robotics (Computer Board)" build_path = /obj/machinery/computer/rdconsole/robotics @@ -338,7 +338,7 @@ build_path = /obj/machinery/computer/libraryconsole /obj/item/circuitboard/computer/libraryconsole/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/screwdriver)) + if(I.tool_behaviour == TOOL_SCREWDRIVER) if(build_path == /obj/machinery/computer/libraryconsole/bookmanagement) name = "Library Visitor Console (Computer Board)" build_path = /obj/machinery/computer/libraryconsole diff --git a/code/game/objects/items/circuitboards/machine_circuitboards.dm b/code/game/objects/items/circuitboards/machine_circuitboards.dm index 89d566f714..e0ea5f3bac 100644 --- a/code/game/objects/items/circuitboards/machine_circuitboards.dm +++ b/code/game/objects/items/circuitboards/machine_circuitboards.dm @@ -296,7 +296,7 @@ /obj/machinery/vending/custom = "Custom Vendor") /obj/item/circuitboard/machine/vendor/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/screwdriver)) + if(I.tool_behaviour == TOOL_SCREWDRIVER) var/position = vending_names_paths.Find(build_path) position = (position == vending_names_paths.len) ? 1 : (position + 1) var/typepath = vending_names_paths[position] @@ -372,7 +372,7 @@ build_path = PATH_HEATER /obj/item/circuitboard/machine/thermomachine/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/screwdriver)) + if(I.tool_behaviour == TOOL_SCREWDRIVER) var/obj/item/circuitboard/new_type var/new_setting switch(build_path) @@ -441,7 +441,7 @@ needs_anchored = FALSE /obj/item/circuitboard/machine/processor/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/screwdriver)) + if(I.tool_behaviour == TOOL_SCREWDRIVER) if(build_path == /obj/machinery/processor) name = "Slime Processor (Machine Board)" build_path = /obj/machinery/processor/slime @@ -477,7 +477,7 @@ return ..() /obj/item/circuitboard/machine/smartfridge/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/screwdriver)) + if(I.tool_behaviour == TOOL_SCREWDRIVER) var/position = fridges_name_paths.Find(build_path, fridges_name_paths) position = (position == fridges_name_paths.len) ? 1 : (position + 1) build_path = fridges_name_paths[position] @@ -658,7 +658,7 @@ build_path = PATH_POWERCOIL /obj/item/circuitboard/machine/tesla_coil/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/screwdriver)) + if(I.tool_behaviour == TOOL_SCREWDRIVER) var/obj/item/circuitboard/new_type var/new_setting switch(build_path) @@ -777,7 +777,7 @@ needs_anchored = FALSE /obj/item/circuitboard/machine/chem_master/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/screwdriver)) + if(I.tool_behaviour == TOOL_SCREWDRIVER) var/new_name = "ChemMaster" var/new_path = /obj/machinery/chem_master diff --git a/code/game/objects/items/defib.dm b/code/game/objects/items/defib.dm index ecc8f9187a..25a5bcc800 100644 --- a/code/game/objects/items/defib.dm +++ b/code/game/objects/items/defib.dm @@ -120,7 +120,7 @@ to_chat(user, "You install a cell in [src].") update_power() - else if(istype(W, /obj/item/screwdriver)) + else if(W.tool_behaviour == TOOL_SCREWDRIVER) if(cell) cell.update_icon() cell.forceMove(get_turf(src)) diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index c09d23aafb..2820b11312 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -665,7 +665,8 @@ GLOBAL_LIST_EMPTY(PDAs) create_message(U, locate(href_list["target"])) if("MessageAll") - send_to_all(U) + if(cartridge?.spam_enabled) + send_to_all(U) if("toggle_block") toggle_blocking(usr, href_list["target"]) diff --git a/code/game/objects/items/devices/geiger_counter.dm b/code/game/objects/items/devices/geiger_counter.dm index f5d3014d35..2413a3fb9a 100644 --- a/code/game/objects/items/devices/geiger_counter.dm +++ b/code/game/objects/items/devices/geiger_counter.dm @@ -166,7 +166,7 @@ to_chat(user, "[icon2html(src, user)] Target is free of radioactive contamination.") /obj/item/geiger_counter/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/screwdriver) && (obj_flags & EMAGGED)) + if(I.tool_behaviour == TOOL_SCREWDRIVER && (obj_flags & EMAGGED)) if(scanning) to_chat(user, "Turn off [src] before you perform this action!") return 0 diff --git a/code/game/objects/items/devices/gps.dm b/code/game/objects/items/devices/gps.dm index a0b695e29f..e0453cebc0 100644 --- a/code/game/objects/items/devices/gps.dm +++ b/code/game/objects/items/devices/gps.dm @@ -8,11 +8,12 @@ slot_flags = ITEM_SLOT_BELT obj_flags = UNIQUE_RENAME var/gpstag = "COM0" + var/emp_proof = FALSE var/starton = TRUE /obj/item/gps/Initialize() . = ..() - AddComponent(/datum/component/gps/item, gpstag, starton) + AddComponent(/datum/component/gps/item, gpstag, emp_proof, starton) /obj/item/gps/science icon_state = "gps-s" diff --git a/code/game/objects/items/devices/laserpointer.dm b/code/game/objects/items/devices/laserpointer.dm index 6d10d31f5c..4d9c0a687c 100644 --- a/code/game/objects/items/devices/laserpointer.dm +++ b/code/game/objects/items/devices/laserpointer.dm @@ -50,7 +50,7 @@ else to_chat(user, "[src] already has a diode installed.") - else if(istype(W, /obj/item/screwdriver)) + else if(W.tool_behaviour == TOOL_SCREWDRIVER) if(diode) to_chat(user, "You remove the [diode.name] from \the [src].") diode.forceMove(drop_location()) diff --git a/code/game/objects/items/devices/multitool.dm b/code/game/objects/items/devices/multitool.dm index c02eb4a051..5177224835 100644 --- a/code/game/objects/items/devices/multitool.dm +++ b/code/game/objects/items/devices/multitool.dm @@ -26,10 +26,9 @@ throw_range = 7 throw_speed = 3 custom_materials = list(/datum/material/iron=50, /datum/material/glass=20) - var/obj/machinery/buffer // simple machine buffer for device linkage + buffer = null // simple machine buffer for device linkage toolspeed = 1 usesound = 'sound/weapons/empty.ogg' - var/datum/integrated_io/selected_io = null //functional for integrated circuits. var/mode = 0 /obj/item/multitool/chaplain @@ -72,7 +71,7 @@ if(selected_io) icon_state += "_red" -/obj/item/multitool/proc/wire(var/datum/integrated_io/io, mob/user) +/obj/item/proc/wire(var/datum/integrated_io/io, mob/user) if(!io.holder.assembly) to_chat(user, "\The [io.holder] needs to be secured inside an assembly first.") return @@ -101,7 +100,7 @@ update_icon() -/obj/item/multitool/proc/unwire(var/datum/integrated_io/io1, var/datum/integrated_io/io2, mob/user) +/obj/item/proc/unwire(var/datum/integrated_io/io1, var/datum/integrated_io/io2, mob/user) if(!io1.linked.len || !io2.linked.len) to_chat(user, "There is nothing connected to the data channel.") return @@ -256,6 +255,7 @@ icon = 'icons/obj/abductor.dmi' icon_state = "multitool" toolspeed = 0.1 + show_wires = TRUE /obj/item/multitool/advanced name = "advanced multitool" @@ -263,6 +263,7 @@ icon = 'icons/obj/advancedtools.dmi' icon_state = "multitool" toolspeed = 0.2 + show_wires = TRUE /obj/item/multitool/advanced/brass name = "clockwork multitool" diff --git a/code/game/objects/items/devices/paicard.dm b/code/game/objects/items/devices/paicard.dm index 9a722feb6a..e7a9d51ebe 100644 --- a/code/game/objects/items/devices/paicard.dm +++ b/code/game/objects/items/devices/paicard.dm @@ -122,7 +122,10 @@ /obj/item/paicard/proc/setPersonality(mob/living/silicon/pai/personality) src.pai = personality src.add_overlay("pai-null") - + var/list/policies = CONFIG_GET(keyed_list/policyconfig) + var/policy = policies[POLICYCONFIG_PAI] + if(policy) + to_chat(personality, policy) playsound(loc, 'sound/effects/pai_boot.ogg', 50, 1, -1) audible_message("\The [src] plays a cheerful startup noise!") diff --git a/code/game/objects/items/devices/powersink.dm b/code/game/objects/items/devices/powersink.dm index 86d7766fd5..838b5376c5 100644 --- a/code/game/objects/items/devices/powersink.dm +++ b/code/game/objects/items/devices/powersink.dm @@ -67,7 +67,7 @@ GLOBAL_LIST_EMPTY(power_sinks) set_light(0) /obj/item/powersink/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/screwdriver)) + if(I.tool_behaviour == TOOL_SCREWDRIVER) if(mode == DISCONNECTED) var/turf/T = loc if(isturf(T) && !T.intact) diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm index 939d77a1f0..54556c20b6 100644 --- a/code/game/objects/items/devices/radio/headset.dm +++ b/code/game/objects/items/devices/radio/headset.dm @@ -69,7 +69,8 @@ GLOBAL_LIST_INIT(channel_tokens, list( /obj/item/radio/headset/talk_into(mob/living/M, message, channel, list/spans,datum/language/language) if (!listening) return ITALICS | REDUCE_RANGE - return ..() + if (language != /datum/language/signlanguage) + return ..() /obj/item/radio/headset/can_receive(freq, level, AIuser) if(ishuman(src.loc)) @@ -277,7 +278,7 @@ GLOBAL_LIST_INIT(channel_tokens, list( to_chat(user,"You upgrade [src].") bowmanize() qdel(W) - if(istype(W, /obj/item/screwdriver)) + if(W.tool_behaviour == TOOL_SCREWDRIVER) if(keyslot || keyslot2) for(var/ch_name in channels) SSradio.remove_object(src, GLOB.radiochannels[ch_name]) diff --git a/code/game/objects/items/devices/radio/intercom.dm b/code/game/objects/items/devices/radio/intercom.dm index 8657684ff4..72552de98d 100644 --- a/code/game/objects/items/devices/radio/intercom.dm +++ b/code/game/objects/items/devices/radio/intercom.dm @@ -23,7 +23,7 @@ freerange = TRUE /obj/item/radio/intercom/ratvar/attackby(obj/item/I, mob/living/user, params) - if(istype(I, /obj/item/screwdriver)) + if(I.tool_behaviour == TOOL_SCREWDRIVER) to_chat(user, "[src] is fastened to the wall with [is_servant_of_ratvar(user) ? "replicant alloy" : "some material you've never seen"], and can't be removed.") return //no unfastening! . = ..() @@ -57,7 +57,7 @@ . += "It's unscrewed from the wall, and can be detached." /obj/item/radio/intercom/attackby(obj/item/I, mob/living/user, params) - if(istype(I, /obj/item/screwdriver)) + if(I.tool_behaviour == TOOL_SCREWDRIVER) if(unfastened) user.visible_message("[user] starts tightening [src]'s screws...", "You start screwing in [src]...") if(I.use_tool(src, user, 30, volume=50)) @@ -69,7 +69,7 @@ user.visible_message("[user] loosens [src]'s screws!", "You unscrew [src], loosening it from the wall.") unfastened = TRUE return - else if(istype(I, /obj/item/wrench)) + else if(I.tool_behaviour == TOOL_WRENCH) if(!unfastened) to_chat(user, "You need to unscrew [src] from the wall first!") return diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index 4623a405de..e81110425c 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -208,6 +208,8 @@ return if(!M.IsVocal()) return + if(language == /datum/language/signlanguage) + return if(use_command) spans |= commandspan @@ -331,7 +333,7 @@ /obj/item/radio/attackby(obj/item/W, mob/user, params) add_fingerprint(user) - if(istype(W, /obj/item/screwdriver)) + if(W.tool_behaviour == TOOL_SCREWDRIVER) unscrewed = !unscrewed if(unscrewed) to_chat(user, "The radio can now be attached and modified!") @@ -382,7 +384,7 @@ /obj/item/radio/borg/attackby(obj/item/W, mob/user, params) - if(istype(W, /obj/item/screwdriver)) + if(W.tool_behaviour == TOOL_SCREWDRIVER) if(keyslot) for(var/ch_name in channels) SSradio.remove_object(src, GLOB.radiochannels[ch_name]) diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index cfe0ba705d..8b5e1edd91 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -893,7 +893,7 @@ GENETICS SCANNER throw_range = 7 custom_materials = list(/datum/material/iron=200) var/list/discovered = list() //hit a dna console to update the scanners database - var/list/buffer + buffer = list() var/ready = TRUE var/cooldown = 200 diff --git a/code/game/objects/items/devices/taperecorder.dm b/code/game/objects/items/devices/taperecorder.dm index 687b3ed771..958877d42d 100644 --- a/code/game/objects/items/devices/taperecorder.dm +++ b/code/game/objects/items/devices/taperecorder.dm @@ -314,7 +314,7 @@ /obj/item/tape/attackby(obj/item/I, mob/user, params) - if(ruined && istype(I, /obj/item/screwdriver) || istype(I, /obj/item/pen)) + if(ruined && I.tool_behaviour == TOOL_SCREWDRIVER || istype(I, /obj/item/pen)) to_chat(user, "You start winding the tape back in...") if(I.use_tool(src, user, 120)) to_chat(user, "You wound the tape back in.") diff --git a/code/game/objects/items/dualsaber.dm b/code/game/objects/items/dualsaber.dm index 6cf6a524de..3d62a98ddf 100644 --- a/code/game/objects/items/dualsaber.dm +++ b/code/game/objects/items/dualsaber.dm @@ -253,7 +253,7 @@ possible_colors = list("purple") /obj/item/dualsaber/attackby(obj/item/W, mob/user, params) - if(istype(W, /obj/item/multitool)) + if(W.tool_behaviour == TOOL_MULTITOOL) if(!hacked) hacked = TRUE to_chat(user, "2XRNBW_ENGAGE") diff --git a/code/game/objects/items/flamethrower.dm b/code/game/objects/items/flamethrower.dm index f0afdfd17c..4f921d2a55 100644 --- a/code/game/objects/items/flamethrower.dm +++ b/code/game/objects/items/flamethrower.dm @@ -79,7 +79,7 @@ flame_turf(turflist) /obj/item/flamethrower/attackby(obj/item/W, mob/user, params) - if(istype(W, /obj/item/wrench) && !status)//Taking this apart + if(W.tool_behaviour == TOOL_WRENCH && !status)//Taking this apart var/turf/T = get_turf(src) if(weldtool) weldtool.forceMove(T) @@ -94,7 +94,7 @@ qdel(src) return - else if(istype(W, /obj/item/screwdriver) && igniter && !lit) + else if(W.tool_behaviour == TOOL_SCREWDRIVER && igniter && !lit) status = !status to_chat(user, "[igniter] is now [status ? "secured" : "unsecured"]!") update_icon() diff --git a/code/game/objects/items/grenades/chem_grenade.dm b/code/game/objects/items/grenades/chem_grenade.dm index f06dd634c6..b67b7ae587 100644 --- a/code/game/objects/items/grenades/chem_grenade.dm +++ b/code/game/objects/items/grenades/chem_grenade.dm @@ -51,7 +51,7 @@ /obj/item/grenade/chem_grenade/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/screwdriver)) + if(I.tool_behaviour == TOOL_SCREWDRIVER) if(stage == WIRED) if(beakers.len) stage_change(READY) @@ -105,11 +105,11 @@ to_chat(user, "You need one length of coil to wire the assembly!") return - else if(stage == READY && istype(I, /obj/item/wirecutters) && !active) + else if(stage == READY && I.tool_behaviour == TOOL_WIRECUTTER && !active) stage_change(WIRED) to_chat(user, "You unlock the [initial(name)] assembly.") - else if(stage == WIRED && istype(I, /obj/item/wrench)) + else if(stage == WIRED && I.tool_behaviour == TOOL_WRENCH) if(beakers.len) for(var/obj/O in beakers) O.forceMove(drop_location()) @@ -275,7 +275,7 @@ var/unit_spread = 10 // Amount of units per repeat. Can be altered with a multitool. /obj/item/grenade/chem_grenade/adv_release/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/multitool)) + if(I.tool_behaviour == TOOL_MULTITOOL) switch(unit_spread) if(0 to 24) unit_spread += 5 diff --git a/code/game/objects/items/grenades/plastic.dm b/code/game/objects/items/grenades/plastic.dm index ee259c4050..23fe128fa8 100644 --- a/code/game/objects/items/grenades/plastic.dm +++ b/code/game/objects/items/grenades/plastic.dm @@ -47,7 +47,7 @@ playsound(src, 'sound/weapons/tap.ogg', 20, 1) update_icon() return - if(nadeassembly && istype(I, /obj/item/wirecutters)) + if(nadeassembly && I.tool_behaviour == TOOL_WIRECUTTER) I.play_tool_sound(src, 20) nadeassembly.forceMove(get_turf(src)) nadeassembly.master = null @@ -206,7 +206,7 @@ user.gib(1, 1) /obj/item/grenade/plastic/c4/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/screwdriver)) + if(I.tool_behaviour == TOOL_SCREWDRIVER) open_panel = !open_panel to_chat(user, "You [open_panel ? "open" : "close"] the wire panel.") else if(is_wire_tool(I)) diff --git a/code/game/objects/items/handcuffs.dm b/code/game/objects/items/handcuffs.dm index 296b46bf85..59b6d56b51 100644 --- a/code/game/objects/items/handcuffs.dm +++ b/code/game/objects/items/handcuffs.dm @@ -245,6 +245,9 @@ slowdown = 7 breakouttime = 300 //Deciseconds = 30s = 0.5 minute +/obj/item/restraints/legcuffs/proc/on_removed() + return + /obj/item/restraints/legcuffs/beartrap name = "bear trap" throw_speed = 1 @@ -376,4 +379,8 @@ icon_state = "ebola" hitsound = 'sound/weapons/taserhit.ogg' w_class = WEIGHT_CLASS_SMALL - breakouttime = 60 + breakouttime = 25 + +/obj/item/restraints/legcuffs/bola/energy/on_removed() + do_sparks(1, TRUE, src) + qdel(src) diff --git a/code/game/objects/items/holy_weapons.dm b/code/game/objects/items/holy_weapons.dm index a541fb8fe3..44121d64d1 100644 --- a/code/game/objects/items/holy_weapons.dm +++ b/code/game/objects/items/holy_weapons.dm @@ -771,7 +771,10 @@ /obj/item/nullrod/tribal_knife/process() slowdown = rand(-2, 2) - + if(iscarbon(loc)) + var/mob/living/carbon/wielder = loc + if(wielder.is_holding(src)) + wielder.update_equipment_speed_mods() /obj/item/nullrod/pitchfork icon_state = "pitchfork0" diff --git a/code/game/objects/items/implants/implant_misc.dm b/code/game/objects/items/implants/implant_misc.dm index 83e9b21e0b..0a86abdec9 100644 --- a/code/game/objects/items/implants/implant_misc.dm +++ b/code/game/objects/items/implants/implant_misc.dm @@ -44,7 +44,7 @@ icon_state = "warp" uses = -1 var/total_delay = 10 SECONDS - var/cooldown = 10 SECONDS + var/cooldown = 30 SECONDS var/last_use = 0 var/list/positions = list() var/next_prune = 0 diff --git a/code/game/objects/items/inducer.dm b/code/game/objects/items/inducer.dm index 8a596b2e6e..ddcd35f834 100644 --- a/code/game/objects/items/inducer.dm +++ b/code/game/objects/items/inducer.dm @@ -62,7 +62,7 @@ /obj/item/inducer/attackby(obj/item/W, mob/user) - if(istype(W, /obj/item/screwdriver)) + if(W.tool_behaviour == TOOL_SCREWDRIVER) W.play_tool_sound(src) if(!opened) to_chat(user, "You unscrew the battery compartment.") diff --git a/code/game/objects/items/melee/energy.dm b/code/game/objects/items/melee/energy.dm index 7d95b8e736..55546a7f9c 100644 --- a/code/game/objects/items/melee/energy.dm +++ b/code/game/objects/items/melee/energy.dm @@ -279,7 +279,7 @@ to_chat(user, "[src] is now [choice].") /obj/item/melee/transforming/energy/sword/saber/attackby(obj/item/W, mob/living/user, params) - if(istype(W, /obj/item/multitool)) + if(W.tool_behaviour == TOOL_MULTITOOL) if(user.a_intent == INTENT_DISARM) if(!active) to_chat(user, "COLOR_SET") @@ -439,7 +439,9 @@ force_on = 15 //As strong a survival knife/bone dagger /obj/item/melee/transforming/energy/sword/cx/attackby(obj/item/W, mob/living/user, params) - if(istype(W, /obj/item/melee/transforming/energy/sword/cx)) + if(istype(W, /obj/item/melee/transforming/energy/sword/cx/traitor)) + return + else if(istype(W, /obj/item/melee/transforming/energy/sword/cx)) if(HAS_TRAIT(W, TRAIT_NODROP) || HAS_TRAIT(src, TRAIT_NODROP)) to_chat(user, "\the [HAS_TRAIT(src, TRAIT_NODROP) ? src : W] is stuck to your hand, you can't attach it to \the [HAS_TRAIT(src, TRAIT_NODROP) ? W : src]!") return diff --git a/code/game/objects/items/pneumaticCannon.dm b/code/game/objects/items/pneumaticCannon.dm index 1db5cdd526..e62208f848 100644 --- a/code/game/objects/items/pneumaticCannon.dm +++ b/code/game/objects/items/pneumaticCannon.dm @@ -84,7 +84,7 @@ updateTank(W, 0, user) else if(W.type == type) to_chat(user, "You're fairly certain that putting a pneumatic cannon inside another pneumatic cannon would cause a spacetime disruption.") - else if(istype(W, /obj/item/wrench)) + else if(W.tool_behaviour == TOOL_WRENCH) switch(pressureSetting) if(1) pressureSetting = 2 @@ -93,7 +93,7 @@ if(3) pressureSetting = 1 to_chat(user, "You tweak \the [src]'s pressure output to [pressureSetting].") - else if(istype(W, /obj/item/screwdriver)) + else if(W.tool_behaviour == TOOL_SCREWDRIVER) if(tank) updateTank(tank, 1, user) else if(loadedWeightClass >= maxWeightClass) diff --git a/code/game/objects/items/powerfist.dm b/code/game/objects/items/powerfist.dm index bd83404356..f95acd6018 100644 --- a/code/game/objects/items/powerfist.dm +++ b/code/game/objects/items/powerfist.dm @@ -36,7 +36,7 @@ to_chat(user, "\The [IT] is too small for \the [src].") return updateTank(W, 0, user) - else if(istype(W, /obj/item/wrench)) + else if(W.tool_behaviour == TOOL_WRENCH) switch(fisto_setting) if(1) fisto_setting = 2 @@ -46,7 +46,7 @@ fisto_setting = 1 W.play_tool_sound(src) to_chat(user, "You tweak \the [src]'s piston valve to [fisto_setting].") - else if(istype(W, /obj/item/screwdriver)) + else if(W.tool_behaviour == TOOL_SCREWDRIVER) if(tank) updateTank(tank, 1, user) diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm index 86468af355..fbb3297f89 100644 --- a/code/game/objects/items/robot/robot_parts.dm +++ b/code/game/objects/items/robot/robot_parts.dm @@ -226,7 +226,7 @@ else to_chat(user, "You need to attach a flash to it first!") - else if (istype(W, /obj/item/multitool)) + else if(W.tool_behaviour == TOOL_MULTITOOL) if(check_completion()) Interact(user) else @@ -382,7 +382,7 @@ var/mob/living/living_user = usr var/obj/item/item_in_hand = living_user.get_active_held_item() - if(!istype(item_in_hand, /obj/item/multitool)) + if(!item_in_hand.tool_behaviour == TOOL_MULTITOOL) to_chat(living_user, "You need a multitool!") return diff --git a/code/game/objects/items/stacks/rods.dm b/code/game/objects/items/stacks/rods.dm index 1277bb3d4e..c6763092ca 100644 --- a/code/game/objects/items/stacks/rods.dm +++ b/code/game/objects/items/stacks/rods.dm @@ -20,7 +20,7 @@ GLOBAL_LIST_INIT(rod_recipes, list ( \ custom_materials = list(/datum/material/iron=1000) max_amount = 50 attack_verb = list("hit", "bludgeoned", "whacked") - hitsound = 'sound/weapons/grenadelaunch.ogg' + hitsound = 'sound/items/trayhit1.ogg' embedding = list() novariants = TRUE @@ -44,7 +44,7 @@ GLOBAL_LIST_INIT(rod_recipes, list ( \ icon_state = "rods" /obj/item/stack/rods/attackby(obj/item/W, mob/user, params) - if(istype(W, /obj/item/weldingtool)) + if(W.tool_behaviour == TOOL_WELDER) if(get_amount() < 2) to_chat(user, "You need at least two rods to do this!") return diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index 62949b45a8..798f1d3a6a 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -466,6 +466,7 @@ GLOBAL_LIST_INIT(cardboard_recipes, list ( \ new/datum/stack_recipe("cardboard cutout", /obj/item/cardboard_cutout, 5), \ new/datum/stack_recipe("pizza box", /obj/item/pizzabox), \ new/datum/stack_recipe("folder", /obj/item/folder), \ + new/datum/stack_recipe("cardboard card", /obj/item/cardboard_card, 1), \ // holy fuck why are there so many boxes new/datum/stack_recipe_list("fancy boxes", list ( \ new /datum/stack_recipe("donut box", /obj/item/storage/fancy/donut_box), \ diff --git a/code/game/objects/items/stacks/tiles/light.dm b/code/game/objects/items/stacks/tiles/light.dm index 85e08aa4d2..00b1f49d9f 100644 --- a/code/game/objects/items/stacks/tiles/light.dm +++ b/code/game/objects/items/stacks/tiles/light.dm @@ -20,7 +20,7 @@ state = 0 //fine /obj/item/stack/tile/light/attackby(obj/item/O, mob/user, params) - if(istype(O, /obj/item/crowbar)) + if(O.tool_behaviour == TOOL_CROWBAR) new/obj/item/stack/sheet/metal(user.loc) amount-- new/obj/item/stack/light_w(user.loc) diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm index 0f338383c0..8b272f98b4 100644 --- a/code/game/objects/items/stacks/tiles/tile_types.dm +++ b/code/game/objects/items/stacks/tiles/tile_types.dm @@ -40,7 +40,7 @@ /obj/item/stack/tile/attackby(obj/item/W, mob/user, params) - if (istype(W, /obj/item/weldingtool)) + if(W.tool_behaviour == TOOL_WELDER) if(get_amount() < 4) to_chat(user, "You need at least four tiles to do this!") return diff --git a/code/game/objects/items/storage/secure.dm b/code/game/objects/items/storage/secure.dm index 4e6a0b3463..2988b54e8f 100644 --- a/code/game/objects/items/storage/secure.dm +++ b/code/game/objects/items/storage/secure.dm @@ -36,14 +36,14 @@ /obj/item/storage/secure/attackby(obj/item/W, mob/user, params) if(SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED)) - if (istype(W, /obj/item/screwdriver)) + if(W.tool_behaviour == TOOL_SCREWDRIVER) if (W.use_tool(src, user, 20)) open =! open to_chat(user, "You [open ? "open" : "close"] the service panel.") return - if (istype(W, /obj/item/wirecutters)) + if(W.tool_behaviour == TOOL_WIRECUTTER) to_chat(user, "[src] is protected from this sort of tampering, yet it appears the internal memory wires can still be pulsed.") - if ((istype(W, /obj/item/multitool)) && (!l_hacking)) + if((W.tool_behaviour == TOOL_MULTITOOL) && (!l_hacking)) if(open == 1) to_chat(user, "Now attempting to reset internal memory, please hold.") l_hacking = 1 diff --git a/code/game/objects/items/storage/uplink_kits.dm b/code/game/objects/items/storage/uplink_kits.dm index 97012528a0..ae2f432d2e 100644 --- a/code/game/objects/items/storage/uplink_kits.dm +++ b/code/game/objects/items/storage/uplink_kits.dm @@ -526,3 +526,8 @@ new /obj/item/book/granter/martial/carp(src) new /obj/item/clothing/suit/hooded/carp_costume(src) new /obj/item/staff/bostaff(src) + +/obj/item/storage/box/syndie_kit/sleepytime/cardpack/PopulateContents() + . = ..() + new /obj/item/cardpack/syndicate(src) + new /obj/item/cardpack/syndicate(src) diff --git a/code/game/objects/items/stunbaton.dm b/code/game/objects/items/stunbaton.dm index 1de77bd8b9..cc01e6aaee 100644 --- a/code/game/objects/items/stunbaton.dm +++ b/code/game/objects/items/stunbaton.dm @@ -119,7 +119,7 @@ to_chat(user, "You install a cell in [src].") update_icon() - else if(istype(W, /obj/item/screwdriver)) + else if(W.tool_behaviour == TOOL_SCREWDRIVER) if(cell) cell.update_icon() cell.forceMove(get_turf(src)) diff --git a/code/game/objects/items/tools/crowbar.dm b/code/game/objects/items/tools/crowbar.dm index 36f89e57f2..f0fd29adbc 100644 --- a/code/game/objects/items/tools/crowbar.dm +++ b/code/game/objects/items/tools/crowbar.dm @@ -88,6 +88,7 @@ usesound = 'sound/items/jaws_pry.ogg' force = 15 toolspeed = 0.25 + can_force_powered = TRUE /obj/item/crowbar/power/suicide_act(mob/user) user.visible_message("[user] is putting [user.p_their()] head in [src], it looks like [user.p_theyre()] trying to commit suicide!") diff --git a/code/game/objects/items/tools/weldingtool.dm b/code/game/objects/items/tools/weldingtool.dm index 6b92b885bb..98889485b6 100644 --- a/code/game/objects/items/tools/weldingtool.dm +++ b/code/game/objects/items/tools/weldingtool.dm @@ -103,7 +103,7 @@ return (FIRELOSS) /obj/item/weldingtool/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/screwdriver)) + if(I.tool_behaviour == TOOL_SCREWDRIVER) flamethrower_screwdriver(I, user) else if(istype(I, /obj/item/stack/rods)) flamethrower_rods(I, user) diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index 97fced4eb7..454016d9e7 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -277,7 +277,7 @@ newSaber.hacked = TRUE qdel(W) qdel(src) - else if(istype(W, /obj/item/multitool)) + else if(W.tool_behaviour == TOOL_MULTITOOL) if(!hacked) hacked = TRUE to_chat(user, "RNBW_ENGAGE") diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm index 07900d6bbf..554ea81974 100644 --- a/code/game/objects/items/weaponry.dm +++ b/code/game/objects/items/weaponry.dm @@ -302,7 +302,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 damtype = STAMINA attack_verb = list("whacked", "smacked", "struck") total_mass = TOTAL_MASS_MEDIEVAL_WEAPON - hitsound = 'sound/weapons/grenadelaunch.ogg' // no good wood thunk sounds + hitsound = 'sound/weapons/woodbonk.ogg' var/harm = FALSE // TRUE = brute, FALSE = stam var/reinforced = FALSE var/burnt = FALSE diff --git a/code/game/objects/structures/ai_core.dm b/code/game/objects/structures/ai_core.dm index 1090bae9f8..3549ab85f8 100644 --- a/code/game/objects/structures/ai_core.dm +++ b/code/game/objects/structures/ai_core.dm @@ -61,7 +61,7 @@ return TRUE /obj/structure/AIcore/latejoin_inactive/attackby(obj/item/P, mob/user, params) - if(istype(P, /obj/item/multitool)) + if(P.tool_behaviour == TOOL_MULTITOOL) active = !active to_chat(user, "You [active? "activate" : "deactivate"] [src]'s transmitters.") return @@ -76,10 +76,10 @@ return ..() /obj/structure/AIcore/attackby(obj/item/P, mob/user, params) - if(istype(P, /obj/item/wrench)) + if(P.tool_behaviour == TOOL_WRENCH) return default_unfasten_wrench(user, P, 20) if(!anchored) - if(istype(P, /obj/item/weldingtool) && can_deconstruct) + if(P.tool_behaviour == TOOL_WELDER && can_deconstruct) if(state != EMPTY_CORE) to_chat(user, "The core must be empty to deconstruct it!") return @@ -105,13 +105,13 @@ circuit = P return if(CIRCUIT_CORE) - if(istype(P, /obj/item/screwdriver)) + if(P.tool_behaviour == TOOL_SCREWDRIVER) P.play_tool_sound(src) to_chat(user, "You screw the circuit board into place.") state = SCREWED_CORE update_icon() return - if(istype(P, /obj/item/crowbar)) + if(P.tool_behaviour == TOOL_CROWBAR) P.play_tool_sound(src) to_chat(user, "You remove the circuit board.") state = EMPTY_CORE @@ -120,7 +120,7 @@ circuit = null return if(SCREWED_CORE) - if(istype(P, /obj/item/screwdriver) && circuit) + if(P.tool_behaviour == TOOL_SCREWDRIVER && circuit) P.play_tool_sound(src) to_chat(user, "You unfasten the circuit board.") state = CIRCUIT_CORE @@ -139,7 +139,7 @@ to_chat(user, "You need five lengths of cable to wire the AI core!") return if(CABLED_CORE) - if(istype(P, /obj/item/wirecutters)) + if(P.tool_behaviour == TOOL_WIRECUTTER) if(brain) to_chat(user, "Get that [brain.name] out of there first!") else @@ -201,7 +201,7 @@ update_icon() return - if(istype(P, /obj/item/crowbar) && brain) + if(P.tool_behaviour == TOOL_CROWBAR && brain) P.play_tool_sound(src) to_chat(user, "You remove the brain.") brain.forceMove(loc) @@ -210,7 +210,7 @@ return if(GLASS_CORE) - if(istype(P, /obj/item/crowbar)) + if(P.tool_behaviour == TOOL_CROWBAR) P.play_tool_sound(src) to_chat(user, "You remove the glass panel.") state = CABLED_CORE @@ -218,7 +218,7 @@ new /obj/item/stack/sheet/rglass(loc, 2) return - if(istype(P, /obj/item/screwdriver)) + if(P.tool_behaviour == TOOL_SCREWDRIVER) P.play_tool_sound(src) to_chat(user, "You connect the monitor.") if(brain) @@ -247,7 +247,7 @@ P.transfer_ai("INACTIVE", "AICARD", src, user) return - if(istype(P, /obj/item/screwdriver)) + if(P.tool_behaviour == TOOL_SCREWDRIVER) P.play_tool_sound(src) to_chat(user, "You disconnect the monitor.") state = GLASS_CORE diff --git a/code/game/objects/structures/barsigns.dm b/code/game/objects/structures/barsigns.dm index acddf27b6f..a96d39316e 100644 --- a/code/game/objects/structures/barsigns.dm +++ b/code/game/objects/structures/barsigns.dm @@ -62,7 +62,7 @@ pick_sign(user) /obj/structure/sign/barsign/attackby(obj/item/I, mob/user) - if(istype(I, /obj/item/screwdriver)) + if(I.tool_behaviour == TOOL_SCREWDRIVER) if(!allowed(user)) to_chat(user, "Access denied.") return diff --git a/code/game/objects/structures/beds_chairs/bed.dm b/code/game/objects/structures/beds_chairs/bed.dm index 2a703ad675..c86c62094b 100644 --- a/code/game/objects/structures/beds_chairs/bed.dm +++ b/code/game/objects/structures/beds_chairs/bed.dm @@ -37,7 +37,7 @@ return attack_hand(user) /obj/structure/bed/attackby(obj/item/W, mob/user, params) - if(istype(W, /obj/item/wrench) && !(flags_1&NODECONSTRUCT_1)) + if(W.tool_behaviour == TOOL_WRENCH && !(flags_1&NODECONSTRUCT_1)) W.play_tool_sound(src) deconstruct(TRUE) else if(istype(W, /obj/item/bedsheet)) diff --git a/code/game/objects/structures/beds_chairs/chair.dm b/code/game/objects/structures/beds_chairs/chair.dm index 39bef1a9c0..76ab086eb2 100644 --- a/code/game/objects/structures/beds_chairs/chair.dm +++ b/code/game/objects/structures/beds_chairs/chair.dm @@ -77,7 +77,7 @@ qdel(src) /obj/structure/chair/attackby(obj/item/W, mob/user, params) - if(istype(W, /obj/item/wrench) && !(flags_1&NODECONSTRUCT_1)) + if(W.tool_behaviour == TOOL_WRENCH && !(flags_1 & NODECONSTRUCT_1)) W.play_tool_sound(src) deconstruct() else if(istype(W, /obj/item/assembly/shock_kit)) diff --git a/code/game/objects/structures/bedsheet_bin.dm b/code/game/objects/structures/bedsheet_bin.dm index 279f581b4d..2172040022 100644 --- a/code/game/objects/structures/bedsheet_bin.dm +++ b/code/game/objects/structures/bedsheet_bin.dm @@ -45,7 +45,7 @@ LINEN BINS return /obj/item/bedsheet/attackby(obj/item/I, mob/user, params) - if(!(flags_1 & HOLOGRAM_1) && (istype(I, /obj/item/wirecutters) || I.get_sharpness())) + if(!(flags_1 & HOLOGRAM_1) && (I.tool_behaviour == TOOL_WIRECUTTER || I.get_sharpness())) var/obj/item/stack/sheet/cloth/C = new (get_turf(src), 3) transfer_fingerprints_to(C) C.add_fingerprint(user) diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 52082637a3..be7a457c7d 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -25,7 +25,7 @@ var/max_mob_size = MOB_SIZE_HUMAN //Biggest mob_size accepted by the container var/mob_storage_capacity = 3 // how many human sized mob/living can fit together inside a closet. var/storage_capacity = 30 //This is so that someone can't pack hundreds of items in a locker/crate then open it in a populated area to crash clients. - var/cutting_tool = /obj/item/weldingtool + var/cutting_tool = TOOL_WELDER var/open_sound = 'sound/machines/click.ogg' var/close_sound = 'sound/machines/click.ogg' var/material_drop = /obj/item/stack/sheet/metal @@ -302,7 +302,9 @@ update_icon() return TRUE -/obj/structure/closet/proc/handle_lock_removal(mob/user, obj/item/screwdriver/S) +/obj/structure/closet/proc/handle_lock_removal(mob/user, obj/item/S) + if(!S.tool_behaviour == TOOL_SCREWDRIVER) + return if(lock_in_use) to_chat(user, "Wait for work on [src] to be done first!") return @@ -357,7 +359,7 @@ if(opened) if(istype(W, cutting_tool)) var/welder = FALSE - if(istype(W, /obj/item/weldingtool)) + if(W.tool_behaviour == TOOL_WELDER) if(!W.tool_start_check(user, amount=0)) return to_chat(user, "You begin [welder ? "slicing" : "deconstructing"] \the [src] apart...") @@ -377,9 +379,9 @@ return TRUE else if(istype(W, /obj/item/electronics/airlock)) handle_lock_addition(user, W) - else if(istype(W, /obj/item/screwdriver)) + else if(W.tool_behaviour == TOOL_SCREWDRIVER) handle_lock_removal(user, W) - else if(istype(W, /obj/item/weldingtool) && can_weld_shut) + else if(W.tool_behaviour == TOOL_WELDER && can_weld_shut) if(!W.tool_start_check(user, amount=0)) return @@ -396,7 +398,7 @@ "You [welded ? "weld" : "unwelded"] \the [src] with \the [W].", "You hear welding.") update_icon() - else if(istype(W, /obj/item/wrench) && anchorable) + else if(W.tool_behaviour == TOOL_WRENCH && anchorable) if(isinspace() && !anchored) return setAnchored(!anchored) diff --git a/code/game/objects/structures/crates_lockers/closets/bodybag.dm b/code/game/objects/structures/crates_lockers/closets/bodybag.dm index 2df57e1d68..09441a577e 100644 --- a/code/game/objects/structures/crates_lockers/closets/bodybag.dm +++ b/code/game/objects/structures/crates_lockers/closets/bodybag.dm @@ -32,7 +32,7 @@ else name = "body bag" return - else if(istype(I, /obj/item/wirecutters)) + else if(I.tool_behaviour == TOOL_WIRECUTTER) to_chat(user, "You cut the tag off [src].") name = "body bag" tagged = 0 diff --git a/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm b/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm index 500b8d6a49..1d6826b548 100644 --- a/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm +++ b/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm @@ -8,7 +8,7 @@ max_integrity = 70 integrity_failure = 0 can_weld_shut = 0 - cutting_tool = /obj/item/wirecutters + cutting_tool = TOOL_WIRECUTTER open_sound = "rustle" material_drop = /obj/item/stack/sheet/cardboard delivery_icon = "deliverybox" @@ -74,7 +74,7 @@ mob_storage_capacity = 5 resistance_flags = NONE move_speed_multiplier = 2 - cutting_tool = /obj/item/weldingtool + cutting_tool = TOOL_WELDER open_sound = 'sound/machines/click.ogg' material_drop = /obj/item/stack/sheet/plasteel #undef SNAKE_SPAM_TICKS diff --git a/code/game/objects/structures/crates_lockers/closets/gimmick.dm b/code/game/objects/structures/crates_lockers/closets/gimmick.dm index 0da502283b..b33962d8de 100644 --- a/code/game/objects/structures/crates_lockers/closets/gimmick.dm +++ b/code/game/objects/structures/crates_lockers/closets/gimmick.dm @@ -5,7 +5,7 @@ resistance_flags = FLAMMABLE max_integrity = 70 material_drop = /obj/item/stack/sheet/mineral/wood - cutting_tool = /obj/item/screwdriver + cutting_tool = TOOL_SCREWDRIVER /obj/structure/closet/acloset name = "strange closet" diff --git a/code/game/objects/structures/crates_lockers/closets/secure/bar.dm b/code/game/objects/structures/crates_lockers/closets/secure/bar.dm index 484d152a3f..36b770cd25 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/bar.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/bar.dm @@ -5,7 +5,7 @@ resistance_flags = FLAMMABLE max_integrity = 70 material_drop = /obj/item/stack/sheet/mineral/wood - cutting_tool = /obj/item/screwdriver + cutting_tool = TOOL_SCREWDRIVER /obj/structure/closet/secure_closet/bar/PopulateContents() ..() diff --git a/code/game/objects/structures/crates_lockers/closets/secure/personal.dm b/code/game/objects/structures/crates_lockers/closets/secure/personal.dm index d127a87b20..52abb00cc7 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/personal.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/personal.dm @@ -26,7 +26,7 @@ resistance_flags = FLAMMABLE max_integrity = 70 material_drop = /obj/item/stack/sheet/mineral/wood - cutting_tool = /obj/item/screwdriver + cutting_tool = TOOL_SCREWDRIVER /obj/structure/closet/secure_closet/personal/cabinet/PopulateContents() new /obj/item/storage/backpack/satchel/leather/withwallet( src ) diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security.dm b/code/game/objects/structures/crates_lockers/closets/secure/security.dm index 2c31303f79..1d23903d03 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm @@ -155,7 +155,7 @@ resistance_flags = FLAMMABLE max_integrity = 70 material_drop = /obj/item/stack/sheet/mineral/wood - cutting_tool = /obj/item/screwdriver + cutting_tool = TOOL_SCREWDRIVER /obj/structure/closet/secure_closet/detective/PopulateContents() ..() diff --git a/code/game/objects/structures/crates_lockers/crates/large.dm b/code/game/objects/structures/crates_lockers/crates/large.dm index 3cee96e435..c376e63880 100644 --- a/code/game/objects/structures/crates_lockers/crates/large.dm +++ b/code/game/objects/structures/crates_lockers/crates/large.dm @@ -16,7 +16,7 @@ to_chat(user, "You need a crowbar to pry this open!") /obj/structure/closet/crate/large/attackby(obj/item/W, mob/user, params) - if(istype(W, /obj/item/crowbar)) + if(W.tool_behaviour == TOOL_CROWBAR) if(manifest) tear_manifest(user) diff --git a/code/game/objects/structures/displaycase.dm b/code/game/objects/structures/displaycase.dm index 2eda9f126a..e3b9ae1df1 100644 --- a/code/game/objects/structures/displaycase.dm +++ b/code/game/objects/structures/displaycase.dm @@ -108,7 +108,7 @@ toggle_lock(user) else to_chat(user, "Access denied.") - else if(istype(W, /obj/item/weldingtool) && user.a_intent == INTENT_HELP && !broken) + else if(W.tool_behaviour == TOOL_WELDER && user.a_intent == INTENT_HELP && !broken) if(obj_integrity < max_integrity) if(!W.tool_start_check(user, amount=5)) return @@ -121,7 +121,7 @@ else to_chat(user, "[src] is already in good condition!") return - else if(!alert && istype(W, /obj/item/crowbar) && openable) //Only applies to the lab cage and player made display cases + else if(!alert && W.tool_behaviour == TOOL_CROWBAR && openable) //Only applies to the lab cage and player made display cases if(broken) if(showpiece) to_chat(user, "Remove the displayed object first.") @@ -187,7 +187,7 @@ /obj/structure/displaycase_chassis/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/wrench)) //The player can only deconstruct the wooden frame + if(I.tool_behaviour == TOOL_WRENCH) //The player can only deconstruct the wooden frame to_chat(user, "You start disassembling [src]...") I.play_tool_sound(src) if(I.use_tool(src, user, 30)) diff --git a/code/game/objects/structures/door_assembly.dm b/code/game/objects/structures/door_assembly.dm index ac6ea27821..aba3b743bb 100644 --- a/code/game/objects/structures/door_assembly.dm +++ b/code/game/objects/structures/door_assembly.dm @@ -58,7 +58,7 @@ return created_name = t - else if(istype(W, /obj/item/weldingtool) && (mineral || glass || !anchored )) + else if(W.tool_behaviour == TOOL_WELDER && (mineral || glass || !anchored )) if(!W.tool_start_check(user, amount=0)) return @@ -88,8 +88,8 @@ to_chat(user, "You disassemble the airlock assembly.") deconstruct(TRUE) - else if(istype(W, /obj/item/wrench)) - if(!anchored ) + else if(W.tool_behaviour == TOOL_WRENCH) + if(!anchored) var/door_check = 1 for(var/obj/machinery/door/D in loc) if(!D.sub_door) @@ -134,7 +134,7 @@ to_chat(user, "You wire the airlock assembly.") name = "wired airlock assembly" - else if(istype(W, /obj/item/wirecutters) && state == AIRLOCK_ASSEMBLY_NEEDS_ELECTRONICS ) + else if(W.tool_behaviour == TOOL_WIRECUTTER && state == AIRLOCK_ASSEMBLY_NEEDS_ELECTRONICS ) user.visible_message("[user] cuts the wires from the airlock assembly.", \ "You start to cut the wires from the airlock assembly...") @@ -162,7 +162,7 @@ electronics = W - else if(istype(W, /obj/item/crowbar) && state == AIRLOCK_ASSEMBLY_NEEDS_SCREWDRIVER ) + else if(W.tool_behaviour == TOOL_CROWBAR && state == AIRLOCK_ASSEMBLY_NEEDS_SCREWDRIVER ) user.visible_message("[user] removes the electronics from the airlock assembly.", \ "You start to remove electronics from the airlock assembly...") @@ -226,7 +226,7 @@ else to_chat(user, "You cannot add [G] to [src]!") - else if(istype(W, /obj/item/screwdriver) && state == AIRLOCK_ASSEMBLY_NEEDS_SCREWDRIVER ) + else if(W.tool_behaviour == TOOL_SCREWDRIVER && state == AIRLOCK_ASSEMBLY_NEEDS_SCREWDRIVER ) user.visible_message("[user] finishes the airlock.", \ "You start finishing the airlock...") diff --git a/code/game/objects/structures/dresser.dm b/code/game/objects/structures/dresser.dm index 7fdec9b3d9..9790a0e661 100644 --- a/code/game/objects/structures/dresser.dm +++ b/code/game/objects/structures/dresser.dm @@ -7,7 +7,7 @@ anchored = TRUE /obj/structure/dresser/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/wrench)) + if(I.tool_behaviour == TOOL_WRENCH) to_chat(user, "You begin to [anchored ? "unwrench" : "wrench"] [src].") if(I.use_tool(src, user, 20, volume=50)) to_chat(user, "You successfully [anchored ? "unwrench" : "wrench"] [src].") diff --git a/code/game/objects/structures/electricchair.dm b/code/game/objects/structures/electricchair.dm index 6f1d56c4a5..c5802b5086 100644 --- a/code/game/objects/structures/electricchair.dm +++ b/code/game/objects/structures/electricchair.dm @@ -11,7 +11,7 @@ add_overlay(mutable_appearance('icons/obj/chairs.dmi', "echair_over", MOB_LAYER + 1)) /obj/structure/chair/e_chair/attackby(obj/item/W, mob/user, params) - if(istype(W, /obj/item/wrench)) + if(W.tool_behaviour == TOOL_WRENCH) var/obj/structure/chair/C = new /obj/structure/chair(loc) W.play_tool_sound(src) C.setDir(dir) diff --git a/code/game/objects/structures/extinguisher.dm b/code/game/objects/structures/extinguisher.dm index 84926ccfb0..467dd47c50 100644 --- a/code/game/objects/structures/extinguisher.dm +++ b/code/game/objects/structures/extinguisher.dm @@ -42,7 +42,7 @@ update_icon() /obj/structure/extinguisher_cabinet/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/wrench) && !stored_extinguisher) + if(I.tool_behaviour == TOOL_WRENCH && !stored_extinguisher) to_chat(user, "You start unsecuring [name]...") I.play_tool_sound(src) if(I.use_tool(src, user, 60)) diff --git a/code/game/objects/structures/false_walls.dm b/code/game/objects/structures/false_walls.dm index b654f4f5c0..5b3cd3139c 100644 --- a/code/game/objects/structures/false_walls.dm +++ b/code/game/objects/structures/false_walls.dm @@ -93,7 +93,7 @@ to_chat(user, "You must wait until the door has stopped moving!") return - if(istype(W, /obj/item/screwdriver)) + if(W.tool_behaviour == TOOL_SCREWDRIVER) if(density) var/turf/T = get_turf(src) if(T.density) @@ -107,7 +107,7 @@ else to_chat(user, "You can't reach, close it first!") - else if(istype(W, /obj/item/weldingtool) || istype(W, /obj/item/gun/energy/plasmacutter)) + else if(W.tool_behaviour == TOOL_WELDER || istype(W, /obj/item/gun/energy/plasmacutter)) if(W.use_tool(src, user, 0, volume=50)) dismantle(user, TRUE) else if(istype(W, /obj/item/pickaxe/drill/jackhammer)) @@ -158,7 +158,7 @@ /obj/structure/falsewall/reinforced/attackby(obj/item/tool, mob/user) ..() - if(istype(tool, /obj/item/wirecutters)) + if(tool.tool_behaviour == TOOL_WIRECUTTER) dismantle(user, TRUE, tool) /* diff --git a/code/game/objects/structures/fence.dm b/code/game/objects/structures/fence.dm index f90161f587..eaf5398605 100644 --- a/code/game/objects/structures/fence.dm +++ b/code/game/objects/structures/fence.dm @@ -57,7 +57,7 @@ hole_size = LARGE_HOLE /obj/structure/fence/attackby(obj/item/W, mob/user) - if(istype(W, /obj/item/wirecutters)) + if(W.tool_behaviour == TOOL_WIRECUTTER) if(!cuttable) to_chat(user, "This section of the fence can't be cut.") return diff --git a/code/game/objects/structures/fireaxe.dm b/code/game/objects/structures/fireaxe.dm index 412730910f..a247908b3b 100644 --- a/code/game/objects/structures/fireaxe.dm +++ b/code/game/objects/structures/fireaxe.dm @@ -24,9 +24,9 @@ return ..() /obj/structure/fireaxecabinet/attackby(obj/item/I, mob/user, params) - if(iscyborg(user) || istype(I, /obj/item/multitool)) + if(iscyborg(user) || I.tool_behaviour == TOOL_MULTITOOL) toggle_lock(user) - else if(istype(I, /obj/item/weldingtool) && user.a_intent == INTENT_HELP && !broken) + else if(I.tool_behaviour == TOOL_WELDER && user.a_intent == INTENT_HELP && !broken) if(obj_integrity < max_integrity) if(!I.tool_start_check(user, amount=2)) return diff --git a/code/game/objects/structures/fluff.dm b/code/game/objects/structures/fluff.dm index bd7ddb36d5..477bc19a22 100644 --- a/code/game/objects/structures/fluff.dm +++ b/code/game/objects/structures/fluff.dm @@ -11,7 +11,7 @@ var/deconstructible = TRUE /obj/structure/fluff/attackby(obj/item/I, mob/living/user, params) - if(istype(I, /obj/item/wrench) && deconstructible) + if(I.tool_behaviour == TOOL_WRENCH && deconstructible) user.visible_message("[user] starts disassembling [src]...", "You start disassembling [src]...") I.play_tool_sound(src) if(I.use_tool(src, user, 50)) diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm index 87cfbb56e0..50240aabb3 100644 --- a/code/game/objects/structures/girders.dm +++ b/code/game/objects/structures/girders.dm @@ -361,7 +361,7 @@ new /obj/item/stack/sheet/runed_metal(drop_location(), 1) qdel(src) - else if(istype(W, /obj/item/weldingtool) || istype(W, /obj/item/gun/energy/plasmacutter)) + else if(W.tool_behaviour == TOOL_WELDER || istype(W, /obj/item/gun/energy/plasmacutter)) if(!W.tool_start_check(user, amount=0)) return @@ -436,7 +436,7 @@ /obj/structure/girder/bronze/attackby(obj/item/W, mob/living/user, params) add_fingerprint(user) - if(istype(W, /obj/item/weldingtool) || istype(W, /obj/item/gun/energy/plasmacutter)) + if(W.tool_behaviour == TOOL_WELDER || istype(W, /obj/item/gun/energy/plasmacutter)) if(!W.tool_start_check(user, amount = 0)) return to_chat(user, "You start slicing apart [src]...") diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm index 7853b9619c..2ac85f79dc 100644 --- a/code/game/objects/structures/grille.dm +++ b/code/game/objects/structures/grille.dm @@ -142,11 +142,11 @@ /obj/structure/grille/attackby(obj/item/W, mob/user, params) user.DelayNextAction(CLICK_CD_MELEE) add_fingerprint(user) - if(istype(W, /obj/item/wirecutters)) + if(W.tool_behaviour == TOOL_WIRECUTTER) if(!shock(user, 100)) W.play_tool_sound(src, 100) deconstruct() - else if((istype(W, /obj/item/screwdriver)) && (isturf(loc) || anchored)) + else if((W.tool_behaviour == TOOL_SCREWDRIVER) && (isturf(loc) || anchored)) if(!shock(user, 90)) W.play_tool_sound(src, 100) setAnchored(!anchored) diff --git a/code/game/objects/structures/janicart.dm b/code/game/objects/structures/janicart.dm index 0c99188c49..bcb9422708 100644 --- a/code/game/objects/structures/janicart.dm +++ b/code/game/objects/structures/janicart.dm @@ -82,7 +82,7 @@ to_chat(user, "[src] can't hold any more signs!") else if(mybag) mybag.attackby(I, user) - else if(istype(I, /obj/item/crowbar)) + else if(I.tool_behaviour == TOOL_CROWBAR) user.visible_message("[user] begins to empty the contents of [src].", "You begin to empty the contents of [src]...") if(I.use_tool(src, user, 30)) to_chat(usr, "You empty the contents of [src]'s bucket onto the floor.") diff --git a/code/game/objects/structures/kitchen_spike.dm b/code/game/objects/structures/kitchen_spike.dm index a23dd3a21e..a37797045f 100644 --- a/code/game/objects/structures/kitchen_spike.dm +++ b/code/game/objects/structures/kitchen_spike.dm @@ -22,7 +22,7 @@ var/obj/F = new /obj/structure/kitchenspike(src.loc) transfer_fingerprints_to(F) qdel(src) - else if(istype(I, /obj/item/weldingtool)) + else if(I.tool_behaviour == TOOL_WELDER) if(!I.tool_start_check(user, amount=0)) return to_chat(user, "You begin cutting \the [src] apart...") diff --git a/code/game/objects/structures/lattice.dm b/code/game/objects/structures/lattice.dm index 17c90e1444..13f86d13bd 100644 --- a/code/game/objects/structures/lattice.dm +++ b/code/game/objects/structures/lattice.dm @@ -39,7 +39,7 @@ /obj/structure/lattice/attackby(obj/item/C, mob/user, params) if(resistance_flags & INDESTRUCTIBLE) return - if(istype(C, /obj/item/wirecutters)) + if(C.tool_behaviour == TOOL_WIRECUTTER) to_chat(user, "Slicing [name] joints ...") deconstruct() else diff --git a/code/game/objects/structures/reflector.dm b/code/game/objects/structures/reflector.dm index 5cc2315352..8174f6a82e 100644 --- a/code/game/objects/structures/reflector.dm +++ b/code/game/objects/structures/reflector.dm @@ -78,13 +78,13 @@ if(admin) return - if(istype(W, /obj/item/screwdriver)) + if(W.tool_behaviour == TOOL_SCREWDRIVER) can_rotate = !can_rotate to_chat(user, "You [can_rotate ? "unlock" : "lock"] [src]'s rotation.") W.play_tool_sound(src) return - if(istype(W, /obj/item/wrench)) + if(W.tool_behaviour == TOOL_WRENCH) if(anchored) to_chat(user, "Unweld [src] from the floor first!") return @@ -95,7 +95,7 @@ if(buildstackamount) new buildstacktype(drop_location(), buildstackamount) qdel(src) - else if(istype(W, /obj/item/weldingtool)) + else if(W.tool_behaviour == TOOL_WELDER) if(obj_integrity < max_integrity) if(!W.tool_start_check(user, amount=0)) return diff --git a/code/game/objects/structures/showcase.dm b/code/game/objects/structures/showcase.dm index b0427274a4..3b7933ab87 100644 --- a/code/game/objects/structures/showcase.dm +++ b/code/game/objects/structures/showcase.dm @@ -109,7 +109,7 @@ //However if a player wants to move an existing showcase or remove one, this is for that. /obj/structure/showcase/attackby(obj/item/W, mob/user) - if(istype(W, /obj/item/screwdriver) && !anchored) + if(W.tool_behaviour == TOOL_SCREWDRIVER && !anchored) if(deconstruction_state == SHOWCASE_SCREWDRIVERED) to_chat(user, "You screw the screws back into the showcase.") W.play_tool_sound(src, 100) @@ -119,7 +119,7 @@ W.play_tool_sound(src, 100) deconstruction_state = SHOWCASE_SCREWDRIVERED - if(istype(W, /obj/item/crowbar) && deconstruction_state == SHOWCASE_SCREWDRIVERED) + if(W.tool_behaviour == TOOL_CROWBAR && deconstruction_state == SHOWCASE_SCREWDRIVERED) if(W.use_tool(src, user, 20, volume=100)) to_chat(user, "You start to crowbar the showcase apart...") new /obj/item/stack/sheet/metal(drop_location(), 4) diff --git a/code/game/objects/structures/signs/_signs.dm b/code/game/objects/structures/signs/_signs.dm index aa31fe9542..8b82cdba5e 100644 --- a/code/game/objects/structures/signs/_signs.dm +++ b/code/game/objects/structures/signs/_signs.dm @@ -26,7 +26,7 @@ playsound(loc, 'sound/items/welder.ogg', 80, 1) /obj/structure/sign/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/wrench) && buildable_sign) + if(I.tool_behaviour == TOOL_WRENCH && buildable_sign) user.visible_message("[user] starts removing [src]...", \ "You start unfastening [src].") I.play_tool_sound(src) diff --git a/code/game/objects/structures/statues.dm b/code/game/objects/structures/statues.dm index f8b54d04b6..2924545cc1 100644 --- a/code/game/objects/structures/statues.dm +++ b/code/game/objects/structures/statues.dm @@ -22,7 +22,7 @@ if(!(flags_1 & NODECONSTRUCT_1)) if(default_unfasten_wrench(user, W)) return - if(istype(W, /obj/item/weldingtool) || istype(W, /obj/item/gun/energy/plasmacutter)) + if(W.tool_behaviour == TOOL_WELDER || istype(W, /obj/item/gun/energy/plasmacutter)) if(!W.tool_start_check(user, amount=0)) return FALSE diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 1ef0726e63..edb69236c6 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -170,13 +170,13 @@ /obj/structure/table/attackby(obj/item/I, mob/user, params) if(!(flags_1 & NODECONSTRUCT_1)) - if(istype(I, /obj/item/screwdriver) && deconstruction_ready) + if(I.tool_behaviour == TOOL_SCREWDRIVER && deconstruction_ready) to_chat(user, "You start disassembling [src]...") if(I.use_tool(src, user, 20, volume=50)) deconstruct(TRUE) return - if(istype(I, /obj/item/wrench) && deconstruction_ready) + if(I.tool_behaviour == TOOL_WRENCH && deconstruction_ready) to_chat(user, "You start deconstructing [src]...") if(I.use_tool(src, user, 40, volume=50)) playsound(src.loc, 'sound/items/deconstruct.ogg', 50, 1) @@ -538,7 +538,7 @@ return "The top cover is firmly welded on." /obj/structure/table/reinforced/attackby(obj/item/W, mob/user, params) - if(istype(W, /obj/item/weldingtool)) + if(W.tool_behaviour == TOOL_WELDER) if(!W.tool_start_check(user, amount=0)) return @@ -689,7 +689,7 @@ step(O, get_dir(O, src)) /obj/structure/rack/attackby(obj/item/W, mob/user, params) - if (istype(W, /obj/item/wrench) && !(flags_1&NODECONSTRUCT_1)) + if(W.tool_behaviour == TOOL_WRENCH && !(flags_1 & NODECONSTRUCT_1)) W.play_tool_sound(src) deconstruct(TRUE) return @@ -747,7 +747,7 @@ var/building = FALSE /obj/item/rack_parts/attackby(obj/item/W, mob/user, params) - if (istype(W, /obj/item/wrench)) + if(W.tool_behaviour == TOOL_WRENCH) new /obj/item/stack/sheet/metal(user.loc) qdel(src) else diff --git a/code/game/objects/structures/tank_dispenser.dm b/code/game/objects/structures/tank_dispenser.dm index 2a441ff0f2..6b5e24089d 100644 --- a/code/game/objects/structures/tank_dispenser.dm +++ b/code/game/objects/structures/tank_dispenser.dm @@ -50,7 +50,7 @@ oxygentanks++ else full = TRUE - else if(istype(I, /obj/item/wrench)) + else if(I.tool_behaviour == TOOL_WRENCH) default_unfasten_wrench(user, I, time = 20) return else if(user.a_intent != INTENT_HARM) diff --git a/code/game/objects/structures/transit_tubes/station.dm b/code/game/objects/structures/transit_tubes/station.dm index c1760fd59a..fb12db04cb 100644 --- a/code/game/objects/structures/transit_tubes/station.dm +++ b/code/game/objects/structures/transit_tubes/station.dm @@ -94,7 +94,7 @@ /obj/structure/transit_tube/station/attackby(obj/item/W, mob/user, params) - if(istype(W, /obj/item/crowbar)) + if(W.tool_behaviour == TOOL_CROWBAR) for(var/obj/structure/transit_tube_pod/P in loc) P.deconstruct(FALSE, user) else diff --git a/code/game/objects/structures/transit_tubes/transit_tube.dm b/code/game/objects/structures/transit_tubes/transit_tube.dm index 56608789f7..7e3684ad32 100644 --- a/code/game/objects/structures/transit_tubes/transit_tube.dm +++ b/code/game/objects/structures/transit_tubes/transit_tube.dm @@ -37,7 +37,7 @@ deconstruct(FALSE) /obj/structure/transit_tube/attackby(obj/item/W, mob/user, params) - if(istype(W, /obj/item/wrench)) + if(W.tool_behaviour == TOOL_WRENCH) if(tube_construction) for(var/obj/structure/transit_tube_pod/pod in src.loc) to_chat(user, "Remove the pod first!") @@ -50,7 +50,7 @@ transfer_fingerprints_to(R) R.add_fingerprint(user) qdel(src) - else if(istype(W, /obj/item/crowbar)) + else if(W.tool_behaviour == TOOL_CROWBAR) for(var/obj/structure/transit_tube_pod/pod in src.loc) pod.attackby(W, user) else 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 21709edf73..89b03a8d78 100644 --- a/code/game/objects/structures/transit_tubes/transit_tube_pod.dm +++ b/code/game/objects/structures/transit_tubes/transit_tube_pod.dm @@ -26,7 +26,7 @@ icon_state = "pod" /obj/structure/transit_tube_pod/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/crowbar)) + if(I.tool_behaviour == TOOL_CROWBAR) if(!moving) I.play_tool_sound(src) if(contents.len) diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm index 2214f9e4bb..2d3ec4bc1f 100644 --- a/code/game/objects/structures/watercloset.dm +++ b/code/game/objects/structures/watercloset.dm @@ -93,7 +93,7 @@ /obj/structure/toilet/attackby(obj/item/I, mob/living/user, params) add_fingerprint(user) - if(istype(I, /obj/item/crowbar)) + if(I.tool_behaviour == TOOL_CROWBAR) to_chat(user, "You start to [cistern ? "replace the lid on the cistern" : "lift the lid off the cistern"]...") playsound(loc, 'sound/effects/stonedoor_openclose.ogg', 50, 1) if(I.use_tool(src, user, 30)) diff --git a/code/game/objects/structures/windoor_assembly.dm b/code/game/objects/structures/windoor_assembly.dm index 4544cab3da..ef1ca6720a 100644 --- a/code/game/objects/structures/windoor_assembly.dm +++ b/code/game/objects/structures/windoor_assembly.dm @@ -87,7 +87,7 @@ add_fingerprint(user) switch(state) if("01") - if(istype(W, /obj/item/weldingtool) && !anchored) + if(W.tool_behaviour == TOOL_WELDER && !anchored) if(!W.tool_start_check(user, amount=0)) return @@ -105,7 +105,7 @@ return //Wrenching an unsecure assembly anchors it in place. Step 4 complete - if(istype(W, /obj/item/wrench) && !anchored) + if(W.tool_behaviour == TOOL_WRENCH && !anchored) for(var/obj/machinery/door/window/WD in loc) if(WD.dir == dir) to_chat(user, "There is already a windoor in that location!") @@ -128,7 +128,7 @@ name = "anchored windoor assembly" //Unwrenching an unsecure assembly un-anchors it. Step 4 undone - else if(istype(W, /obj/item/wrench) && anchored) + else if(W.tool_behaviour == TOOL_WRENCH && anchored) user.visible_message("[user] unsecures the windoor assembly to the floor.", "You start to unsecure the windoor assembly to the floor...") @@ -184,7 +184,7 @@ if("02") //Removing wire from the assembly. Step 5 undone. - if(istype(W, /obj/item/wirecutters)) + if(W.tool_behaviour == TOOL_WIRECUTTER) user.visible_message("[user] cuts the wires from the airlock assembly.", "You start to cut the wires from airlock assembly...") if(W.use_tool(src, user, 40, volume=100)) @@ -218,7 +218,7 @@ W.forceMove(drop_location()) //Screwdriver to remove airlock electronics. Step 6 undone. - else if(istype(W, /obj/item/screwdriver)) + else if(W.tool_behaviour == TOOL_SCREWDRIVER) if(!electronics) return @@ -245,7 +245,7 @@ //Crowbar to complete the assembly, Step 7 complete. - else if(istype(W, /obj/item/crowbar)) + else if(W.tool_behaviour == TOOL_CROWBAR) if(!electronics) to_chat(usr, "The assembly is missing electronics!") return diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 74f006296f..d0b21016d4 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -191,7 +191,7 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup) add_fingerprint(user) - if(istype(I, /obj/item/weldingtool) && user.a_intent == INTENT_HELP) + if(I.tool_behaviour == TOOL_WELDER && user.a_intent == INTENT_HELP) if(obj_integrity < max_integrity) if(!I.tool_start_check(user, amount=0)) return @@ -224,7 +224,7 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup) qdel(K) if(!(flags_1&NODECONSTRUCT_1)) - if(istype(I, /obj/item/screwdriver)) + if(I.tool_behaviour == TOOL_SCREWDRIVER) I.play_tool_sound(src, 75) if(reinf) if(state == WINDOW_SCREWED_TO_FRAME || state == WINDOW_IN_FRAME) @@ -245,7 +245,7 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup) return - else if (istype(I, /obj/item/crowbar) && reinf && (state == WINDOW_OUT_OF_FRAME || state == WINDOW_IN_FRAME)) + else if(I.tool_behaviour == TOOL_CROWBAR && reinf && (state == WINDOW_OUT_OF_FRAME || state == WINDOW_IN_FRAME)) to_chat(user, "You begin to lever the window [state == WINDOW_OUT_OF_FRAME ? "into":"out of"] the frame...") I.play_tool_sound(src, 75) if(I.use_tool(src, user, decon_speed, extra_checks = CALLBACK(src, .proc/check_state_and_anchored, state, anchored))) @@ -253,7 +253,7 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup) to_chat(user, "You pry the window [state == WINDOW_IN_FRAME ? "into":"out of"] the frame.") return - else if(istype(I, /obj/item/wrench) && !anchored) + else if(I.tool_behaviour == TOOL_WRENCH && !anchored) I.play_tool_sound(src, 75) to_chat(user, " You begin to disassemble [src]...") if(I.use_tool(src, user, decon_speed, extra_checks = CALLBACK(src, .proc/check_state_and_anchored, state, anchored))) diff --git a/code/game/turfs/simulated/floor.dm b/code/game/turfs/simulated/floor.dm index 2ee6f77eb1..ba5b12f872 100644 --- a/code/game/turfs/simulated/floor.dm +++ b/code/game/turfs/simulated/floor.dm @@ -171,7 +171,7 @@ /turf/open/floor/proc/try_replace_tile(obj/item/stack/tile/T, mob/user, params) if(T.turf_type == type) return - var/obj/item/crowbar/CB = user.is_holding_item_of_type(/obj/item/crowbar) + var/obj/item/CB = user.is_holding_tool_quality(TOOL_CROWBAR) if(!CB) return var/turf/open/floor/plating/P = pry_tile(CB, user, TRUE) diff --git a/code/game/turfs/simulated/floor/fancy_floor.dm b/code/game/turfs/simulated/floor/fancy_floor.dm index ce27f8fd24..f707037771 100644 --- a/code/game/turfs/simulated/floor/fancy_floor.dm +++ b/code/game/turfs/simulated/floor/fancy_floor.dm @@ -32,9 +32,9 @@ /turf/open/floor/wood/try_replace_tile(obj/item/stack/tile/T, mob/user, params) if(T.turf_type == type) return - var/obj/item/tool = user.is_holding_item_of_type(/obj/item/screwdriver) + var/obj/item/tool = user.is_holding_tool_quality(TOOL_SCREWDRIVER) if(!tool) - tool = user.is_holding_item_of_type(/obj/item/crowbar) + tool = user.is_holding_tool_quality(TOOL_CROWBAR) if(!tool) return var/turf/open/floor/plating/P = pry_tile(tool, user, TRUE) diff --git a/code/game/turfs/simulated/wall/reinf_walls.dm b/code/game/turfs/simulated/wall/reinf_walls.dm index 5e60f65ccc..03d5cecc26 100644 --- a/code/game/turfs/simulated/wall/reinf_walls.dm +++ b/code/game/turfs/simulated/wall/reinf_walls.dm @@ -65,7 +65,7 @@ //DECONSTRUCTION switch(d_state) if(INTACT) - if(istype(W, /obj/item/wirecutters)) + if(W.tool_behaviour == TOOL_WIRECUTTER) W.play_tool_sound(src, 100) d_state = SUPPORT_LINES update_icon() @@ -73,7 +73,7 @@ return 1 if(SUPPORT_LINES) - if(istype(W, /obj/item/screwdriver)) + if(W.tool_behaviour == TOOL_SCREWDRIVER) to_chat(user, "You begin unsecuring the support lines...") if(W.use_tool(src, user, 40, volume=100)) if(!istype(src, /turf/closed/wall/r_wall) || d_state != SUPPORT_LINES) @@ -83,7 +83,7 @@ to_chat(user, "You unsecure the support lines.") return 1 - else if(istype(W, /obj/item/wirecutters)) + else if(W.tool_behaviour == TOOL_WIRECUTTER) W.play_tool_sound(src, 100) d_state = INTACT update_icon() @@ -91,7 +91,7 @@ return 1 if(COVER) - if(istype(W, /obj/item/weldingtool) || istype(W, /obj/item/gun/energy/plasmacutter)) + if(W.tool_behaviour == TOOL_WELDER || istype(W, /obj/item/gun/energy/plasmacutter)) if(!W.tool_start_check(user, amount=0)) return to_chat(user, "You begin slicing through the metal cover...") @@ -103,7 +103,7 @@ to_chat(user, "You press firmly on the cover, dislodging it.") return 1 - if(istype(W, /obj/item/screwdriver)) + if(W.tool_behaviour == TOOL_SCREWDRIVER) to_chat(user, "You begin securing the support lines...") if(W.use_tool(src, user, 40, volume=100)) if(!istype(src, /turf/closed/wall/r_wall) || d_state != COVER) @@ -114,7 +114,7 @@ return 1 if(CUT_COVER) - if(istype(W, /obj/item/crowbar)) + if(W.tool_behaviour == TOOL_CROWBAR) to_chat(user, "You struggle to pry off the cover...") if(W.use_tool(src, user, 100, volume=100)) if(!istype(src, /turf/closed/wall/r_wall) || d_state != CUT_COVER) @@ -124,7 +124,7 @@ to_chat(user, "You pry off the cover.") return 1 - if(istype(W, /obj/item/weldingtool)) + if(W.tool_behaviour == TOOL_WELDER) if(!W.tool_start_check(user, amount=0)) return to_chat(user, "You begin welding the metal cover back to the frame...") @@ -137,7 +137,7 @@ return 1 if(ANCHOR_BOLTS) - if(istype(W, /obj/item/wrench)) + if(W.tool_behaviour == TOOL_WRENCH) to_chat(user, "You start loosening the anchoring bolts which secure the support rods to their frame...") if(W.use_tool(src, user, 40, volume=100)) if(!istype(src, /turf/closed/wall/r_wall) || d_state != ANCHOR_BOLTS) @@ -147,7 +147,7 @@ to_chat(user, "You remove the bolts anchoring the support rods.") return 1 - if(istype(W, /obj/item/crowbar)) + if(W.tool_behaviour == TOOL_CROWBAR) to_chat(user, "You start to pry the cover back into place...") if(W.use_tool(src, user, 20, volume=100)) if(!istype(src, /turf/closed/wall/r_wall) || d_state != ANCHOR_BOLTS) @@ -158,7 +158,7 @@ return 1 if(SUPPORT_RODS) - if(istype(W, /obj/item/weldingtool) || istype(W, /obj/item/gun/energy/plasmacutter)) + if(W.tool_behaviour == TOOL_WELDER || istype(W, /obj/item/gun/energy/plasmacutter)) if(!W.tool_start_check(user, amount=0)) return to_chat(user, "You begin slicing through the support rods...") @@ -170,7 +170,7 @@ to_chat(user, "You slice through the support rods.") return 1 - if(istype(W, /obj/item/wrench)) + if(W.tool_behaviour == TOOL_WRENCH) to_chat(user, "You start tightening the bolts which secure the support rods to their frame...") W.play_tool_sound(src, 100) if(W.use_tool(src, user, 40)) @@ -182,7 +182,7 @@ return 1 if(SHEATH) - if(istype(W, /obj/item/crowbar)) + if(W.tool_behaviour == TOOL_CROWBAR) to_chat(user, "You struggle to pry off the outer sheath...") if(W.use_tool(src, user, 100, volume=100)) if(!istype(src, /turf/closed/wall/r_wall) || d_state != SHEATH) @@ -191,7 +191,7 @@ dismantle_wall() return 1 - if(istype(W, /obj/item/weldingtool)) + if(W.tool_behaviour == TOOL_WELDER) if(!W.tool_start_check(user, amount=0)) return to_chat(user, "You begin welding the support rods back together...") diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm index 402ab36947..79ca5add10 100644 --- a/code/game/turfs/simulated/walls.dm +++ b/code/game/turfs/simulated/walls.dm @@ -199,7 +199,7 @@ if((user.a_intent != INTENT_HELP) || !LAZYLEN(dent_decals)) return FALSE - if(istype(W, /obj/item/weldingtool)) + if(W.tool_behaviour == TOOL_WELDER) if(!W.tool_start_check(user, amount=0)) return FALSE @@ -233,7 +233,7 @@ return FALSE /turf/closed/wall/proc/try_decon(obj/item/I, mob/user, turf/T) - if(istype(I, /obj/item/weldingtool) || istype(I, /obj/item/gun/energy/plasmacutter)) + if(I.tool_behaviour == TOOL_WELDER || istype(I, /obj/item/gun/energy/plasmacutter)) if(!I.tool_start_check(user, amount=0)) return FALSE diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index e0434a6fea..86ddc24ca3 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -257,9 +257,8 @@ for(var/mob/M in GLOB.player_list) if(M.ckey == banckey) - playermob = M - break - + if(!playermob || M.client) // prioritise mobs with a client to stop the 'oops the dead body with no client got forwarded' + playermob = M banreason = "(MANUAL BAN) "+banreason diff --git a/code/modules/antagonists/bloodsucker/items/bloodsucker_stake.dm b/code/modules/antagonists/bloodsucker/items/bloodsucker_stake.dm index 2aed251189..69410027a4 100644 --- a/code/modules/antagonists/bloodsucker/items/bloodsucker_stake.dm +++ b/code/modules/antagonists/bloodsucker/items/bloodsucker_stake.dm @@ -43,14 +43,13 @@ // This exists so Hardened/Silver Stake can't have a welding torch used on them. /obj/item/stake/basic/attackby(obj/item/W, mob/user, params) - if(istype(W, /obj/item/weldingtool)) + if(W.tool_behaviour == TOOL_WELDER) //if (amWelded) // to_chat(user, "This stake has already been treated with fire.") // return //amWelded = TRUE // Weld it - var/obj/item/weldingtool/WT = W - if(WT.use(0))//remove_fuel(0,user)) + if(W.use(0))//remove_fuel(0,user)) user.visible_message("[user.name] scorched the pointy end of [src] with the welding tool.", \ "You scorch the pointy end of [src] with the welding tool.", \ "You hear welding.") diff --git a/code/modules/antagonists/bloodsucker/objects/bloodsucker_coffin.dm b/code/modules/antagonists/bloodsucker/objects/bloodsucker_coffin.dm index a555677719..881da8f282 100644 --- a/code/modules/antagonists/bloodsucker/objects/bloodsucker_coffin.dm +++ b/code/modules/antagonists/bloodsucker/objects/bloodsucker_coffin.dm @@ -164,11 +164,11 @@ if(istype(W, cutting_tool)) to_chat(user, "This is a much more complex mechanical structure than you thought. You don't know where to begin cutting [src].") return - else if(anchored && istype(W, /obj/item/wrench)) // Can't unanchor unless owner. + else if(anchored && W.tool_behaviour == TOOL_WRENCH) // Can't unanchor unless owner. to_chat(user, "The coffin won't come unanchored from the floor.") return - if(locked && istype(W, /obj/item/crowbar)) + if(locked && W.tool_behaviour == TOOL_CROWBAR) var/pry_time = pryLidTimer * W.toolspeed // Pry speed must be affected by the speed of the tool. user.visible_message("[user] tries to pry the lid off of [src] with [W].", \ "You begin prying the lid off of [src] with [W]. This should take about [DisplayTimeText(pry_time)].") diff --git a/code/modules/antagonists/brother/brother.dm b/code/modules/antagonists/brother/brother.dm index 0a2e079921..30e6a80e85 100644 --- a/code/modules/antagonists/brother/brother.dm +++ b/code/modules/antagonists/brother/brother.dm @@ -149,8 +149,6 @@ if(prob(50)) if(LAZYLEN(active_ais()) && prob(100/GLOB.joined_player_list.len)) add_objective(new/datum/objective/destroy, TRUE) - else if(prob(30)) - add_objective(new/datum/objective/maroon, TRUE) else add_objective(new/datum/objective/assassinate, TRUE) else diff --git a/code/modules/antagonists/changeling/changeling.dm b/code/modules/antagonists/changeling/changeling.dm index 7a34af4d13..9c0b19cd83 100644 --- a/code/modules/antagonists/changeling/changeling.dm +++ b/code/modules/antagonists/changeling/changeling.dm @@ -433,30 +433,21 @@ destroy_objective.find_target() objectives += destroy_objective else - if(prob(70)) - var/datum/objective/assassinate/once/kill_objective = new - kill_objective.owner = owner - if(team_mode) //No backstabbing while in a team - kill_objective.find_target_by_role(role = ROLE_CHANGELING, role_type = 1, invert = 1) - else - kill_objective.find_target() - objectives += kill_objective + var/datum/objective/assassinate/once/kill_objective = new + kill_objective.owner = owner + if(team_mode) //No backstabbing while in a team + kill_objective.find_target_by_role(role = ROLE_CHANGELING, role_type = 1, invert = 1) else - var/datum/objective/maroon/maroon_objective = new - maroon_objective.owner = owner - if(team_mode) - maroon_objective.find_target_by_role(role = ROLE_CHANGELING, role_type = 1, invert = 1) - else - maroon_objective.find_target() - objectives += maroon_objective + kill_objective.find_target() + objectives += kill_objective - if (!(locate(/datum/objective/escape) in objectives) && escape_objective_possible) - var/datum/objective/escape/escape_with_identity/identity_theft = new - identity_theft.owner = owner - identity_theft.target = maroon_objective.target - identity_theft.update_explanation_text() - objectives += identity_theft - escape_objective_possible = FALSE + if(!(locate(/datum/objective/escape) in objectives) && escape_objective_possible && prob(50)) + var/datum/objective/escape/escape_with_identity/identity_theft = new + identity_theft.owner = owner + identity_theft.target = kill_objective.target + identity_theft.update_explanation_text() + objectives += identity_theft + escape_objective_possible = FALSE if (!(locate(/datum/objective/escape) in objectives) && escape_objective_possible) if(prob(50)) diff --git a/code/modules/antagonists/clockcult/clock_scriptures/scripture_applications.dm b/code/modules/antagonists/clockcult/clock_scriptures/scripture_applications.dm index cbf3bdaa38..77dc174238 100644 --- a/code/modules/antagonists/clockcult/clock_scriptures/scripture_applications.dm +++ b/code/modules/antagonists/clockcult/clock_scriptures/scripture_applications.dm @@ -8,7 +8,7 @@ descname = "Powers Nearby Structures" name = "Sigil of Transmission" desc = "Places a sigil that can drain and will store energy to power clockwork structures." - invocations = list("Divinity...", "...power our creations!") + invocations = list("Divinity...", "...power our creations.") channel_time = 70 power_cost = 200 whispered = TRUE @@ -28,7 +28,7 @@ descname = "Powered Structure, Delay Emergency Shuttles" name = "Prolonging Prism" desc = "Creates a mechanized prism which will delay the arrival of an emergency shuttle by 2 minutes at a massive power cost." - invocations = list("May this prism...", "...grant us time to enact his will!") + invocations = list("May this prism...", "...grant us time to enact his will.") channel_time = 80 power_cost = 300 object_path = /obj/structure/destructible/clockwork/powered/prolonging_prism @@ -60,7 +60,7 @@ descname = "Powered Structure, Area Denial" name = "Mania Motor" desc = "Creates a mania motor which causes minor damage and a variety of negative mental effects in nearby non-Servant humans, potentially up to and including conversion." - invocations = list("May this transmitter...", "...break the will of all who oppose us!") + invocations = list("May this transmitter...", "...break the will of all who oppose us.") channel_time = 80 power_cost = 750 object_path = /obj/structure/destructible/clockwork/powered/mania_motor @@ -83,7 +83,7 @@ descname = "Powered Structure, Teleportation Hub" name = "Clockwork Obelisk" desc = "Creates a clockwork obelisk that can broadcast messages over the Hierophant Network or open a Spatial Gateway to any living Servant or clockwork obelisk." - invocations = list("May this obelisk...", "...take us to all places!") + invocations = list("May this obelisk...", "...take us to all places.") channel_time = 80 power_cost = 300 object_path = /obj/structure/destructible/clockwork/powered/clockwork_obelisk @@ -163,7 +163,7 @@ descname = "Well-Rounded Combat Construct" name = "Clockwork Marauder" desc = "Creates a shell for a clockwork marauder, a balanced frontline construct that can deflect projectiles with its shield." - invocations = list("Arise, avatar of Arbiter!", "Defend the Ark with vengeful zeal.") + invocations = list("Arise, avatar of Arbiter!", "Defend the Ark with vengeful zeal!") channel_time = 80 power_cost = 8000 creator_message = "Your slab disgorges several chunks of replicant alloy that form into a suit of thrumming armor." diff --git a/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm b/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm index 0a59656e31..b79bcfa03d 100644 --- a/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm +++ b/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm @@ -7,7 +7,7 @@ descname = "Generates Power From Starlight" name = "Stargazer" desc = "Forms a weak structure that generates power every second while within three tiles of starlight." - invocations = list("Capture their inferior light for us!") + invocations = list("Capture their inferior light for us.") channel_time = 50 power_cost = 200 object_path = /obj/structure/destructible/clockwork/stargazer @@ -16,6 +16,7 @@ usage_tip = "For obvious reasons, make sure to place this near a window or somewhere else that can see space!" tier = SCRIPTURE_DRIVER one_per_tile = TRUE + whispered = TRUE primary_component = HIEROPHANT_ANSIBLE sort_priority = 1 quickbind = TRUE @@ -34,7 +35,7 @@ descname = "Power Generation" name = "Integration Cog" desc = "Fabricates an integration cog, which can be used on an open APC to replace its innards and passively siphon its power." - invocations = list("Take that which sustains them!") + invocations = list("Take that which sustains them.") channel_time = 10 power_cost = 10 whispered = TRUE @@ -55,7 +56,7 @@ descname = "Trap, Stunning" name = "Sigil of Transgression" desc = "Wards a tile with a sigil, which will briefly stun the next non-Servant to cross it and apply Belligerent to them." - invocations = list("Divinity, smite...", "...those who trespass here!") + invocations = list("Divinity, smite...", "...those who trespass here.") channel_time = 50 power_cost = 50 whispered = TRUE @@ -75,7 +76,7 @@ descname = "Trap, Conversion" name = "Sigil of Submission" desc = "Places a luminous sigil that will convert any non-Servants that remain on it for 8 seconds." - invocations = list("Divinity, enlighten...", "...those who trespass here!") + invocations = list("Divinity, enlighten...", "...those who trespass here.") channel_time = 60 power_cost = 125 whispered = TRUE @@ -95,7 +96,7 @@ descname = "Short-Range Single-Target Stun" name = "Kindle" desc = "Charges your slab with divine energy, allowing you to overwhelm a target with Ratvar's light." - invocations = list("Divinity, show them your light!") + invocations = list("Divinity, show them your light.") whispered = TRUE channel_time = 25 //2.5 seconds should be a okay compromise between being able to use it when needed, and not being able to just pause in combat for a second and hardstunning your enemy power_cost = 125 @@ -118,7 +119,7 @@ descname = "Handcuffs" name = "Hateful Manacles" desc = "Forms replicant manacles around a target's wrists that function like handcuffs." - invocations = list("Shackle the heretic!", "Break them in body and spirit!") + invocations = list("Shackle the heretic!", "Break them in body and spirit.") channel_time = 15 power_cost = 25 whispered = TRUE @@ -269,7 +270,7 @@ descname = "New Clockwork Slab" name = "Replicant" desc = "Creates a new clockwork slab." - invocations = list("Metal, become greater!") + invocations = list("Metal, become greater.") channel_time = 10 power_cost = 25 whispered = TRUE @@ -290,7 +291,7 @@ descname = "Limited Xray Vision Glasses" name = "Wraith Spectacles" desc = "Fabricates a pair of glasses which grant true sight but cause gradual vision loss." - invocations = list("Show the truth of this world to me!") + invocations = list("Show the truth of this world to me.") channel_time = 10 power_cost = 50 whispered = TRUE @@ -310,7 +311,7 @@ name = "Spatial Gateway" desc = "Tears open a miniaturized gateway in spacetime to any conscious servant that can transport objects or creatures to its destination. \ Each servant assisting in the invocation adds one additional use and four additional seconds to the gateway's uses and duration." - invocations = list("Spatial Gateway...", "...activate!") + invocations = list("Spatial Gateway...", "...activate.") channel_time = 30 power_cost = 400 whispered = TRUE diff --git a/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm b/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm index b559b34d5e..7ba4ce0936 100644 --- a/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm +++ b/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm @@ -29,7 +29,7 @@ descname = "Structure, Turret" name = "Ocular Warden" desc = "Forms an automatic short-range turret which will automatically attack nearby unrestrained non-Servants that can see it." - invocations = list("Guardians of Engine...", "...judge those who would harm us!") + invocations = list("Guardians of Engine...", "...judge those who would harm us.") channel_time = 100 power_cost = 250 object_path = /obj/structure/destructible/clockwork/ocular_warden @@ -105,7 +105,7 @@ descname = "Delayed Area Knockdown Glasses" name = "Judicial Visor" desc = "Creates a visor that can smite an area, applying Belligerent and briefly stunning. The smote area will explode after 3 seconds." - invocations = list("Grant me the flames of Engine!") + invocations = list("Grant me the flames of Engine.") channel_time = 10 power_cost = 400 whispered = TRUE @@ -124,7 +124,7 @@ descname = "Shield with empowerable bashes" name = "Nezbere's shield" desc = "Creates a shield which generates charge from blocking damage, using it to empower its bashes tremendously. It is repaired with brass, and while very durable, extremely weak to lasers and, even more so, to energy weaponry." - invocations = list("Shield me...", "... from the coming dark!") + invocations = list("Shield me...", "... from the coming dark.") channel_time = 20 power_cost = 600 //Shouldn't be too spammable but not too hard to get either whispered = TRUE @@ -143,7 +143,7 @@ descname = "Summonable Armor and Weapons" name = "Clockwork Armaments" desc = "Allows the invoker to summon clockwork armor and a Ratvarian spear at will. The spear's attacks will generate Vitality, used for healing." - invocations = list("Grant me armaments...", "...from the forge of Armorer!") + invocations = list("Grant me armaments...", "...from the forge of Armorer.") channel_time = 20 power_cost = 250 whispered = TRUE diff --git a/code/modules/antagonists/clockcult/clock_structure.dm b/code/modules/antagonists/clockcult/clock_structure.dm index 2464015b6b..380e93f102 100644 --- a/code/modules/antagonists/clockcult/clock_structure.dm +++ b/code/modules/antagonists/clockcult/clock_structure.dm @@ -95,7 +95,7 @@ return ..() /obj/structure/destructible/clockwork/attackby(obj/item/I, mob/user, params) - if(is_servant_of_ratvar(user) && istype(I, /obj/item/wrench) && unanchored_icon) + if(is_servant_of_ratvar(user) && I.tool_behaviour == TOOL_WRENCH && unanchored_icon) if(default_unfasten_wrench(user, I, 50) == SUCCESSFUL_UNFASTEN) update_anchored(user) return 1 diff --git a/code/modules/antagonists/clockcult/clock_structures/wall_gear.dm b/code/modules/antagonists/clockcult/clock_structures/wall_gear.dm index d823f19d4a..7e4822b622 100644 --- a/code/modules/antagonists/clockcult/clock_structures/wall_gear.dm +++ b/code/modules/antagonists/clockcult/clock_structures/wall_gear.dm @@ -23,10 +23,10 @@ return /obj/structure/destructible/clockwork/wall_gear/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/wrench)) + if(I.tool_behaviour == TOOL_WRENCH) default_unfasten_wrench(user, I, 10) return 1 - else if(istype(I, /obj/item/screwdriver)) + else if(I.tool_behaviour == TOOL_SCREWDRIVER) if(anchored) to_chat(user, "[src] needs to be unsecured to disassemble it!") else diff --git a/code/modules/antagonists/clockcult/clockcult.dm b/code/modules/antagonists/clockcult/clockcult.dm index b6ed7dfe65..b935258c27 100644 --- a/code/modules/antagonists/clockcult/clockcult.dm +++ b/code/modules/antagonists/clockcult/clockcult.dm @@ -15,13 +15,16 @@ var/ignore_holy_water = FALSE /datum/antagonist/clockcult/silent + name = "Silent Clock Cultist" silent = TRUE show_in_antagpanel = FALSE //internal /datum/antagonist/clockcult/neutered + name = "Neutered Clock Cultist" neutered = TRUE /datum/antagonist/clockcult/neutered/traitor + name = "Traitor Clock Cultist" ignore_eligibility_check = TRUE ignore_holy_water = TRUE show_in_roundend = FALSE @@ -185,7 +188,7 @@ /datum/antagonist/clockcult/admin_add(datum/mind/new_owner,mob/admin) - add_servant_of_ratvar(new_owner.current, TRUE) + add_servant_of_ratvar(new_owner.current, TRUE, override_type = type) message_admins("[key_name_admin(admin)] has made [new_owner.current] into a servant of Ratvar.") log_admin("[key_name(admin)] has made [new_owner.current] into a servant of Ratvar.") diff --git a/code/modules/antagonists/cult/cult.dm b/code/modules/antagonists/cult/cult.dm index a2ec4a47a4..09d8771a62 100644 --- a/code/modules/antagonists/cult/cult.dm +++ b/code/modules/antagonists/cult/cult.dm @@ -19,9 +19,11 @@ var/ignore_holy_water = FALSE /datum/antagonist/cult/neutered + name = "Neutered Cultist" neutered = TRUE /datum/antagonist/cult/neutered/traitor + name = "Traitor Cultist" ignore_eligibility_checks = TRUE ignore_holy_water = TRUE show_in_roundend = FALSE diff --git a/code/modules/antagonists/disease/disease_abilities.dm b/code/modules/antagonists/disease/disease_abilities.dm index 496d11bcbc..fc53575bd8 100644 --- a/code/modules/antagonists/disease/disease_abilities.dm +++ b/code/modules/antagonists/disease/disease_abilities.dm @@ -191,8 +191,6 @@ new /datum/disease_ability/symptom/powerful/youth /datum/disease_ability/action/sneeze name = "Voluntary Sneezing" actions = list(/datum/action/cooldown/disease_sneeze) - cost = 2 - required_total_points = 3 short_desc = "Force the host you are following to sneeze, spreading your infection to those in front of them." long_desc = "Force the host you are following to sneeze with extra force, spreading your infection to any victims in a 4 meter cone in front of your host.
Cooldown: 20 seconds" @@ -229,8 +227,6 @@ new /datum/disease_ability/symptom/powerful/youth /datum/disease_ability/action/infect name = "Secrete Infection" actions = list(/datum/action/cooldown/disease_infect) - cost = 2 - required_total_points = 3 short_desc = "Cause all objects your host is touching to become infectious for a limited time, spreading your infection to anyone who touches them." long_desc = "Cause the host you are following to excrete an infective substance from their pores, causing all objects touching their skin to transmit your infection to anyone who touches them for the next 30 seconds. This includes the floor, if they are not wearing shoes, and any items they are holding, if they are not wearing gloves.
Cooldown: 40 seconds" @@ -271,23 +267,20 @@ new /datum/disease_ability/symptom/powerful/youth //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/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 + required_total_points = 5 malefit = -1 category = "Symptom (+)" /datum/disease_ability/symptom/powerful cost = 4 - required_total_points = 16 + required_total_points = 10 category = "Symptom (Strong)" /datum/disease_ability/symptom/powerful/heal diff --git a/code/modules/antagonists/disease/disease_disease.dm b/code/modules/antagonists/disease/disease_disease.dm index c37abefab0..5e98962740 100644 --- a/code/modules/antagonists/disease/disease_disease.dm +++ b/code/modules/antagonists/disease/disease_disease.dm @@ -5,6 +5,7 @@ viable_mobtypes = list(/mob/living/carbon/human) mutable = FALSE var/mob/camera/disease/overmind + infectable_biotypes = MOB_ORGANIC|MOB_ROBOTIC /datum/disease/advance/sentient_disease/New() ..() diff --git a/code/modules/antagonists/eldritch_cult/eldritch_effects.dm b/code/modules/antagonists/eldritch_cult/eldritch_effects.dm index 99f0ae7596..ad39e549eb 100644 --- a/code/modules/antagonists/eldritch_cult/eldritch_effects.dm +++ b/code/modules/antagonists/eldritch_cult/eldritch_effects.dm @@ -254,6 +254,7 @@ to_chat(human_user,"Your brain hurts when you look at this!") human_user.adjustOrganLoss(ORGAN_SLOT_BRAIN,20,190) SEND_SIGNAL(human_user, COMSIG_ADD_MOOD_EVENT, "gates_of_mansus", /datum/mood_event/gates_of_mansus) + log_game("[key_name(user)] stared at a pierced reality at [AREACOORD(user)]") /obj/effect/reality_smash name = "/improper reality smash" diff --git a/code/modules/antagonists/eldritch_cult/eldritch_items.dm b/code/modules/antagonists/eldritch_cult/eldritch_items.dm index fbf0740e50..ea6d1d50e2 100644 --- a/code/modules/antagonists/eldritch_cult/eldritch_items.dm +++ b/code/modules/antagonists/eldritch_cult/eldritch_items.dm @@ -50,7 +50,8 @@ background_icon_state = "bg_ecult" button_icon_state = "shatter" icon_icon = 'icons/mob/actions/actions_ecult.dmi' - check_flags = MOBILITY_HOLD|MOBILITY_MOVE|MOBILITY_USE + check_flags = NONE // required_mobility_flags handles this + required_mobility_flags = MOBILITY_HOLD|MOBILITY_MOVE|MOBILITY_USE var/mob/living/carbon/human/holder var/obj/item/melee/sickly_blade/sword @@ -62,11 +63,12 @@ /datum/action/innate/heretic_shatter/IsAvailable() if(IS_HERETIC(holder) || IS_HERETIC_MONSTER(holder)) - return TRUE + return ..() else return FALSE /datum/action/innate/heretic_shatter/Activate() + . = ..() var/turf/safe_turf = find_safe_turf(zlevels = sword.z, extended_safety_checks = TRUE) do_teleport(holder,safe_turf,forceMove = TRUE) to_chat(holder,"You feel a gust of energy flow through your body... the Rusted Hills heard your call...") diff --git a/code/modules/antagonists/eldritch_cult/eldritch_magic.dm b/code/modules/antagonists/eldritch_cult/eldritch_magic.dm index ba79cca07a..bb95a8bdf3 100644 --- a/code/modules/antagonists/eldritch_cult/eldritch_magic.dm +++ b/code/modules/antagonists/eldritch_cult/eldritch_magic.dm @@ -566,7 +566,7 @@ human_user.adjustBruteLoss(-10, FALSE) human_user.adjustFireLoss(-10, FALSE) human_user.adjustStaminaLoss(-10, FALSE) - human_user.adjustToxLoss(-10, FALSE) + human_user.adjustToxLoss(-10, FALSE, TRUE) human_user.adjustOxyLoss(-10) /obj/effect/proc_holder/spell/pointed/manse_link diff --git a/code/modules/antagonists/eldritch_cult/knowledge/rust_lore.dm b/code/modules/antagonists/eldritch_cult/knowledge/rust_lore.dm index 9d65396c63..43678e17c6 100644 --- a/code/modules/antagonists/eldritch_cult/knowledge/rust_lore.dm +++ b/code/modules/antagonists/eldritch_cult/knowledge/rust_lore.dm @@ -183,7 +183,7 @@ var/mob/living/carbon/human/human_user = user human_user.adjustBruteLoss(-6, FALSE) human_user.adjustFireLoss(-6, FALSE) - human_user.adjustToxLoss(-6, FALSE) + human_user.adjustToxLoss(-6, FALSE, TRUE) human_user.adjustOxyLoss(-6, FALSE) human_user.adjustStaminaLoss(-20) diff --git a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm index bf6599d782..7d669e5c41 100644 --- a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm +++ b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm @@ -104,7 +104,7 @@ switch(deconstruction_state) if(NUKESTATE_INTACT) - if(istype(I, /obj/item/screwdriver/nuke)) + if(istype(I, /obj/item/screwdriver/nuke)) //Special case, cannot replace with tool_behavior to_chat(user, "You start removing [src]'s front panel's screws...") if(I.use_tool(src, user, 60, volume=100)) deconstruction_state = NUKESTATE_UNSCREWED diff --git a/code/modules/antagonists/swarmer/swarmer.dm b/code/modules/antagonists/swarmer/swarmer.dm index d1bdac7e05..f283e33899 100644 --- a/code/modules/antagonists/swarmer/swarmer.dm +++ b/code/modules/antagonists/swarmer/swarmer.dm @@ -43,7 +43,7 @@ to_chat(user, "Picking up the swarmer may cause it to activate. You should be careful about this.") /obj/effect/mob_spawn/swarmer/attackby(obj/item/W, mob/user, params) - if(istype(W, /obj/item/screwdriver) && user.a_intent != INTENT_HARM) + if(W.tool_behaviour == TOOL_SCREWDRIVER && user.a_intent != INTENT_HARM) user.visible_message("[usr.name] deactivates [src].", "After some fiddling, you find a way to disable [src]'s power source.", "You hear clicking.") diff --git a/code/modules/antagonists/traitor/classes/assassin.dm b/code/modules/antagonists/traitor/classes/assassin.dm index 6b709aac59..8175ad9736 100644 --- a/code/modules/antagonists/traitor/classes/assassin.dm +++ b/code/modules/antagonists/traitor/classes/assassin.dm @@ -8,11 +8,9 @@ /datum/traitor_class/human/assassin/forge_single_objective(datum/antagonist/traitor/T) .=1 var/permakill_prob = 20 - var/is_dynamic = FALSE var/datum/game_mode/dynamic/mode if(istype(SSticker.mode,/datum/game_mode/dynamic)) mode = SSticker.mode - is_dynamic = TRUE permakill_prob = max(0,mode.threat_level-50) var/list/active_ais = active_ais() if(active_ais.len && prob(100/GLOB.joined_player_list.len)) @@ -20,11 +18,6 @@ destroy_objective.owner = T.owner destroy_objective.find_target() T.add_objective(destroy_objective) - else if(prob(30) || (is_dynamic && (mode.storyteller.flags & NO_ASSASSIN))) - var/datum/objective/maroon/maroon_objective = new - maroon_objective.owner = T.owner - maroon_objective.find_target() - T.add_objective(maroon_objective) else if(prob(permakill_prob)) var/datum/objective/assassinate/kill_objective = new kill_objective.owner = T.owner diff --git a/code/modules/antagonists/traitor/classes/human.dm b/code/modules/antagonists/traitor/classes/human.dm index 30aa11e39d..16f65a63c3 100644 --- a/code/modules/antagonists/traitor/classes/human.dm +++ b/code/modules/antagonists/traitor/classes/human.dm @@ -41,11 +41,6 @@ destroy_objective.owner = T.owner destroy_objective.find_target() T.add_objective(destroy_objective) - else if(prob(30) || (is_dynamic && (mode.storyteller.flags & NO_ASSASSIN))) - var/datum/objective/maroon/maroon_objective = new - maroon_objective.owner = T.owner - maroon_objective.find_target() - T.add_objective(maroon_objective) else if(prob(max(0,assassin_prob-20))) var/datum/objective/assassinate/kill_objective = new kill_objective.owner = T.owner diff --git a/code/modules/antagonists/traitor/classes/subterfuge.dm b/code/modules/antagonists/traitor/classes/subterfuge.dm index 07707b69e1..73dc455a45 100644 --- a/code/modules/antagonists/traitor/classes/subterfuge.dm +++ b/code/modules/antagonists/traitor/classes/subterfuge.dm @@ -12,16 +12,10 @@ mode = SSticker.mode assassin_prob = max(0,mode.threat_level-40) if(prob(assassin_prob)) - if(prob(assassin_prob)) - var/datum/objective/assassinate/once/kill_objective = new - kill_objective.owner = T.owner - kill_objective.find_target() - T.add_objective(kill_objective) - else - var/datum/objective/maroon/maroon_objective = new - maroon_objective.owner = T.owner - maroon_objective.find_target() - T.add_objective(maroon_objective) + var/datum/objective/assassinate/once/kill_objective = new + kill_objective.owner = T.owner + kill_objective.find_target() + T.add_objective(kill_objective) else var/list/weights = list() weights["sabo"] = length(subtypesof(/datum/sabotage_objective)) diff --git a/code/modules/arousal/arousal.dm b/code/modules/arousal/arousal.dm index 99683f1688..2f7f701012 100644 --- a/code/modules/arousal/arousal.dm +++ b/code/modules/arousal/arousal.dm @@ -9,6 +9,7 @@ var/hidden_underwear = FALSE var/hidden_undershirt = FALSE var/hidden_socks = FALSE + var/arousal_rate = 1 //Mob procs /mob/living/carbon/human/verb/underwear_toggle() @@ -20,29 +21,34 @@ return if(confirm == "Top") hidden_undershirt = !hidden_undershirt + log_message("[hidden_undershirt ? "removed" : "put on" ] [p_their()] undershirt.", LOG_EMOTE) if(confirm == "Bottom") hidden_underwear = !hidden_underwear + log_message("[hidden_underwear ? "removed" : "put on"] [p_their()] underwear.", LOG_EMOTE) if(confirm == "Socks") hidden_socks = !hidden_socks + log_message("[hidden_socks ? "removed" : "put on"] [p_their()] socks.", LOG_EMOTE) if(confirm == "All") var/on_off = (hidden_undershirt || hidden_underwear || hidden_socks) ? FALSE : TRUE hidden_undershirt = on_off hidden_underwear = on_off hidden_socks = on_off + log_message("[on_off ? "removed" : "put on"] all [p_their()] undergarments.", LOG_EMOTE) update_body(TRUE) -/mob/living/carbon/human/proc/adjust_arousal(strength,aphro = FALSE,maso = FALSE) // returns all genitals that were adjust +/mob/living/carbon/human/proc/adjust_arousal(strength, cause = "manual toggle", aphro = FALSE,maso = FALSE) // returns all genitals that were adjust var/list/obj/item/organ/genital/genit_list = list() if(!client?.prefs.arousable || (aphro && (client?.prefs.cit_toggles & NO_APHRO)) || (maso && !HAS_TRAIT(src, TRAIT_MASO))) return // no adjusting made here + var/enabling = strength > 0 for(var/obj/item/organ/genital/G in internal_organs) - if(G.genital_flags & GENITAL_CAN_AROUSE && !G.aroused_state && prob(strength*G.sensitivity)) - G.set_aroused_state(strength > 0) + if(G.genital_flags & GENITAL_CAN_AROUSE && !G.aroused_state && prob(abs(strength)*G.sensitivity * arousal_rate)) + G.set_aroused_state(enabling,cause) G.update_appearance() if(G.aroused_state) genit_list += G @@ -64,6 +70,7 @@ return var/turfing = isturf(target) G.generate_fluid(R) + log_message("Climaxed using [G] with [target]", LOG_EMOTE) if(spill && R.total_volume >= 5) R.reaction(turfing ? target : target.loc, TOUCH, 1, 0) if(!turfing) @@ -189,7 +196,7 @@ return TRUE //Here's the main proc itself -/mob/living/carbon/human/proc/mob_climax(forced_climax=FALSE) //Forced is instead of the other proc, makes you cum if you have the tools for it, ignoring restraints +/mob/living/carbon/human/proc/mob_climax(forced_climax=FALSE,cause = "") //Forced is instead of the other proc, makes you cum if you have the tools for it, ignoring restraints if(mb_cd_timer > world.time) if(!forced_climax) //Don't spam the message to the victim if forced to come too fast to_chat(src, "You need to wait [DisplayTimeText((mb_cd_timer - world.time), TRUE)] before you can do that again!") @@ -202,6 +209,7 @@ to_chat(src, "You can't do that while dead!") return if(forced_climax) //Something forced us to cum, this is not a masturbation thing and does not progress to the other checks + log_message("was forced to climax by [cause]",LOG_EMOTE) for(var/obj/item/organ/genital/G in internal_organs) if(!CHECK_BITFIELD(G.genital_flags, CAN_CLIMAX_WITH)) //Skip things like wombs and testicles continue @@ -272,7 +280,6 @@ var/obj/item/reagent_containers/fluid_container = pick_climax_container() if(fluid_container && available_rosie_palms(TRUE, /obj/item/reagent_containers)) mob_fill_container(picked_organ, fluid_container) - mb_cd_timer = world.time + mb_cd_length /mob/living/carbon/human/verb/climax_verb() diff --git a/code/modules/arousal/genitals.dm b/code/modules/arousal/genitals.dm index 67de745d22..723049a784 100644 --- a/code/modules/arousal/genitals.dm +++ b/code/modules/arousal/genitals.dm @@ -27,11 +27,12 @@ if(do_update) update() -/obj/item/organ/genital/proc/set_aroused_state(new_state) +/obj/item/organ/genital/proc/set_aroused_state(new_state,cause = "manual toggle") if(!(genital_flags & GENITAL_CAN_AROUSE)) return FALSE if(!((HAS_TRAIT(owner,TRAIT_PERMABONER) && !new_state) || HAS_TRAIT(owner,TRAIT_NEVERBONER) && new_state)) aroused_state = new_state + owner.log_message("[src]'s arousal was [new_state ? "enabled" : "disabled"] due to [cause]", LOG_EMOTE) return aroused_state /obj/item/organ/genital/proc/update() @@ -76,11 +77,19 @@ if(GEN_VISIBLE_ALWAYS) genital_flags |= GENITAL_THROUGH_CLOTHES if(owner) + owner.log_message("Exposed their [src]",LOG_EMOTE) owner.exposed_genitals += src + if(GEN_VISIBLE_NO_CLOTHES) + if(owner) + owner.log_message("Hid their [src] under clothes only",LOG_EMOTE) if(GEN_VISIBLE_NO_UNDIES) genital_flags |= GENITAL_UNDIES_HIDDEN + if(owner) + owner.log_message("Hid their [src] under underwear",LOG_EMOTE) if(GEN_VISIBLE_NEVER) genital_flags |= GENITAL_HIDDEN + if(owner) + owner.log_message("Hid their [src] completely",LOG_EMOTE) if(update && owner && ishuman(owner)) //recast to use update genitals proc var/mob/living/carbon/human/H = owner diff --git a/code/modules/atmospherics/gasmixtures/reactions.dm b/code/modules/atmospherics/gasmixtures/reactions.dm index 7f073567c5..743931fbdd 100644 --- a/code/modules/atmospherics/gasmixtures/reactions.dm +++ b/code/modules/atmospherics/gasmixtures/reactions.dm @@ -256,6 +256,8 @@ /datum/gas_reaction/fusion/react(datum/gas_mixture/air, datum/holder) var/turf/open/location + if (isopenturf(holder)) + return 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)) diff --git a/code/modules/atmospherics/machinery/airalarm.dm b/code/modules/atmospherics/machinery/airalarm.dm index 6049ee965e..c63797282d 100644 --- a/code/modules/atmospherics/machinery/airalarm.dm +++ b/code/modules/atmospherics/machinery/airalarm.dm @@ -304,7 +304,7 @@ "danger_level" = cur_tlv.get_danger_level(environment.get_moles(gas_id) * partial_pressure) )) - if(!locked || hasSiliconAccessInArea(user, PRIVILEDGES_SILICON|PRIVILEDGES_DRONE)) + if(!locked || hasSiliconAccessInArea(user, PRIVILEGES_SILICON|PRIVILEGES_DRONE)) data["vents"] = list() for(var/id_tag in A.air_vent_names) var/long_name = A.air_vent_names[id_tag] @@ -385,13 +385,13 @@ if(..() || buildstage != 2) return var/silicon_access = hasSiliconAccessInArea(usr) - var/bot_priviledges = silicon_access || (usr.silicon_privileges & PRIVILEDGES_DRONE) - if((locked && !bot_priviledges) || (silicon_access && aidisabled)) + var/bot_privileges = silicon_access || (usr.silicon_privileges & PRIVILEGES_DRONE) + if((locked && !bot_privileges) || (silicon_access && aidisabled)) return var/device_id = params["id_tag"] switch(action) if("lock") - if(bot_priviledges && !wires.is_cut(WIRE_IDSCAN)) + if(bot_privileges && !wires.is_cut(WIRE_IDSCAN)) locked = !locked . = TRUE if("power", "toggle_filter", "widenet", "scrubbing") @@ -762,14 +762,14 @@ /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()) + if(W.tool_behaviour == TOOL_WIRECUTTER && 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. + else if(W.tool_behaviour == TOOL_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"].") @@ -781,7 +781,7 @@ wires.interact(user) return if(1) - if(istype(W, /obj/item/crowbar)) + if(W.tool_behaviour == TOOL_CROWBAR) user.visible_message("[user.name] removes the electronics from [src.name].",\ "You start prying out the circuit...") W.play_tool_sound(src) @@ -832,7 +832,7 @@ update_icon() return - if(istype(W, /obj/item/wrench)) + if(W.tool_behaviour == TOOL_WRENCH) to_chat(user, "You detach \the [src] from the wall.") W.play_tool_sound(src) new /obj/item/wallframe/airalarm( user.loc ) diff --git a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm index c08eaf2e8a..cf2cdd80a7 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm @@ -326,7 +326,7 @@ || default_deconstruction_crowbar(I)) update_icon() return - else if(istype(I, /obj/item/screwdriver)) + else if(I.tool_behaviour == TOOL_SCREWDRIVER) to_chat(user, "You can't access the maintenance panel while the pod is " \ + (on ? "active" : (occupant ? "full" : "open")) + ".") return @@ -454,8 +454,10 @@ return G.return_temperature() return ..() -/obj/machinery/atmospherics/components/unary/cryo_cell/default_change_direction_wrench(mob/user, obj/item/wrench/W) +/obj/machinery/atmospherics/components/unary/cryo_cell/default_change_direction_wrench(mob/user, obj/item/W) . = ..() + if(!W.tool_behaviour == TOOL_WRENCH) + return if(.) SetInitDirections() var/obj/machinery/atmospherics/node = nodes[1] diff --git a/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm b/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm index 43879038a9..93dc414968 100644 --- a/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm +++ b/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm @@ -115,7 +115,7 @@ to_chat(user, "[holding ? "In one smooth motion you pop [holding] out of [src]'s connector and replace it with [T]" : "You insert [T] into [src]"].") replace_tank(user, FALSE, T) update_icon() - else if(istype(W, /obj/item/wrench)) + else if(W.tool_behaviour == TOOL_WRENCH) if(!(stat & BROKEN)) if(connected_port) disconnect() diff --git a/code/modules/awaymissions/mission_code/jungleresort.dm b/code/modules/awaymissions/mission_code/jungleresort.dm index 6c78a81da2..6c82b2c0c4 100644 --- a/code/modules/awaymissions/mission_code/jungleresort.dm +++ b/code/modules/awaymissions/mission_code/jungleresort.dm @@ -18,6 +18,66 @@ hitsound = 'sound/weapons/whip.ogg' icon_state = "whip" +/obj/item/clothing/suit/hooded/wintercoat/captain/jungle + armor = list("melee" = 5, "bullet" = 5, "laser" = 5, "energy" = 0, "bomb" = 0, "bio" = 10, "rad" = 0, "fire" = 0, "acid" = 0) + +/obj/item/clothing/head/rice_hat/cursed // this was a stupid idea lmao + name = "cursed rice hat" + desc = "Welcome to the rice fields, motherfucker. This particular one seems to give you second thoughts about wearing it." + +/obj/item/clothing/head/rice_hat/cursed/equipped(mob/M, slot) + . = ..() + if (slot == SLOT_HEAD) + RegisterSignal(M, COMSIG_MOB_SAY, .proc/handle_speech) + else + UnregisterSignal(M, COMSIG_MOB_SAY) + +/obj/item/clothing/head/rice_hat/cursed/Initialize() + . = ..() + ADD_TRAIT(src, TRAIT_NODROP, SHAMEBRERO_TRAIT) + +/obj/item/clothing/head/rice_hat/cursed/proc/handle_speech(datum/source, list/speech_args) + var/message = speech_args[SPEECH_MESSAGE] + if(message[1] != "*") + var/list/temp_message = splittext(message, " ") + var/list/pick_list = list() + for(var/i in 1 to temp_message.len) + pick_list += i + for(var/i in 1 to abs(temp_message.len/3)) + var/H = pick(pick_list) + if(findtext(temp_message[H], "*") || findtext(temp_message[H], ";") || findtext(temp_message[H], ":")) + continue + temp_message[H] = ninjaspeak(temp_message[H]) + pick_list -= H + message = temp_message.Join(" ") + + //The Alternate speech mod is now the main one. + message = replacetext(message, "l", "r") + message = replacetext(message, "rr", "ru") + message = replacetext(message, "v", "b") + message = replacetext(message, "f", "hu") + message = replacetext(message, "'t", "") + message = replacetext(message, "t ", "to ") + message = replacetext(message, " I ", " ai ") + message = replacetext(message, "th", "z") + message = replacetext(message, "is", "izu") + message = replacetext(message, "ziz", "zis") + message = replacetext(message, "se", "su") + message = replacetext(message, "br", "bur") + message = replacetext(message, "ry", "ri") + message = replacetext(message, "you", "yuu") + message = replacetext(message, "ck", "cku") + message = replacetext(message, "eu", "uu") + message = replacetext(message, "ow", "au") + message = replacetext(message, "are", "aa") + message = replacetext(message, "ay", "ayu") + message = replacetext(message, "ea", "ii") + message = replacetext(message, "ch", "chi") + message = replacetext(message, "than", "sen") + message = replacetext(message, ".", "") + message = lowertext(message) + speech_args[SPEECH_MESSAGE] = message + //turfs /turf/open/water/jungle @@ -41,4 +101,9 @@ rare_pet_monkey_names = list("Sun Mukong", "Monkey Kong") /mob/living/simple_animal/hostile/jungle/leaper/boss - health = 450 + health = 550 + name = "Froggerosa" + +/mob/living/simple_animal/hostile/gorilla/jungle + tame = 1 + faction = list("neutral") diff --git a/code/modules/cargo/packs/costumes_toys.dm b/code/modules/cargo/packs/costumes_toys.dm index 08f9a927c6..6a37ef80a9 100644 --- a/code/modules/cargo/packs/costumes_toys.dm +++ b/code/modules/cargo/packs/costumes_toys.dm @@ -318,7 +318,7 @@ /obj/item/clothing/under/suit/white, // white is a weird color for a groom but some people are weird /obj/item/clothing/under/suit/polychromic, /obj/item/clothing/under/suit/polychromic, // in case you can't be satisfied with the most fitting choices, of course. - /obj/item/clothing/under/dress/wedding, + /obj/item/clothing/under/dress/wedding, /obj/item/clothing/under/dress/wedding, // this is what you actually bought the crate for. You can't get these anywhere else. /obj/item/clothing/under/dress/wedding/orange, /obj/item/clothing/under/dress/wedding/orange, @@ -333,4 +333,22 @@ /obj/item/storage/fancy/ringbox/silver, /obj/item/storage/fancy/ringbox/silver) //diamond rings cost the same price as this crate via cargo so we're not giving you two for free. Wedding rings are traditionally less valuable anyway. crate_name = "wedding crate" - + +/datum/supply_pack/costumes_toys/randomised/tcg + name = "Big-Ass Booster Pack Pack" + desc = "A bumper load of NT TCG Booster Packs of varying series. Collect them all!" + cost = 3000 + contains = list() + crate_name = "booster pack pack" + +/datum/supply_pack/costumes_toys/randomised/tcg/generate() + . = ..() + var/list/cardtypes = subtypesof(/obj/item/cardpack) + for(var/cardtype in cardtypes) + var/obj/item/cardpack/pack = new cardtype(.) + if(pack.illegal) + cardtypes.Remove(cardtype) + qdel(pack) + for(var/i in 1 to 10) + var/cardpacktype = pick(cardtypes) + new cardpacktype(.) diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index 5f567f1360..970e34cabe 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -76,9 +76,15 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( to_chat(src, "Your previous action was ignored because you've done too many in a second") return - //Logs all hrefs, except chat pings - if(!(href_list["_src_"] == "chat" && href_list["proc"] == "ping" && LAZYLEN(href_list) == 2)) - log_href("[src] (usr:[usr]\[[COORD(usr)]\]) : [hsrc ? "[hsrc] " : ""][href]") + + // Tgui Topic middleware + if(tgui_Topic(href_list)) + if(CONFIG_GET(flag/emergency_tgui_logging)) + log_href("[src] (usr:[usr]\[[COORD(usr)]\]) : [hsrc ? "[hsrc] " : ""][href]") + return + + //Logs all hrefs + log_href("[src] (usr:[usr]\[[COORD(usr)]\]) : [hsrc ? "[hsrc] " : ""][href]") //byond bug ID:2256651 if (asset_cache_job && (asset_cache_job in completed_asset_jobs)) @@ -105,10 +111,6 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( handle_statpanel_click(href_list) return - // Tgui Topic middleware - if(tgui_Topic(href_list)) - return - // Admin PM if(href_list["priv_msg"]) cmd_admin_pm(href_list["priv_msg"],null) diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 7cc8be800c..dbbf648d1f 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -99,6 +99,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/be_random_body = 0 //whether we'll have a random body every round var/gender = MALE //gender of character (well duh) var/age = 30 //age of character + var/language = "Random" //bonus language + var/choselanguage = "Random" //language appearance var/underwear = "Nude" //underwear type var/undie_color = "FFFFFF" var/undershirt = "Nude" //undershirt type @@ -218,6 +220,9 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/hide_ckey = FALSE //pref for hiding if your ckey shows round-end or not + var/list/tcg_cards = list() + var/list/tcg_decks = list() + /datum/preferences/New(client/C) parent = C @@ -308,6 +313,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "Gender: [gender == MALE ? "Male" : (gender == FEMALE ? "Female" : (gender == PLURAL ? "Non-binary" : "Object"))]
" dat += "Age: [age]
" + dat += "Language: [choselanguage]
" dat += "Special Names:
" var/old_group @@ -963,6 +969,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "Breast Enlargement: [(cit_toggles & BREAST_ENLARGEMENT) ? "Allowed" : "Disallowed"]
" dat += "Penis Enlargement: [(cit_toggles & PENIS_ENLARGEMENT) ? "Allowed" : "Disallowed"]
" dat += "Hypno: [(cit_toggles & NEVER_HYPNO) ? "Disallowed" : "Allowed"]
" + dat += "Aphrodisiacs: [(cit_toggles & NO_APHRO) ? "Disallowed" : "Allowed"]
" dat += "Ass Slapping: [(cit_toggles & NO_ASS_SLAP) ? "Disallowed" : "Allowed"]
" dat += "Automatic Wagging: [(cit_toggles & NO_AUTO_WAG) ? "Disabled" : "Enabled"]
" dat += "" @@ -2315,6 +2322,28 @@ GLOBAL_LIST_EMPTY(preferences_datums) features["body_model"] = chosengender gender = chosengender + if("language") + choselanguage = input(user, "Select a language.", "Language", language) as null|anything in list("Beachtongue","Draconic","Dwarven", + "Chimpanzee","Space Sign Language","Random") + if(!choselanguage) + return + switch(choselanguage) + if("Rachidian") + language = /datum/language/arachnid + if("Beachtongue") + language = /datum/language/beachbum + if("Draconic") + language = /datum/language/draconic + if("Dwarven") + language = /datum/language/dwarf + if("Chimpanzee") + language = /datum/language/monkey + if("Space Sign Language") + language = /datum/language/signlanguage + if("Random") + language = pick(list("Rachidian", "Beachtongue","Draconic","Dwarven", + "Chimpanzee","Space Sign Language")) + if("body_size") var/new_body_size = input(user, "Choose your desired sprite size: (90-125%)\nWarning: This may make your character look distorted. Additionally, any size under 100% takes a 10% maximum health penalty", "Character Preference", features["body_size"]*100) as num|null if(new_body_size) diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index 0db9fbb66c..141346acde 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -271,7 +271,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car loadout_data["SAVE_[i]"] = list() for(var/some_gear_item in saved_loadout_paths) if(!ispath(text2path(some_gear_item))) - message_admins("Failed to copy item [some_gear_item] to new loadout system when migrating from version [current_version] to 40, issue: item is not a path") + log_game("Failed to copy item [some_gear_item] to new loadout system when migrating from version [current_version] to 40, issue: item is not a path") continue var/datum/gear/gear_item = text2path(some_gear_item) if(!(initial(gear_item.loadout_flags) & LOADOUT_CAN_COLOR_POLYCHROMIC)) @@ -604,6 +604,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car S["body_model"] >> features["body_model"] S["body_size"] >> features["body_size"] S["age"] >> age + S["language"] >> language + S["choselanguage"] >> choselanguage S["hair_color"] >> hair_color S["facial_hair_color"] >> facial_hair_color S["eye_type"] >> eye_type @@ -656,6 +658,21 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car modified_limbs = safe_json_decode(limbmodstr) else modified_limbs = list() + + var/tcgcardstr + S["tcg_cards"] >> tcgcardstr + if(length(tcgcardstr)) + tcg_cards = safe_json_decode(tcgcardstr) + else + tcg_cards = list() + + var/tcgdeckstr + S["tcg_decks"] >> tcgdeckstr + if(length(tcgdeckstr)) + tcg_decks = safe_json_decode(tcgdeckstr) + else + tcg_decks = list() + S["chosen_limb_id"] >> chosen_limb_id S["hide_ckey"] >> hide_ckey //saved per-character @@ -947,6 +964,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car WRITE_FILE(S["body_model"] , features["body_model"]) WRITE_FILE(S["body_size"] , features["body_size"]) WRITE_FILE(S["age"] , age) + WRITE_FILE(S["language"] , language) + WRITE_FILE(S["choselanguage"] , choselanguage) WRITE_FILE(S["hair_color"] , hair_color) WRITE_FILE(S["facial_hair_color"] , facial_hair_color) WRITE_FILE(S["eye_type"] , eye_type) @@ -1091,6 +1110,16 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car else S["loadout"] << safe_json_encode(list()) + if(length(tcg_cards)) + S["tcg_cards"] << safe_json_encode(tcg_cards) + else + S["tcg_cards"] << safe_json_encode(list()) + + if(length(tcg_decks)) + S["tcg_decks"] << safe_json_encode(tcg_decks) + else + S["tcg_decks"] << safe_json_encode(list()) + cit_character_pref_save(S) return 1 diff --git a/code/modules/client/verbs/aooc.dm b/code/modules/client/verbs/aooc.dm index 1a019bba80..182975d192 100644 --- a/code/modules/client/verbs/aooc.dm +++ b/code/modules/client/verbs/aooc.dm @@ -13,7 +13,7 @@ GLOBAL_VAR_INIT(normal_aooc_colour, "#ce254f") if(!mob) return - if(!(prefs.toggles & CHAT_OOC)) + if(!(prefs.chat_toggles & CHAT_OOC)) to_chat(src, " You have OOC muted.") return if(jobban_isbanned(mob, "OOC")) diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index ea01b0c0ed..018c3d9a3f 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -31,6 +31,9 @@ // What items can be consumed to repair this clothing (must by an /obj/item/stack) var/repairable_by = /obj/item/stack/sheet/cloth + // has this item been upgraded by an upgrade kit (see: durathread armor kits) + var/upgrade_prefix + //Var modification - PLEASE be careful with this I know who you are and where you live var/list/user_vars_to_edit //VARNAME = VARVALUE eg: "name" = "butts" var/list/user_vars_remembered //Auto built by the above + dropped() + equipped() @@ -120,6 +123,8 @@ update_clothes_damaged_state(CLOTHING_PRISTINE) obj_integrity = max_integrity name = initial(name) // remove "tattered" or "shredded" if there's a prefix + if(upgrade_prefix) + name = upgrade_prefix + " " + initial(name) body_parts_covered = initial(body_parts_covered) slot_flags = initial(slot_flags) damage_by_parts = null diff --git a/code/modules/clothing/glasses/_glasses.dm b/code/modules/clothing/glasses/_glasses.dm index 11de0124cb..c79dee926c 100644 --- a/code/modules/clothing/glasses/_glasses.dm +++ b/code/modules/clothing/glasses/_glasses.dm @@ -311,7 +311,7 @@ to_chat(user, "Install a new flash in [src]!") /obj/item/clothing/glasses/sunglasses/stunglasses/attackby(obj/item/W,mob/user) - if (istype(W,/obj/item/screwdriver)) + if (W.tool_behaviour == TOOL_SCREWDRIVER) if (installed) installed.forceMove(get_turf(src)) to_chat(user, "You remove [installed] from [src].") diff --git a/code/modules/clothing/gloves/color.dm b/code/modules/clothing/gloves/color.dm index 56d6e7d38f..836b845faa 100644 --- a/code/modules/clothing/gloves/color.dm +++ b/code/modules/clothing/gloves/color.dm @@ -99,7 +99,7 @@ name = "fingerless insulated gloves" /obj/item/clothing/gloves/color/yellow/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/wirecutters)) + if(I.tool_behaviour == TOOL_WIRECUTTER) if(can_be_cut && icon_state == initial(icon_state))//only if not dyed to_chat(user, "You snip the fingertips off of [src].") I.play_tool_sound(src) @@ -108,7 +108,7 @@ ..() /obj/item/clothing/gloves/color/fyellow/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/wirecutters)) + if(I.tool_behaviour == TOOL_WIRECUTTER) if(can_be_cut && icon_state == initial(icon_state))//only if not dyed to_chat(user, "You snip the fingertips off of [src].") I.play_tool_sound(src) @@ -130,7 +130,7 @@ strip_mod = 1.2 /obj/item/clothing/gloves/color/black/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/wirecutters)) + if(I.tool_behaviour == TOOL_WIRECUTTER) if(can_be_cut && icon_state == initial(icon_state))//only if not dyed to_chat(user, "You snip the fingertips off of [src].") I.play_tool_sound(src) diff --git a/code/modules/clothing/gloves/miscellaneous.dm b/code/modules/clothing/gloves/miscellaneous.dm index c069649848..a558abbfe8 100644 --- a/code/modules/clothing/gloves/miscellaneous.dm +++ b/code/modules/clothing/gloves/miscellaneous.dm @@ -161,6 +161,68 @@ return NO_AUTO_CLICKDELAY_HANDLING | ATTACK_IGNORE_ACTION +/obj/item/clothing/gloves/fingerless/ablative + name = "ablative armwraps" + desc = "Armwraps made out of a highly durable, reflective metal. Has the side effect of absorbing shocks." + siemens_coefficient = 0 + icon_state = "ablative_armwraps" + item_state = "ablative_armwraps" + block_parry_data = /datum/block_parry_data/ablative_armwraps + var/wornonce = FALSE + +/obj/item/clothing/gloves/fingerless/ablative/proc/get_component_parry_data(datum/source, parrying_method, datum/parrying_item_mob_or_art, list/backup_items, list/override) + if(parrying_method && !(parrying_method == UNARMED_PARRY)) + return + override[src] = ITEM_PARRY + +/obj/item/clothing/gloves/fingerless/ablative/equipped(mob/user, slot) + . = ..() + if(current_equipped_slot == SLOT_GLOVES) + RegisterSignal(user, COMSIG_LIVING_ACTIVE_PARRY_START, .proc/get_component_parry_data) + wornonce = TRUE + +/obj/item/clothing/gloves/fingerless/ablative/dropped(mob/user) + . = ..() + if(wornonce) + UnregisterSignal(user, COMSIG_LIVING_ACTIVE_PARRY_START) + wornonce = FALSE + +/obj/item/clothing/gloves/fingerless/ablative/can_active_parry(mob/user) + var/mob/living/carbon/human/H = user + if(!istype(H)) + return FALSE + return src == H.gloves + +/obj/item/clothing/gloves/fingerless/ablative/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/block_return, parry_efficiency, parry_time) + . = ..() + if(parry_efficiency > 0) + owner.visible_message("[owner] deflects \the [object] with their armwraps!") + +/datum/block_parry_data/ablative_armwraps + parry_stamina_cost = 4 + parry_attack_types = ATTACK_TYPE_UNARMED | ATTACK_TYPE_PROJECTILE | ATTACK_TYPE_TACKLE | ATTACK_TYPE_THROWN | ATTACK_TYPE_MELEE + parry_flags = NONE + + parry_time_windup = 0 + parry_time_spindown = 0 + parry_time_active = 7.5 + + parry_time_perfect = 1 + parry_time_perfect_leeway = 7.5 + parry_imperfect_falloff_percent = 20 + parry_efficiency_perfect = 100 + parry_time_perfect_leeway_override = list( + TEXT_ATTACK_TYPE_MELEE = 1 + ) + + parry_efficiency_considered_successful = 0.01 + parry_efficiency_to_counterattack = INFINITY // no auto counter + parry_max_attacks = INFINITY + parry_failed_cooldown_duration = 2.25 SECONDS + parry_failed_stagger_duration = 2.25 SECONDS + parry_cooldown = 0 + parry_failed_clickcd_duration = 0 + /obj/item/clothing/gloves/botanic_leather name = "botanist's leather gloves" desc = "These leather gloves protect against thorns, barbs, prickles, spikes and other harmful objects of floral origin. They're also quite warm." diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm index 662318fb82..de68883a7b 100644 --- a/code/modules/clothing/head/helmet.dm +++ b/code/modules/clothing/head/helmet.dm @@ -313,7 +313,7 @@ A.Grant(user) return - if(istype(I, /obj/item/screwdriver)) + if(I.tool_behaviour == TOOL_SCREWDRIVER) if(F) for(var/obj/item/flashlight/seclite/S in src) to_chat(user, "You unscrew the seclite from [src].") diff --git a/code/modules/clothing/masks/miscellaneous.dm b/code/modules/clothing/masks/miscellaneous.dm index fc4185f207..fe08cbd63e 100644 --- a/code/modules/clothing/masks/miscellaneous.dm +++ b/code/modules/clothing/masks/miscellaneous.dm @@ -36,7 +36,7 @@ /obj/item/clothing/mask/surgical/aesthetic name = "aesthetic sterile mask" desc = "A sterile mask designed to help prevent the spread of diseases. This one doesn't seem like it does a whole lot, somehow." - flags_inv = HIDEFACE + flags_inv = null flags_cover = null visor_flags_inv = null visor_flags_cover = null diff --git a/code/modules/clothing/shoes/colour.dm b/code/modules/clothing/shoes/colour.dm index df0f03f614..9d51753c78 100644 --- a/code/modules/clothing/shoes/colour.dm +++ b/code/modules/clothing/shoes/colour.dm @@ -51,6 +51,17 @@ desc = "Very gay shoes." icon_state = "rain_bow" +/obj/item/clothing/shoes/sneakers/poly/polychromic + name = "polychromic shoes" + desc = "Every color." + icon_state = "poly" + item_state = "poly" + var/list/poly_colors = list("#FFFFFF", "#1D1D1D") + +/obj/item/clothing/shoes/sneakers/poly/polychromic/ComponentInitialize() + . = ..() + AddElement(/datum/element/polychromic, poly_colors, 2) + /obj/item/clothing/shoes/sneakers/orange name = "orange shoes" icon_state = "orange" diff --git a/code/modules/clothing/shoes/miscellaneous.dm b/code/modules/clothing/shoes/miscellaneous.dm index d99d52666b..cc14424980 100644 --- a/code/modules/clothing/shoes/miscellaneous.dm +++ b/code/modules/clothing/shoes/miscellaneous.dm @@ -97,12 +97,14 @@ SEND_SIGNAL(t_loc, COMSIG_TURF_MAKE_DRY, TURF_WET_WATER, TRUE, INFINITY) /obj/item/clothing/shoes/clown_shoes - desc = "The prankster's standard-issue clowning shoes. Damn, they're huge!" + desc = "The prankster's standard-issue clowning shoes. Damn, they're huge! Ctrl-click to toggle waddle dampeners." name = "clown shoes" icon_state = "clown_shoes" slowdown = SHOES_SLOWDOWN+1 pocket_storage_component_path = /datum/component/storage/concrete/pockets/shoes/clown lace_time = 20 SECONDS // how the hell do these laces even work?? + var/datum/component/waddle + var/enabled_waddle = TRUE /obj/item/clothing/shoes/clown_shoes/Initialize() . = ..() @@ -110,14 +112,31 @@ /obj/item/clothing/shoes/clown_shoes/equipped(mob/user, slot) . = ..() - if(user.mind && HAS_TRAIT(user.mind, TRAIT_CLOWN_MENTALITY)) - SEND_SIGNAL(user, COMSIG_CLEAR_MOOD_EVENT, "noshoes") + if(slot == SLOT_SHOES) + if(enabled_waddle) + waddle = user.AddComponent(/datum/component/waddling) + if(user.mind && HAS_TRAIT(user.mind, TRAIT_CLOWN_MENTALITY)) + SEND_SIGNAL(user, COMSIG_CLEAR_MOOD_EVENT, "noshoes") /obj/item/clothing/shoes/clown_shoes/dropped(mob/user) . = ..() + QDEL_NULL(waddle) if(user.mind && HAS_TRAIT(user.mind, TRAIT_CLOWN_MENTALITY)) SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "noshoes", /datum/mood_event/noshoes) +/obj/item/clothing/shoes/clown_shoes/CtrlClick(mob/living/user) + if(!isliving(user)) + return + if(user.get_active_held_item() != src) + to_chat(user, "You must hold the [src] in your hand to do this!") + return + if (!enabled_waddle) + to_chat(user, "You switch off the waddle dampeners!") + enabled_waddle = TRUE + else + to_chat(user, "You switch on the waddle dampeners!") + enabled_waddle = FALSE + /obj/item/clothing/shoes/clown_shoes/jester name = "jester shoes" desc = "A court jester's shoes, updated with modern squeaking technology." diff --git a/code/modules/clothing/spacesuits/hardsuit.dm b/code/modules/clothing/spacesuits/hardsuit.dm index 40ad6dddd1..4af9e7387d 100644 --- a/code/modules/clothing/spacesuits/hardsuit.dm +++ b/code/modules/clothing/spacesuits/hardsuit.dm @@ -122,7 +122,7 @@ jetpack = I to_chat(user, "You successfully install the jetpack into [src].") return - else if(istype(I, /obj/item/screwdriver)) + else if(I.tool_behaviour == TOOL_SCREWDRIVER) if(!jetpack) to_chat(user, "[src] has no jetpack installed.") return diff --git a/code/modules/clothing/suits/cloaks.dm b/code/modules/clothing/suits/cloaks.dm index 133956e44e..b56f689979 100644 --- a/code/modules/clothing/suits/cloaks.dm +++ b/code/modules/clothing/suits/cloaks.dm @@ -102,7 +102,18 @@ /obj/item/clothing/neck/cloak/polychromic/ComponentInitialize() . = ..() AddElement(/datum/element/polychromic, poly_colors, 3) - + +/obj/item/clothing/neck/cancloak/polychromic + name = "canvas cloak" + desc = "A rugged cloak made of canvas." + icon_state = "cancloak" + item_state = "cloak" + var/list/poly_colors = list("#585858", "#373737", "#BEBEBE") + +/obj/item/clothing/neck/cancloak/polychromic/ComponentInitialize() + . = ..() + AddElement(/datum/element/polychromic, poly_colors, 3) + /obj/item/clothing/neck/cloak/alt name = "cloak" desc = "A ragged up white cloak. It reminds you of a place not far from here." diff --git a/code/modules/clothing/suits/miscellaneous.dm b/code/modules/clothing/suits/miscellaneous.dm index a47d55bfcb..3e72765234 100644 --- a/code/modules/clothing/suits/miscellaneous.dm +++ b/code/modules/clothing/suits/miscellaneous.dm @@ -487,6 +487,17 @@ item_state = "militaryjacket" 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/gun/ballistic/automatic/pistol, /obj/item/gun/ballistic/revolver, /obj/item/radio) +/obj/item/clothing/suit/jacket/urbanjacket/polychromic + name = "urban jacket" + desc = "A canvas jacket styled with a fur neck piece, stylish." + icon_state = "urbanjacket" + item_state = "urbanjacket" + 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/gun/ballistic/automatic/pistol, /obj/item/gun/ballistic/revolver, /obj/item/radio) + +/obj/item/clothing/suit/jacket/urbanjacket/polychromic/ComponentInitialize() + . = ..() + AddElement(/datum/element/polychromic, list("#3D4C31", "#CBBDAF", "#3B3B3B"), 3) + /obj/item/clothing/suit/jacket/letterman name = "letterman jacket" desc = "A classic brown letterman jacket. Looks pretty hot and heavy." @@ -1023,6 +1034,22 @@ alternate_worn_layer = UNDER_HEAD_LAYER mutantrace_variation = STYLE_DIGITIGRADE|STYLE_NO_ANTHRO_ICON +/obj/item/clothing/suit/toggle/wbreakpoly + name = "polychromic windbreaker" + desc = "Perfect for windy days." + icon_state = "wbreakpoly" + item_state = "wbreakpoly" + +/obj/item/clothing/suit/toggle/wbreakpoly/on_toggle(mob/user) + if(suittoggled) + to_chat(usr, "You zip up [src].") + else + to_chat(usr, "You unzip [src].") + +/obj/item/clothing/suit/toggle/wbreakpoly/polychromic/ComponentInitialize() + . = ..() + AddElement(/datum/element/polychromic, list("#464F65", "#916035", "#474747"), 3) + /obj/item/clothing/suit/flakjack name = "flak jacket" desc = "A dilapidated jacket made of a supposedly bullet-proof material (Hint: It isn't.). Smells faintly of napalm." diff --git a/code/modules/clothing/suits/toggles.dm b/code/modules/clothing/suits/toggles.dm index aa22834670..98d6809d64 100644 --- a/code/modules/clothing/suits/toggles.dm +++ b/code/modules/clothing/suits/toggles.dm @@ -110,6 +110,9 @@ suit_toggle(user) return TRUE +/obj/item/clothing/suit/toggle/proc/on_toggle(mob/user) // override this, not suit_toggle, which does checks + to_chat(usr, "You toggle [src]'s [togglename].") + /obj/item/clothing/suit/toggle/ui_action_click() suit_toggle() @@ -119,7 +122,7 @@ if(!can_use(usr)) return 0 - to_chat(usr, "You toggle [src]'s [togglename].") + on_toggle(usr) if(src.suittoggled) src.icon_state = "[initial(icon_state)]" src.suittoggled = FALSE diff --git a/code/modules/clothing/under/_under.dm b/code/modules/clothing/under/_under.dm index e617d2d57b..3207a5842f 100644 --- a/code/modules/clothing/under/_under.dm +++ b/code/modules/clothing/under/_under.dm @@ -32,6 +32,9 @@ /obj/item/clothing/under/attackby(obj/item/I, mob/user, params) if((has_sensor == BROKEN_SENSORS) && istype(I, /obj/item/stack/cable_coil)) + if(damaged_clothes) + to_chat(user,"You should repair the damage done to [src] first.") + return 0 var/obj/item/stack/cable_coil/C = I I.use_tool(src, user, 0, 1) has_sensor = HAS_SENSORS diff --git a/code/modules/clothing/under/pants.dm b/code/modules/clothing/under/pants.dm index c93cefeae9..a76bf41e62 100644 --- a/code/modules/clothing/under/pants.dm +++ b/code/modules/clothing/under/pants.dm @@ -46,6 +46,17 @@ desc = "Some tan pants. You look like a white collar worker with these on." icon_state = "tanpants" +/obj/item/clothing/under/pants/polypants/polychromic + name = "polychromic pants" + desc = "Some stylish pair of pants made from polychrome." + icon_state = "polypants" + item_state = "polypants" + var/list/poly_colors = list("#75634F", "#3D3D3D", "#575757") + +/obj/item/clothing/under/pants/polypants/polychromic/ComponentInitialize() + . = ..() + AddElement(/datum/element/polychromic, poly_colors, 3) + /obj/item/clothing/under/pants/track name = "track pants" desc = "A pair of track pants, for the athletic." diff --git a/code/modules/clothing/under/suits.dm b/code/modules/clothing/under/suits.dm index 87e6e94b6b..7f0ecf3d70 100644 --- a/code/modules/clothing/under/suits.dm +++ b/code/modules/clothing/under/suits.dm @@ -91,6 +91,12 @@ icon_state = "tan_suit" item_state = "tan_suit" +/obj/item/clothing/under/suit/charismatic_suit + name = "charismatic suit" + desc = "Luck is for losers, baby." + icon_state = "charismatic_suit" + item_state = "charismatic_suit" + /obj/item/clothing/under/suit/white name = "white suit" desc = "A white suit and jacket with a blue shirt. You wanna play rough? OKAY!" @@ -132,3 +138,27 @@ icon_state = "greyturtle" item_state = "greyturtle" can_adjust = FALSE + +/obj/item/clothing/under/suit/turtle/purple + name = "purple turtleneck" + icon_state = "turtle_sci" + item_state = "turtle_sci" + can_adjust = FALSE + +/obj/item/clothing/under/suit/turtle/orange + name = "orange turtleneck" + icon_state = "turtle_eng" + item_state = "turtle_eng" + can_adjust = FALSE + +/obj/item/clothing/under/suit/turtle/red + name = "red turtleneck" + icon_state = "turtle_sec" + item_state = "turtle_sec" + can_adjust = FALSE + +/obj/item/clothing/under/suit/turtle/blue + name = "blue turtleneck" + icon_state = "turtle_med" + item_state = "turtle_med" + can_adjust = FALSE diff --git a/code/modules/events/anomaly_bluespace.dm b/code/modules/events/anomaly_bluespace.dm index 7f0dedaab6..70d6b00fa4 100644 --- a/code/modules/events/anomaly_bluespace.dm +++ b/code/modules/events/anomaly_bluespace.dm @@ -11,7 +11,4 @@ anomaly_path = /obj/effect/anomaly/bluespace /datum/round_event/anomaly/anomaly_bluespace/announce(fake) - if(prob(90)) - priority_announce("Unstable bluespace anomaly detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert") - else - print_command_report("Unstable bluespace anomaly detected on long range scanners. Expected location: [impact_area.name].", "Unstable bluespace anomaly") + priority_announce("Unstable bluespace anomaly detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert") diff --git a/code/modules/events/anomaly_flux.dm b/code/modules/events/anomaly_flux.dm index 8047976330..0ba347af57 100644 --- a/code/modules/events/anomaly_flux.dm +++ b/code/modules/events/anomaly_flux.dm @@ -12,7 +12,5 @@ anomaly_path = /obj/effect/anomaly/flux /datum/round_event/anomaly/anomaly_flux/announce(fake) - if(prob(90)) - priority_announce("Localized hyper-energetic flux wave detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert") - else - print_command_report("Localized hyper-energetic flux wave detected on long range scanners. Expected location: [impact_area.name].","Localized hyper-energetic flux wave") + priority_announce("Localized hyper-energetic flux wave detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert") + diff --git a/code/modules/events/anomaly_grav.dm b/code/modules/events/anomaly_grav.dm index 7d2bb33889..01e70c290c 100644 --- a/code/modules/events/anomaly_grav.dm +++ b/code/modules/events/anomaly_grav.dm @@ -12,7 +12,4 @@ anomaly_path = /obj/effect/anomaly/grav /datum/round_event/anomaly/anomaly_grav/announce(fake) - if(prob(90)) - priority_announce("Gravitational anomaly detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert") - else - print_command_report("Gravitational anomaly detected on long range scanners. Expected location: [impact_area.name].", "Gravitational anomaly") + priority_announce("Gravitational anomaly detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert") diff --git a/code/modules/events/anomaly_pyro.dm b/code/modules/events/anomaly_pyro.dm index 350c8fc946..29c6e15d28 100644 --- a/code/modules/events/anomaly_pyro.dm +++ b/code/modules/events/anomaly_pyro.dm @@ -11,7 +11,4 @@ anomaly_path = /obj/effect/anomaly/pyro /datum/round_event/anomaly/anomaly_pyro/announce(fake) - if(prob(90)) - priority_announce("Pyroclastic anomaly detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert") - else - print_command_report("Pyroclastic anomaly detected on long range scanners. Expected location: [impact_area.name].", "Pyroclastic anomaly") + priority_announce("Pyroclastic anomaly detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert") diff --git a/code/modules/events/anomaly_vortex.dm b/code/modules/events/anomaly_vortex.dm index e2a4ceadf3..6a17a47d2b 100644 --- a/code/modules/events/anomaly_vortex.dm +++ b/code/modules/events/anomaly_vortex.dm @@ -12,7 +12,4 @@ anomaly_path = /obj/effect/anomaly/bhole /datum/round_event/anomaly/anomaly_vortex/announce(fake) - if(prob(90)) - priority_announce("Localized high-intensity vortex anomaly detected on long range scanners. Expected location: [impact_area.name]", "Anomaly Alert") - else - print_command_report("Localized high-intensity vortex anomaly detected on long range scanners. Expected location: [impact_area.name].","Vortex anomaly") + priority_announce("Localized high-intensity vortex anomaly detected on long range scanners. Expected location: [impact_area.name]", "Anomaly Alert") diff --git a/code/modules/events/brand_intelligence.dm b/code/modules/events/brand_intelligence.dm index 7c55bbfcd1..7d4ea66d30 100644 --- a/code/modules/events/brand_intelligence.dm +++ b/code/modules/events/brand_intelligence.dm @@ -35,10 +35,7 @@ source = initial(example.name) else if(originMachine) source = originMachine.name - if(prob(50)) - priority_announce("Rampant brand intelligence has been detected aboard [station_name()]. Please stand by. The origin is believed to be \a [source].", "Machine Learning Alert") - else - print_command_report("Rampant brand intelligence has been detected aboard [station_name()]. Please stand by. The origin is believed to be \a [source].", "Rampant brand intelligence") + priority_announce("Rampant brand intelligence has been detected aboard [station_name()]. Please stand by. The origin is believed to be \a [source].", "Machine Learning Alert") /datum/round_event/brand_intelligence/start() for(var/obj/machinery/vending/V in GLOB.machines) diff --git a/code/modules/events/holiday/vday.dm b/code/modules/events/holiday/vday.dm index 1da03623e6..df00f873b5 100644 --- a/code/modules/events/holiday/vday.dm +++ b/code/modules/events/holiday/vday.dm @@ -21,27 +21,6 @@ new /obj/item/reagent_containers/food/snacks/candyheart(B) new /obj/item/storage/fancy/heart_box(B) - var/list/valentines = list() - for(var/mob/living/M in GLOB.player_list) - if(!M.stat && M.client && M.mind && !HAS_TRAIT(M, TRAIT_NO_MIDROUND_ANTAG)) - valentines |= M - - - while(valentines.len) - var/mob/living/L = pick_n_take(valentines) - if(valentines.len) - var/mob/living/date = pick_n_take(valentines) - - - forge_valentines_objective(L, date) - forge_valentines_objective(date, L) - - if(valentines.len && prob(4)) - var/mob/living/notgoodenough = pick_n_take(valentines) - forge_valentines_objective(notgoodenough, date) - else - L.mind.add_antag_datum(/datum/antagonist/heartbreaker) - /proc/forge_valentines_objective(mob/living/lover,mob/living/date,var/chemLove = FALSE) lover.mind.special_role = "valentine" if (chemLove == TRUE) diff --git a/code/modules/events/pirates.dm b/code/modules/events/pirates.dm index 8bada6da77..5a5df41163 100644 --- a/code/modules/events/pirates.dm +++ b/code/modules/events/pirates.dm @@ -267,8 +267,8 @@ var/sending_state = "lpad-beam" var/cargo_hold_id -/obj/machinery/piratepad/multitool_act(mob/living/user, obj/item/multitool/I) - if (istype(I)) +/obj/machinery/piratepad/multitool_act(mob/living/user, obj/item/I) + if(I.tool_behaviour == TOOL_MULTITOOL) to_chat(user, "You register [src] in [I]s buffer.") I.buffer = src return TRUE @@ -291,8 +291,8 @@ ..() return INITIALIZE_HINT_LATELOAD -/obj/machinery/computer/piratepad_control/multitool_act(mob/living/user, obj/item/multitool/I) - if (istype(I) && istype(I.buffer,/obj/machinery/piratepad)) +/obj/machinery/computer/piratepad_control/multitool_act(mob/living/user, obj/item/I) + if(I.tool_behaviour == TOOL_MULTITOOL && istype(I.buffer,/obj/machinery/piratepad)) to_chat(user, "You link [src] with [I.buffer] in [I] buffer.") pad = I.buffer return TRUE diff --git a/code/modules/events/shuttle_loan.dm b/code/modules/events/shuttle_loan.dm index bf9f25cb04..347162d9c5 100644 --- a/code/modules/events/shuttle_loan.dm +++ b/code/modules/events/shuttle_loan.dm @@ -45,7 +45,7 @@ if(ANTIDOTE_NEEDED) message = "Cargo: Your station has been chosen for an epidemiological research project. Send us your cargo shuttle to receive your research samples." title = "CentCom Research Initiatives" - if (PIZZA_DELIVERY) + if(PIZZA_DELIVERY) message = "Cargo: It looks like a neighbouring station accidentally delivered their pizza to you instead." title = "CentCom Spacepizza Division" if(ITS_HIP_TO) @@ -57,7 +57,7 @@ title = "CentCom Security Division" bonus_points = 45000 //If you mess up, people die and the shuttle gets turned into swiss cheese if(DELTA_CRATES) - message = "Cargo: We have discovered a warehouse of DELTA locked crates, we cant store any more of them at CC can you take them for us?." + message = "Cargo: We have discovered a warehouse of DELTA locked crates. We can't store any more of them at CC, can you take them for us?" title = "CentCom Security Division" bonus_points = 25000 //If you mess up, people die and the shuttle gets turned into swiss cheese if(prob(50)) diff --git a/code/modules/events/spacevine.dm b/code/modules/events/spacevine.dm index edc062f78f..c8679447b8 100644 --- a/code/modules/events/spacevine.dm +++ b/code/modules/events/spacevine.dm @@ -3,7 +3,7 @@ typepath = /datum/round_event/spacevine weight = 15 max_occurrences = 3 - min_players = 10 + min_players = 20 /datum/round_event/spacevine fakeable = FALSE diff --git a/code/modules/events/supermatter_surge.dm b/code/modules/events/supermatter_surge.dm new file mode 100644 index 0000000000..d54fc4dcd2 --- /dev/null +++ b/code/modules/events/supermatter_surge.dm @@ -0,0 +1,23 @@ +/datum/round_event_control/supermatter_surge + name = "Supermatter Surge" + typepath = /datum/round_event/supermatter_surge + weight = 20 + max_occurrences = 4 + earliest_start = 10 MINUTES + +/datum/round_event_control/supermatter_surge/canSpawnEvent() + if(GLOB.main_supermatter_engine?.has_been_powered) + return ..() + +/datum/round_event/supermatter_surge + var/power = 2000 + +/datum/round_event/supermatter_surge/setup() + power = rand(200,4000) + +/datum/round_event/supermatter_surge/announce() + if(power > 800 || prob(round(power/8))) + priority_announce("Class [round(power/500) + 1] supermatter surge detected. Intervention may be required.", "Anomaly Alert") + +/datum/round_event/supermatter_surge/start() + GLOB.main_supermatter_engine.matter_power += power diff --git a/code/modules/food_and_drinks/food/snacks_meat.dm b/code/modules/food_and_drinks/food/snacks_meat.dm index 05a0da2793..152740f932 100644 --- a/code/modules/food_and_drinks/food/snacks_meat.dm +++ b/code/modules/food_and_drinks/food/snacks_meat.dm @@ -435,7 +435,7 @@ name = "alien drone cube" desc = "Just add water and run!" tastes = list("the jungle" = 1, "acid" = 1) - dried_being = /mob/living/carbon/alien/humanoid/drone + dried_being = /mob/living/simple_animal/hostile/alien/sentinel/cube /obj/item/reagent_containers/food/snacks/cube/goat name = "goat cube" diff --git a/code/modules/food_and_drinks/food/snacks_pie.dm b/code/modules/food_and_drinks/food/snacks_pie.dm index a4287d3d19..5329829637 100644 --- a/code/modules/food_and_drinks/food/snacks_pie.dm +++ b/code/modules/food_and_drinks/food/snacks_pie.dm @@ -54,7 +54,7 @@ H.visible_message("[H] is creamed by [src]!", "You've been creamed by [src]!") playsound(H, "desceration", 50, TRUE) if(!H.is_mouth_covered()) - reagents.trans_to(H, 15, log = TRUE) //Cream pie combat + reagents.trans_to(H, 15, log = "creampie hit") //Cream pie combat if(!H.creamed) // one layer at a time H.add_overlay(creamoverlay) H.creamed = TRUE diff --git a/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm b/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm index fecc9467a1..ebde504ec0 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm @@ -79,7 +79,7 @@ God bless America. to_chat(user, "There's nothing to dissolve [I] in!") return user.visible_message("[user] drops [I] into [src].", "You dissolve [I] in [src].") - I.reagents.trans_to(src, I.reagents.total_volume) + I.reagents.trans_to(src, I.reagents.total_volume, log = "pill into deep fryer") qdel(I) return if(istype(I,/obj/item/clothing/head/mob_holder)) diff --git a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm index 35fa40e15d..b79efdd39b 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm @@ -259,7 +259,9 @@ /obj/machinery/smartfridge/drying_rack/exchange_parts() /obj/machinery/smartfridge/drying_rack/spawn_frame() -/obj/machinery/smartfridge/drying_rack/default_deconstruction_crowbar(obj/item/crowbar/C, ignore_panel = 1) +/obj/machinery/smartfridge/drying_rack/default_deconstruction_crowbar(obj/item/C, ignore_panel = 1) + if(!C.tool_behaviour == TOOL_CROWBAR) + return ..() /obj/machinery/smartfridge/drying_rack/ui_data(mob/user) diff --git a/code/modules/holiday/halloween/jacqueen.dm b/code/modules/holiday/halloween/jacqueen.dm index 4212a2e296..11bd330112 100644 --- a/code/modules/holiday/halloween/jacqueen.dm +++ b/code/modules/holiday/halloween/jacqueen.dm @@ -72,16 +72,14 @@ if((last_poof+3 MINUTES) < world.realtime) poof() -/mob/living/simple_animal/jacq/Destroy() //I.e invincible +/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) - var/mob/living/simple_animal/jacq/Jacq = new src.type(loc) - Jacq.progression = progression - if(ckey) //transfer over any ghost posessions - Jacq.key = key - ..() + fully_heal(FALSE) + health = 25 + poof() -/mob/living/simple_animal/jacq/death() //What is alive may never die +/mob/living/simple_animal/jacq/gib() visible_message("[src] cackles, \"You'll nae get rid a me that easily!\"") playsound(loc, 'sound/spookoween/ahaha.ogg', 100, 0.25) fully_heal(FALSE) diff --git a/code/modules/holodeck/computer.dm b/code/modules/holodeck/computer.dm index e5cd36cad6..e94cc17041 100644 --- a/code/modules/holodeck/computer.dm +++ b/code/modules/holodeck/computer.dm @@ -115,13 +115,20 @@ return FALSE var/valid = FALSE var/list/checked = program_cache.Copy() - if(obj_flags & EMAGGED) - checked |= emag_programs for(var/prog in checked) var/list/P = prog if(P["type"] == program_to_load) valid = TRUE break + if(obj_flags & EMAGGED) //split up into separate for loops instead of together so we can adminlog it + checked = emag_programs.Copy() + for(var/prog in checked) + var/list/P = prog + if(P["type"] == program_to_load) + valid = TRUE + log_game("[key_name(usr)] has loaded the restricted holodeck program [program_to_load]") + message_admins("[ADMIN_LOOKUPFLW(usr)] has loaded the restricted holodeck program [program_to_load]") + break if(!valid) return FALSE @@ -134,6 +141,14 @@ nerf(obj_flags & EMAGGED) obj_flags ^= EMAGGED say("Safeties restored. Restarting...") + if(obj_flags & EMAGGED) + to_chat(usr,"You vastly increase projector power and override the safety and security protocols.") + log_game("[key_name(usr)] has disabled safeties on the holodeck computer") + message_admins("[ADMIN_LOOKUPFLW(usr)] has disabled safeties on the holodeck computer") + else + to_chat(usr,"You restore the safeties to the holodeck.") + log_game("[key_name(usr)] has reenabled safeties on the holodeck computer") + message_admins("[ADMIN_LOOKUPFLW(usr)] has reenabled safeties on the holodeck computer") /obj/machinery/computer/holodeck/process() if(damaged && prob(10)) @@ -179,6 +194,7 @@ to_chat(user, "You vastly increase projector power and override the safety and security protocols.") say("Warning. Automatic shutoff and derezzing protocols have been corrupted. Please call Nanotrasen maintenance and do not use the simulator.") log_game("[key_name(user)] emagged the Holodeck Control Console") + message_admins("[ADMIN_LOOKUPFLW(user)] emagged the Holodeck Control Console.") nerf(!(obj_flags & EMAGGED)) /obj/machinery/computer/holodeck/emp_act(severity) diff --git a/code/modules/hydroponics/beekeeping/beebox.dm b/code/modules/hydroponics/beekeeping/beebox.dm index a058601c39..2857099d0f 100644 --- a/code/modules/hydroponics/beekeeping/beebox.dm +++ b/code/modules/hydroponics/beekeeping/beebox.dm @@ -155,7 +155,7 @@ to_chat(user, "There's no room for any more frames in the apiary!") return - if(istype(I, /obj/item/wrench)) + if(I.tool_behaviour == TOOL_WRENCH) if(default_unfasten_wrench(user, I, time = 20)) return diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm index 24f65756c8..aca727ad8d 100644 --- a/code/modules/hydroponics/hydroponics.dm +++ b/code/modules/hydroponics/hydroponics.dm @@ -97,6 +97,7 @@ if(myseed.mutatelist.len > 0) myseed.instability = (myseed.instability/2) mutatespecie() + return BULLET_ACT_HIT else return ..() @@ -527,12 +528,13 @@ else if(istype(O, /obj/item/seeds) && !istype(O, /obj/item/seeds/sample)) if(!myseed) if(istype(O, /obj/item/seeds/kudzu)) - investigate_log("had Kudzu planted in it by [key_name(user)] at [AREACOORD(src)]","kudzu") + investigate_log("had Kudzu planted in it by [key_name(user)] at [AREACOORD(src)]", INVESTIGATE_BOTANY) if(!user.transferItemToLoc(O, src)) return to_chat(user, "You plant [O].") dead = FALSE myseed = O + investigate_log("planting: [user] planted [O] with traits [english_list(myseed)] and reagents [english_list_assoc(myseed.reagents_add)] and potency [myseed.potency]", INVESTIGATE_BOTANY) TRAY_NAME_UPDATE age = 1 plant_health = myseed.endurance diff --git a/code/modules/hydroponics/seed_extractor.dm b/code/modules/hydroponics/seed_extractor.dm index 71701d9637..e0e15ac111 100644 --- a/code/modules/hydroponics/seed_extractor.dm +++ b/code/modules/hydroponics/seed_extractor.dm @@ -76,7 +76,7 @@ /obj/machinery/seed_extractor/examine(mob/user) . = ..() if(in_range(user, src) || isobserver(user)) - . += "The status display reads: Extracting [seed_multiplier] seed(s) per piece of produce.
Machine can store up to [max_seeds]% seeds.
" + . += "The status display reads: Extracting [seed_multiplier] seed(s) per piece of produce.
Machine can store up to [max_seeds] seeds.
" /obj/machinery/seed_extractor/attackby(obj/item/O, mob/user, params) diff --git a/code/modules/hydroponics/seeds.dm b/code/modules/hydroponics/seeds.dm index d8082e667d..577635cd1c 100644 --- a/code/modules/hydroponics/seeds.dm +++ b/code/modules/hydroponics/seeds.dm @@ -188,6 +188,8 @@ ///The Number of products produced by the plant, typically the yield. var/product_count = getYield() + parent.investigate_log("manual harvest by [key_name(user)] of [getYield()] of [src], with seed traits [english_list(genes)] and reagents_add [english_list_assoc(reagents_add)] and potency [potency].", INVESTIGATE_BOTANY) + while(t_amount < product_count) var/obj/item/reagent_containers/food/snacks/grown/t_prod if(instability >= 30 && (seed_flags & MUTATE_EARLY) && LAZYLEN(mutatelist) && prob(instability/3)) diff --git a/code/modules/integrated_electronics/core/assemblies.dm b/code/modules/integrated_electronics/core/assemblies.dm index 6cb578dfb1..ac27b4a30e 100644 --- a/code/modules/integrated_electronics/core/assemblies.dm +++ b/code/modules/integrated_electronics/core/assemblies.dm @@ -452,7 +452,7 @@ for(var/obj/item/integrated_circuit/input/S in assembly_components) S.attackby_react(I,user,user.a_intent) return ..() - else if(istype(I, /obj/item/multitool) || istype(I, /obj/item/integrated_electronics/wirer) || istype(I, /obj/item/integrated_electronics/debugger)) + else if(I.tool_behaviour == TOOL_MULTITOOL || istype(I, /obj/item/integrated_electronics/wirer) || istype(I, /obj/item/integrated_electronics/debugger)) if(opened) interact(user) return TRUE diff --git a/code/modules/integrated_electronics/core/integrated_circuit.dm b/code/modules/integrated_electronics/core/integrated_circuit.dm index 92d2aa270f..756706dcdf 100644 --- a/code/modules/integrated_electronics/core/integrated_circuit.dm +++ b/code/modules/integrated_electronics/core/integrated_circuit.dm @@ -252,7 +252,7 @@ a creative player the means to solve many problems. Circuits are held inside an var/update = TRUE var/update_to_assembly = FALSE - var/obj/held_item = usr.get_active_held_item() + var/obj/item/held_item = usr.get_active_held_item() if(href_list["rename"]) rename_component(usr) @@ -267,7 +267,7 @@ a creative player the means to solve many problems. Circuits are held inside an if(href_list["link"]) linked = locate(href_list["link"]) in pin.linked - if(istype(held_item, /obj/item/integrated_electronics) || istype(held_item, /obj/item/multitool)) + if(istype(held_item, /obj/item/integrated_electronics) || held_item.tool_behaviour == TOOL_MULTITOOL) pin.handle_wire(linked, held_item, href_list["act"], usr) else to_chat(usr, "You can't do a whole lot without the proper tools.") diff --git a/code/modules/integrated_electronics/core/pins.dm b/code/modules/integrated_electronics/core/pins.dm index c1bbb900fa..e08d77007d 100644 --- a/code/modules/integrated_electronics/core/pins.dm +++ b/code/modules/integrated_electronics/core/pins.dm @@ -105,15 +105,14 @@ D [1]/ || push_data() /datum/integrated_io/proc/handle_wire(datum/integrated_io/linked_pin, obj/item/tool, action, mob/living/user) - if(istype(tool, /obj/item/multitool)) - var/obj/item/multitool/multitool = tool + if(tool.tool_behaviour == TOOL_MULTITOOL) switch(action) if("wire") - multitool.wire(src, user) + tool.wire(src, user) return TRUE if("unwire") if(linked_pin) - multitool.unwire(src, linked_pin, user) + tool.unwire(src, linked_pin, user) return TRUE if("data") ask_for_pin_data(user) diff --git a/code/modules/integrated_electronics/core/wirer.dm b/code/modules/integrated_electronics/core/wirer.dm index 95f46564cb..73dfa4e44a 100644 --- a/code/modules/integrated_electronics/core/wirer.dm +++ b/code/modules/integrated_electronics/core/wirer.dm @@ -12,13 +12,12 @@ icon_state = "wirer-wire" flags_1 = CONDUCT_1 w_class = WEIGHT_CLASS_SMALL - var/datum/integrated_io/selected_io = null var/mode = WIRE /obj/item/integrated_electronics/wirer/update_icon_state() icon_state = "wirer-[mode]" -/obj/item/integrated_electronics/wirer/proc/wire(var/datum/integrated_io/io, mob/user) +/obj/item/integrated_electronics/wirer/wire(var/datum/integrated_io/io, mob/user) if(!io.holder.assembly) to_chat(user, "\The [io.holder] needs to be secured inside an assembly first.") return diff --git a/code/modules/integrated_electronics/subtypes/weaponized.dm b/code/modules/integrated_electronics/subtypes/weaponized.dm index 96a732d08f..25fa7058fb 100644 --- a/code/modules/integrated_electronics/subtypes/weaponized.dm +++ b/code/modules/integrated_electronics/subtypes/weaponized.dm @@ -137,6 +137,10 @@ //Shooting Code: A.preparePixelProjectile(target, src) A.fire() + if(ismob(loc.loc)) + installed_gun.shoot_live_shot(loc.loc) + else + installed_gun.shoot_live_shot() //Shitcode, but we don't have much of a choice log_attack("[assembly] [REF(assembly)] has fired [installed_gun].") return A diff --git a/code/modules/language/signlanguage.dm b/code/modules/language/signlanguage.dm new file mode 100644 index 0000000000..97705d4a4c --- /dev/null +++ b/code/modules/language/signlanguage.dm @@ -0,0 +1,12 @@ +/datum/language/signlanguage + name = "Space Sign Language" + desc = "Those who cannot speak can learn this instead." + speech_verb = "signs" + whisper_verb = "gestures" + key = "9" + flags = TONGUELESS_SPEECH + + syllables = list(".") + + icon_state = "ssl" + default_priority = 90 diff --git a/code/modules/library/lib_items.dm b/code/modules/library/lib_items.dm index a4d88158e2..ef0ee2ee77 100644 --- a/code/modules/library/lib_items.dm +++ b/code/modules/library/lib_items.dm @@ -53,12 +53,12 @@ /obj/structure/bookcase/attackby(obj/item/I, mob/user, params) switch(state) if(0) - if(istype(I, /obj/item/wrench)) + if(I.tool_behaviour == TOOL_WRENCH) if(I.use_tool(src, user, 20, volume=50)) to_chat(user, "You wrench the frame into place.") anchored = TRUE state = 1 - if(istype(I, /obj/item/crowbar)) + if(I.tool_behaviour == TOOL_CROWBAR) if(I.use_tool(src, user, 20, volume=50)) to_chat(user, "You pry the frame apart.") deconstruct(TRUE) @@ -71,7 +71,7 @@ to_chat(user, "You add a shelf.") state = 2 icon_state = "book-0" - if(istype(I, /obj/item/wrench)) + if(I.tool_behaviour == TOOL_WRENCH) I.play_tool_sound(src, 100) to_chat(user, "You unwrench the frame.") anchored = FALSE @@ -100,7 +100,7 @@ return else name = "bookcase ([sanitize(newname)])" - else if(istype(I, /obj/item/crowbar)) + else if(I.tool_behaviour == TOOL_CROWBAR) if(contents.len) to_chat(user, "You need to remove the books first!") else @@ -302,7 +302,7 @@ scanner.computer.inventory.Add(src) to_chat(user, "[I]'s screen flashes: 'Book stored in buffer. Title added to general inventory.'") - else if(istype(I, /obj/item/kitchen/knife) || istype(I, /obj/item/wirecutters)) + else if(istype(I, /obj/item/kitchen/knife) || I.tool_behaviour == TOOL_WIRECUTTER) to_chat(user, "You begin to carve out [title]...") if(do_after(user, 30, target = src)) to_chat(user, "You carve out the pages from [title]! You didn't want to read it anyway.") diff --git a/code/modules/mining/abandoned_crates.dm b/code/modules/mining/abandoned_crates.dm index 8c9b0b53e1..e97060b45d 100644 --- a/code/modules/mining/abandoned_crates.dm +++ b/code/modules/mining/abandoned_crates.dm @@ -190,7 +190,7 @@ /obj/structure/closet/crate/secure/loot/attackby(obj/item/W, mob/user) if(locked) - if(istype(W, /obj/item/multitool)) + if(W.tool_behaviour == TOOL_MULTITOOL) to_chat(user, "DECA-CODE LOCK REPORT:") if(attempts == 1) to_chat(user, "* Anti-Tamper Bomb will activate on next failed access attempt.") diff --git a/code/modules/mining/equipment/kinetic_crusher.dm b/code/modules/mining/equipment/kinetic_crusher.dm index a6f456ce6f..859ea58d26 100644 --- a/code/modules/mining/equipment/kinetic_crusher.dm +++ b/code/modules/mining/equipment/kinetic_crusher.dm @@ -65,7 +65,7 @@ . += "It has \a [T] attached, which causes [T.effect_desc()]." /obj/item/kinetic_crusher/attackby(obj/item/I, mob/living/user) - if(istype(I, /obj/item/crowbar)) + if(I.tool_behaviour == TOOL_CROWBAR) if(LAZYLEN(trophies)) to_chat(user, "You remove [src]'s trophies.") I.play_tool_sound(src) diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm index 9c39601b4e..6af1c2118c 100644 --- a/code/modules/mining/lavaland/necropolis_chests.dm +++ b/code/modules/mining/lavaland/necropolis_chests.dm @@ -522,7 +522,7 @@ max_charges = 1 item_flags = NEEDS_PERMIT | NOBLUDGEON w_class = WEIGHT_CLASS_BULKY - force = 18 + force = 15 /obj/item/ammo_casing/magic/hook name = "hook" @@ -536,11 +536,11 @@ icon_state = "hook" icon = 'icons/obj/lavaland/artefacts.dmi' pass_flags = PASSTABLE - damage = 25 - armour_penetration = 100 + damage = 15 + armour_penetration = 10 + knockdown = 5 damage_type = BRUTE hitsound = 'sound/effects/splat.ogg' - knockdown = 30 var/chain /obj/item/projectile/hook/fire(setAngle) diff --git a/code/modules/mining/machine_redemption.dm b/code/modules/mining/machine_redemption.dm index d6c4dfae34..6cba540ca0 100644 --- a/code/modules/mining/machine_redemption.dm +++ b/code/modules/mining/machine_redemption.dm @@ -188,8 +188,10 @@ return ..() -/obj/machinery/mineral/ore_redemption/multitool_act(mob/living/user, obj/item/multitool/I) - if (panel_open) +/obj/machinery/mineral/ore_redemption/multitool_act(mob/living/user, obj/item/I) + if(!I.tool_behaviour == TOOL_MULTITOOL) + return + if(panel_open) input_dir = turn(input_dir, -90) output_dir = turn(output_dir, -90) to_chat(user, "You change [src]'s I/O settings, setting the input to [dir2text(input_dir)] and the output to [dir2text(output_dir)].") diff --git a/code/modules/mining/machine_silo.dm b/code/modules/mining/machine_silo.dm index 09246abc46..b0055204f9 100644 --- a/code/modules/mining/machine_silo.dm +++ b/code/modules/mining/machine_silo.dm @@ -170,8 +170,8 @@ GLOBAL_LIST_EMPTY(silo_access_logs) updateUsrDialog() return TRUE -/obj/machinery/ore_silo/multitool_act(mob/living/user, obj/item/multitool/I) - if (istype(I)) +/obj/machinery/ore_silo/multitool_act(mob/living/user, obj/item/I) + if(I.tool_behaviour == TOOL_MULTITOOL) to_chat(user, "You log [src] in the multitool's buffer.") I.buffer = src return TRUE diff --git a/code/modules/mining/machine_stacking.dm b/code/modules/mining/machine_stacking.dm index a5ff27e75e..d27e49b48c 100644 --- a/code/modules/mining/machine_stacking.dm +++ b/code/modules/mining/machine_stacking.dm @@ -38,9 +38,8 @@ user << browse(dat, "window=console_stacking_machine") /obj/machinery/mineral/stacking_unit_console/multitool_act(mob/living/user, obj/item/I) - if(istype(I, /obj/item/multitool)) - var/obj/item/multitool/M = I - M.buffer = src + if(I.tool_behaviour == TOOL_MULTITOOL) + I.buffer = src to_chat(user, "You store linkage information in [I]'s buffer.") return TRUE @@ -97,8 +96,8 @@ if(istype(AM, /obj/item/stack/sheet) && AM.loc == get_step(src, input_dir)) process_sheet(AM) -/obj/machinery/mineral/stacking_machine/multitool_act(mob/living/user, obj/item/multitool/M) - if(istype(M)) +/obj/machinery/mineral/stacking_machine/multitool_act(mob/living/user, obj/item/M) + if(M.tool_behaviour == TOOL_MULTITOOL) if(istype(M.buffer, /obj/machinery/mineral/stacking_unit_console)) CONSOLE = M.buffer CONSOLE.machine = src diff --git a/code/modules/mining/minebot.dm b/code/modules/mining/minebot.dm index 627d79d6ba..8037a22a52 100644 --- a/code/modules/mining/minebot.dm +++ b/code/modules/mining/minebot.dm @@ -105,7 +105,7 @@ to_chat(user, "You instruct [src] to drop any collected ore.") DropOre() return - if(istype(I, /obj/item/crowbar) || istype(I, /obj/item/borg/upgrade/modkit)) + if(I.tool_behaviour == TOOL_CROWBAR || istype(I, /obj/item/borg/upgrade/modkit)) I.melee_attack_chain(user, stored_gun, params) return ..() diff --git a/code/modules/mining/ores_coins.dm b/code/modules/mining/ores_coins.dm index 26a3ca1b70..a3399bf46c 100644 --- a/code/modules/mining/ores_coins.dm +++ b/code/modules/mining/ores_coins.dm @@ -251,7 +251,7 @@ GLOBAL_LIST_INIT(sand_recipes, list(\ GibtoniteReaction(user) return if(primed) - if(istype(I, /obj/item/mining_scanner) || istype(I, /obj/item/t_scanner/adv_mining_scanner) || istype(I, /obj/item/multitool)) + if(istype(I, /obj/item/mining_scanner) || istype(I, /obj/item/t_scanner/adv_mining_scanner) || I.tool_behaviour == TOOL_MULTITOOL) primed = FALSE if(det_timer) deltimer(det_timer) diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm index 00c22ad96d..dbab6a558c 100644 --- a/code/modules/mob/dead/new_player/new_player.dm +++ b/code/modules/mob/dead/new_player/new_player.dm @@ -128,10 +128,58 @@ if(dbflags & DB_FLAG_AGE_CONFIRMATION_INCOMPLETE) //they have not completed age gate var/age_verification = age_gate() if(age_verification != 1) - client.add_system_note("Automated-Age-Gate", "Failed automatic age gate process") + client.add_system_note("Automated-Age-Gate", "Failed automatic age gate process.") //ban them and kick them - AddBan(client.ckey, client.computer_id, "SYSTEM BAN - Inputted date during join verification was under 18 years of age. Contact administration on discord for verification.", "SYSTEM", FALSE, null, client.address) + + //parameters used by sql line, easier to read: + var/bantype_str = "ADMIN_PERMABAN" + var/reason = "SYSTEM BAN - Inputted date during join verification was under 18 years of age. Contact administration on discord for verification." + var/duration = -1 + var/sql_ckey = sanitizeSQL(client.ckey) + var/computerid = client.computer_id + if(!computerid) + computerid = "0" + var/sql_computerid = sanitizeSQL(computerid) + var/ip = client.address + if(!ip) + ip = "0.0.0.0" + var/sql_ip = sanitizeSQL(ip) + + //parameter not used as there's no job but i want to fill out all parameters for the insert line + var/sql_job + + // these are typically the banning admin's, but it's the system so we leave them null, but they're still here for the sake of a full set of values + var/sql_a_ckey + var/sql_a_computerid + var/sql_a_ip + + // record all admins and non-admins online at the time + var/who + for(var/client/C in GLOB.clients) + if(!who) + who = "[C]" + else + who += ", [C]" + + var/adminwho + for(var/client/C in GLOB.admins) + if(!adminwho) + adminwho = "[C]" + else + adminwho += ", [C]" + + var/sql = "INSERT INTO [format_table_name("ban")] (`bantime`,`server_ip`,`server_port`,`round_id`,`bantype`,`reason`,`job`,`duration`,`expiration_time`,`ckey`,`computerid`,`ip`,`a_ckey`,`a_computerid`,`a_ip`,`who`,`adminwho`) VALUES (Now(), INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')), '[world.port]', '[GLOB.round_id]', '[bantype_str]', '[reason]', '[sql_job]', [(duration)?"[duration]":"0"], Now() + INTERVAL [(duration>0) ? duration : 0] MINUTE, '[sql_ckey]', '[sql_computerid]', INET_ATON('[sql_ip]'), '[sql_a_ckey]', '[sql_a_computerid]', INET_ATON('[sql_a_ip]'), '[who]', '[adminwho]')" + var/datum/DBQuery/query_add_ban = SSdbcore.NewQuery(sql) + qdel(query_add_ban) + + // announce this + message_admins("[html_encode(client.ckey)] has been banned for failing the automatic age gate.") + send2irc("[html_encode(client.ckey)] has been banned for failing the automatic age gate.") + + // removing the client disconnects them qdel(client) + + return FALSE else //they claim to be of age, so allow them to continue and update their flags diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index dc53f9487f..783f55d12d 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -556,7 +556,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp var/list/dest = list() //List of possible destinations (mobs) var/target = null //Chosen target. - dest += getpois(mobs_only=1) //Fill list, prompt user with list + dest += getpois(mobs_only = TRUE) //Fill list, prompt user with list target = input("Please, select a player!", "Jump to Mob", null, null) as null|anything in dest if (!target)//Make sure we actually have a target @@ -893,7 +893,9 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp if (!eye_name) return - var/mob/mob_eye = creatures[eye_name] + do_observe(creatures[eye_name]) + +/mob/dead/observer/proc/do_observe(mob/mob_eye) //Istype so we filter out points of interest that are not mobs if(client && mob_eye && istype(mob_eye)) client.eye = mob_eye diff --git a/code/modules/mob/dead/observer/orbit.dm b/code/modules/mob/dead/observer/orbit.dm index 3aa5f8e302..26494dcb34 100644 --- a/code/modules/mob/dead/observer/orbit.dm +++ b/code/modules/mob/dead/observer/orbit.dm @@ -1,5 +1,6 @@ /datum/orbit_menu var/mob/dead/observer/owner + var/auto_observe = FALSE /datum/orbit_menu/New(mob/dead/observer/new_owner) if(!istype(new_owner)) @@ -10,6 +11,7 @@ return GLOB.observer_state /datum/orbit_menu/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if (!ui) ui = new(user, src, "Orbit") ui.open() @@ -18,15 +20,35 @@ if (..()) return - if (action == "orbit") - var/ref = params["ref"] - var/atom/movable/poi = (locate(ref) in GLOB.mob_list) || (locate(ref) in GLOB.poi_list) - if (poi != null) + switch(action) + if ("orbit") + var/ref = params["ref"] + var/atom/movable/poi = (locate(ref) in GLOB.mob_list) || (locate(ref) in GLOB.poi_list) + if (poi == null) + . = TRUE + return owner.ManualFollow(poi) + owner.reset_perspective(null) + if (auto_observe) + owner.do_observe(poi) + . = TRUE + if ("refresh") + update_static_data(owner, ui) + . = TRUE + if ("toggle_observe") + auto_observe = !auto_observe + if (auto_observe && owner.orbit_target) + owner.do_observe(owner.orbit_target) + else + owner.reset_perspective(null) /datum/orbit_menu/ui_data(mob/user) var/list/data = list() + data["auto_observe"] = auto_observe + return data +/datum/orbit_menu/ui_static_data(mob/user) + var/list/data = list() var/list/alive = list() var/list/antagonists = list() var/list/dead = list() @@ -34,7 +56,7 @@ var/list/misc = list() var/list/npcs = list() - var/list/pois = getpois(skip_mindless = 1) + var/list/pois = getpois(skip_mindless = TRUE, specify_dead_role = FALSE) for (var/name in pois) var/list/serialized = list() serialized["name"] = name @@ -80,7 +102,7 @@ data["npcs"] = npcs return data - + /datum/orbit_menu/ui_assets() . = ..() || list() . += get_asset_datum(/datum/asset/simple/orbit) diff --git a/code/modules/mob/living/carbon/alien/alien.dm b/code/modules/mob/living/carbon/alien/alien.dm index 7c80d1d426..f5970d9da2 100644 --- a/code/modules/mob/living/carbon/alien/alien.dm +++ b/code/modules/mob/living/carbon/alien/alien.dm @@ -11,6 +11,10 @@ bubble_icon = "alien" type_of_meat = /obj/item/reagent_containers/food/snacks/meat/slab/xeno + /// Whether they can ventcrawl; this is set individually for 'humanoid' and 'royal' types + /// 'royal' types (Praetorian, Queen) cannot ventcrawl + var/can_ventcrawl + /// How much brute damage without armor piercing they do against mobs in melee var/meleeSlashHumanPower = 20 /// How much power they have for DefaultCombatKnockdown when attacking humans @@ -38,7 +42,8 @@ create_internal_organs() - AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) + if(can_ventcrawl) + AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) . = ..() diff --git a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm index d0addbab21..0d2a1c0c59 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm @@ -20,6 +20,8 @@ bodyparts = list(/obj/item/bodypart/chest/alien, /obj/item/bodypart/head/alien, /obj/item/bodypart/l_arm/alien, /obj/item/bodypart/r_arm/alien, /obj/item/bodypart/r_leg/alien, /obj/item/bodypart/l_leg/alien) + can_ventcrawl = TRUE + //This is fine right now, if we're adding organ specific damage this needs to be updated /mob/living/carbon/alien/humanoid/Initialize() diff --git a/code/modules/mob/living/carbon/alien/humanoid/queen.dm b/code/modules/mob/living/carbon/alien/humanoid/queen.dm index 42b62e37a0..bcc83f14f9 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/queen.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/queen.dm @@ -9,6 +9,7 @@ layer = LARGE_MOB_LAYER //above most mobs, but below speechbubbles pressure_resistance = 200 //Because big, stompy xenos should not be blown around like paper. butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/xeno = 20, /obj/item/stack/sheet/animalhide/xeno = 3) + can_ventcrawl = FALSE meleeKnockdownPower = 125 meleeSlashHumanPower = 30 diff --git a/code/modules/mob/living/carbon/alien/larva/larva.dm b/code/modules/mob/living/carbon/alien/larva/larva.dm index 8f0ef2b384..77c9a8c579 100644 --- a/code/modules/mob/living/carbon/alien/larva/larva.dm +++ b/code/modules/mob/living/carbon/alien/larva/larva.dm @@ -11,6 +11,8 @@ maxHealth = 25 health = 25 + can_ventcrawl = TRUE + var/amount_grown = 0 var/max_grown = 100 var/time_of_birth diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 979baeb065..f143f6302d 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -434,6 +434,9 @@ legcuffed.forceMove(drop_location()) legcuffed = null I.dropped(src) + if(istype(I, /obj/item/restraints/legcuffs)) + var/obj/item/restraints/legcuffs/lgcf = I + lgcf.on_removed() update_inv_legcuffed() return else diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index df7ed66169..8660e115a6 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -281,11 +281,13 @@ dropItemToGround(pocket_item) if(!usr.can_hold_items() || !usr.put_in_hands(pocket_item)) pocket_item.forceMove(drop_location()) + log_combat(usr, src, "pickpocketed of item: [pocket_item]") else if(place_item) if(place_item.mob_can_equip(src, usr, pocket_id, FALSE, TRUE)) usr.temporarilyRemoveItemFromInventory(place_item, TRUE) equip_to_slot(place_item, pocket_id, TRUE) + log_combat(usr, src, "placed item [place_item] onto") //do nothing otherwise // Update strip window @@ -293,8 +295,9 @@ show_inv(usr) else // Display a warning if the user mocks up - if (!strip_silence) + if(!strip_silence) to_chat(src, "You feel your [pocket_side] pocket being fumbled with!") + log_combat(usr, src, "failed to [pocket_item ? "pickpocket item [pocket_item] from" : "place item [place_item] onto "]") if(usr.canUseTopic(src, BE_CLOSE, NO_DEXTERY, null, FALSE)) // separate from first canusetopic @@ -938,43 +941,43 @@ admin_ticket_log(src, msg) /mob/living/carbon/human/MouseDrop_T(mob/living/target, mob/living/user) - if(pulling == target && grab_state >= GRAB_AGGRESSIVE && stat == CONSCIOUS) + var/GS_needed = istype(target, /mob/living/silicon/pai)? GRAB_PASSIVE : GRAB_AGGRESSIVE + if(pulling == target && grab_state >= GS_needed && 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) + else if(user == src) if(user.a_intent == INTENT_GRAB) fireman_carry(target) return . = ..() //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) +/mob/living/carbon/human/proc/can_piggyback(mob/living/target) + return (iscarbon(target) || ispAI(target)) && target.stat == CONSCIOUS /mob/living/carbon/human/proc/can_be_firemanned(mob/living/carbon/target) - return (ishuman(target) && !CHECK_MOBILITY(target, MOBILITY_STAND)) + return (ishuman(target) && !CHECK_MOBILITY(target, MOBILITY_STAND)) || ispAI(target) /mob/living/carbon/human/proc/fireman_carry(mob/living/carbon/target) var/carrydelay = 50 //if you have latex you are faster at grabbing var/skills_space = "" //cobby told me to do this if(HAS_TRAIT(src, TRAIT_QUICKER_CARRY)) carrydelay = 30 - skills_space = "expertly" + skills_space = "expertly " else if(HAS_TRAIT(src, TRAIT_QUICK_CARRY)) carrydelay = 40 - skills_space = "quickly" + skills_space = "quickly " if(can_be_firemanned(target) && !incapacitated(FALSE, TRUE)) - visible_message("[src] starts [skills_space] lifting [target] onto their back..", + visible_message("[src] starts [skills_space]lifting [target] onto their back..", //Joe Medic starts quickly/expertly lifting Grey Tider onto their back.. - "[carrydelay < 35 ? "Using your gloves' nanochips, you" : "You"] [skills_space] start to lift [target] onto your back[carrydelay == 40 ? ", while assisted by the nanochips in your gloves.." : "..."]") + "[carrydelay < 35 ? "Using your gloves' nanochips, you" : "You"] [skills_space]start to lift [target] onto your back[carrydelay == 40 ? ", while assisted by the nanochips in your gloves.." : "..."]") //(Using your gloves' nanochips, you/You) ( /quickly/expertly) start to lift Grey Tider onto your back(, while assisted by the nanochips in your gloves../...) if(do_after(src, carrydelay, TRUE, target)) //Second check to make sure they're still valid to be carried if(can_be_firemanned(target) && !incapacitated(FALSE, TRUE)) - target.set_resting(FALSE, TRUE) buckle_mob(target, TRUE, TRUE, 90, 1, 0, TRUE) return visible_message("[src] fails to fireman carry [target]!") @@ -992,13 +995,13 @@ if(target.incapacitated(FALSE, TRUE) || incapacitated(FALSE, TRUE)) target.visible_message("[target] can't hang onto [src]!") return - buckle_mob(target, TRUE, TRUE, FALSE, 1, 2, FALSE) + buckle_mob(target, TRUE, TRUE, 0, 1, 2, FALSE) 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, fireman = FALSE) +/mob/living/carbon/human/buckle_mob(mob/living/target, force = FALSE, check_loc = TRUE, lying_buckle = 0, hands_needed = 0, target_hands_needed = 0, fireman = FALSE) if(!force)//humans are only meant to be ridden through piggybacking and special cases return if(!is_type_in_typecache(target, can_ride_typecache)) @@ -1010,6 +1013,9 @@ riding_datum.ride_check_rider_restrained = TRUE if(buckled_mobs && ((target in buckled_mobs) || (buckled_mobs.len >= max_buckled_mobs)) || buckled) return + if(istype(target, /mob/living/silicon/pai)) + hands_needed = 1 + target_hands_needed = 0 var/equipped_hands_self var/equipped_hands_target if(hands_needed) diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index a82151cc1d..66d3154ee3 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -71,7 +71,7 @@ var/list/datum/bioware = list() var/creamed = FALSE //to use with creampie overlays - var/static/list/can_ride_typecache = typecacheof(list(/mob/living/carbon/human, /mob/living/simple_animal/slime, /mob/living/simple_animal/parrot)) + var/static/list/can_ride_typecache = typecacheof(list(/mob/living/carbon/human, /mob/living/simple_animal/slime, /mob/living/simple_animal/parrot, /mob/living/silicon/pai)) var/lastpuke = 0 var/account_id var/last_fire_update @@ -95,9 +95,10 @@ parry_efficiency_considered_successful = 0.01 parry_efficiency_to_counterattack = 0.01 parry_max_attacks = 3 - parry_cooldown = 30 - parry_failed_stagger_duration = 0 - parry_failed_clickcd_duration = 0.4 + parry_cooldown = 3 SECONDS + parry_failed_cooldown_duration = 1.5 SECONDS + parry_failed_stagger_duration = 1 SECONDS + parry_failed_clickcd_duration = 0.4 SECONDS parry_data = list( // yeah it's snowflake "UNARMED_PARRY_STAGGER" = 3 SECONDS, @@ -135,14 +136,14 @@ parry_imperfect_falloff_percent = 20 parry_efficiency_perfect = 100 parry_efficiency_perfect_override = list( - ATTACK_TYPE_PROJECTILE_TEXT = 60, + TEXT_ATTACK_TYPE_PROJECTILE = 60, ) parry_efficiency_considered_successful = 0.01 parry_efficiency_to_counterattack = 0.01 parry_max_attacks = INFINITY parry_failed_cooldown_duration = 1.5 SECONDS - parry_failed_stagger_duration = 0 + parry_failed_stagger_duration = 1 SECONDS parry_cooldown = 0 parry_failed_clickcd_duration = 0.8 diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 8d473639b4..600045e9c5 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -80,6 +80,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) var/list/inherent_traits = list() var/inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID + var/list/blacklisted_quirks = list() // Quirks that will be removed upon gaining this species, to be defined by species + var/list/removed_quirks = list() // Quirks that got removed due to being blacklisted, and will be restored when on_species_loss() is called + var/attack_verb = "punch" // punch-specific attack verb var/sound/attack_sound = 'sound/weapons/punch1.ogg' var/sound/miss_sound = 'sound/weapons/punchmiss.ogg' @@ -342,6 +345,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) for(var/X in inherent_traits) ADD_TRAIT(C, X, SPECIES_TRAIT) + //lets remove those conflicting quirks + remove_blacklisted_quirks(C) + if(TRAIT_VIRUSIMMUNE in inherent_traits) for(var/datum/disease/A in C.diseases) A.cure(FALSE) @@ -395,6 +401,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) for(var/X in inherent_traits) REMOVE_TRAIT(C, X, SPECIES_TRAIT) + // lets restore the quirks that got removed when gaining this species + restore_quirks(C) + C.remove_movespeed_modifier(/datum/movespeed_modifier/species) if(mutant_bodyparts["meat_type"]) @@ -424,6 +433,26 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) SEND_SIGNAL(C, COMSIG_SPECIES_LOSS, src) +// shamelessly inspired by antag_datum.remove_blacklisted_quirks() +/datum/species/proc/remove_blacklisted_quirks(mob/living/carbon/C) + var/mob/living/L = C.mind?.current + if(istype(L)) + var/list/my_quirks = L.client?.prefs.all_quirks.Copy() + SSquirks.filter_quirks(my_quirks, blacklisted_quirks) + for(var/q in L.roundstart_quirks) + var/datum/quirk/Q = q + if(!(SSquirks.quirk_name_by_path(Q.type) in my_quirks)) + L.remove_quirk(Q.type) + removed_quirks += Q.type + +// restore any quirks that we removed +/datum/species/proc/restore_quirks(mob/living/carbon/C) + var/mob/living/L = C.mind?.current + if(istype(L)) + for(var/q in removed_quirks) + L.add_quirk(q) + + /datum/species/proc/handle_hair(mob/living/carbon/human/H, forced_colour) H.remove_overlay(HAIR_LAYER) var/obj/item/bodypart/head/HD = H.get_bodypart(BODY_ZONE_HEAD) @@ -1425,8 +1454,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) var/damage = rand(user.dna.species.punchdamagelow, user.dna.species.punchdamagehigh) var/punchwoundbonus = user.dna.species.punchwoundbonus - var/puncherstam = user.getStaminaLoss() - var/puncherbrute = user.getBruteLoss() var/punchedstam = target.getStaminaLoss() var/punchedbrute = target.getBruteLoss() @@ -1434,7 +1461,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) if(!SEND_SIGNAL(target, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE)) damage *= 1.2 if(!CHECK_MOBILITY(user, MOBILITY_STAND)) - damage *= 0.8 + damage *= 0.65 if(SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE)) damage *= 0.8 //END OF CITADEL CHANGES @@ -1446,19 +1473,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) if(!affecting) //Maybe the bodypart is missing? Or things just went wrong.. affecting = target.get_bodypart(BODY_ZONE_CHEST) //target chest instead, as failsafe. Or hugbox? You decide. - var/miss_chance = 100//calculate the odds that a punch misses entirely. considers stamina and brute damage of the puncher. punches miss by default to prevent weird cases - if(attackchain_flags & ATTACK_IS_PARRY_COUNTERATTACK) - miss_chance = 0 - else - if(user.dna.species.punchdamagelow) - if(atk_verb == ATTACK_EFFECT_KICK) //kicks never miss (provided your species deals more than 0 damage) - miss_chance = 0 - else if(HAS_TRAIT(user, TRAIT_PUGILIST)) //pugilists, being good at Punching People, also never miss - miss_chance = 0 - else - miss_chance = min(10 + max(puncherstam * 0.5, puncherbrute * 0.5), 100) //probability of miss has a base of 10, and modified based on half brute total. Capped at max 100 to prevent weirdness in prob() - - if(!damage || !affecting || prob(miss_chance))//future-proofing for species that have 0 damage/weird cases where no zone is targeted + if(!damage || !affecting)//future-proofing for species that have 0 damage/weird cases where no zone is targeted playsound(target.loc, user.dna.species.miss_sound, 25, TRUE, -1) target.visible_message("[user]'s [atk_verb] misses [target]!", \ "You avoid [user]'s [atk_verb]!", "You hear a swoosh!", null, COMBAT_MESSAGE_RANGE, null, \ @@ -1468,9 +1483,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) var/armor_block = target.run_armor_check(affecting, "melee") - if(HAS_TRAIT(user, TRAIT_MAULER)) // maulers get 15 armorpierce because if you're going to punch someone you might as well do a good job of it - armor_block = target.run_armor_check(affecting, "melee", armour_penetration = 15) // lot of good that sec jumpsuit did you - playsound(target.loc, user.dna.species.attack_sound, 25, 1, -1) target.visible_message("[user] [atk_verb]ed [target]!", \ "[user] [atk_verb]ed you!", null, COMBAT_MESSAGE_RANGE, null, \ @@ -1487,9 +1499,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) target.apply_damage(damage*1.5, attack_type, affecting, armor_block, wound_bonus = punchwoundbonus) target.apply_damage(damage*0.5, STAMINA, affecting, armor_block) log_combat(user, target, "kicked") - else if(HAS_TRAIT(user, TRAIT_MAULER)) // mauler punches deal 1.1x raw damage + 1.3x stam damage, and have some armor pierce - target.apply_damage(damage*1.1, attack_type, affecting, armor_block, wound_bonus = punchwoundbonus) - target.apply_damage(damage*1.3, STAMINA, affecting, armor_block) + else if(HAS_TRAIT(user, TRAIT_MAULER)) // mauler punches deal 1.2x raw damage but nstam + target.apply_damage(damage*1.2, attack_type, affecting, armor_block, wound_bonus = punchwoundbonus) log_combat(user, target, "punched (mauler)") else //other attacks deal full raw damage + 2x in stamina damage target.apply_damage(damage, attack_type, affecting, armor_block, wound_bonus = punchwoundbonus) @@ -1561,9 +1572,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) if(!user.UseStaminaBuffer(3, warn = TRUE)) return FALSE user.do_attack_animation(target, ATTACK_EFFECT_ASS_SLAP) - target.adjust_arousal(20,maso = TRUE) + target.adjust_arousal(20,"masochism", maso = TRUE) if (ishuman(target) && HAS_TRAIT(target, TRAIT_MASO) && target.has_dna() && prob(10)) - target.mob_climax(forced_climax=TRUE) + target.mob_climax(forced_climax=TRUE, cause = "masochism") if (!HAS_TRAIT(target, TRAIT_PERMABONER)) stop_wagging_tail(target) playsound(target.loc, 'sound/weapons/slap.ogg', 50, 1, -1) @@ -1945,7 +1956,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) if(BP.receive_damage(damage_amount, 0, wound_bonus = wound_bonus, bare_wound_bonus = bare_wound_bonus, sharpness = sharpness)) H.update_damage_overlays() if(HAS_TRAIT(H, TRAIT_MASO) && prob(damage_amount)) - H.mob_climax(forced_climax=TRUE) + H.mob_climax(forced_climax=TRUE, cause = "masochism") else//no bodypart, we deal damage with a more general method. H.adjustBruteLoss(damage_amount) diff --git a/code/modules/mob/living/carbon/human/species_types/dwarves.dm b/code/modules/mob/living/carbon/human/species_types/dwarves.dm index 7c35ade4f2..e0a9bcaa36 100644 --- a/code/modules/mob/living/carbon/human/species_types/dwarves.dm +++ b/code/modules/mob/living/carbon/human/species_types/dwarves.dm @@ -30,10 +30,7 @@ GLOBAL_LIST_INIT(dwarf_last, world.file2list("strings/names/dwarf_last.txt")) // /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.AddElement(/datum/element/dwarfism, COMSIG_SPECIES_LOSS, src) RegisterSignal(C, COMSIG_MOB_SAY, .proc/handle_speech) //We register handle_speech is being used. 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 5e07150ce6..89b3d603ea 100644 --- a/code/modules/mob/living/carbon/human/species_types/vampire.dm +++ b/code/modules/mob/living/carbon/human/species_types/vampire.dm @@ -58,7 +58,7 @@ to_chat(C, "You ran out of blood!") C.dust() var/area/A = get_area(C) - if(istype(A, /area/chapel)) + if(istype(A, /area/chapel) && C.mind?.assigned_role != "Chaplain") to_chat(C, "You don't belong here!") C.adjustFireLoss(5) C.adjust_fire_stacks(6) 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 385dd94f04..57a11481d7 100644 --- a/code/modules/mob/living/carbon/human/species_types/zombies.dm +++ b/code/modules/mob/living/carbon/human/species_types/zombies.dm @@ -37,6 +37,7 @@ armor = 20 // 120 damage to KO a zombie, which kills it speedmod = 1.6 // they're very slow mutanteyes = /obj/item/organ/eyes/night_vision/zombie + blacklisted_quirks = list(/datum/quirk/nonviolent) var/heal_rate = 1 var/regen_cooldown = 0 diff --git a/code/modules/mob/living/carbon/say.dm b/code/modules/mob/living/carbon/say.dm index 27d0e9cbaf..67c29b4211 100644 --- a/code/modules/mob/living/carbon/say.dm +++ b/code/modules/mob/living/carbon/say.dm @@ -10,6 +10,8 @@ /mob/living/carbon/can_speak_vocal(message) if(silent) return 0 + if(get_selected_language() == /datum/language/signlanguage && handcuffed) + return 0 return ..() /mob/living/carbon/could_speak_language(datum/language/language) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 302eb3087d..b3b539e3cd 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -866,7 +866,7 @@ if(istype(G)) strip_mod = G.strip_mod strip_silence = G.strip_silence - if (!strip_silence) + if(!strip_silence) who.visible_message("[src] tries to remove [who]'s [what.name].", \ "[src] tries to remove your [what.name].", target = src, target_message = "You try to remove [who]'s [what.name].") diff --git a/code/modules/mob/living/living_active_parry.dm b/code/modules/mob/living/living_active_parry.dm index 8d1ee38de6..10f8aaf2f4 100644 --- a/code/modules/mob/living/living_active_parry.dm +++ b/code/modules/mob/living/living_active_parry.dm @@ -2,7 +2,7 @@ /** * Determines if we can actively parry. */ -/obj/item/proc/can_active_parry() +/obj/item/proc/can_active_parry(mob/user) return block_parry_data && (item_flags & ITEM_CAN_PARRY) /** @@ -23,13 +23,16 @@ if(!(combat_flags & COMBAT_FLAG_PARRY_CAPABLE)) to_chat(src, "You are not something that can parry attacks.") return + if(!(mobility_flags & MOBILITY_STAND)) + to_chat(src, "You aren't able to parry without solid footing!") + return // Prioritize item, then martial art, then unarmed. // yanderedev else if time var/obj/item/using_item = get_active_held_item() var/datum/block_parry_data/data var/datum/tool var/method - if(using_item?.can_active_parry()) + if(using_item?.can_active_parry(src)) data = using_item.block_parry_data method = ITEM_PARRY tool = using_item @@ -50,9 +53,20 @@ using_item = backup method = ITEM_PARRY var/list/other_items = list() - if(SEND_SIGNAL(src, COMSIG_LIVING_ACTIVE_PARRY_START, method, tool, other_items) & COMPONENT_PREVENT_PARRY_START) + var/list/override = list() + if(SEND_SIGNAL(src, COMSIG_LIVING_ACTIVE_PARRY_START, method, tool, other_items, override) & COMPONENT_PREVENT_PARRY_START) to_chat(src, "Something is preventing you from parrying!") return + if(length(override)) + var/datum/thing = override[1] + var/_method = override[thing] + if(_method == ITEM_PARRY) + using_item = thing + method = ITEM_PARRY + data = using_item.block_parry_data + else if(_method == UNARMED_PARRY) + method = UNARMED_PARRY + data = thing if(!using_item && !method && length(other_items)) using_item = other_items[1] method = ITEM_PARRY @@ -94,7 +108,7 @@ */ /mob/living/proc/find_backup_parry_item() for(var/obj/item/I in held_items - get_active_held_item()) - if(I.can_active_parry()) + if(I.can_active_parry(src)) return I /** @@ -231,7 +245,7 @@ var/efficiency = data.get_parry_efficiency(attack_type, get_parry_time()) switch(parrying) if(ITEM_PARRY) - if(!active_parry_item.can_active_parry()) + if(!active_parry_item.can_active_parry(src)) return BLOCK_NONE . = active_parry_item.on_active_parry(src, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, efficiency, get_parry_time()) if(UNARMED_PARRY) @@ -243,6 +257,18 @@ if(efficiency <= 0) // Do not allow automatically handled/standardized parries that increase damage for now. return . |= BLOCK_SHOULD_PARTIAL_MITIGATE + if(efficiency >= data.parry_efficiency_perfect) + . |= data.perfect_parry_block_return_flags + if(data.perfect_parry_block_return_list) + return_list |= data.perfect_parry_block_return_list + else if(efficiency >= data.parry_efficiency_considered_successful) + . |= data.imperfect_parry_block_return_flags + if(data.imperfect_parry_block_return_list) + return_list |= data.imperfect_parry_block_return_list + else + . |= data.failed_parry_block_return_flags + if(data.failed_parry_block_return_list) + return_list |= data.failed_parry_block_return_list if(isnull(return_list[BLOCK_RETURN_MITIGATION_PERCENT])) // if one of the on_active_parry procs overrode. We don't have to worry about interference since parries are the first thing checked in the [do_run_block()] sequence. return_list[BLOCK_RETURN_MITIGATION_PERCENT] = clamp(efficiency, 0, 100) // do not allow > 100% or < 0% for now. if((return_list[BLOCK_RETURN_MITIGATION_PERCENT] >= 100) || (damage <= 0)) diff --git a/code/modules/mob/living/living_blocking_parrying.dm b/code/modules/mob/living/living_blocking_parrying.dm index e290956873..9e974177e5 100644 --- a/code/modules/mob/living/living_blocking_parrying.dm +++ b/code/modules/mob/living/living_blocking_parrying.dm @@ -157,6 +157,16 @@ GLOBAL_LIST_EMPTY(block_parry_data) /// Parry cooldown post-parry if failed. This is ADDED to parry_cooldown!!! var/parry_failed_cooldown_duration = 0 SECONDS + // Advanced + /// Flags added to return value + var/perfect_parry_block_return_flags = NONE + var/imperfect_parry_block_return_flags = NONE + var/failed_parry_block_return_flags = NONE + /// List appended to block return + var/perfect_parry_block_return_list + var/imperfect_parry_block_return_list + var/failed_parry_block_return_list + /** * Quirky proc to get average of flags in list that are in attack_type because why is attack_type a flag. */ diff --git a/code/modules/mob/living/living_sprint.dm b/code/modules/mob/living/living_sprint.dm index 3ef67c9edd..728645c3eb 100644 --- a/code/modules/mob/living/living_sprint.dm +++ b/code/modules/mob/living/living_sprint.dm @@ -26,6 +26,8 @@ update_sprint_icon() /mob/living/proc/enable_sprint_mode(update_icon = TRUE) + if(!CONFIG_GET(flag/sprint_enabled)) + return if(combat_flags & COMBAT_FLAG_SPRINT_ACTIVE) return ENABLE_BITFIELD(combat_flags, COMBAT_FLAG_SPRINT_ACTIVE) @@ -61,6 +63,8 @@ update_sprint_icon() /mob/living/proc/user_toggle_intentional_sprint_mode() + if(!CONFIG_GET(flag/sprint_enabled)) + return var/old = (combat_flags & COMBAT_FLAG_SPRINT_TOGGLED) if(old) if(combat_flags & COMBAT_FLAG_SPRINT_FORCED) diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index 4c03e74d70..9646796802 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -329,8 +329,26 @@ GLOBAL_LIST_INIT(department_radio_keys, list( return 1 /mob/living/proc/can_speak_vocal(message) //Check AFTER handling of xeno and ling channels - if(HAS_TRAIT(src, TRAIT_MUTE)) + var/obj/item/bodypart/leftarm = get_bodypart(BODY_ZONE_L_ARM) + var/obj/item/bodypart/rightarm = get_bodypart(BODY_ZONE_R_ARM) + if(HAS_TRAIT(src, TRAIT_MUTE) && get_selected_language() != /datum/language/signlanguage) return 0 + + if (get_selected_language() == /datum/language/signlanguage) + var/left_disabled = FALSE + var/right_disabled = FALSE + if (istype(leftarm)) // Need to check if the arms exist first before checking if they are disabled or else it will runtime + if (leftarm.is_disabled()) + left_disabled = TRUE + else + left_disabled = TRUE + if (istype(rightarm)) + if (rightarm.is_disabled()) + right_disabled = TRUE + else + right_disabled = TRUE + if (left_disabled && right_disabled) // We want this to only return false if both arms are either missing or disabled since you could technically sign one-handed. + return 0 if(is_muzzled()) return 0 diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index 2ab74664a3..4e33fba208 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -11,7 +11,7 @@ maxHealth = 500 layer = BELOW_MOB_LAYER var/obj/item/instrument/piano_synth/internal_instrument - silicon_privileges = PRIVILEDGES_PAI + silicon_privileges = PRIVILEGES_PAI var/network = "ss13" var/obj/machinery/camera/current = null @@ -143,6 +143,10 @@ custom_holoform.Grant(src) emitter_next_use = world.time + 10 SECONDS +/mob/living/silicon/pai/deployed/Initialize() + . = ..() + fold_out(TRUE) + /mob/living/silicon/pai/ComponentInitialize() . = ..() if(possible_chassis[chassis]) diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 7db417b8fa..36b5edcbc9 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -289,11 +289,13 @@ return FALSE return ISINRANGE(T1.x, T0.x - interaction_range, T0.x + interaction_range) && ISINRANGE(T1.y, T0.y - interaction_range, T0.y + interaction_range) -/mob/living/silicon/robot/proc/attempt_welder_repair(obj/item/weldingtool/W, mob/user) - if (!getBruteLoss()) +/mob/living/silicon/robot/proc/attempt_welder_repair(obj/item/W, mob/user) + if(!W.tool_behaviour == TOOL_WELDER) + return + if(!getBruteLoss()) to_chat(user, "[src] is already in good condition!") return - if (!W.tool_start_check(user, amount=0)) //The welder has 1u of fuel consumed by it's afterattack, so we don't need to worry about taking any away. + if(!W.tool_start_check(user, amount=0)) //The welder has 1u of fuel consumed by it's afterattack, so we don't need to worry about taking any away. return user.DelayNextAction(CLICK_CD_MELEE) if(src == user) @@ -333,7 +335,7 @@ to_chat(user, "The wires seem fine, there's no need to fix them.") /mob/living/silicon/robot/attackby(obj/item/W, mob/user, params) - if(istype(W, /obj/item/weldingtool) && (user.a_intent != INTENT_HARM || user == src)) + if(W.tool_behaviour == TOOL_WELDER && (user.a_intent != INTENT_HARM || user == src)) INVOKE_ASYNC(src, .proc/attempt_welder_repair, W, user) return @@ -341,7 +343,7 @@ INVOKE_ASYNC(src, .proc/attempt_cable_repair, W, user) return - else if(istype(W, /obj/item/crowbar)) // crowbar means open or close the cover + else if(W.tool_behaviour == TOOL_CROWBAR) // crowbar means open or close the cover if(opened) to_chat(user, "You close the cover.") opened = 0 @@ -373,12 +375,12 @@ else to_chat(user, "You can't reach the wiring!") - else if(istype(W, /obj/item/screwdriver) && opened && !cell) // haxing + else if(W.tool_behaviour == TOOL_SCREWDRIVER && opened && !cell) // haxing wiresexposed = !wiresexposed to_chat(user, "The wires have been [wiresexposed ? "exposed" : "unexposed"]") update_icons() - else if(istype(W, /obj/item/screwdriver) && opened && cell) // radio + else if((W.tool_behaviour == TOOL_SCREWDRIVER) && opened && cell) // radio if(shell) to_chat(user, "You cannot seem to open the radio compartment") //Prevent AI radio key theft else if(radio) @@ -387,7 +389,7 @@ to_chat(user, "Unable to locate a radio!") update_icons() - else if(istype(W, /obj/item/wrench) && opened && !cell) //Deconstruction. The flashes break from the fall, to prevent this from being a ghetto reset module. + else if(W.tool_behaviour == TOOL_WRENCH && opened && !cell) //Deconstruction. The flashes break from the fall, to prevent this from being a ghetto reset module. if(!locked_down) to_chat(user, "[src]'s bolts spark! Maybe you should lock them down first!") spark_system.start() diff --git a/code/modules/mob/living/silicon/robot/robot_sprint.dm b/code/modules/mob/living/silicon/robot/robot_sprint.dm index dff0d9dd0d..80adfe80fd 100644 --- a/code/modules/mob/living/silicon/robot/robot_sprint.dm +++ b/code/modules/mob/living/silicon/robot/robot_sprint.dm @@ -1,4 +1,7 @@ /mob/living/silicon/robot/default_toggle_sprint(shutdown = FALSE) + if(!CONFIG_GET(flag/sprint_enabled)) + disable_intentional_sprint_mode() + return var/current = (combat_flags & COMBAT_FLAG_SPRINT_ACTIVE) if(current || shutdown || !cell || (cell.charge < 25) || !cansprint) disable_intentional_sprint_mode() diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index 944b909463..b2b27c7d70 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -1,6 +1,6 @@ /mob/living/silicon gender = NEUTER - silicon_privileges = PRIVILEDGES_SILICON + silicon_privileges = PRIVILEGES_SILICON verb_say = "states" verb_ask = "queries" verb_exclaim = "declares" diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index bb7c437ca7..a7fd9c5ac0 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -15,7 +15,7 @@ maxbodytemp = INFINITY minbodytemp = 0 blood_volume = 0 - silicon_privileges = PRIVILEDGES_BOT + silicon_privileges = PRIVILEGES_BOT sentience_type = SENTIENCE_ARTIFICIAL status_flags = NONE //no default canpush verb_say = "states" @@ -306,7 +306,7 @@ show_controls(user) /mob/living/simple_animal/bot/attackby(obj/item/W, mob/user, params) - if(istype(W, /obj/item/screwdriver)) + if(W.tool_behaviour == TOOL_SCREWDRIVER) if(!locked) open = !open to_chat(user, "The maintenance panel is now [open ? "opened" : "closed"].") @@ -335,7 +335,7 @@ user.visible_message("[user] uses [W] to pull [paicard] out of [bot_name]!","You pull [paicard] out of [bot_name] with [W].") ejectpai(user) else - if(istype(W, /obj/item/weldingtool) && user.a_intent != INTENT_HARM) + if(W.tool_behaviour == TOOL_WELDER && user.a_intent != INTENT_HARM) if(health >= maxHealth) to_chat(user, "[src] does not need a repair!") return diff --git a/code/modules/mob/living/simple_animal/bot/construction.dm b/code/modules/mob/living/simple_animal/bot/construction.dm index 5102c02ecf..fff1782154 100644 --- a/code/modules/mob/living/simple_animal/bot/construction.dm +++ b/code/modules/mob/living/simple_animal/bot/construction.dm @@ -100,7 +100,7 @@ build_step++ if(ASSEMBLY_FOURTH_STEP) - if(istype(W, /obj/item/weldingtool)) + if(W.tool_behaviour == TOOL_WELDER) if(W.use_tool(src, user, 0, volume=40) && build_step == ASSEMBLY_FOURTH_STEP) name = "shielded frame assembly" to_chat(user, "You weld the vest to [src].") @@ -180,7 +180,7 @@ build_step++ if(8) - if(istype(W, /obj/item/screwdriver)) + if(W.tool_behaviour == TOOL_SCREWDRIVER) to_chat(user, "You start attaching the gun to the frame...") if(W.use_tool(src, user, 40, volume=100) && build_step == 8) name = "armed [name]" @@ -386,13 +386,13 @@ var/atom/Tsec = drop_location() switch(build_step) if(ASSEMBLY_FIRST_STEP) - if(istype(I, /obj/item/weldingtool)) + if(I.tool_behaviour == TOOL_WELDER) if(I.use_tool(src, user, 0, volume=40)) add_overlay("hs_hole") to_chat(user, "You weld a hole in [src]!") build_step++ - else if(istype(I, /obj/item/screwdriver)) //deconstruct + else if(I.tool_behaviour == TOOL_SCREWDRIVER) //deconstruct new /obj/item/assembly/signaler(Tsec) new /obj/item/clothing/head/helmet/sec(Tsec) to_chat(user, "You disconnect the signaler from the helmet.") @@ -408,7 +408,7 @@ qdel(I) build_step++ - else if(istype(I, /obj/item/weldingtool)) //deconstruct + else if(I.tool_behaviour == TOOL_WELDER) //deconstruct if(I.use_tool(src, user, 0, volume=40)) cut_overlay("hs_hole") to_chat(user, "You weld the hole in [src] shut!") @@ -425,7 +425,7 @@ qdel(I) build_step++ - else if(istype(I, /obj/item/screwdriver)) //deconstruct + else if(I.tool_behaviour == TOOL_SCREWDRIVER) //deconstruct cut_overlay("hs_eye") new /obj/item/assembly/prox_sensor(Tsec) to_chat(user, "You detach the proximity sensor from [src].") @@ -442,7 +442,7 @@ S.robot_arm = robot_arm qdel(I) qdel(src) - if(istype(I, /obj/item/wrench)) + if(I.tool_behaviour == TOOL_WRENCH) to_chat(user, "You adjust [src]'s arm slots to mount extra weapons") build_step ++ return @@ -466,7 +466,7 @@ qdel(I) qdel(src) - else if(istype(I, /obj/item/screwdriver)) //deconstruct + else if(I.tool_behaviour == TOOL_SCREWDRIVER) //deconstruct cut_overlay("hs_arm") var/obj/item/bodypart/dropped_arm = new robot_arm(Tsec) robot_arm = null @@ -499,7 +499,7 @@ S.robot_arm = robot_arm qdel(I) qdel(src) - else if(istype(I, /obj/item/screwdriver)) //deconstruct + else if(I.tool_behaviour == TOOL_SCREWDRIVER) //deconstruct build_step-- icon_state = initial(icon_state) to_chat(user, "You unbolt [src]'s energy swords") diff --git a/code/modules/mob/living/simple_animal/bot/ed209bot.dm b/code/modules/mob/living/simple_animal/bot/ed209bot.dm index 8375d621d4..604a72b43e 100644 --- a/code/modules/mob/living/simple_animal/bot/ed209bot.dm +++ b/code/modules/mob/living/simple_animal/bot/ed209bot.dm @@ -184,9 +184,9 @@ Auto Patrol[]"}, /mob/living/simple_animal/bot/ed209/attackby(obj/item/W, mob/user, params) ..() - if(istype(W, /obj/item/weldingtool) && user.a_intent != INTENT_HARM) // Any intent but harm will heal, so we shouldn't get angry. + if(W.tool_behaviour == TOOL_WELDER && user.a_intent != INTENT_HARM) // Any intent but harm will heal, so we shouldn't get angry. return - if(!istype(W, /obj/item/screwdriver) && (!target)) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass. + if(!W.tool_behaviour == TOOL_SCREWDRIVER && (!target)) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass. if(W.force && W.damtype != STAMINA)//If force is non-zero and damage type isn't stamina. retaliate(user) if(lasercolor)//To make up for the fact that lasertag bots don't hunt diff --git a/code/modules/mob/living/simple_animal/bot/honkbot.dm b/code/modules/mob/living/simple_animal/bot/honkbot.dm index 0ee600ed1d..9625d2b084 100644 --- a/code/modules/mob/living/simple_animal/bot/honkbot.dm +++ b/code/modules/mob/living/simple_animal/bot/honkbot.dm @@ -120,9 +120,9 @@ Maintenance panel panel is [open ? "opened" : "closed"]"}, /mob/living/simple_animal/bot/honkbot/attackby(obj/item/W, mob/user, params) - if(istype(W, /obj/item/weldingtool) && user.a_intent != INTENT_HARM) + if(W.tool_behaviour == TOOL_WELDER && user.a_intent != INTENT_HARM) return - if(!istype(W, /obj/item/screwdriver) && (W.force) && (!target) && (W.damtype != STAMINA) ) // Check for welding tool to fix #2432. + if(!W.tool_behaviour == TOOL_SCREWDRIVER && (W.force) && (!target) && (W.damtype != STAMINA) ) // Check for welding tool to fix #2432. retaliate(user) addtimer(CALLBACK(src, .proc/react_buzz), 5) ..() diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm index cf9698655b..8bb30a11a6 100644 --- a/code/modules/mob/living/simple_animal/bot/secbot.dm +++ b/code/modules/mob/living/simple_animal/bot/secbot.dm @@ -299,12 +299,12 @@ Auto Patrol: []"}, /mob/living/simple_animal/bot/secbot/attackby(obj/item/W, mob/user, params) ..() - if(istype(W, /obj/item/weldingtool) && user.a_intent != INTENT_HARM) // Any intent but harm will heal, so we shouldn't get angry. + if(W.tool_behaviour == TOOL_WELDER && user.a_intent != INTENT_HARM) // Any intent but harm will heal, so we shouldn't get angry. return if(istype(W, /obj/item/clothing/head)) attempt_place_on_head(user, W) return - if(!istype(W, /obj/item/screwdriver) && (W.force) && (!target) && (W.damtype != STAMINA) ) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass. + if(!W.tool_behaviour == TOOL_SCREWDRIVER && (W.force) && (!target) && (W.damtype != STAMINA) ) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass. retaliate(user) if(special_retaliate_after_attack(user)) return 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 e11facb4ba..ecd5db3ccf 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm @@ -40,7 +40,7 @@ bubble_icon = "machine" initial_language_holder = /datum/language_holder/drone mob_size = MOB_SIZE_SMALL - silicon_privileges = PRIVILEDGES_DRONE + silicon_privileges = PRIVILEGES_DRONE damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0) hud_possible = list(DIAG_STAT_HUD, DIAG_HUD, ANTAG_HUD) unique_name = TRUE 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 22dbdd3db7..12b6447a02 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 @@ -160,7 +160,7 @@ ..() /mob/living/simple_animal/drone/attackby(obj/item/I, mob/user) - if(istype(I, /obj/item/screwdriver) && stat == DEAD) + if(I.tool_behaviour == TOOL_SCREWDRIVER && stat == DEAD) try_reactivate(user) else ..() diff --git a/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm b/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm index 11d7884999..d9ea6f4a8a 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm @@ -55,7 +55,7 @@ /mob/living/simple_animal/drone/attackby(obj/item/I, mob/user) - if(istype(I, /obj/item/screwdriver) && stat != DEAD) + if(I.tool_behaviour == TOOL_SCREWDRIVER && stat != DEAD) if(health < maxHealth) to_chat(user, "You start to tighten loose screws on [src]...") if(I.use_tool(src, user, 80)) @@ -66,7 +66,7 @@ else to_chat(user, "[src]'s screws can't get any tighter!") return //This used to not exist and drones who repaired themselves also stabbed the shit out of themselves. - else if(istype(I, /obj/item/wrench) && user != src) //They aren't required to be hacked, because laws can change in other ways (i.e. admins) + else if(I.tool_behaviour == TOOL_WRENCH && user != src) //They aren't required to be hacked, because laws can change in other ways (i.e. admins) user.visible_message("[user] starts resetting [src]...", \ "You press down on [src]'s factory reset control...") if(I.use_tool(src, user, 50, volume=50)) diff --git a/code/modules/mob/living/simple_animal/hostile/alien.dm b/code/modules/mob/living/simple_animal/hostile/alien.dm index 86467624b5..05d6eda435 100644 --- a/code/modules/mob/living/simple_animal/hostile/alien.dm +++ b/code/modules/mob/living/simple_animal/hostile/alien.dm @@ -78,6 +78,15 @@ projectiletype = /obj/item/projectile/neurotox projectilesound = 'sound/weapons/pierce.ogg' +/mob/living/simple_animal/hostile/alien/sentinel/cube + gold_core_spawnable = NO_SPAWN + health = 220 + maxHealth = 220 + melee_damage_lower = 20 + melee_damage_upper = 20 + del_on_death = TRUE + loot = list(/obj/effect/mob_spawn/alien/corpse/humanoid/sentinel) + /mob/living/simple_animal/hostile/alien/queen name = "alien queen" 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 a584d34995..d087d9399a 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm @@ -424,7 +424,7 @@ Difficulty: Very Hard /obj/machinery/anomalous_crystal/honk //Strips and equips you as a clown. I apologize for nothing observer_desc = "This crystal strips and equips its targets as clowns." - possible_methods = list(ACTIVATE_MOB_BUMP, ACTIVATE_SPEECH) + possible_methods = list(ACTIVATE_TOUCH) //Because We love AOE transformations! activation_sound = 'sound/items/bikehorn.ogg' /obj/machinery/anomalous_crystal/honk/ActivationReaction(mob/user) diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm index 477483862b..cd7f2fe328 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm @@ -398,6 +398,14 @@ Difficulty: Medium crusher_loot = list() butcher_results = list(/obj/item/stack/ore/diamond = 5, /obj/item/stack/sheet/sinew = 5, /obj/item/stack/sheet/bone = 30) +/mob/living/simple_animal/hostile/megafauna/dragon/lesser/transformed //ash drake balanced around player control + name = "transformed ash drake" + desc = "A sentient being transformed into an ash drake" + mob_size = MOB_SIZE_HUMAN //prevents crusher vulnerability + move_force = MOVE_FORCE_NORMAL //stops them from destroying and unanchoring shit by walking into it + environment_smash = ENVIRONMENT_SMASH_STRUCTURES //no we dont want sentient megafauna be able to delete the entire station in a minute flat + damage_coeff = list(BRUTE = 0.7, BURN = 0.5, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1) //200 health but not locked to standard movespeed, needs armor befitting of a dragon + /mob/living/simple_animal/hostile/megafauna/dragon/lesser/grant_achievement(medaltype,scoretype) return @@ -413,7 +421,8 @@ Difficulty: Medium if(L in hit_list || L == source) continue hit_list += L - L.adjustFireLoss(20) + L.adjustFireLoss(5) + L.adjust_fire_stacks(6) to_chat(L, "You're hit by [source]'s fire breath!") // deals damage to mechs diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm index ae0f5ea3ca..446fe80c7d 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm @@ -42,6 +42,8 @@ A.GiveTarget(target) A.friends = friends A.faction = faction.Copy() + if(!A == /mob/living/simple_animal/hostile/poison/bees/toxin) + A.my_creator = type ranged_cooldown = world.time + ranged_cooldown_time /mob/living/simple_animal/hostile/asteroid/hivelord/AttackingTarget() @@ -88,6 +90,7 @@ density = FALSE del_on_death = 1 var/swarming = FALSE + var/my_creator = null /mob/living/simple_animal/hostile/asteroid/hivelordbrood/Initialize() . = ..() @@ -205,11 +208,7 @@ /mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion/proc/infest(mob/living/carbon/human/H) visible_message("[name] burrows into the flesh of [H]!") - var/mob/living/simple_animal/hostile/asteroid/hivelord/legion/L - if(HAS_TRAIT(H, TRAIT_DWARF)) //dwarf legions aren't just fluff! - L = new /mob/living/simple_animal/hostile/asteroid/hivelord/legion/dwarf(H.loc) - else - L = new(H.loc) + var/mob/living/simple_animal/hostile/asteroid/hivelord/legion/L = check_infest_type(H) visible_message("[L] staggers to [L.p_their()] feet!") H.death() H.adjustBruteLoss(1000) @@ -217,6 +216,20 @@ H.forceMove(L) qdel(src) +/mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion/proc/check_infest_type(mob/living/carbon/human/human) + var/mob/living/simple_animal/hostile/asteroid/hivelord/legion/L + var/list/blacklisted_types = list(/mob/living/simple_animal/hostile/asteroid/hivelord/legion/dwarf) + if(HAS_TRAIT(human, TRAIT_DWARF)) //dwarf legions aren't just fluff! + L = new /mob/living/simple_animal/hostile/asteroid/hivelord/legion/dwarf(human.loc) + else if(my_creator) + if(my_creator in blacklisted_types) + L = new(human.loc) + else + L = new my_creator(human.loc) + else + L = new(human.loc) + return L + //Advanced Legion is slightly tougher to kill and can raise corpses (revive other legions) /mob/living/simple_animal/hostile/asteroid/hivelord/legion/advanced stat_attack = DEAD diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 605f0a2d55..4b0f505067 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -408,7 +408,7 @@ It's fairly easy to fix if dealing with single letters but not so much with comp return return TRUE -/atom/proc/hasSiliconAccessInArea(mob/user, flags = PRIVILEDGES_SILICON) +/atom/proc/hasSiliconAccessInArea(mob/user, flags = PRIVILEGES_SILICON) return user.silicon_privileges & (flags) || (user.siliconaccesstoggle && (get_area(src) in user.siliconaccessareas)) /mob/proc/toggleSiliconAccessArea(area/area) @@ -496,7 +496,7 @@ It's fairly easy to fix if dealing with single letters but not so much with comp colored_message = "[message]" else colored_message = "[message]" - + //This makes readability a bit better for admins. switch(message_type) if(LOG_WHISPER) @@ -507,7 +507,7 @@ It's fairly easy to fix if dealing with single letters but not so much with comp colored_message = "(ASAY) [colored_message]" if(LOG_EMOTE) colored_message = "(EMOTE) [colored_message]" - + var/list/timestamped_message = list("\[[TIME_STAMP("hh:mm:ss", FALSE)]\] [key_name(src)] [loc_name(src)] (Event #[LAZYLEN(logging[smessage_type])])" = colored_message) logging[smessage_type] += timestamped_message diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index e49bd5162b..fcaa77cac4 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -178,10 +178,7 @@ new /obj/effect/temp_visual/monkeyify/humanify(loc) - transformation_timer = addtimer(CALLBACK(src, .proc/finish_humanize, tr_flags), TRANSFORMATION_DURATION, TIMER_UNIQUE) - -/mob/living/carbon/proc/finish_humanize(tr_flags) - transformation_timer = null + sleep(TRANSFORMATION_DURATION) //This entire proc CANNOT be split into two var/list/stored_implants = list() var/list/int_organs = list() diff --git a/code/modules/modular_computers/computers/item/computer.dm b/code/modules/modular_computers/computers/item/computer.dm index 63cb1cc5fa..e53f4087ab 100644 --- a/code/modules/modular_computers/computers/item/computer.dm +++ b/code/modules/modular_computers/computers/item/computer.dm @@ -9,6 +9,7 @@ var/light_on = FALSE integrity_failure = 0.5 max_integrity = 100 + rad_flags = RAD_PROTECT_CONTENTS armor = list("melee" = 0, "bullet" = 20, "laser" = 20, "energy" = 100, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = 0, "acid" = 0) var/enabled = 0 // Whether the computer is turned on. diff --git a/code/modules/modular_computers/file_system/programs/card.dm b/code/modules/modular_computers/file_system/programs/card.dm index 6d45914add..3455547d20 100644 --- a/code/modules/modular_computers/file_system/programs/card.dm +++ b/code/modules/modular_computers/file_system/programs/card.dm @@ -175,7 +175,7 @@ if("PRG_edit") if(!computer || !authenticated || !target_id_card) return - var/new_name = params["name"] + var/new_name = reject_bad_name(params["name"]) if(!new_name) return target_id_card.registered_name = new_name @@ -190,7 +190,7 @@ return if(target == "Custom") - var/custom_name = params["custom_name"] + var/custom_name = reject_bad_name(params["custom_name"]) if(custom_name) target_id_card.assignment = custom_name target_id_card.update_label() diff --git a/code/modules/movespeed/modifiers/reagents.dm b/code/modules/movespeed/modifiers/reagents.dm index b6c2458670..1a03e8a602 100644 --- a/code/modules/movespeed/modifiers/reagents.dm +++ b/code/modules/movespeed/modifiers/reagents.dm @@ -12,3 +12,7 @@ /datum/movespeed_modifier/reagent/nitryl multiplicative_slowdown = -1 + +/datum/movespeed_modifier/reagent/meth + multiplicative_slowdown = -0.5 + absolute_max_tiles_per_second = 11 diff --git a/code/modules/newscaster/newscaster_machine.dm b/code/modules/newscaster/newscaster_machine.dm index 7e515bf0f5..c81a8f5d1a 100644 --- a/code/modules/newscaster/newscaster_machine.dm +++ b/code/modules/newscaster/newscaster_machine.dm @@ -552,7 +552,7 @@ GLOBAL_LIST_EMPTY(allCasters) updateUsrDialog() /obj/machinery/newscaster/attackby(obj/item/I, mob/living/user, params) - if(istype(I, /obj/item/wrench)) + if(I.tool_behaviour == TOOL_WRENCH) to_chat(user, "You start [anchored ? "un" : ""]securing [name]...") I.play_tool_sound(src) if(I.use_tool(src, user, 60)) @@ -566,7 +566,7 @@ GLOBAL_LIST_EMPTY(allCasters) to_chat(user, "You [anchored ? "un" : ""]secure [name].") new /obj/item/wallframe/newscaster(loc) qdel(src) - else if(istype(I, /obj/item/weldingtool) && user.a_intent != INTENT_HARM) + else if(I.tool_behaviour == TOOL_WELDER && user.a_intent != INTENT_HARM) if(stat & BROKEN) if(!I.tool_start_check(user, amount=0)) return diff --git a/code/modules/paperwork/ticketmachine.dm b/code/modules/paperwork/ticketmachine.dm index 25b5cfb51b..9f4a864e9c 100644 --- a/code/modules/paperwork/ticketmachine.dm +++ b/code/modules/paperwork/ticketmachine.dm @@ -22,10 +22,11 @@ var/list/obj/item/ticket_machine_ticket/tickets = list() /obj/machinery/ticket_machine/multitool_act(mob/living/user, obj/item/I) + if(!I.tool_behaviour == TOOL_MULTITOOL) + return if(!multitool_check_buffer(user, I)) //make sure it has a data buffer return - var/obj/item/multitool/M = I - M.buffer = src + I.buffer = src to_chat(user, "You store linkage information in [I]'s buffer.") return TRUE @@ -77,11 +78,10 @@ /obj/machinery/button/ticket_machine/multitool_act(mob/living/user, obj/item/I) . = ..() if(I.tool_behaviour == TOOL_MULTITOOL) - var/obj/item/multitool/M = I - if(M.buffer && !istype(M.buffer, /obj/machinery/ticket_machine)) + if(I.buffer && !istype(I.buffer, /obj/machinery/ticket_machine)) return var/obj/item/assembly/control/ticket_machine/controller = device - controller.linked = M.buffer + controller.linked = I.buffer id = null controller.id = null to_chat(user, "You've linked [src] to [controller.linked].") diff --git a/code/modules/photography/photos/frame.dm b/code/modules/photography/photos/frame.dm index d306c46815..4000bf843c 100644 --- a/code/modules/photography/photos/frame.dm +++ b/code/modules/photography/photos/frame.dm @@ -115,14 +115,14 @@ return ..() /obj/structure/sign/picture_frame/attackby(obj/item/I, mob/user, params) - if(can_decon && (istype(I, /obj/item/screwdriver) || istype(I, /obj/item/wrench))) + if(can_decon && (I.tool_behaviour == TOOL_SCREWDRIVER || I.tool_behaviour == TOOL_WRENCH)) to_chat(user, "You start unsecuring [name]...") if(I.use_tool(src, user, 30, volume=50)) playsound(loc, 'sound/items/deconstruct.ogg', 50, 1) to_chat(user, "You unsecure [name].") deconstruct() - else if(istype(I, /obj/item/wirecutters) && framed) + else if(I.tool_behaviour == TOOL_WIRECUTTER && framed) framed.forceMove(drop_location()) framed = null user.visible_message("[user] cuts away [framed] from [src]!") diff --git a/code/modules/pool/pool_controller.dm b/code/modules/pool/pool_controller.dm index 17faa7a3e3..9f670de282 100644 --- a/code/modules/pool/pool_controller.dm +++ b/code/modules/pool/pool_controller.dm @@ -146,7 +146,7 @@ return reagents.clear_reagents() // This also reacts them. No nitroglycerin deathpools, sorry gamers :( - W.reagents.trans_to(reagents, max_beaker_transfer) + W.reagents.trans_to(reagents, max_beaker_transfer, log = "pool fill from reagent container") user.visible_message("[src] makes a slurping noise.", "All of the contents of [W] are quickly suctioned out by the machine!You cut the cable.") @@ -177,7 +177,7 @@ By design, d1 is the smallest direction and d2 is the highest R.loaded.cable_join(src, user) R.is_empty(user) - else if(istype(W, /obj/item/multitool)) + else if(W.tool_behaviour == TOOL_MULTITOOL) if(powernet && (powernet.avail > 0)) // is it powered? to_chat(user, "[DisplayPower(powernet.avail)] in power network.") else diff --git a/code/modules/power/floodlight.dm b/code/modules/power/floodlight.dm index 466030b83c..274d4cd7af 100644 --- a/code/modules/power/floodlight.dm +++ b/code/modules/power/floodlight.dm @@ -9,7 +9,7 @@ var/state = FLOODLIGHT_NEEDS_WRENCHING /obj/structure/floodlight_frame/attackby(obj/item/O, mob/user, params) - if(istype(O, /obj/item/wrench) && (state == FLOODLIGHT_NEEDS_WRENCHING)) + if(O.tool_behaviour == TOOL_WRENCH && (state == FLOODLIGHT_NEEDS_WRENCHING)) to_chat(user, "You secure [src].") anchored = TRUE state = FLOODLIGHT_NEEDS_WIRES @@ -26,7 +26,7 @@ to_chat(user, "You put lights in [src].") new /obj/machinery/power/floodlight(src.loc) qdel(src) - else if(istype(O, /obj/item/screwdriver) && (state == FLOODLIGHT_NEEDS_SECURING)) + else if(O.tool_behaviour == TOOL_SCREWDRIVER && (state == FLOODLIGHT_NEEDS_SECURING)) to_chat(user, "You fasten the wiring and electronics in [src].") name = "secured [name]" desc = "A bare metal frame that looks like a floodlight. Requires light tubes." @@ -82,7 +82,7 @@ to_chat(user, "You set [src] to [setting_text].") /obj/machinery/power/floodlight/attackby(obj/item/O, mob/user, params) - if(istype(O, /obj/item/wrench)) + if(O.tool_behaviour == TOOL_WRENCH) default_unfasten_wrench(user, O, time = 20) change_setting(1) if(anchored) diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm index 4c76c4b5b1..00487ee607 100644 --- a/code/modules/power/lighting.dm +++ b/code/modules/power/lighting.dm @@ -107,7 +107,7 @@ return switch(stage) if(1) - if(istype(W, /obj/item/wrench)) + if(W.tool_behaviour == TOOL_WRENCH) to_chat(usr, "You begin deconstructing [src]...") if (W.use_tool(src, user, 30, volume=50)) new /obj/item/stack/sheet/metal(drop_location(), sheets_refunded) @@ -127,11 +127,11 @@ to_chat(user, "You need one length of cable to wire [src]!") return if(2) - if(istype(W, /obj/item/wrench)) + if(W.tool_behaviour == TOOL_WRENCH) to_chat(usr, "You have to remove the wires first!") return - if(istype(W, /obj/item/wirecutters)) + if(W.tool_behaviour == TOOL_WIRECUTTER) stage = 1 icon_state = "[fixture_type]-construct-stage1" new /obj/item/stack/cable_coil(drop_location(), 1, "red") @@ -140,7 +140,7 @@ W.play_tool_sound(src, 100) return - if(istype(W, /obj/item/screwdriver)) + if(W.tool_behaviour == TOOL_SCREWDRIVER) user.visible_message("[user.name] closes [src]'s casing.", \ "You close [src]'s casing.", "You hear screwing.") W.play_tool_sound(src, 75) @@ -462,7 +462,7 @@ // attempt to stick weapon into light socket else if(status == LIGHT_EMPTY) - if(istype(W, /obj/item/screwdriver)) //If it's a screwdriver open it. + if(W.tool_behaviour == TOOL_SCREWDRIVER) //If it acts like a screwdriver, open it. W.play_tool_sound(src, 75) user.visible_message("[user.name] opens [src]'s casing.", \ "You open [src]'s casing.", "You hear a noise.") @@ -621,7 +621,7 @@ else to_chat(H, "You can't receive charge from the [fitting]!") return - + if(H.gloves) var/obj/item/clothing/gloves/G = H.gloves if(G.max_heat_protection_temperature) diff --git a/code/modules/power/singularity/generator.dm b/code/modules/power/singularity/generator.dm index 98729de3cc..f5e3bbc141 100644 --- a/code/modules/power/singularity/generator.dm +++ b/code/modules/power/singularity/generator.dm @@ -18,7 +18,7 @@ var/creation_type = /obj/singularity /obj/machinery/the_singularitygen/attackby(obj/item/W, mob/user, params) - if(istype(W, /obj/item/wrench)) + if(W.tool_behaviour == TOOL_WRENCH) default_unfasten_wrench(user, W, 0) else return ..() diff --git a/code/modules/power/singularity/particle_accelerator/particle_accelerator.dm b/code/modules/power/singularity/particle_accelerator/particle_accelerator.dm index 528a3abb8b..60c97eda76 100644 --- a/code/modules/power/singularity/particle_accelerator/particle_accelerator.dm +++ b/code/modules/power/singularity/particle_accelerator/particle_accelerator.dm @@ -63,7 +63,7 @@ switch(construction_state) if(PA_CONSTRUCTION_UNSECURED) - if(istype(W, /obj/item/wrench) && !isinspace()) + if(W.tool_behaviour == TOOL_WRENCH && !isinspace()) W.play_tool_sound(src, 75) anchored = TRUE user.visible_message("[user.name] secures the [name] to the floor.", \ @@ -71,7 +71,7 @@ construction_state = PA_CONSTRUCTION_UNWIRED did_something = TRUE if(PA_CONSTRUCTION_UNWIRED) - if(istype(W, /obj/item/wrench)) + if(W.tool_behaviour == TOOL_WRENCH) W.play_tool_sound(src, 75) anchored = FALSE user.visible_message("[user.name] detaches the [name] from the floor.", \ @@ -85,18 +85,18 @@ construction_state = PA_CONSTRUCTION_PANEL_OPEN did_something = TRUE if(PA_CONSTRUCTION_PANEL_OPEN) - if(istype(W, /obj/item/wirecutters))//TODO:Shock user if its on? + if(W.tool_behaviour == TOOL_WIRECUTTER)//TODO:Shock user if its on? user.visible_message("[user.name] removes some wires from the [name].", \ "You remove some wires.") construction_state = PA_CONSTRUCTION_UNWIRED did_something = TRUE - else if(istype(W, /obj/item/screwdriver)) + else if(W.tool_behaviour == TOOL_SCREWDRIVER) user.visible_message("[user.name] closes the [name]'s access panel.", \ "You close the access panel.") construction_state = PA_CONSTRUCTION_COMPLETE did_something = TRUE if(PA_CONSTRUCTION_COMPLETE) - if(istype(W, /obj/item/screwdriver)) + if(W.tool_behaviour == TOOL_SCREWDRIVER) user.visible_message("[user.name] opens the [name]'s access panel.", \ "You open the access panel.") construction_state = PA_CONSTRUCTION_PANEL_OPEN diff --git a/code/modules/power/smes.dm b/code/modules/power/smes.dm index f0f99ab7da..32e6186133 100644 --- a/code/modules/power/smes.dm +++ b/code/modules/power/smes.dm @@ -162,8 +162,8 @@ return TRUE -/obj/machinery/power/smes/default_deconstruction_crowbar(obj/item/crowbar/C) - if(istype(C) && terminal) +/obj/machinery/power/smes/default_deconstruction_crowbar(obj/item/C) + if(C.tool_behaviour == TOOL_CROWBAR && terminal) to_chat(usr, "You must first remove the power terminal!") return FALSE diff --git a/code/modules/power/solar.dm b/code/modules/power/solar.dm index cf526f083d..da99ecaf73 100644 --- a/code/modules/power/solar.dm +++ b/code/modules/power/solar.dm @@ -227,7 +227,7 @@ /obj/item/solar_assembly/attackby(obj/item/W, mob/user, params) - if(istype(W, /obj/item/wrench) && isturf(loc)) + if(W.tool_behaviour == TOOL_WRENCH && isturf(loc)) if(isinspace()) to_chat(user, "You can't secure [src] here.") return @@ -269,7 +269,7 @@ user.visible_message("[user] inserts the electronics into the solar assembly.", "You insert the electronics into the solar assembly.") return 1 else - if(istype(W, /obj/item/crowbar)) + if(W.tool_behaviour == TOOL_CROWBAR) new /obj/item/electronics/tracker(src.loc) tracker = 0 user.visible_message("[user] takes out the electronics from the solar assembly.", "You take out the electronics from the solar assembly.") diff --git a/code/modules/power/tesla/coil.dm b/code/modules/power/tesla/coil.dm index be24ea0fef..13f2aab811 100644 --- a/code/modules/power/tesla/coil.dm +++ b/code/modules/power/tesla/coil.dm @@ -131,8 +131,10 @@ else . = ..() -/obj/machinery/power/tesla_coil/research/default_unfasten_wrench(mob/user, obj/item/wrench/W, time = 20) +/obj/machinery/power/tesla_coil/research/default_unfasten_wrench(mob/user, obj/item/W, time = 20) . = ..() + if(!W.tool_behaviour == TOOL_WRENCH) + return if(. == SUCCESSFUL_UNFASTEN) if(panel_open) icon_state = "rpcoil_open[anchored]" diff --git a/code/modules/projectiles/ammunition/caseless/foam.dm b/code/modules/projectiles/ammunition/caseless/foam.dm index 91ed69f7a5..ac0358e220 100644 --- a/code/modules/projectiles/ammunition/caseless/foam.dm +++ b/code/modules/projectiles/ammunition/caseless/foam.dm @@ -24,13 +24,13 @@ /obj/item/ammo_casing/caseless/foam_dart/attackby(obj/item/A, mob/user, params) var/obj/item/projectile/bullet/reusable/foam_dart/FD = BB - if (istype(A, /obj/item/screwdriver) && !modified) + if(A.tool_behaviour == TOOL_SCREWDRIVER && !modified) modified = TRUE FD.modified = TRUE FD.damage_type = BRUTE to_chat(user, "You pop the safety cap off [src].") update_icon() - else if (istype(A, /obj/item/pen)) + else if(istype(A, /obj/item/pen)) if(modified) if(!FD.pen) harmful = TRUE diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index e3a2da68da..63d019f97f 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -434,7 +434,7 @@ to_chat(user, "You attach \the [K] to the front of \the [src].") bayonet = K update_icon() - else if(istype(I, /obj/item/screwdriver)) + else if(I.tool_behaviour == TOOL_SCREWDRIVER) if(gun_light) var/obj/item/flashlight/seclite/S = gun_light to_chat(user, "You unscrew the seclite from \the [src].") diff --git a/code/modules/projectiles/guns/ballistic/automatic.dm b/code/modules/projectiles/guns/ballistic/automatic.dm index 00e59d09f8..e8d53ddeb8 100644 --- a/code/modules/projectiles/guns/ballistic/automatic.dm +++ b/code/modules/projectiles/guns/ballistic/automatic.dm @@ -12,6 +12,7 @@ name = "\improper Nanotrasen Saber SMG" desc = "A prototype three-round burst 9mm submachine gun, designated 'SABR'. Has a threaded barrel for suppressors." icon_state = "saber" + fire_sound = "sound/weapons/gunshot_smg_alt.ogg" mag_type = /obj/item/ammo_box/magazine/smgm9mm pin = null @@ -125,6 +126,7 @@ desc = "An outdated personal defence weapon. Uses 4.6x30mm rounds and is designated the WT-550 Semi-Automatic SMG." icon_state = "wt550" item_state = "arg" + fire_sound = "sound/weapons/gunshot_smg_alt.ogg" mag_type = /obj/item/ammo_box/magazine/wt550m9 can_suppress = FALSE burst_size = 2 @@ -138,6 +140,10 @@ . = ..() spread = 15 +/obj/item/gun/ballistic/automatic/wt550/afterattack() + . = ..() + empty_alarm() + /obj/item/gun/ballistic/automatic/wt550/disable_burst() . = ..() spread = 0 @@ -158,7 +164,7 @@ icon_state = "m90" item_state = "m90" mag_type = /obj/item/ammo_box/magazine/m556 - fire_sound = 'sound/weapons/gunshot_smg.ogg' + fire_sound = 'sound/weapons/rifleshot.ogg' can_suppress = FALSE automatic_burst_overlay = FALSE var/obj/item/gun/ballistic/revolver/grenadelauncher/underbarrel @@ -243,7 +249,7 @@ item_state = "arg" slot_flags = 0 mag_type = /obj/item/ammo_box/magazine/m556 - fire_sound = 'sound/weapons/gunshot_smg.ogg' + fire_sound = 'sound/weapons/rifleshot.ogg' can_suppress = FALSE burst_size = 3 burst_shot_delay = 1 @@ -258,7 +264,7 @@ w_class = WEIGHT_CLASS_NORMAL weapon_weight = WEAPON_MEDIUM mag_type = /obj/item/ammo_box/magazine/m12g - fire_sound = 'sound/weapons/gunshot.ogg' + fire_sound = 'sound/weapons/gunshotshotgunshot.ogg' automatic_burst_overlay = FALSE can_suppress = FALSE burst_size = 1 @@ -293,11 +299,11 @@ desc = "A heavily modified 1.95x129mm light machine gun, designated 'L6 SAW'. Has 'Aussec Armoury - 2531' engraved on the receiver below the designation." icon_state = "l6closed100" item_state = "l6closedmag" + fire_sound = "sound/weapons/lmgshot.ogg" w_class = WEIGHT_CLASS_HUGE slot_flags = 0 mag_type = /obj/item/ammo_box/magazine/mm195x129 weapon_weight = WEAPON_HEAVY - fire_sound = 'sound/weapons/gunshot_smg.ogg' var/cover_open = FALSE can_suppress = FALSE burst_size = 3 @@ -363,6 +369,7 @@ desc = "A long ranged weapon that does significant damage. No, you can't quickscope." icon_state = "sniper" item_state = "sniper" + fire_sound = "sound/weapons/noscope.ogg" recoil = 2 weapon_weight = WEAPON_HEAVY mag_type = /obj/item/ammo_box/magazine/sniper_rounds @@ -397,6 +404,7 @@ desc = "One of countless obsolete ballistic rifles that still sees use as a cheap deterrent. Uses 10mm ammo and its bulky frame prevents one-hand firing." icon_state = "surplus" item_state = "moistnugget" + fire_sound = 'sound/weapons/rifleshot.ogg' weapon_weight = WEAPON_HEAVY mag_type = /obj/item/ammo_box/magazine/m10mm/rifle fire_delay = 30 diff --git a/code/modules/projectiles/guns/ballistic/launchers.dm b/code/modules/projectiles/guns/ballistic/launchers.dm index 9e03207888..c53366c4f5 100644 --- a/code/modules/projectiles/guns/ballistic/launchers.dm +++ b/code/modules/projectiles/guns/ballistic/launchers.dm @@ -35,7 +35,7 @@ name = "gyrojet pistol" desc = "A prototype pistol designed to fire self propelled rockets." icon_state = "gyropistol" - fire_sound = 'sound/weapons/grenadelaunch.ogg' + fire_sound = 'sound/weapons/rocketlaunch.ogg' mag_type = /obj/item/ammo_box/magazine/m75 burst_size = 1 fire_delay = 0 diff --git a/code/modules/projectiles/guns/ballistic/pistol.dm b/code/modules/projectiles/guns/ballistic/pistol.dm index 9ed9630f2f..98b654aadb 100644 --- a/code/modules/projectiles/guns/ballistic/pistol.dm +++ b/code/modules/projectiles/guns/ballistic/pistol.dm @@ -138,7 +138,7 @@ can_suppress = FALSE w_class = WEIGHT_CLASS_NORMAL actions_types = list() - fire_sound = 'sound/weapons/blastcannon.ogg' + fire_sound = 'sound/weapons/noscope.ogg' spread = 20 //damn thing has no rifling. automatic_burst_overlay = FALSE diff --git a/code/modules/projectiles/guns/ballistic/revolver.dm b/code/modules/projectiles/guns/ballistic/revolver.dm index 3e564a9ace..06342937dc 100644 --- a/code/modules/projectiles/guns/ballistic/revolver.dm +++ b/code/modules/projectiles/guns/ballistic/revolver.dm @@ -3,6 +3,7 @@ desc = "A suspicious revolver. Uses .357 ammo." //usually used by syndicates icon_state = "revolver" mag_type = /obj/item/ammo_box/magazine/internal/cylinder + fire_sound = "sound/weapons/revolvershot.ogg" casing_ejector = FALSE /obj/item/gun/ballistic/revolver/Initialize() diff --git a/code/modules/projectiles/guns/ballistic/shotgun.dm b/code/modules/projectiles/guns/ballistic/shotgun.dm index 796e544603..8035440906 100644 --- a/code/modules/projectiles/guns/ballistic/shotgun.dm +++ b/code/modules/projectiles/guns/ballistic/shotgun.dm @@ -3,6 +3,7 @@ desc = "A traditional shotgun with wood furniture and a four-shell capacity underneath." icon_state = "shotgun" item_state = "shotgun" + fire_sound = "sound/weapons/gunshotshotgunshot.ogg" w_class = WEIGHT_CLASS_BULKY force = 10 flags_1 = CONDUCT_1 diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm index c489edf88e..fd6204a8e3 100644 --- a/code/modules/reagents/chemistry/holder.dm +++ b/code/modules/reagents/chemistry/holder.dm @@ -973,10 +973,8 @@ for(var/A in cached_reagents) var/datum/reagent/R = A if (R.type == 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(!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/)) @@ -987,6 +985,8 @@ amount = clamp(amount, 0, R.volume) R.volume -= amount update_total() + if(total_volume <= 0)//Because this can result in 0, I don't want it to crash. + pH = REAGENT_NORMAL_PH if(!safety)//So it does not handle reactions when it need not to handle_reactions() if(my_atom) diff --git a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm index d1c18f0510..22aadc06f4 100644 --- a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm +++ b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm @@ -24,9 +24,11 @@ circuit = /obj/item/circuitboard/machine/chem_dispenser var/obj/item/stock_parts/cell/cell var/powerefficiency = 0.0666666 + var/dispenceUnit = 5 var/amount = 30 var/recharge_amount = 10 var/recharge_counter = 0 + var/canStore = TRUE//If this can hold reagents or not var/mutable_appearance/beaker_overlay var/working_state = "dispenser_working" var/nopower_state = "dispenser_nopower" @@ -102,6 +104,7 @@ if(upgrade_reagents3) upgrade_reagents3 = sortList(upgrade_reagents3, /proc/cmp_reagents_asc) dispensable_reagents = sortList(dispensable_reagents, /proc/cmp_reagents_asc) + create_reagents(200, NO_REACT) update_icon() /obj/machinery/chem_dispenser/Destroy() @@ -190,24 +193,27 @@ data["amount"] = amount data["energy"] = cell.charge ? cell.charge * powerefficiency : "0" //To prevent NaN in the UI. data["maxEnergy"] = cell.maxcharge * powerefficiency + data["storedVol"] = reagents.total_volume + data["maxVol"] = reagents.maximum_volume data["isBeakerLoaded"] = beaker ? 1 : 0 + data["stepAmount"] = dispenceUnit + data["canStore"] = canStore var/beakerContents[0] var/beakerCurrentVolume = 0 if(beaker && beaker.reagents && beaker.reagents.reagent_list.len) for(var/datum/reagent/R in beaker.reagents.reagent_list) - beakerContents.Add(list(list("name" = R.name, "volume" = R.volume))) // list in a list because Byond merges the first list... + beakerContents.Add(list(list("name" = R.name, "id" = R.type, "volume" = round(R.volume, 0.01)))) // list in a list because Byond merges the first list... beakerCurrentVolume += R.volume data["beakerContents"] = beakerContents if (beaker) - data["beakerCurrentVolume"] = beakerCurrentVolume + data["beakerCurrentVolume"] = round(beakerCurrentVolume, 0.01) 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) + data["beakerCurrentpH"] = round(beaker.reagents.pH, 10**-(C.rating+1)) else data["beakerCurrentVolume"] = null @@ -225,11 +231,17 @@ var/chemname = temp.name if(is_hallucinating && prob(5)) chemname = "[pick_list_replacements("hallucination.json", "chemicals")]" - chemicals.Add(list(list("title" = chemname, "id" = ckey(temp.name)))) + chemicals.Add(list(list("title" = chemname, "id" = ckey(temp.name), "pH" = temp.pH, "pHCol" = ConvertpHToCol(temp.pH)))) data["chemicals"] = chemicals data["recipes"] = saved_recipes data["recordingRecipe"] = recording_recipe + + var/storedContents[0] + if(reagents.total_volume) + for(var/datum/reagent/N in reagents.reagent_list) + storedContents.Add(list(list("name" = N.name, "id" = N.type, "volume" = N.volume))) + data["storedContents"] = storedContents return data /obj/machinery/chem_dispenser/ui_act(action, params) @@ -240,10 +252,9 @@ if(!is_operational() || QDELETED(beaker)) return var/target = text2num(params["target"]) - if(target in beaker.possible_transfer_amounts) - amount = target - work_animation() - . = TRUE + SetAmount(target) + work_animation() + . = TRUE if("dispense") if(!is_operational() || QDELETED(cell)) return @@ -269,10 +280,9 @@ if(!is_operational() || recording_recipe) return var/amount = text2num(params["amount"]) - if(beaker && (amount in beaker.possible_transfer_amounts)) - beaker.reagents.remove_all(amount) - work_animation() - . = TRUE + beaker.reagents.remove_all(amount) //This should be set correctly in "amount" + work_animation() + . = TRUE if("eject") replace_beaker(usr) . = TRUE @@ -350,6 +360,52 @@ recording_recipe = null . = TRUE + //Storing and unstoring reagents + if("store") + if(!is_operational() || QDELETED(cell)) + return + if(!beaker) + return + if(recording_recipe) + say("Cannot store while recording!") + return + if(beaker.reagents.fermiIsReacting) + say("Cannot store ongoing reactions!") + return + var/reagent = text2path(params["id"]) + var/datum/reagent/R = beaker.reagents.has_reagent(reagent) + var/potentialAmount = min(amount, R.volume) + if(reagents.total_volume+potentialAmount > reagents.maximum_volume) + say("Not enough storage space left!") + return + beaker.reagents.trans_id_to(src, R.type, potentialAmount) + work_animation() + . = TRUE + + if("unstore") + if(!is_operational() || QDELETED(cell)) + return + if(!beaker) + return + if(recording_recipe) + say("Cannot distribute while recording!") + return + var/reagent = text2path(params["id"]) + var/datum/reagent/R = reagents.has_reagent(reagent) + reagents.trans_id_to(beaker, R.type, amount) + work_animation() + . = TRUE + +/obj/machinery/chem_dispenser/proc/SetAmount(inputAmount) + if(inputAmount % 5 == 0) //Always allow 5u values + amount = inputAmount + return + inputAmount -= inputAmount % dispenceUnit + if(inputAmount == 0) //Prevent ghost entries in macros + amount = dispenceUnit + return + amount = inputAmount + /obj/machinery/chem_dispenser/attackby(obj/item/I, mob/user, params) if(default_unfasten_wrench(user, I)) return @@ -402,6 +458,8 @@ cell = P for(var/obj/item/stock_parts/matter_bin/M in component_parts) newpowereff += 0.0166666666*M.rating + if(reagents) + reagents.maximum_volume = 200*(M.rating) for(var/obj/item/stock_parts/capacitor/C in component_parts) recharge_amount *= C.rating for(var/obj/item/stock_parts/manipulator/M in component_parts) @@ -411,6 +469,15 @@ dispensable_reagents |= upgrade_reagents2 if(M.rating > 3) dispensable_reagents |= upgrade_reagents3 + switch(M.rating) + if(-INFINITY to 1) + dispenceUnit = 5 + if(2) + dispenceUnit = 3 + if(3) + dispenceUnit = 2 + if(4 to INFINITY) + dispenceUnit = 1 powerefficiency = round(newpowereff, 0.01) /obj/machinery/chem_dispenser/proc/replace_beaker(mob/living/user, obj/item/reagent_containers/new_beaker) @@ -421,6 +488,8 @@ user.put_in_hands(B) if(new_beaker) beaker = new_beaker + if(amount > beaker.reagents.maximum_volume) + amount = beaker.reagents.maximum_volume else beaker = null update_icon() @@ -439,6 +508,32 @@ replace_beaker(user) return TRUE +/obj/machinery/chem_dispenser/proc/ConvertpHToCol(pH) + switch(pH) + if(-INFINITY to 1) + return "red" + if(1 to 2) + return "orange" + if(2 to 3) + return "average" + if(3 to 4) + return "yellow" + if(4 to 5) + return "olive" + if(5 to 6) + return "good" + if(6 to 8) + return "green" + if(8 to 9.5) + return "teal" + if(9.5 to 11) + return "blue" + if(11 to 12.5) + return "violet" + if(12.5 to INFINITY) + return "purple" + + /obj/machinery/chem_dispenser/drinks/Initialize() . = ..() AddComponent(/datum/component/simple_rotation, ROTATION_ALTCLICK | ROTATION_CLOCKWISE) @@ -466,6 +561,7 @@ b_o.pixel_x = rand(-9, 9) return b_o + /obj/machinery/chem_dispenser/drinks name = "soda dispenser" desc = "Contains a large reservoir of soft drinks." @@ -479,6 +575,7 @@ working_state = null nopower_state = null pass_flags = PASSTABLE + canStore = FALSE dispensable_reagents = list( /datum/reagent/water, /datum/reagent/consumable/ice, @@ -611,12 +708,14 @@ dispensable_reagents = list(/datum/reagent/toxin/mutagen) upgrade_reagents = null emagged_reagents = list(/datum/reagent/toxin/plasma) + canStore = FALSE /obj/machinery/chem_dispenser/mutagensaltpeter name = "botanical chemical dispenser" desc = "Creates and dispenses chemicals useful for botany." flags_1 = NODECONSTRUCT_1 + canStore = FALSE dispensable_reagents = list( /datum/reagent/toxin/mutagen, @@ -739,6 +838,7 @@ working_state = "minidispenser_working" nopower_state = "minidispenser_nopower" circuit = /obj/item/circuitboard/machine/chem_dispenser/apothecary + canStore = FALSE powerefficiency = 0.0833333 dispensable_reagents = list( //radium and stable plasma moved to upgrade tier 1 and 2, they've little to do with most medicines anyway. /datum/reagent/hydrogen, diff --git a/code/modules/reagents/chemistry/machinery/chem_heater.dm b/code/modules/reagents/chemistry/machinery/chem_heater.dm index 8c3b9c7f99..cd8ee2d986 100644 --- a/code/modules/reagents/chemistry/machinery/chem_heater.dm +++ b/code/modules/reagents/chemistry/machinery/chem_heater.dm @@ -126,7 +126,7 @@ 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, "purity" = R.purity))) // list in a list because Byond merges the first list... + beakerContents.Add(list(list("name" = R.name, "volume" = round(R.volume, 0.01), "purity" = round(R.purity, 0.01)))) // 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 89fdb52b2a..285ef70433 100644 --- a/code/modules/reagents/chemistry/machinery/chem_master.dm +++ b/code/modules/reagents/chemistry/machinery/chem_master.dm @@ -184,13 +184,13 @@ var/beakerContents[0] if(beaker) for(var/datum/reagent/R in beaker.reagents.reagent_list) - beakerContents.Add(list(list("name" = R.name, "id" = ckey(R.name), "volume" = R.volume))) // list in a list because Byond merges the first list... + beakerContents.Add(list(list("name" = R.name, "id" = R.type, "volume" = R.volume))) // list in a list because Byond merges the first list... data["beakerContents"] = beakerContents var/bufferContents[0] if(reagents.total_volume) for(var/datum/reagent/N in reagents.reagent_list) - bufferContents.Add(list(list("name" = N.name, "id" = ckey(N.name), "volume" = N.volume))) // ^ + bufferContents.Add(list(list("name" = N.name, "id" = N.type, "volume" = N.volume))) // ^ data["bufferContents"] = bufferContents //Calculated at init time as it never changes @@ -216,7 +216,7 @@ if(action == "transfer") if(!beaker) return FALSE - var/reagent = GLOB.name2reagent[params["id"]] + var/reagent = text2path(params["id"]) var/amount = text2num(params["amount"]) var/to_container = params["to"] // Custom amount @@ -386,7 +386,7 @@ if(action == "analyze") // var/datum/reagent/R = GLOB.name2reagent[params["id"]] - var/reagent = GLOB.name2reagent[params["id"]] + var/reagent = text2path(params["id"]) var/datum/reagent/R = GLOB.chemical_reagents_list[reagent] if(R) var/state = "Unknown" @@ -405,7 +405,7 @@ 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" = R.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)) + 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" = R.purity) screen = "analyze" return TRUE diff --git a/code/modules/reagents/chemistry/reagents/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drink_reagents.dm index 1a8f6edcbe..f4f5b90398 100644 --- a/code/modules/reagents/chemistry/reagents/drink_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drink_reagents.dm @@ -504,6 +504,14 @@ glass_desc = "Don't cry, Don't raise your eye, It's only nuclear wasteland." value = REAGENT_VALUE_COMMON +/datum/reagent/consumable/nuka_cola/on_mob_metabolize(mob/living/carbon/M) + M.add_movespeed_modifier(/datum/movespeed_modifier/reagent/meth) + return ..() + +/datum/reagent/consumable/nuka_cola/on_mob_end_metabolize(mob/living/carbon/M) + M.remove_movespeed_modifier(/datum/movespeed_modifier/reagent/meth) + return ..() + /datum/reagent/consumable/nuka_cola/on_mob_life(mob/living/carbon/M) M.Jitter(20) M.set_drugginess(30) @@ -608,7 +616,7 @@ name = "Buzz Fuzz" description = "~A Hive of Flavour!~ NOTICE: Addicting." nutriment_factor = 0 - addiction_threshold = 26 //A can and a sip + addiction_threshold = 31 //A can and a sip color = "#8CFF00" // rgb: 135, 255, 0 taste_description = "carbonated honey and pollen" glass_icon_state = "buzz_fuzz" diff --git a/code/modules/reagents/chemistry/reagents/drug_reagents.dm b/code/modules/reagents/chemistry/reagents/drug_reagents.dm index 0b44c33926..96985514b5 100644 --- a/code/modules/reagents/chemistry/reagents/drug_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drug_reagents.dm @@ -45,6 +45,13 @@ trippy = FALSE pH = 8 +//Nicotine is used as a pesticide IRL. +/datum/reagent/drug/nicotine/on_hydroponics_apply(obj/item/seeds/myseed, datum/reagents/chems, obj/machinery/hydroponics/mytray, mob/user) + . = ..() + if(chems.has_reagent(type, 1)) + mytray.adjustToxic(round(chems.get_reagent_amount(type))) + mytray.adjustPests(-rand(1,2)) + /datum/reagent/drug/nicotine/on_mob_life(mob/living/carbon/M) if(prob(1)) var/smoke_message = pick("You feel relaxed.", "You feel calmed.","You feel alert.","You feel rugged.") @@ -174,11 +181,13 @@ ADD_TRAIT(L, TRAIT_IGNOREDAMAGESLOWDOWN, type) L.update_movespeed() ADD_TRAIT(L, TRAIT_TASED_RESISTANCE, type) + L.add_movespeed_modifier(/datum/movespeed_modifier/reagent/meth) /datum/reagent/drug/methamphetamine/on_mob_end_metabolize(mob/living/L) REMOVE_TRAIT(L, TRAIT_IGNOREDAMAGESLOWDOWN, type) L.update_movespeed() REMOVE_TRAIT(L, TRAIT_TASED_RESISTANCE, type) + L.remove_movespeed_modifier(/datum/movespeed_modifier/reagent/meth) ..() /datum/reagent/drug/methamphetamine/on_mob_life(mob/living/carbon/M) @@ -561,3 +570,129 @@ var/mob/living/carbon/C = M if(!C.undergoing_cardiac_arrest()) C.set_heartattack(TRUE) + +//aphrodisiac & anaphrodisiac + +/datum/reagent/drug/aphrodisiac + name = "Crocin" + description = "Naturally found in the crocus and gardenia flowers, this drug acts as a natural and safe aphrodisiac." + taste_description = "strawberries" + color = "#FFADFF"//PINK, rgb(255, 173, 255) + can_synth = FALSE + +/datum/reagent/drug/aphrodisiac/on_mob_life(mob/living/M) + if(M && M.client?.prefs.arousable && !(M.client?.prefs.cit_toggles & NO_APHRO)) + if((prob(min(current_cycle/2,5)))) + M.emote(pick("moan","blush")) + if(prob(min(current_cycle/4,10))) + var/aroused_message = pick("You feel frisky.", "You're having trouble suppressing your urges.", "You feel in the mood.") + to_chat(M, "[aroused_message]") + if(ishuman(M)) + var/mob/living/carbon/human/H = M + var/list/genits = H.adjust_arousal(current_cycle, "crocin", aphro = TRUE) // redundant but should still be here + for(var/g in genits) + var/obj/item/organ/genital/G = g + to_chat(M, "[G.arousal_verb]!") + ..() + +/datum/reagent/drug/aphrodisiacplus + name = "Hexacrocin" + description = "Chemically condensed form of basic crocin. This aphrodisiac is extremely powerful and addictive in most animals.\ + Addiction withdrawals can cause brain damage and shortness of breath. Overdosage can lead to brain damage and a \ + permanent increase in libido (commonly referred to as 'bimbofication')." + taste_description = "liquid desire" + color = "#FF2BFF"//dark pink + addiction_threshold = 20 + overdose_threshold = 20 + can_synth = FALSE + +/datum/reagent/drug/aphrodisiacplus/on_mob_life(mob/living/M) + if(M && M.client?.prefs.arousable && !(M.client?.prefs.cit_toggles & NO_APHRO)) + if(prob(5)) + if(prob(current_cycle)) + M.say(pick("Hnnnnngghh...", "Ohh...", "Mmnnn...")) + else + M.emote(pick("moan","blush")) + if(prob(5)) + var/aroused_message + if(current_cycle>25) + aroused_message = pick("You need to fuck someone!", "You're bursting with sexual tension!", "You can't get sex off your mind!") + else + aroused_message = pick("You feel a bit hot.", "You feel strong sexual urges.", "You feel in the mood.", "You're ready to go down on someone.") + to_chat(M, "[aroused_message]") + REMOVE_TRAIT(M,TRAIT_NEVERBONER,APHRO_TRAIT) + if(ishuman(M)) + var/mob/living/carbon/human/H = M + var/list/genits = H.adjust_arousal(100, "hexacrocin", aphro = TRUE) // redundant but should still be here + for(var/g in genits) + var/obj/item/organ/genital/G = g + to_chat(M, "[G.arousal_verb]!") + ..() + +/datum/reagent/drug/aphrodisiacplus/addiction_act_stage2(mob/living/M) + if(prob(30)) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 2) + ..() +/datum/reagent/drug/aphrodisiacplus/addiction_act_stage3(mob/living/M) + if(prob(30)) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 3) + + ..() +/datum/reagent/drug/aphrodisiacplus/addiction_act_stage4(mob/living/M) + if(prob(30)) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 4) + ..() + +/datum/reagent/drug/aphrodisiacplus/overdose_process(mob/living/M) + if(M && M.client?.prefs.arousable && !(M.client?.prefs.cit_toggles & NO_APHRO) && prob(33)) + if(prob(5) && ishuman(M) && M.has_dna() && (M.client?.prefs.cit_toggles & BIMBOFICATION)) + if(!HAS_TRAIT(M,TRAIT_PERMABONER)) + to_chat(M, "Your libido is going haywire!") + M.log_message("Made perma-horny by hexacrocin.",LOG_EMOTE) + ADD_TRAIT(M,TRAIT_PERMABONER,APHRO_TRAIT) + ..() + +/datum/reagent/drug/anaphrodisiac + name = "Camphor" + description = "Naturally found in some species of evergreen trees, camphor is a waxy substance. When injested by most animals, it acts as an anaphrodisiac\ + , reducing libido and calming them. Non-habit forming and not addictive." + taste_description = "dull bitterness" + taste_mult = 2 + color = "#D9D9D9"//rgb(217, 217, 217) + reagent_state = SOLID + can_synth = FALSE + +/datum/reagent/drug/anaphrodisiac/on_mob_life(mob/living/M) + if(M && M.client?.prefs.arousable && prob(16)) + if(ishuman(M)) + var/mob/living/carbon/human/H = M + var/list/genits = H.adjust_arousal(-100, "camphor", aphro = TRUE) + if(genits.len) + to_chat(M, "You no longer feel aroused.") + ..() + +/datum/reagent/drug/anaphrodisiacplus + name = "Hexacamphor" + description = "Chemically condensed camphor. Causes an extreme reduction in libido and a permanent one if overdosed. Non-addictive." + taste_description = "tranquil celibacy" + color = "#D9D9D9"//rgb(217, 217, 217) + reagent_state = SOLID + overdose_threshold = 20 + can_synth = FALSE + +/datum/reagent/drug/anaphrodisiacplus/on_mob_life(mob/living/M) + if(M && M.client?.prefs.arousable) + REMOVE_TRAIT(M,TRAIT_PERMABONER,APHRO_TRAIT) + if(ishuman(M)) + var/mob/living/carbon/human/H = M + var/list/genits = H.adjust_arousal(-100, "hexacamphor", aphro = TRUE) + if(genits.len) + to_chat(M, "You no longer feel aroused.") + + ..() + +/datum/reagent/drug/anaphrodisiacplus/overdose_process(mob/living/M) + if(M && M.client?.prefs.arousable && prob(5)) + to_chat(M, "You feel like you'll never feel aroused again...") + ADD_TRAIT(M,TRAIT_NEVERBONER,APHRO_TRAIT) + ..() diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm index 1975eede70..303fd981fb 100644 --- a/code/modules/reagents/chemistry/reagents/food_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm @@ -49,6 +49,11 @@ var/brute_heal = 1 var/burn_heal = 0 +/datum/reagent/consumable/nutriment/on_hydroponics_apply(obj/item/seeds/myseed, datum/reagents/chems, obj/machinery/hydroponics/mytray, mob/user) + . = ..() + if(chems.has_reagent(type, 1)) + mytray.adjustHealth(round(chems.get_reagent_amount(type) * 0.2)) + /datum/reagent/consumable/nutriment/on_mob_life(mob/living/carbon/M) if(!HAS_TRAIT(M, TRAIT_NO_PROCESS_FOOD)) if(prob(50)) diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm index e55286ed3f..65443b65c7 100644 --- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm @@ -155,6 +155,12 @@ pH = 11 value = REAGENT_VALUE_COMMON +// Healing +/datum/reagent/medicine/cryoxadone/on_hydroponics_apply(obj/item/seeds/myseed, datum/reagents/chems, obj/machinery/hydroponics/mytray, mob/user) + . = ..() + mytray.adjustHealth(round(chems.get_reagent_amount(type) * 3)) + mytray.adjustToxic(-round(chems.get_reagent_amount(type) * 3)) + /datum/reagent/medicine/cryoxadone/on_mob_life(mob/living/carbon/M) var/power = -0.00003 * (M.bodytemperature ** 2) + 3 if(M.bodytemperature < T0C) @@ -499,7 +505,7 @@ SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "painful_medicine", /datum/mood_event/painful_medicine) var/vol = reac_volume + M.reagents.get_reagent_amount(/datum/reagent/medicine/synthflesh) //Has to be at less than THRESHOLD_UNHUSK burn damage and have 100 synthflesh before unhusking. Corpses dont metabolize. - if(HAS_TRAIT_FROM(M, TRAIT_HUSK, "burn") && M.getFireLoss() < THRESHOLD_UNHUSK && (vol > 100)) + if(HAS_TRAIT_FROM(M, TRAIT_HUSK, "burn") && M.getFireLoss() < THRESHOLD_UNHUSK && (vol >= 100)) M.cure_husk("burn") M.visible_message("Most of [M]'s burnt off or charred flesh has been restored.") ..() @@ -935,6 +941,12 @@ pH = 0 value = REAGENT_VALUE_RARE +// FEED ME SEYMOUR +/datum/reagent/medicine/strange_reagent/on_hydroponics_apply(obj/item/seeds/myseed, datum/reagents/chems, obj/machinery/hydroponics/mytray, mob/user) + . = ..() + if(chems.has_reagent(type, 1)) + mytray.spawnplant() + /datum/reagent/medicine/strange_reagent/reaction_mob(mob/living/M, method=TOUCH, reac_volume) if(M.stat == DEAD) if(M.suiciding || M.hellbound) //they are never coming back diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index 90f570e4d1..fe8f923e1a 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -2362,6 +2362,12 @@ 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?")]") + if(ishuman(M)) + var/mob/living/carbon/human/H = M + var/list/adjusted = H.adjust_arousal(2,"catnip", aphro = TRUE) + for(var/g in adjusted) + var/obj/item/organ/genital/G = g + to_chat(M, "You feel like playing with your [G.name]!") ..() /datum/reagent/preservahyde @@ -2539,7 +2545,7 @@ M.drowsyness = max(M.drowsyness-5, 0) M.AdjustAllImmobility(-40, FALSE) M.adjustStaminaLoss(-15, FALSE) - M.adjustToxLoss(-3, FALSE) + M.adjustToxLoss(-3, FALSE, TRUE) M.adjustOxyLoss(-3, FALSE) M.adjustBruteLoss(-3, FALSE) M.adjustFireLoss(-3, FALSE) @@ -2663,3 +2669,32 @@ M.SetSleeping(0, 0) ..() +//Nerdy card reagents + +/datum/reagent/card_powder + var/rarity = "Stoopid" + +/datum/reagent/card_powder/blue + name = "Blue Card Powder" + rarity = "Rare" + color = "#00B7EF" // blue + +/datum/reagent/card_powder/purple + name = "Purple Card Powder" + rarity = "Epic" + color = "#DA00FF" // purple + +/datum/reagent/card_powder/yellow + name = "Yellow Crayon Powder" + rarity = "Legendary" + color = "#FFF200" // yellow + +/datum/reagent/card_powder/green + name = "Green Crayon Powder" + rarity = "Common" + color = "#A8E61D" // green + +/datum/reagent/card_powder/black + name = "Black Crayon Powder" + rarity = "Exodia" + color = "#1C1C1C" // not quite black diff --git a/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm b/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm index 3f0ebcb3e3..2e05f66cf8 100644 --- a/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm @@ -32,6 +32,12 @@ value = REAGENT_VALUE_VERY_COMMON taste_description = "metal" +//It has stable IN THE NAME. IT WAS MADE FOR THIS MOMENT. +/datum/reagent/stabilizing_agent/on_hydroponics_apply(obj/item/seeds/myseed, datum/reagents/chems, obj/machinery/hydroponics/mytray, mob/user) + . = ..() + if(myseed && chems.has_reagent(type, 1)) + myseed.adjust_instability(-1) + /datum/reagent/clf3 name = "Chlorine Trifluoride" description = "Makes a temporary 3x3 fireball when it comes into existence, so be careful when mixing. ClF3 applied to a surface burns things that wouldn't otherwise burn, sometimes through the very floors of the station and exposing it to the vacuum of space." @@ -167,6 +173,15 @@ taste_description = "burning" value = REAGENT_VALUE_COMMON +// Smells like victory... +/datum/reagent/napalm/on_hydroponics_apply(obj/item/seeds/myseed, datum/reagents/chems, obj/machinery/hydroponics/mytray, mob/user) + . = ..() + if(chems.has_reagent(type, 1)) + if(!(myseed.resistance_flags & FIRE_PROOF)) + mytray.adjustHealth(-round(chems.get_reagent_amount(type) * 6)) + mytray.adjustToxic(round(chems.get_reagent_amount(type) * 7)) + mytray.adjustWeeds(-rand(5,9)) //At least give them a small reward if they bother. + /datum/reagent/napalm/on_mob_life(mob/living/carbon/M) M.adjust_fire_stacks(1) ..() diff --git a/code/modules/reagents/chemistry/recipes/drugs.dm b/code/modules/reagents/chemistry/recipes/drugs.dm index 468d29c052..8de4b1248f 100644 --- a/code/modules/reagents/chemistry/recipes/drugs.dm +++ b/code/modules/reagents/chemistry/recipes/drugs.dm @@ -62,3 +62,35 @@ results = list(/datum/reagent/moonsugar = 1, /datum/reagent/medicine/morphine = 2.5) required_temp = 315 //a little above normal body temperature required_reagents = list(/datum/reagent/drug/skooma = 1) + +/datum/chemical_reaction/aphro + name = "crocin" + id = /datum/reagent/drug/aphrodisiac + results = list(/datum/reagent/drug/aphrodisiac = 6) + required_reagents = list(/datum/reagent/carbon = 2, /datum/reagent/hydrogen = 2, /datum/reagent/oxygen = 2, /datum/reagent/water = 1) + required_temp = 400 + mix_message = "The mixture boils off a pink vapor..."//The water boils off, leaving the crocin + +/datum/chemical_reaction/aphroplus + name = "hexacrocin" + id = /datum/reagent/drug/aphrodisiacplus + results = list(/datum/reagent/drug/aphrodisiacplus = 1) + required_reagents = list(/datum/reagent/drug/aphrodisiac = 6, /datum/reagent/phenol = 1) + required_temp = 400 + mix_message = "The mixture rapidly condenses and darkens in color..." + +/datum/chemical_reaction/anaphro + name = "camphor" + id = /datum/reagent/drug/anaphrodisiac + results = list(/datum/reagent/drug/anaphrodisiac = 6) + required_reagents = list(/datum/reagent/carbon = 2, /datum/reagent/hydrogen = 2, /datum/reagent/oxygen = 2, /datum/reagent/sulfur = 1) + required_temp = 400 + mix_message = "The mixture boils off a yellow, smelly vapor..."//Sulfur burns off, leaving the camphor + +/datum/chemical_reaction/anaphroplus + name = "pentacamphor" + id = /datum/reagent/drug/anaphrodisiacplus + results = list(/datum/reagent/drug/anaphrodisiacplus = 1) + required_reagents = list(/datum/reagent/drug/aphrodisiac = 5, /datum/reagent/acetone = 1) + required_temp = 300 + mix_message = "The mixture thickens and heats up slighty..." diff --git a/code/modules/reagents/chemistry/recipes/medicine.dm b/code/modules/reagents/chemistry/recipes/medicine.dm index d4d66af240..f2e9bd9e1a 100644 --- a/code/modules/reagents/chemistry/recipes/medicine.dm +++ b/code/modules/reagents/chemistry/recipes/medicine.dm @@ -116,7 +116,10 @@ holder.remove_reagent(id, added_volume*temp_ratio) if(St.purity < 1) St.volume *= St.purity + added_volume *= St.purity St.purity = 1 + if(!N) + return var/amount = clamp(0.002, 0, N.volume) N.volume -= amount St.data["grown_volume"] = St.data["grown_volume"] + added_volume diff --git a/code/modules/reagents/chemistry/recipes/others.dm b/code/modules/reagents/chemistry/recipes/others.dm index 019394e3c8..6eb0d5825c 100644 --- a/code/modules/reagents/chemistry/recipes/others.dm +++ b/code/modules/reagents/chemistry/recipes/others.dm @@ -718,7 +718,7 @@ name = "felinid mutation toxin" id = /datum/reagent/mutationtoxin/felinid results = list(/datum/reagent/mutationtoxin/felinid = 1) - required_reagents = list(/datum/reagent/toxin/mindbreaker = 1, /datum/reagent/ammonia = 1, /datum/reagent/water = 1, /datum/reagent/pax/catnip = 1, /datum/reagent/mutationtoxin = 1) + required_reagents = list(/datum/reagent/toxin/mindbreaker = 1, /datum/reagent/ammonia = 1, /datum/reagent/water = 1, /datum/reagent/drug/aphrodisiac = 10, /datum/reagent/mutationtoxin = 1) required_temp = 450 /datum/chemical_reaction/moff @@ -881,3 +881,29 @@ results = list(/datum/reagent/carbon = 1) required_reagents = list(/datum/reagent/cellulose = 1) required_temp = 512 + +//Nerdy card shit + +/datum/chemical_reaction/card_powder/blue + name = "Blue Card Powder" + id = /datum/reagent/card_powder/blue + results = list(/datum/reagent/card_powder/blue = 1) + required_reagents = list(/datum/reagent/card_powder/green = 12) + +/datum/chemical_reaction/card_powder/purple + name = "Purple Card Powder" + id = /datum/reagent/card_powder/purple + results = list(/datum/reagent/card_powder/purple = 1) + required_reagents = list(/datum/reagent/card_powder/blue = 12) + +/datum/chemical_reaction/card_powder/yellow + name = "Yellow Card Powder" + id = /datum/reagent/card_powder/yellow + results = list(/datum/reagent/card_powder/yellow = 1) + required_reagents = list(/datum/reagent/card_powder/purple = 12) + +/datum/chemical_reaction/card_powder/black + name = "Black Card Powder" + id = /datum/reagent/card_powder/black + results = list(/datum/reagent/card_powder/black = 1) + required_reagents = list(/datum/reagent/card_powder/yellow = 12) diff --git a/code/modules/reagents/reagent_containers/bottle.dm b/code/modules/reagents/reagent_containers/bottle.dm index e0a7f7c00e..76b08c7cdf 100644 --- a/code/modules/reagents/reagent_containers/bottle.dm +++ b/code/modules/reagents/reagent_containers/bottle.dm @@ -417,6 +417,26 @@ name = "bromine bottle" list_reagents = list(/datum/reagent/bromine = 30) +/obj/item/reagent_containers/glass/bottle/crocin + name = "Crocin bottle" + desc = "A bottle of mild aphrodisiac. Increases libido." + list_reagents = list(/datum/reagent/drug/aphrodisiac = 30) + +/obj/item/reagent_containers/glass/bottle/hexacrocin + name = "Hexacrocin bottle" + desc = "A bottle of strong aphrodisiac. Increases libido." + list_reagents = list(/datum/reagent/drug/aphrodisiacplus = 30) + +/obj/item/reagent_containers/glass/bottle/camphor + name = "Camphor bottle" + desc = "A bottle of mild anaphrodisiac. Reduces libido." + list_reagents = list(/datum/reagent/drug/anaphrodisiac = 30) + +/obj/item/reagent_containers/glass/bottle/hexacamphor + name = "Hexacamphor bottle" + desc = "A bottle of strong anaphrodisiac. Reduces libido." + list_reagents = list(/datum/reagent/drug/anaphrodisiacplus = 30) + //Ichors /obj/item/reagent_containers/glass/bottle/ichor possible_transfer_amounts = list(1) diff --git a/code/modules/reagents/reagent_containers/dropper.dm b/code/modules/reagents/reagent_containers/dropper.dm index 3ed946d0c5..bad9417dc8 100644 --- a/code/modules/reagents/reagent_containers/dropper.dm +++ b/code/modules/reagents/reagent_containers/dropper.dm @@ -48,7 +48,7 @@ safe_thing.create_reagents(100, NONE, NO_REAGENTS_VALUE) reagents.reaction(safe_thing, TOUCH, fraction) - trans = reagents.trans_to(safe_thing, amount_per_transfer_from_this) + trans = reagents.trans_to(safe_thing, amount_per_transfer_from_this, log = "failed squirt") target.visible_message("[user] tries to squirt something into [target]'s eyes, but fails!", \ "[user] tries to squirt something into [target]'s eyes, but fails!") @@ -67,7 +67,7 @@ var/mob/M = target log_combat(user, M, "squirted", reagents.log_list()) - trans = src.reagents.trans_to(target, amount_per_transfer_from_this) + trans = src.reagents.trans_to(target, amount_per_transfer_from_this, log = "dropper drop") to_chat(user, "You transfer [trans] unit\s of the solution.") update_icon() @@ -81,7 +81,7 @@ to_chat(user, "[target] is empty!") return - var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this) + var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this, log = "dropper fill") to_chat(user, "You fill [src] with [trans] unit\s of the solution.") diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm index 1f89af420e..143025aed1 100644 --- a/code/modules/reagents/reagent_containers/hypospray.dm +++ b/code/modules/reagents/reagent_containers/hypospray.dm @@ -41,7 +41,7 @@ if(M.reagents) var/trans = 0 if(!infinite) - trans = reagents.trans_to(M, amount_per_transfer_from_this, log = TRUE) + trans = reagents.trans_to(M, amount_per_transfer_from_this, log = "hypospray injection") else trans = reagents.copy_to(M, amount_per_transfer_from_this) @@ -427,7 +427,7 @@ var/fraction = min(vial.amount_per_transfer_from_this/vial.reagents.total_volume, 1) vial.reagents.reaction(L, method, fraction) - vial.reagents.trans_to(target, vial.amount_per_transfer_from_this, log = TRUE) + vial.reagents.trans_to(target, vial.amount_per_transfer_from_this, log = "hypospray fill") var/long_sound = vial.amount_per_transfer_from_this >= 15 playsound(loc, long_sound ? 'sound/items/hypospray_long.ogg' : pick('sound/items/hypospray.ogg','sound/items/hypospray2.ogg'), 50, 1, -1) to_chat(user, "You [fp_verb] [vial.amount_per_transfer_from_this] units of the solution. The hypospray's cartridge now contains [vial.reagents.total_volume] units.") diff --git a/code/modules/reagents/reagent_containers/rags.dm b/code/modules/reagents/reagent_containers/rags.dm index 5d94e78809..8a6e2bf2e7 100644 --- a/code/modules/reagents/reagent_containers/rags.dm +++ b/code/modules/reagents/reagent_containers/rags.dm @@ -39,7 +39,7 @@ C.visible_message("[user] is trying to smother \the [C] with \the [src]!", "[user] is trying to smother you with \the [src]!", "You hear some struggling and muffled cries of surprise.") if(do_after(user, 20, target = C)) reagents.reaction(C, INGEST) - reagents.trans_to(C, 5, log = TRUE) + reagents.trans_to(C, 5, log = "rag smother") C.visible_message("[user] has smothered \the [C] with \the [src]!", "[user] has smothered you with \the [src]!", "You hear some struggling and a heavy breath taken.") log_combat(user, C, "smothered", log_object) else @@ -107,7 +107,7 @@ reagents.clear_reagents() else msg += "'s liquids into \the [target]" - reagents.trans_to(target, reagents.total_volume, log = TRUE) + reagents.trans_to(target, reagents.total_volume, log = "rag squeeze dry") to_chat(user, "[msg].") return TRUE diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm index 39ccdd23a2..26f0ca66ee 100644 --- a/code/modules/reagents/reagent_dispenser.dm +++ b/code/modules/reagents/reagent_dispenser.dm @@ -173,7 +173,7 @@ boom() /obj/structure/reagent_dispensers/fueltank/attackby(obj/item/I, mob/living/user, params) - if(istype(I, /obj/item/weldingtool)) + if(I.tool_behaviour == TOOL_WELDER) if(!reagents.has_reagent(/datum/reagent/fuel)) to_chat(user, "[src] is out of fuel!") return diff --git a/code/modules/recycling/conveyor2.dm b/code/modules/recycling/conveyor2.dm index b81c3b88f8..aefb670dd3 100644 --- a/code/modules/recycling/conveyor2.dm +++ b/code/modules/recycling/conveyor2.dm @@ -145,7 +145,7 @@ GLOBAL_LIST_EMPTY(conveyors_by_id) // attack with item, place item on conveyor /obj/machinery/conveyor/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/crowbar)) + if(I.tool_behaviour == TOOL_CROWBAR) user.visible_message("[user] struggles to pry up \the [src] with \the [I].", \ "You struggle to pry up \the [src] with \the [I].") if(I.use_tool(src, user, 40, volume=40)) @@ -155,14 +155,14 @@ GLOBAL_LIST_EMPTY(conveyors_by_id) to_chat(user, "You remove the conveyor belt.") qdel(src) - else if(istype(I, /obj/item/wrench)) + else if(I.tool_behaviour == TOOL_WRENCH) if(!(stat & BROKEN)) I.play_tool_sound(src) setDir(turn(dir,-45)) update_move_direction() to_chat(user, "You rotate [src].") - else if(istype(I, /obj/item/screwdriver)) + else if(I.tool_behaviour == TOOL_SCREWDRIVER) if(!(stat & BROKEN)) verted = verted * -1 update_move_direction() @@ -306,7 +306,7 @@ GLOBAL_LIST_EMPTY(conveyors_by_id) CHECK_TICK /obj/machinery/conveyor_switch/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/crowbar)) + if(I.tool_behaviour == TOOL_CROWBAR) var/obj/item/conveyor_switch_construct/C = new/obj/item/conveyor_switch_construct(src.loc) C.id = id transfer_fingerprints_to(C) diff --git a/code/modules/research/rdconsole.dm b/code/modules/research/rdconsole.dm index a7b266fc0e..a9284a19f7 100644 --- a/code/modules/research/rdconsole.dm +++ b/code/modules/research/rdconsole.dm @@ -194,7 +194,9 @@ Nothing else in the console has ID requirements. locked = FALSE return TRUE -/obj/machinery/computer/rdconsole/multitool_act(mob/user, obj/item/multitool/I) +/obj/machinery/computer/rdconsole/multitool_act(mob/user, obj/item/I) + if(!I.tool_behaviour == TOOL_MULTITOOL) + return var/lathe = linked_lathe && linked_lathe.multitool_act(user, I) var/print = linked_imprinter && linked_imprinter.multitool_act(user, I) return lathe || print diff --git a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm index c35f062739..f3e14993ed 100644 --- a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm +++ b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm @@ -469,6 +469,10 @@ qdel(src) return ..() +/datum/status_effect/stabilized/Destroy() + linked_extract = null + return ..() + /datum/status_effect/stabilized/null //This shouldn't ever happen, but just in case. id = "stabilizednull" @@ -884,7 +888,8 @@ /datum/status_effect/stabilized/oil/tick() if(owner.stat == DEAD) explosion(get_turf(owner),1,2,4,flame_range = 5) - owner.remove_status_effect(/datum/status_effect/stabilized/oil) + qdel(linked_extract) + return return ..() /datum/status_effect/stabilized/black diff --git a/code/modules/shuttle/spaceship_navigation_beacon.dm b/code/modules/shuttle/spaceship_navigation_beacon.dm index 7488bdd205..dbf81d791e 100644 --- a/code/modules/shuttle/spaceship_navigation_beacon.dm +++ b/code/modules/shuttle/spaceship_navigation_beacon.dm @@ -39,7 +39,9 @@ . = ..() update_icon() -/obj/machinery/spaceship_navigation_beacon/multitool_act(mob/living/user, obj/item/multitool/I) +/obj/machinery/spaceship_navigation_beacon/multitool_act(mob/living/user, obj/item/I) + if(!I.tool_behaviour == TOOL_MULTITOOL) + return if(panel_open) var/new_name = "Beacon_[input("Enter the custom name for this beacon", "It be Beacon ..your input..") as text]" if(new_name && Adjacent(user)) diff --git a/code/modules/spells/spell_types/shapeshift.dm b/code/modules/spells/spell_types/shapeshift.dm index e513865246..67c2e3e941 100644 --- a/code/modules/spells/spell_types/shapeshift.dm +++ b/code/modules/spells/spell_types/shapeshift.dm @@ -78,7 +78,7 @@ desc = "Take on the shape a lesser ash drake." invocation = "RAAAAAAAAWR!" - shapeshift_type = /mob/living/simple_animal/hostile/megafauna/dragon/lesser + shapeshift_type = /mob/living/simple_animal/hostile/megafauna/dragon/lesser/transformed /obj/shapeshift_holder diff --git a/code/modules/station_goals/bsa.dm b/code/modules/station_goals/bsa.dm index 9ebcfe91d6..cb1fdcfc2e 100644 --- a/code/modules/station_goals/bsa.dm +++ b/code/modules/station_goals/bsa.dm @@ -41,9 +41,8 @@ icon_state = "power_box" /obj/machinery/bsa/back/multitool_act(mob/living/user, obj/item/I) - if(istype(I, /obj/item/multitool)) // Only this multitool type has a data buffer. - var/obj/item/multitool/M = I - M.buffer = src + if(I.tool_behaviour == TOOL_MULTITOOL) // Lies and deception + I.buffer = src to_chat(user, "You store linkage information in [I]'s buffer.") else to_chat(user, "[I] has no data buffer!") @@ -55,9 +54,8 @@ icon_state = "emitter_center" /obj/machinery/bsa/front/multitool_act(mob/living/user, obj/item/I) - if(istype(I, /obj/item/multitool)) // Only this multitool type has a data buffer. - var/obj/item/multitool/M = I - M.buffer = src + if(I.tool_behaviour == TOOL_MULTITOOL) // Lies and deception + I.buffer = src to_chat(user, "You store linkage information in [I]'s buffer.") else to_chat(user, "[I] has no data buffer!") @@ -71,16 +69,15 @@ var/obj/machinery/bsa/front/front /obj/machinery/bsa/middle/multitool_act(mob/living/user, obj/item/I) - if(istype(I, /obj/item/multitool)) // Only this multitool type has a data buffer. - var/obj/item/multitool/M = I - if(M.buffer) - if(istype(M.buffer, /obj/machinery/bsa/back)) - back = M.buffer - M.buffer = null + if(I.tool_behaviour == TOOL_MULTITOOL) // Lies and deception + if(I.buffer) + if(istype(I.buffer, /obj/machinery/bsa/back)) + back = I.buffer + I.buffer = null to_chat(user, "You link [src] with [back].") - else if(istype(M.buffer, /obj/machinery/bsa/front)) - front = M.buffer - M.buffer = null + else if(istype(I.buffer, /obj/machinery/bsa/front)) + front = I.buffer + I.buffer = null to_chat(user, "You link [src] with [front].") else to_chat(user, "[I]'s data buffer is empty!") diff --git a/code/modules/station_goals/shield.dm b/code/modules/station_goals/shield.dm index c8fbda8988..e317820e7d 100644 --- a/code/modules/station_goals/shield.dm +++ b/code/modules/station_goals/shield.dm @@ -122,7 +122,7 @@ icon_state = active ? "sat_active" : "sat_inactive" /obj/machinery/satellite/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/multitool)) + if(I.tool_behaviour == TOOL_MULTITOOL) to_chat(user, "// NTSAT-[id] // Mode : [active ? "PRIMARY" : "STANDBY"] //[(obj_flags & EMAGGED) ? "DEBUG_MODE //" : ""]") else return ..() diff --git a/code/modules/surgery/advanced/toxichealing.dm b/code/modules/surgery/advanced/toxichealing.dm index 0e0fd10c1c..376fb43c31 100644 --- a/code/modules/surgery/advanced/toxichealing.dm +++ b/code/modules/surgery/advanced/toxichealing.dm @@ -24,6 +24,13 @@ /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/initiate(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, try_to_fail = FALSE) + if(..()) + while((target.getToxLoss() >= 1) || (target.getOxyLoss() >= 1)) + . = ..() + if(!.) + break + /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 diff --git a/code/modules/surgery/bodyparts/robot_bodyparts.dm b/code/modules/surgery/bodyparts/robot_bodyparts.dm index d08d8bfa09..07b7ae1456 100644 --- a/code/modules/surgery/bodyparts/robot_bodyparts.dm +++ b/code/modules/surgery/bodyparts/robot_bodyparts.dm @@ -209,7 +209,7 @@ else src.flash1 = F to_chat(user, "You insert the flash into the eye socket.") - else if(istype(W, /obj/item/crowbar)) + else if(W.tool_behaviour == TOOL_CROWBAR) if(flash1 || flash2) W.play_tool_sound(src) to_chat(user, "You remove the flash from [src].") diff --git a/code/modules/surgery/dental_implant.dm b/code/modules/surgery/dental_implant.dm index 311c886c9d..f41f299439 100644 --- a/code/modules/surgery/dental_implant.dm +++ b/code/modules/surgery/dental_implant.dm @@ -36,6 +36,6 @@ log_combat(owner, null, "swallowed an implanted pill", target) if(target.reagents.total_volume) target.reagents.reaction(owner, INGEST) - target.reagents.trans_to(owner, target.reagents.total_volume, log = TRUE) + target.reagents.trans_to(owner, target.reagents.total_volume, log = "dental pill swallow") qdel(target) return 1 diff --git a/code/modules/surgery/organs/eyes.dm b/code/modules/surgery/organs/eyes.dm index a088eb2e4f..09f0a901a3 100644 --- a/code/modules/surgery/organs/eyes.dm +++ b/code/modules/surgery/organs/eyes.dm @@ -404,6 +404,7 @@ on_mob.set_light(1, 1, current_color_string) /obj/effect/abstract/eye_lighting + mouse_opacity = MOUSE_OPACITY_TRANSPARENT var/obj/item/organ/eyes/robotic/glow/parent /obj/effect/abstract/eye_lighting/Initialize() diff --git a/code/modules/surgery/organs/tongue.dm b/code/modules/surgery/organs/tongue.dm index a3edfc2887..7cba3d358a 100644 --- a/code/modules/surgery/organs/tongue.dm +++ b/code/modules/surgery/organs/tongue.dm @@ -25,6 +25,7 @@ /datum/language/slime, /datum/language/vampiric, /datum/language/dwarf, + /datum/language/signlanguage, )) healing_factor = STANDARD_ORGAN_HEALING*5 //Fast!! decay_factor = STANDARD_ORGAN_DECAY/2 diff --git a/code/modules/surgery/organs/vocal_cords.dm b/code/modules/surgery/organs/vocal_cords.dm index 47b504c86e..0e6456e8b0 100644 --- a/code/modules/surgery/organs/vocal_cords.dm +++ b/code/modules/surgery/organs/vocal_cords.dm @@ -1,4 +1,5 @@ #define COOLDOWN_STUN 1200 +#define COOLDOWN_KNOCKDOWN 600 #define COOLDOWN_DAMAGE 600 #define COOLDOWN_MEME 300 #define COOLDOWN_NONE 100 @@ -213,7 +214,6 @@ var/static/regex/stun_words = regex("stop|wait|stand still|hold on|halt") var/static/regex/knockdown_words = regex("drop|fall|trip|knockdown") - var/static/regex/sleep_words = regex("sleep|slumber|rest") var/static/regex/vomit_words = regex("vomit|throw up|sick") var/static/regex/silence_words = regex("shut up|silence|be silent|ssh|quiet|hush") var/static/regex/hallucinate_words = regex("see the truth|hallucinate") @@ -264,26 +264,20 @@ cooldown = COOLDOWN_STUN for(var/V in listeners) var/mob/living/L = V - L.Stun(60 * power_multiplier) + L.Stagger(60 * power_multiplier) //KNOCKDOWN else if(findtext(message, knockdown_words)) - cooldown = COOLDOWN_STUN + cooldown = COOLDOWN_KNOCKDOWN for(var/V in listeners) var/mob/living/L = V - L.DefaultCombatKnockdown(60 * power_multiplier) - - //SLEEP - else if((findtext(message, sleep_words))) - cooldown = COOLDOWN_STUN - for(var/mob/living/carbon/C in listeners) - C.Sleeping(40 * power_multiplier) + L.DefaultCombatKnockdown() //VOMIT else if((findtext(message, vomit_words))) - cooldown = COOLDOWN_STUN + cooldown = COOLDOWN_DAMAGE for(var/mob/living/carbon/C in listeners) - C.vomit(10 * power_multiplier, distance = power_multiplier) + C.vomit(10 * power_multiplier, distance = power_multiplier, stun = FALSE) //SILENCE else if((findtext(message, silence_words))) @@ -835,7 +829,7 @@ if(HAS_TRAIT(L, TRAIT_MASO)) if(ishuman(L)) var/mob/living/carbon/human/H = L - H.adjust_arousal(3*power_multiplier,maso = TRUE) + H.adjust_arousal(3*power_multiplier,"velvet speech", maso = TRUE) 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 diff --git a/code/modules/tcg/cards.dm b/code/modules/tcg/cards.dm new file mode 100644 index 0000000000..f5c7c47aaf --- /dev/null +++ b/code/modules/tcg/cards.dm @@ -0,0 +1,822 @@ +#define TAPPED_ANGLE 90 +#define UNTAPPED_ANGLE 0 + +#define COMMON_SERIES list(/datum/tcg_card/pack_1, /datum/tcg_card/exodia) //So star cards don't drop + +/datum/tcg_card + var/name = "Stupid Coder" + var/desc = "A coder that fucked up this card. Report if you see this." + var/rules = "Tap this card. It will ahelp itself" + var/icon_state = "cardback" + var/pack = 'icons/obj/tcg/pack_1.dmi' + + var/mana_cost = 0 + var/attack = 0 + var/health = 0 + + var/faction = "Coderbus" + var/rarity = "Stoopid" + var/card_type = "Unit" + + var/obj/item/tcg_card/card + +/*Uncomment if you want to make the game automatic + +/datum/tcg_card/proc/Use(datum/tcg_card/affected_card, mob/living/user) + if(card_type == "Equipment") + affected_card.health += health + affected_card.attack += attack + to_chat(user, "You use [card] on [affected_card.card], upgrading it's stats.") + user.emote("uses [card] on [affected_card.card], upgrading it's stats.") //To get that visible emote. Useful if you want nice gameplay + else if (card_type == "Unit") + affected_card.health -= attack + health -= affected_card.attack + var/flavortext = "." + if(affected_card.health <= 0) + flavortext = ", killing [affected_card.card]!" + if(health <= 0) + flavortext = ", killing both [affected_card.card] and [card]!" + else + flavortext = ", killing [card] in the process!" + to_chat(user, "You attack [affected_card.card] with [card][flavortext]") + user.emote("attacks [affected_card.card] with [card][flavortext]") + +*/ + +/datum/tcg_card/proc/UseSelf(mob/living/user) + return + +/datum/tcg_card/proc/Tap(mob/living/user) //Actually runtimes on tap! Tapping is basically disabling a card for a turn in exchange for special effects + if(type == /datum/tcg_card) + log_runtime("[user] managed to get a blank TCG card.") + +/datum/tcg_card/proc/Untap(mob/living/user) + return + +/datum/tcg_card/proc/Reset(mob/living/user) + to_chat(user, "You reset [card]'s stats to original.") + mana_cost = initial(mana_cost) + rules = initial(rules) + health = initial(health) + attack = initial(attack) + faction = initial(faction) + +/obj/item/tcg_card + name = "TCG card" + desc = "A flipped TCG-branded card." + icon_state = "cardback" + icon = 'icons/obj/tcg/pack_1.dmi' + + var/datum_type = /datum/tcg_card + var/datum/tcg_card/card_datum + + w_class = WEIGHT_CLASS_TINY + + var/flipped = FALSE + var/tapped = FALSE + var/special = FALSE + var/illegal = FALSE + +/obj/item/tcg_card/special + special = TRUE + +/obj/item/tcg_card/examine(mob/user) + . = ..() + sleep(2) //So it prints this shit after the examine + if(flipped) + return + to_chat(user, "This card has following stats:") + to_chat(user, "Mana cost: [card_datum.mana_cost]") + to_chat(user, "Health: [card_datum.health]") + to_chat(user, "Attack: [card_datum.attack]") + to_chat(user, "Faction: [card_datum.faction]") + to_chat(user, "Rarity: [card_datum.rarity]") + to_chat(user, "Card Type: [card_datum.card_type]") + to_chat(user, "It's effect is: [card_datum.rules]") + if(illegal) + to_chat(user, "It's a low-quality copy of a real card. TCG Gaming Community won't probably accept it.") //Doesn't do crap, just for lulz + +/obj/item/tcg_card/openTip(location, control, params, user) //Overriding for nice UI + if(flipped) + return ..() + var/desc_content = "[desc]
\ + This card has following stats:
\ + Mana cost: [card_datum.mana_cost]
\ + Health: [card_datum.health]
\ + Attack: [card_datum.attack]
\ + Faction: [card_datum.faction]
\ + Rarity: [card_datum.rarity]
\ + Card Type: [card_datum.card_type]
\ + It's effect is: [card_datum.rules]" + openToolTip(user,src,params,title = name,content = desc_content,theme = "") + +/obj/item/tcg_card/New(loc, new_datum, illegal_card = FALSE) + . = ..() + if(!special) + datum_type = new_datum + card_datum = new datum_type + icon = card_datum.pack + icon_state = card_datum.icon_state + name = card_datum.name + desc = card_datum.desc + illegal = illegal_card + + switch(card_datum.rarity) + if("Common") + grind_results = list(/datum/reagent/card_powder/green = 1) + if("Rare") + grind_results = list(/datum/reagent/card_powder/blue = 1) + if("Epic") + grind_results = list(/datum/reagent/card_powder/purple = 1) + if("Legendary") + grind_results = list(/datum/reagent/card_powder/yellow = 1) + if("Exodia") + grind_results = list(/datum/reagent/card_powder/black = 1) + +/obj/item/tcg_card/attack_hand(mob/user) + var/list/possible_actions = list( + "Pick Up" = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_pickup"), + "Tap" = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_tap"), + "Flip" = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_flip") + ) + var/result = show_radial_menu(user, src, possible_actions, require_near = TRUE, tooltips = TRUE) + switch(result) + if("Pick Up") + . = ..() + if("Flip") + flipped = !flipped + if(flipped) + icon_state = "cardback" + name = "TCG card" + desc = "A flipped TCG-branded card." + else + name = card_datum.name + desc = card_datum.desc + icon_state = card_datum.icon_state + if("Tap") + var/matrix/ntransform = matrix(transform) + if(tapped) + ntransform.TurnTo(TAPPED_ANGLE , UNTAPPED_ANGLE) + else + ntransform.TurnTo(UNTAPPED_ANGLE , TAPPED_ANGLE) + tapped = !tapped + animate(src, transform = ntransform, time = 2, easing = (EASE_IN|EASE_OUT)) + if(tapped) + card_datum.Tap(user) + else + card_datum.Untap(user) + +/obj/item/tcg_card/attackby(obj/item/I, mob/living/user, params) + if(istype(I, /obj/item/tcg_card)) + var/obj/item/tcg_card/second_card = I + if(loc == user && second_card.loc == user) + var/obj/item/tcgcard_hand/hand = new(get_turf(user)) + src.forceMove(hand) + second_card.forceMove(hand) + hand.cards.Add(src) + hand.cards.Add(second_card) + user.put_in_hands(hand) + hand.update_icon() + return ..() + var/obj/item/tcgcard_deck/new_deck = new /obj/item/tcgcard_deck(drop_location()) + new_deck.flipped = flipped + user.transferItemToLoc(second_card, new_deck)//Start a new pile with both cards, in the order of card placement. + user.transferItemToLoc(src, new_deck) + new_deck.update_icon_state() + new_deck.update_icon() + if(istype(I, /obj/item/tcgcard_deck)) + var/obj/item/tcgcard_deck/old_deck = I + if(length(old_deck.contents) >= 30) + to_chat(user, "This pile has too many cards for a regular deck!") + return + user.transferItemToLoc(src, old_deck) + flipped = old_deck.flipped + old_deck.update_icon() + update_icon() + return ..() + +/obj/item/tcg_card/attack_self(mob/user) + var/list/possible_actions = list( + "Reset to Default" = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_reset"), + "Change stats" = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_change_stats") + ) + var/result = show_radial_menu(user, src, possible_actions, require_near = TRUE, tooltips = TRUE) + switch(result) + if("Reset to Default") + card_datum.Reset(user) + user.visible_message("[user] resets [src]'s stats.") + if("Change stats") + possible_actions = list( + "Health" = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_health"), + "Attack" = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_attack"), + "Mana" = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_mana") + ) + result = show_radial_menu(user, src, possible_actions, require_near = TRUE, tooltips = TRUE) + switch(result) + if("Health") + card_datum.health = input(user, "What do you want health to be?", "Changing [src]'s health") as num|null + if("Attack") + card_datum.attack = input(user, "What do you want attack to be?", "Changing [src]'s attack") as num|null + if("Mana") + card_datum.mana_cost = input(user, "What do you want mana cost to be?", "Changing [src]'s mana cost") as num|null + user.visible_message("[user] changes [src]'s [result].") + +/obj/item/tcg_card/equipped(mob/user, slot, initial) + . = ..() + transform = matrix() + +/obj/item/tcg_card/dropped(mob/user, silent) + . = ..() + transform = matrix(0.5,0,0,0,0.5,0) + +/obj/item/cardpack + name = "Trading Card Pack: Coder" + desc = "Contains six complete fuckups by the coders. Report this on github please!" + icon = 'icons/obj/tcg/misc.dmi' + icon_state = "cardpack" + w_class = WEIGHT_CLASS_TINY + ///The card series to look in + var/list/series = list(/datum/tcg_card/pack_1, /datum/tcg_card/exodia) + ///Chance of the pack having a coin in it out of 10 + var/contains_coin = -1 + ///The amount of cards to draw from the rarity table + var/card_count = 5 + ///The rarity table, the set must contain at least one of each + var/list/rarity_table = list( + "Common" = 900, + "Rare" = 300, + "Epic" = 50, + "Legendary" = 3, + "Exodia" = 1) //Basically 0.1%, it doesn't have guar. rarity + ///The amount of cards to draw from the guarenteed rarity table + var/guaranteed_count = 1 + ///The guaranteed rarity table, acts about the same as the rarity table. it can have as many or as few raritys as you'd like + var/list/guar_rarity = list( + "Legendary" = 1, + "Epic" = 9, + "Rare" = 30) + + var/illegal = FALSE //Can cargo get it? + + custom_price = PRICE_EXPENSIVE + +/obj/item/cardpack/series_one + name = "Trading Card Pack: 2560 Core Set" + desc = "Contains six cards of varying rarity from the 2560 Core Set. Collect them all!" + icon_state = "cardpack" + series = list(/datum/tcg_card/pack_1, /datum/tcg_card/exodia) + contains_coin = 10 + +/obj/item/cardpack/syndicate //More cards. Perfect stuff for gaming gang + name = "Trading Card Pack: Nuclear Danger" + desc = "Contains twelve cards of varying rarity from 2560 Core Set and 2560 Nuclear Danger. This pack was stamped by Waffle Co." + icon_state = "cardpack_syndicate" + series = list(/datum/tcg_card/pack_1, /datum/tcg_card/pack_nuclear) + contains_coin = 100 + + card_count = 9 + guaranteed_count = 3 + + illegal = TRUE + + guar_rarity = list( //Better chances + "Legendary" = 5, + "Epic" = 10, + "Rare" = 30) + +/obj/item/cardpack/equipped(mob/user, slot, initial) + . = ..() + transform = matrix() + +/obj/item/cardpack/dropped(mob/user, silent) + . = ..() + transform = matrix(0.5,0,0,0,0.5,0) + +/obj/item/cardpack/attack_self(mob/user) + . = ..() + var/list/cards = buildCardListWithRarity(card_count, guaranteed_count) + var/obj/item/tcgcard_hand/hand = new(get_turf(user)) + for(var/template in cards) + var/obj/item/tcg_card/card = new(hand, template, illegal) + hand.cards.Add(card) + user.put_in_hands(hand) + hand.update_icon() + to_chat(user, "Wow! Check out these cards!
") + playsound(loc, 'sound/items/poster_ripped.ogg', 20, TRUE) + if(prob(contains_coin)) + to_chat(user, "...and it came with a flipper, too!
") + new /obj/item/coin/thunderdome(get_turf(user)) + new /obj/item/paper/tcg_rules(get_turf(user)) + qdel(src) + +/obj/item/cardpack/proc/buildCardListWithRarity(card_cnt, rarity_cnt) + var/list/return_cards = list() + + var/list/cards = list() + for(var/card_type in series) + for(var/card in subtypesof(card_type)) + var/datum/tcg_card/new_card = new card() + if(new_card.name == "Stupid Coder") + continue + cards.Add(card) + qdel(new_card) + var/list/possible_cards = list() + var/list/rarity_cards = list("Exodia" = list(), "Legendary" = list(), "Epic" = list(), "Rare" = list(), "Common" = list()) + for(var/card in cards) + var/datum/tcg_card/new_card = new card() + if(new_card.name == "Stupid Coder") + continue + possible_cards[card] = rarity_table[new_card.rarity] + var/list/rarity_card_type = rarity_cards[new_card.rarity] + if(!rarity_card_type) + rarity_card_type = list() + rarity_card_type.Add(card) + rarity_cards[new_card.rarity] = rarity_card_type //FUCK CI + qdel(new_card) + + for(var/card_counter = 1 to card_count) + var/cardtype = pickweight(possible_cards) + return_cards.Add(cardtype) + + for(var/card_counter = 1 to guaranteed_count) + var/card_list = pickweight(guar_rarity) + return_cards.Add(pick(rarity_cards[card_list])) + + return return_cards + +/obj/item/coin/thunderdome + name = "Thunderdome Flipper" + desc = "A Thunderdome TCG flipper, for deciding who gets to go first. Also conveniently acts as a counter, for various purposes." + icon = 'icons/obj/tcg/misc.dmi' + icon_state = "coin_nanotrasen" + custom_materials = list(/datum/material/plastic = 400) + material_flags = NONE + sideslist = list("nanotrasen", "syndicate") + +/obj/item/coin/thunderdome/Initialize() + . = ..() + transform = matrix(0.5,0,0,0,0.5,0) + +/obj/item/coin/thunderdome/equipped(mob/user, slot, initial) + . = ..() + transform = matrix() + +/obj/item/coin/thunderdome/dropped(mob/user, silent) + . = ..() + transform = matrix(0.5,0,0,0,0.5,0) + +/obj/item/tcgcard_deck + name = "Trading Card Pile" + desc = "A stack of TCG cards." + icon = 'icons/obj/tcg/misc.dmi' + icon_state = "deck_up" + + var/flipped = FALSE + + var/static/radial_draw = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_draw") + var/static/radial_shuffle = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_shuffle") + var/static/radial_pickup = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_pickup") + +/obj/item/tcgcard_deck/Initialize() + . = ..() + LoadComponent(/datum/component/storage/concrete/tcg) + +/obj/item/tcgcard_deck/ComponentInitialize() + . = ..() + var/datum/component/storage/STR = GetComponent(/datum/component/storage/concrete/tcg) + STR.storage_flags = STORAGE_FLAGS_LEGACY_DEFAULT + STR.max_volume = DEFAULT_VOLUME_TINY * 30 + STR.max_w_class = DEFAULT_VOLUME_TINY + STR.max_items = 30 + +/obj/item/tcgcard_deck/update_icon_state() + . = ..() + if(flipped) + switch(contents.len) + if(1 to 10) + icon_state = "deck_low" + if(11 to 20) + icon_state = "deck_half" + if(21 to INFINITY) + icon_state = "deck_full" + else + icon_state = "deck_up" + +/obj/item/tcgcard_deck/examine(mob/user) + . = ..() + . += "\The [src] has [contents.len] cards inside." + +/obj/item/tcgcard_deck/attack_hand(mob/user) + var/list/choices = list( + "Draw" = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_draw"), + "Shuffle" = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_shuffle"), + "Pickup" = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_pickup"), + "Flip" = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_flip"), + ) + var/choice = show_radial_menu(user, src, choices, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = TRUE, tooltips = TRUE) + if(!check_menu(user)) + return + switch(choice) + if("Draw") + draw_card(user) + if("Shuffle") + shuffle_deck(user) + if("Pickup") + user.put_in_hands(src) + if("Flip") + flip_deck() + +/obj/item/tcgcard_deck/Destroy() + for(var/card in 1 to contents.len) + var/obj/item/tcg_card/stored_card = contents[card] + stored_card.forceMove(drop_location()) + . = ..() + +/obj/item/tcgcard_deck/proc/check_menu(mob/living/user) + if(!istype(user)) + return FALSE + if(user.incapacitated() || !user.Adjacent(src)) + return FALSE + return TRUE + +/obj/item/tcgcard_deck/attackby(obj/item/I, mob/living/user, params) + . = ..() + if(istype(I, /obj/item/tcg_card)) + if(contents.len > 30) + to_chat(user, "This pile has too many cards for a regular deck!") + return FALSE + var/obj/item/tcg_card/new_card = I + new_card.flipped = flipped + new_card.forceMove(src) + + if(istype(I, /obj/item/tcgcard_hand)) + var/obj/item/tcgcard_hand/hand = I + for(var/obj/item/tcg_card/card in hand.cards) + if(contents.len > 30) + return FALSE + card.flipped = flipped + card.forceMove(src) + hand.cards.Remove(card) + +/obj/item/tcgcard_deck/attack_self(mob/living/carbon/user) + shuffle_deck(user) + return ..() + +/obj/item/tcgcard_deck/proc/draw_card(mob/user) + if(!contents.len) + CRASH("A TCG deck was created with no cards inside of it.") + var/obj/item/tcg_card/drawn_card = contents[contents.len] + user.put_in_hands(drawn_card) + drawn_card.flipped = flipped //If it's a face down deck, it'll be drawn face down, if it's a face up pile you'll draw it face up. + drawn_card.update_icon_state() + user.visible_message("[user] draws a card from \the [src]!", \ + "You draw a card from \the [src]!") + if(contents.len <= 1) + var/obj/item/tcg_card/final_card = contents[1] + user.transferItemToLoc(final_card, drop_location()) + qdel(src) + +/obj/item/tcgcard_deck/proc/shuffle_deck(mob/user, visable = TRUE) + if(!contents) + return + contents = shuffle(contents) + if(user.active_storage) + user.active_storage.close(user) + if(visable) + user.visible_message("[user] shuffles \the [src]!", \ + "You shuffle \the [src]!") + +/obj/item/tcgcard_deck/proc/flip_deck() + flipped = !flipped + var/list/temp_deck = contents.Copy() + contents = reverseRange(temp_deck) + //Now flip the cards to their opposite positions. + for(var/a in 1 to contents.len) + var/obj/item/tcg_card/nu_card = contents[a] + nu_card.flipped = flipped + nu_card.update_icon_state() + update_icon_state() + +/obj/item/tcgcard_hand + name = "Trading Card Hand" + desc = "A hand full of TCG cards." + icon = 'icons/effects/effects.dmi' + icon_state = "nothing" + w_class = WEIGHT_CLASS_TINY + var/list/cards = list() + +/obj/item/tcgcard_hand/update_icon() + . = ..() + cut_overlays() + var/angular = length(cards) / 2 * -30 + 15 + for(var/obj/item/tcg_card/card in cards) + var/image/I = image(icon = card.icon, icon_state = card.icon_state) + var/matrix/ntransform = matrix(I.transform) + ntransform.TurnTo(angular, 0) + ntransform.Translate(sin(angular) * -15, cos(angular) * 15) + I.transform = ntransform + angular += 30 + overlays += I + +/obj/item/tcgcard_hand/attackby(obj/item/I, mob/living/user, params) + if(istype(I, /obj/item/tcg_card)) + var/obj/item/tcg_card/card = I + if(loc == user && card.loc == user) + card.forceMove(src) + cards.Add(card) + update_icon() + . = ..() + +/obj/item/tcgcard_hand/attack_hand(mob/living/carbon/user) + if(loc == user) + var/list/choices = list() + for(var/obj/item/tcg_card/card in cards) + choices[card] = image(icon = card.icon, icon_state = card.icon_state) + var/obj/item/tcg_card/choice = show_radial_menu(user, src, choices, require_near = TRUE, tooltips = TRUE) + if(choice) + choice.forceMove(get_turf(src)) + user.put_in_hands(choice) + cards.Remove(choice) + update_icon() + if(length(cards) == 0) + qdel(src) + return + . = ..() + +/obj/item/tcgcard_hand/equipped(mob/user, slot, initial) + . = ..() + transform = matrix() + +/obj/item/tcgcard_hand/dropped(mob/user, silent) + . = ..() + transform = matrix(0.5,0,0,0,0.5,0) + +/obj/item/tcgcard_binder + name = "Trading Card Binder" + desc = "A TCG-branded card binder, specifically for your infinite collection of TCG cards!" + icon = 'icons/obj/tcg/misc.dmi' + icon_state = "binder" + w_class = WEIGHT_CLASS_SMALL + + var/list/cards = list() + var/list/decks = list() + var/mode = 0 //If 1, will show all the cards even if you don't have em. If 2, will show your decks + +/obj/item/tcgcard_binder/attackby(obj/item/I, mob/living/user, params) + if(istype(I, /obj/item/tcg_card)) + var/obj/item/tcg_card/card = I + card.forceMove(src) + cards.Add(card) + if(istype(I, /obj/item/tcgcard_hand)) + var/obj/item/tcgcard_hand/hand = I + for(var/obj/item/tcg_card/card in hand.cards) + card.forceMove(src) + cards.Add(card) + qdel(I) + if(istype(I, /obj/item/tcgcard_deck)) + var/obj/item/tcgcard_deck/deck = I + var/named = input(user, "How will this deck be named? Leave this field empty if you don't want to save this deck.") + if(named) + decks[named] = list() + for(var/obj/item/tcg_card/card in deck.contents) + card.forceMove(src) + cards.Add(card) + if(named) + decks[named] += card.name + qdel(I) + . = ..() + +/obj/item/tcgcard_binder/attack_self(mob/living/carbon/user) + mode = (mode + 1) % 3 + switch(mode) + if(0) + to_chat(user, "[src] now shows you the cards you already have.") + if(1) + to_chat(user, "[src] now shows you all the different cards.") + if(2) + to_chat(user, "[src] now shows you your deck menu.") + +/obj/item/tcgcard_binder/attack_hand(mob/living/carbon/user) + if(loc == user) + var/list/choices = list() + switch(mode) + if(1) + var/card_types = list() + + for(var/obj/item/tcg_card/card in cards) + card_types[card.datum_type] = card + + for(var/card_type in subtypesof(/datum/tcg_card)) + if(card_type in card_types) + var/obj/item/tcg_card/card = card_types[card_type] + choices[card] = image(icon = card.icon, icon_state = card.icon_state) + continue + + var/datum/tcg_card/card_dat = new card_type + if(card_dat.name == "Stupid Coder") + continue + var/image/I = image(icon = card_dat.pack, icon_state = card_dat.icon_state) + I.color = "#999999" + choices[card_dat.name] = I + qdel(card_dat) + if(0) + for(var/obj/item/tcg_card/card in cards) + choices[card] = image(icon = card.icon, icon_state = card.icon_state) + + if(2) + for(var/deck in decks) + choices[deck] = image(icon = 'icons/obj/tcg/misc.dmi', icon_state = "deck_up") + + var/obj/item/tcg_card/choice = show_radial_menu(user, src, choices, require_near = TRUE, tooltips = TRUE) + if(choice && (choice in cards)) + choice.forceMove(get_turf(src)) + user.put_in_hands(choice) + cards.Remove(choice) + + if(choice && (choice in decks)) + var/obj/item/tcgcard_deck/new_deck = new(get_turf(user)) + var/list/required_cards = decks[choice] + for(var/obj/item/tcg_card/card in cards) + if(card.name in required_cards) + required_cards.Remove(card.name) + cards.Remove(card) + card.forceMove(new_deck) + user.put_in_hands(new_deck) + + if(choice) + return + . = ..() + +/obj/item/tcgcard_binder/proc/check_for_exodia() + var/list/card_types = list() + for(var/obj/item/tcg_card/card in cards) + card_types.Add(card.datum_type) + + for(var/card_type in subtypesof(/datum/tcg_card)) + var/datum/tcg_card/card_dat = new card_type + + if(card_dat.name == "Eldritch Horror" && (card_type in card_types)) //We already have Exodia saved + qdel(card_dat) + return + + if(card_dat.name == "Stupid Coder" || card_dat.name == "Eldritch Horror") //It would be stupid if we require exodia or system cards to get exodia + continue + qdel(card_dat) + if(!(card_type in card_types)) + return + + var/obj/item/tcg_card/card = new(get_turf(src), /datum/tcg_card/exodia/exodia) + card.forceMove(src) + cards.Add(card) + +/obj/item/tcgcard_binder/full/Initialize() //For admemes. + . = ..() + for(var/cardtype in subtypesof(/datum/tcg_card)) + var/obj/item/tcg_card/card = new(get_turf(src), cardtype) + if(card.card_datum.name == "Stupid Coder") + qdel(card) + continue + card.forceMove(src) + cards.Add(card) + +/obj/item/paper/tcg_rules + name = "TCG Rulebook" + desc = "A small rulebook containing a starter guide for TCG." + icon = 'icons/obj/tcg/misc.dmi' + icon_state = "deck_low" + w_class = WEIGHT_CLASS_TINY + + info = "*---------* \n\ + Welcome to the Exciting world of Tactical Card Game! Sponsored by Nanotrasen Edu-tainment Devision. \n \ + Core Rules: \n \ +
\n \ + Tactical Card Game (Also known as TCG) is a traditional trading card game. It's played between two players, each with a deck or collection of cards. \n \ + +
\n \ + Each player's deck contains up to 30 cards. Each player's hand can hold a maximum of 7 cards. At the end of your turn, if you have more than 7 cards, you must choose cards to discard to your discard pile until you have 7 cards. \n \ + To begin a match, both players must flip a coin to decide who goes first. The winner of the coin toss then decides if they go first or second. Before the match begins each player draws 5 cards each with the ability to mulligan cards from their hand facedown once (Basically, you get a first pass where you can replace cards in your hands back into your deck, shuffle your deck, then draw until you're back to 5). \n \ + Each player begins with 1 Max Mana to start with, which serves as the cost to playing cards. \n \ + +
\n \ + In order to play the TCG, a deck is required. As stated above, decks must contain up to 30 cards. \n \ + Additionally, to save cards you need to have a card binder on yourself to store the cards. When the shift ends, your cards will be automatically saved by integrated scanners in your card binder. \n \ + Finally, a stock of Thunderdome Flippers to use for coin tosses and counter effects is recommended- these can be obtained occasionally from cardpacks, but any coin will do. \n \ + +
\n \ + Win condition is simple - kill your opponent's hero by depleting all of their 20 lifeshards. \n \ + +
\n \ + Gameplay Phases: \n \ + +
\n \ + A single turn of the game goes as follows, and the order of card effects is very similar to other card games. Within a single turn, the following phases are gone through, in order, unless otherwise altered by a card effect. Turn Phases are the Draw Phase, Effect Phase 1, Play Phase, Combat Phase, Effect Phase 2, and the End Phase. \n \ + +
\n \ + During the draw phase, the player whose turn it is untaps all their cards, then draws a single card. They gain 1 Max Mana, and their Mana is refilled. Cards with missing health due to defending, attacking, or damage effects return to max health at the end of the draw phase. \n \ + During the First Effect Phase, this is when effects that take place at the start of your turn would occur. If an opponent's effect takes place at the start of your turn, their effects will always take place first, then yours, unless otherwise stated by a card effect. If an opponent's effect would cause you to lose the game, and your effects would prevent that condition from happening afterwards, you would lose the game. As a general roll, when it's your turn, your opponent's effects take place FIRST, then yours. \n \ + +
\n \ + During the Play Phase, this is when you can play, summon, or activate your own cards. Card Effects that don't state when they're activated MUST be activated during the Play Phase. Your opponent can also activate their own card effects in response to one of your actions during your play phase, if able. Any card played during the play phase can activate its effect as soon as it's played. More details within the Card Breakdown section. \n \ + +
\n \ + During the Battle Phase, a Unit Card is able to battle other Unit Cards, or attack their opponent once per turn. Neither player can attack on their first turn, and all cards that enter the field can attack as soon as they can, unless it is that player's first turn, or they are prevented by a card effect. More details within the Card Combat section. \n \ + +
\n \ + During the End Phase, end of turn effects will occur. If the active player has more than 7 cards in their hand by this point, this is when they must discard cards. All of the player's cards who used an effect at any point in the turn are refreshed, and able to use their effect again going into the opponent's turn. By the end of their turn, if the player has more than 7 cards, they must discard cards from their hand until 7 remain. \n \ + After all 5 phases have passed, the players turn officially ends, and the opponent begins their turn, starting anew from the draw phase. \n \ + +
\n \ + Card effects are typically limited to the turn that that card is played. For example, a card effect that provides a card +1/+1 attack/health would only last until the end of the turn, unless otherwise stated, OR if the card is an Equipment Card. More on those below. \n \ + +
\n \ + Card Breakdown: \n \ + +
\n \ + Within the game, there are 3 kinds of cards (So far), Unit, Equipment and Spell cards. \n \ + +
\n \ + Unit Cards. All Unit Cards have 4 core values to keep in mind, Attack, Health, Faction, and Summoning Cost. Attack serves as a card's offensive value in combat. Health serves as a card's defensive value in combat, and doubles as a card's health. Factions are groupings of cards that can often share effects and traits together. Summoning Cost is how much mana a card needs in order to be summoned. \n \ + +
\n \ + Equipment Cards. All Equipment Cards similarly to Unit Cards have Attack, Health, and Summon Cost values, but for equipment, these values are added to the attached card's values. Equipment can only be attached (Equip) to units, and they last until the unit dies, or otherwise leaves the field, following it's equipt card. If returned to the hand, send to the discard pile, or otherwise leaves the field, it is detatched from the equipt card. When a Equipment Card increases a card's attack or health, those effects stay on the equip card until the equipment is unequip or removed from the parent card. \n \ + If a card would have it's health decreased by having it's equip card removed, it's handled by having it's maximum health decreased, not it's current health. For example, lets say you had a card with 1/1 attack/health, and give it an equipment giving it +1/+2, then that card enters combat, dropping it down to 2/1. If by an opponent's card effect it lost that +1/+2 equipment now, it's stats would be 1/1 once again. If an equip card explicitly lowers a card's stats, it is possible for a card to be killed as a result, but drops in attack will always bottom out at 0 attack at any given time. \n \ + +
\n \ + Spell Cards. Spell Cards don't have attack or health values, instead, they activate their effects as soon as they are summoned and leave the field afterwards(if not stated otherwise). \n \ +
\n \ + Card Subtypes: \n \ +
\n \ + Card effects: \n \ + Asimov - Unit cannot attack units with Human subtype \n \ + Changeling - Unit posesses all the subtypes at the same time \n \ + Greytide - On summon, unit gains amount of power equal to amount of other units with Greytide for 1 turn \n \ + Holy - Unit can't be targeted by spells \n \ + Taunt - All opposing unit attacks must be directed towards the unit with Taunt. \n \ + First Strike - This unit attacks first. If attacked unit is dead, unit doesn't recieve damage from it. \n \ + Deadeye - This unit can always hit opponents, regardless of effects or immunities. \n \ + Squad Tactics - When this unit attacks an opponent's unit and defeats it in combat, the owner of the defeated card takes 1 lifeshard of damage from combat. \n \ + Immunity - The unit cannot be affected by card effects or combat of its immunity type. This includes both friendly and opposing effects. \n \ + Fury - The unit must attack at every possibility. \n \ + Blocker - The unit cannot declare attacks, but can defend. \n \ + Hivemind - The unit enters combat with a hivemind token on it. The first time this card would take damage, remove that token instead. This does not apply to instant removal effects, only points of damage. \n \ + Clockwork - The unit can copy a single keyword on another unit on the field, until they lose the clockwork keyword or leave the field. \n \ +
\n \ + Card Combat: \n \ +
\n \ + Card combat is determined as follows. On your turn, any non-tapped unit card with a positive attack power is capable of declaring an attack. Upon declaring an attack, you must state if you're attacking your opponent directly, or if you're going to attack a specific opponent's unit. Unless otherwise stated, cards can only attack or defend one time per turn. \n \ +
\n \ + An attack against a unit healths as follows: Both units will do their power as damage to the opponent's unit's health. Damage is typically dealt at the same time, and if both units would kill each other through combat, both are destroyed at the same time. If One or both units would not be destroyed by combat, they would have their health reduced by the difference of their health minus their opponent's power, until the start of your next turn. If the attacker or defender has a keyword or effect that prevents them from attacking their opponent (Like silicon, immunity), then they are not able to attack, but may still defend against the opponent's attack. Once combat has healthd, all remaining participants become tapped. \n \ +
\n \ + A direct attack healths as follows: The attacking unit declares an attack against the opponent's lifeshards. Your opponent may then declare a defender if one is available, who will then turn the combat into an attack against a unit for the purposes of combat that turn. If the attack is not blocked, and the direct attack connects, then your opponent loses a number of lifeshards equal to the attacking units power.
" + +/obj/item/cardboard_card + name = "cardboard card cutout" + desc = "A small piece of cardboard shaped as a TCG card." + icon = 'icons/obj/tcg/misc.dmi' + icon_state = "template" + +/datum/reagent/card_powder/reaction_obj(obj/O, reac_volume) + if(istype(O, /obj/item/cardboard_card)) + var/list/possible_cards = list() + for(var/card_series in COMMON_SERIES) + for(var/card_type in subtypesof(card_series)) + var/datum/tcg_card/card = new card_type + if(card.rarity == rarity) + possible_cards.Add(card_type) + qdel(card) + if(length(possible_cards)) + new /obj/item/tcg_card(get_turf(O), pick(possible_cards), TRUE) + qdel(O) + + . = ..() + +/mob/living/carbon/human/proc/SaveTCGCards() + if(!client) + return + + var/obj/item/tcgcard_binder/binder = locate() in src + if(!binder) + var/obj/item/storage/backpack/back = locate() in src + binder = locate() in back + + if(!binder) + return + + var/list/card_types = list() + for(var/obj/item/tcg_card/card in binder.cards) + //if(!card.illegal) //Uncomment if you want to block syndie cards from saving + if(!(card.datum_type in card_types)) + card_types[card.datum_type] = card.illegal + else + if(islist(card_types[card.datum_type])) + card_types[card.datum_type] += card.illegal + else + card_types[card.datum_type] = list(card_types[card.datum_type], card.illegal) + + client.prefs.tcg_decks = binder.decks + client.prefs.tcg_cards = card_types + client.prefs.save_character(TRUE) + +#undef COMMON_SERIES +#undef TAPPED_ANGLE +#undef UNTAPPED_ANGLE diff --git a/code/modules/tcg/pack_1.dm b/code/modules/tcg/pack_1.dm new file mode 100644 index 0000000000..a3920fcdaa --- /dev/null +++ b/code/modules/tcg/pack_1.dm @@ -0,0 +1,1431 @@ +/datum/tcg_card/pack_1 + pack = 'icons/obj/tcg/pack_1.dmi' + +//COMMAND + +/datum/tcg_card/pack_1/captain + name = "Captain" + desc = "Nanotrasen hires a captain for every station. However, most of the time they just drink wishkey and secure the disk." + rules = "Human. Tap this card for 1 mana: inflict -1/-1 to an opposing creature card." + icon_state = "captain" + + mana_cost = 7 + attack = 5 + health = 5 + + faction = "Command" + rarity = "Epic" + card_type = "Unit" + +/datum/tcg_card/pack_1/captain_hardsuit + name = "Apadyne Technologies Mk.2 R.I.O.T. Suit (Captain's Version)" + desc = "A heavily customised Apadyne Technologies Mk.2 R.I.O.T. Suit, rebuilt and refitted to Nanotrasen's highest standards for issue to Station Captains." + rules = "On equip: Equipped unit gains +1/+1 for one turn" + icon_state = "captain_hardsuit" + + mana_cost = 3 + attack = -1 + health = 5 + + faction = "Command" + rarity = "Legendary" + card_type = "Equipment" + +/datum/tcg_card/pack_1/hop + name = "Head of Personnel" + desc = "The head of the Cargo and Service Departments, guardian of all access, and Ian's lovable, yet dumb, sidekick." + rules = "Human. Blocker. Once per turn: A friendly card of your choice attacks twice." + icon_state = "hop" + + mana_cost = 7 + attack = 4 + health = 3 + + faction = "Command" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_1/ian_hop + name = "Head of Ians" + desc = "What can be better than a corgi? A corgi with all access and HoP's hat!" + rules = "On summon: Summon a Command unit for free." + icon_state = "hop_ian" + + mana_cost = 5 + attack = 0 + health = 4 + + faction = "Command" + rarity = "Epic" + card_type = "Unit" + +/datum/tcg_card/pack_1/cmo + name = "Chief Medical Officer" + desc = "Head of the medical department, the CMO is expected to maintain the standards of his underlings." + rules = "Human. Whenever a Medical unit gains power, it gains +1 more." + icon_state = "cmo" + + mana_cost = 5 + attack = 4 + health = 4 + + faction = "Command" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/cmo_suit + name = "DeForest Medical Corporation 'Lifesaver' Carapace" + desc = "An advanced voidsuit designed for emergency medical personnel. Features include a built-in medical HUD and advanced medical gauntlets." + rules = "Tap this card: Re-equip 'DeForest Medical Corporation 'Lifesaver' Carapace' on a different friendly creature" + icon_state = "cmo_hardsuit" + + mana_cost = 3 + attack = 1 + health = 3 + + faction = "Command" + rarity = "Rare" + card_type = "Equipment" + +/datum/tcg_card/pack_1/hos + name = "Head of Security" + desc = "Nanotrasen hires most heads of staff based on their qualifications as being amicable, good at conflict resolution, ability to handle high-stakes situations, humanity, and desire to learn. Heads of Security only need a highschool degree." + rules = "Human. All opponent's cards cost 1 more until Head Of Security is removed from the battlefield." + icon_state = "hos" + + mana_cost = 7 + attack = 4 + health = 4 + + faction = "Command" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_1/hos_suit + name = "Apadyne Technologies 'Tyrant' Class Hardshell" + desc = "The distinctive shape of the Tyrant Class Hardshell is caused, in part, by the large amount of kevlar reinforcement and the ablative armour layer. Perhaps more importantly, it also looks rad." + rules = "Grant the equipped card Fury." + icon_state = "hos_hardsuit" + + mana_cost = 6 + attack = 4 + health = 2 + + faction = "Command" + rarity = "Epic" + card_type = "Equipment" + +/datum/tcg_card/pack_1/ce + name = "Chief Engineer" + desc = "The Chief Engineer is in charge of keeping the station powered and intact. Most of CE's usually fail this task." + rules = "Human. Protect a friendly card from one spell." + icon_state = "ce" + + mana_cost = 6 + attack = 3 + health = 6 + + faction = "Command" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_1/ce_suit + name = "Nakamura Engineering R.I.G.Suit (Advanced)" + desc = "An updated version of Nakamura Engineering's R.I.G.Suit fitted with advanced radiation shielding and extra armour." + rules = "On equip: Equipped creature is protected from one spell." + icon_state = "ce_hardsuit" + + mana_cost = 3 + attack = 0 + health = 3 + + faction = "Command" + rarity = "Rare" + card_type = "Equipment" + +/datum/tcg_card/pack_1/rd + name = "Research Director" + desc = "The Research Director is the head of the Science Division and is responsible for shockingly directing research." + rules = "Human. All Science card activate their effects twice." + icon_state = "rd" + + mana_cost = 7 + attack = 2 + health = 5 + + faction = "Command" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/rd_suit + name = "Nakamura Engineering B.O.M.B.Suit" + desc = "The Nakamura Engineering B.O.M.B.Suit is an innovative combination of a R.I.G.Suit and a bomb suit perfect for toxins research." + rules = "Reduces all incoming damage for 1. Does not work if damage is lethal." + icon_state = "rd_hardsuit" + + mana_cost = 3 + attack = 0 + health = 0 + + faction = "Command" + rarity = "Rare" + card_type = "Equipment" + + +//COMMAND END + +//SILICONS + +/datum/tcg_card/pack_1/ai + name = "AI" + desc = "The latest generation of NT's top secret artificial intelligence project this time with actual human brains in a jar! Don't tell the press though." + rules = "Asimov. All silicon cards gain +1/0 while this creature is alive." + icon_state = "ai" + + mana_cost = 5 + attack = 3 + health = 6 + + faction = "Silicon" + rarity = "Epic" + card_type = "Unit" + +/datum/tcg_card/pack_1/pai + name = "Personal AI Device" + desc = "Personal AI Devices are able to take the form of many household pets to provide a homely sense of comfort and companionship to their owners." + rules = "Asimov. Taunt." + icon_state = "pai" + + mana_cost = 2 + attack = 1 + health = 1 + + faction = "Silicon" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/cyborg + name = "Cyborg" + desc = "Created as part of humanity's first foray into artificial intelligence the original cyborg models used organic parts in lieu of sophisticated artificial brains." + rules = "Asimov." + icon_state = "borg_basic" + + mana_cost = 2 + attack = 3 + health = 3 + + faction = "Silicon" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/cyborg_clown + name = "Cyborg (Clown Shell)" + desc = "The clown shell is a new development in cyborg technology designed to capture the joyous hijinks of the station clown in a notably more macabre and disturbing fashion." + rules = "Asimov. Taunt." + icon_state = "borg_clown" + + mana_cost = 2 + attack = 2 + health = 4 + + faction = "Silicon" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/cyborg_engi + name = "Cyborg (Engineering Shell)" + desc = "A common sight on Nanotrasen Stations Engineering Shells maintain critical station systems in hazardous conditions." + rules = "Asimov." + icon_state = "borg_engi" + + mana_cost = 2 + attack = 4 + health = 2 + + faction = "Silicon" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_1/cyborg_sec + name = "Cyborg (Security Shell)" + desc = "Following an incident in 2554 the Security Cyborg Shell was unilaterally phased out and replaced by the Peacekeeper. Nonetheless many units remain in service with various other organisations such as private militaries." + rules = "Asimov. Can attack humans, but deals only 1 damage." + icon_state = "borg_sec" + + mana_cost = 6 + attack = 4 + health = 2 + + faction = "Silicon" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_1/cyborg_sec + name = "Cyborg (Peacekeeper Shell)" + desc = "After the unilateral phasing out of Security Shells in 2554 following mass reports of cyborg-on-human violence the Peacekeeper Shell was introduced as a stopgap solution until the problems could be resolved." + rules = "Asimov. Tap this card: Restore 2 health for a friendly creature." + icon_state = "borg_peace" + + mana_cost = 2 + attack = 4 + health = 3 + + faction = "Silicon" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/cyborg_med + name = "Cyborg (Medical Shell)" + desc = "A state of the art medical shell for when biological life just can't take care of itself. Comes equipped with built-in surgical equipment and all the medicated lollipops you could ever want." + rules = "Asimov. Loses 1 power for every Human on opponent's field." + icon_state = "borg_med" + + mana_cost = 2 + attack = 4 + health = 3 + + faction = "Silicon" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/cyborg_service + name = "Cyborg (Service Shell)" + desc = "Sometimes a cyborg just needs to show a bit of flamboyance you know?" + rules = "Asimov. Gains +2/+2 when it's the only card on your field." + icon_state = "borg_service" + + mana_cost = 1 + attack = 0 + health = 1 + + faction = "Silicon" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/cyborg_janitor + name = "Cyborg (Custodial Shell)" + desc = "A powerful state of the act cleaning machine. They exist to eradicate stains snag garbage and replace lights forever. We are legally obligated by the Janitor's Union to state that these machines are no replacement for a flesh-and-blood janitor." + rules = "Asimov. After tapping this card, tap an opponent's Human card as well." + icon_state = "borg_janitor" + + mana_cost = 2 + attack = 1 + health = 3 + + faction = "Silicon" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/cyborg_miner + name = "Cyborg (Mining Shell)" + desc = "Fitted with a drill and tracks the Mining Shell is designed to hold up to the rigours of mining be that on the hellish surface of Indecipheres or in the silent vacuum of the asteroid belt." + rules = "Asimov. Gain 1 additional mana every turn." + icon_state = "borg_miner" + + mana_cost = 2 + attack = 3 + health = 1 + + faction = "Silicon" + rarity = "Rare" + card_type = "Unit" + +//SILICONS END + +//CIVILIANS + +/datum/tcg_card/pack_1/assistant + name = "Assistant" + desc = "The lowest ladder on the Nanotrasen Employment Ladder, Assistants are employed to help out with tasks deemed 'too menial for robots'." + rules = "Greytide." + icon_state = "assistant" + + mana_cost = 1 + attack = 1 + health = 1 + + faction = "Civilian" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/greytider + name = "Greytider" + desc = "The lowest ladder on the Nanotrasen Employment Ladder, Assistants are employed to help out with tasks deemed 'too menial for robots'." + rules = "Greytide. Instead of getting +1/+1 on the first turn, get it permanently." + icon_state = "greytider" + + mana_cost = 1 + attack = 2 + health = 1 + + faction = "Civilian" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_1/bartender + name = "Bartender" + desc = "Prior to the introduction of on-station psychologists the Bartender served to alleviate many employees' woes and fears. Remember always drink responsibly." + rules = "" + icon_state = "bartender" + + mana_cost = 3 + attack = 3 + health = 2 + + faction = "Civilian" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/botanist + name = "Botanist" + desc = "The Botanist is in charge of keeping the station's food supply happy healthy and preferably not laced with hallucinogens." + rules = "" + icon_state = "botanist" + + mana_cost = 1 + attack = 1 + health = 4 + + faction = "Civilian" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/botanist + name = "Botanist" + desc = "The Botanist is in charge of keeping the station's food supply happy healthy and preferably not laced with hallucinogens." + rules = "" + icon_state = "botanist" + + mana_cost = 1 + attack = 1 + health = 4 + + faction = "Civilian" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/chaplain + name = "Chaplain" + desc = "Every station should have it's own chaplain for religious purposes. Keyword is 'Should'." + rules = "Holy" + icon_state = "chaplain" + + mana_cost = 2 + attack = 2 + health = 3 + + faction = "Civilian" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/inquisitor + name = "Inquisitor's Hardsuit" + desc = "Nanotrasen officially doesn't believe in ghosts magic or anything that can't be solved with science. When you see someone show up in one of these let that remind you of that fact." + rules = "Holy. First Strike." + icon_state = "inquisitor" + + mana_cost = 4 + attack = 2 + health = 2 + + faction = "Civilian" + rarity = "Epic" + card_type = "Equipment" + +/datum/tcg_card/pack_1/janitor + name = "Janitor" + desc = "A true testament to futility they clean and they clean and they clean knowing that there's no way they can clean it all. Yet they perservere knowing that without them the crew would simply give in to their base animalistic nature." + rules = "Taunt" + icon_state = "janitor" + + mana_cost = 1 + attack = 1 + health = 1 + + faction = "Civilian" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/lawyer + name = "Lawyer" + desc = "Nanotrasen knows the value of a good lawyer. That's why they're all working hard at our home offices defending us from frivolous labor suits from lazy no-good employees who should be working hard instead of slacking off reading trading cards." + rules = "When an opponent attacks with a creature with 3 or more power this card gains Taunt." + icon_state = "lawyer" + + mana_cost = 2 + attack = 0 + health = 4 + + faction = "Civilian" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/clown + name = "Clown" + desc = "Every Nanotrasen station has a clown on board as high command believes that a source of entertainment will reduce instances of murder-suicide on board Spinward Stations. The results of this hypothesis are as of yet unproven." + rules = "Taunt. When killed, attacking creature dies as well" + icon_state = "clown" + + mana_cost = 3 + attack = 2 + health = 4 + + faction = "Civilian" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_1/clown_hardsuit + name = "HONK Ltd. Entertainment Voidsuit" + desc = "The most advanced clown suit produced by HONK Ltd. the Entertainment Voidsuit is designed to withstand extreme conditions while still maintaining the aesthetic expected of clowns." + rules = "Give the equipped unit Taunt." + icon_state = "clown_hardsuit" + + mana_cost = 2 + attack = 1 + health = 5 + + faction = "Civilian" + rarity = "Legendary" + card_type = "Equipment" + +/datum/tcg_card/pack_1/mime + name = "Mime" + desc = "Si vous regardez attentivement dans les yeux d'un mime vous pouvez voir le tourment sans fin derrière leur façade silencieuse. C'est vraiment tragique." + rules = "Tap this card: Pick an opponent's card and nullify it's effect until it leaves play." + icon_state = "mime" + + mana_cost = 1 + attack = 2 + health = 1 + + faction = "Civilian" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_1/cook + name = "Cook" + desc = "Every Nanotrasen chef is trained in 3 cuisines of their choosing upon being hired alongside the closely guarded secret of Close Quarters Cooking." + rules = "First Strike. When attacked, gain +1/0." + icon_state = "cook" + + mana_cost = 3 + attack = 3 + health = 2 + + faction = "Civilian" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/curator + name = "Curator" + desc = "In Nanotrasen polls the Curator has ranked as the most pointless job on station much to the ire of the Curator's union. Thankfully we don't have to listen to them." + rules = "On Summon: Draw a card. If it's a spell, discard it." + icon_state = "curator" + + mana_cost = 2 + attack = 1 + health = 1 + + faction = "Civilian" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/ian + name = "Ian" + desc = "This adorable corgi has become the defacto mascot of the Spinward Stations to many. He comes in many forms many sizes and many shapes but he's still just as lovable. Hand wash only." + rules = "Holy. Taunt." + icon_state = "ian" + + mana_cost = 3 + attack = 0 + health = 2 + + faction = "Civilian" + rarity = "Rare" + card_type = "Unit" + +//CIVILIAN END + +//SECURITY + +/datum/tcg_card/pack_1/sec_officer + name = "Security Officer" + desc = "Nanotrasen would like to remind all employees to support their station security team; remember the boys in red keep you safe!" + rules = "Squad Tactics." + icon_state = "officer" + + mana_cost = 3 + attack = 2 + health = 2 + + faction = "Security" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/warden + name = "Warden" + desc = "The Warden is tasked with the herculean (and futile) feat of defending the armory and brig and never leaving his post no matter the situation." + rules = "Squad Tactics. Blocker." + icon_state = "warden" + + mana_cost = 4 + attack = 2 + health = 4 + + faction = "Security" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_1/detective + name = "Security Officer" + desc = "Nanotrasen hires nothing but the best detectives to investigate crime on our stations. A penchant for cigarettes and outdated fashion isn't mandatory but is appreciated." + rules = "Deadeye." + icon_state = "detective" + + mana_cost = 5 + attack = 3 + health = 2 + + faction = "Security" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/officer_ethereal + name = "Security Officer(Ethereal)" + desc = "A trained officer with BlueShift equipment. Wait, is he a red boy or a blue boy?" + rules = "Squad Tactics. On summon: This character can't be attacked for the first turn." + icon_state = "officer_ethereal" + + mana_cost = 6 + attack = 4 + health = 4 + + faction = "Security" + rarity = "Rare" + card_type = "Unit" + +//SECURITY END + +//RESEARCH AND DEVELOPMENT + +/datum/tcg_card/pack_1/scientist + name = "Scientist" + desc = "Rumours that Nanotrasen hires 'mad scientists' are greatly exaggerated. Scientists are regularly screened to ensure that their insanity remains within acceptable limits." + rules = "When this card is targeted by an opponent's single target spell you gain 1 lifeshard." + icon_state = "scientist" + + mana_cost = 4 + attack = 1 + health = 2 + + faction = "Research" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/scientist_moth + name = "Scientist(Moth)" + desc = "Moths are a common sight in Nanotrasen research departments acting as integral ideas guys for new clothing designs and lighting innovations." + rules = "" + icon_state = "scientist_moth" + + mana_cost = 1 + attack = 2 + health = 2 + + faction = "Research" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/roboticist + name = "Roboticist" + desc = "The roboticist's work is as close as Nanotrasen legally allows its employees to come to necromancy." + rules = "If a Asimov card on your side of the field is destroyed you may pay 2 mana and tap this card: Return that card to your hand." + icon_state = "roboticist" + + mana_cost = 3 + attack = 2 + health = 2 + + faction = "Research" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_1/monkey + name = "Monkey" + desc = "Nanotrasen seeks to phase out animal testing by 2570 in accordance with new TerraGov legislation. This will be replaced with more ethical solutions such as computer simulations or experimentation on Assistants." + rules = "Greytide. This card is considered Human with a Geneticist on your side of the field." + icon_state = "monkey" + + mana_cost = 1 + attack = 1 + health = 1 + + faction = "Research" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/geneticist + name = "Geneticist" + desc = "Geneticists are tasked with manipulating human DNA to produce special effects. Nanotrasen maintains a strict 'no superhero' policy for mutations following the Superhero Civil War of 2150." + rules = "Tap this card and pay 3 mana: Give a friendly creature Human until this card leaves the field." + icon_state = "geneticist" + + mana_cost = 3 + attack = 3 + health = 4 + + faction = "Research" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/borgi + name = "Borgi Ian" + desc = "While Ian's cyborg costume is very convincing we at the NTED would like to remind all employees that Ian has not been experimented on." + rules = "Asimov. You may sacrifice this card in play: Summon a Silicon type card from your hand worth up to double this card's cost." + icon_state = "ian_robot" + + mana_cost = 2 + attack = 0 + health = 3 + + faction = "Research" + rarity = "Rare" + card_type = "Unit" + +//SCIENCE END + +//MEDICAL + +/datum/tcg_card/pack_1/doctor + name = "Medical Doctor" + desc = "Nanotrasen's doctors are well known for their ability to treat almost any ailment known to mankind... as well as causing a fair few in the process." + rules = "Tap this card: Select a card that has less attack than this card from your graveyard and summon it to your side of the field." + icon_state = "doctor" + + mana_cost = 3 + attack = 2 + health = 3 + + faction = "Medical" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/runtime + name = "Runtime" + desc = "Runtime is the CMO's personal feline companion and is well known for her laziness. It's said that opening a tin of tuna anywhere on the station will bring her running." + rules = "You may sacrifice this card: reduce the cost of summoning a Medical card this turn by 2 mana." + icon_state = "runtime" + + mana_cost = 3 + attack = 0 + health = 1 + + faction = "Medical" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_1/chemist + name = "Chemist" + desc = "Chemists are encouraged to not set up illicit methamphetamine factories on the company's dime." + rules = "Tap this card: flip a coin. If heads: a friendly Medical card gains 0/+2. If tails an opponents unit of your choice gains +2/0." + icon_state = "chemist" + + mana_cost = 2 + attack = 0 + health = 3 + + faction = "Medical" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_1/virologist + name = "Virologist" + desc = "Officially the virologist is present on station to deal with novel diseases and ailments that originate from deep space. As everyone knows this is not what the virologist actually does." + rules = "" + icon_state = "virologist" + + mana_cost = 3 + attack = 5 + health = 1 + + faction = "Medical" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/paramedic + name = "Paramedic" + desc = "Nanotrasen encourages all paramedics to think of others before themselves- if this means running through a plasma fire to save a colleague so be it." + rules = "Taunt, First Strike" + icon_state = "paramedic" + + mana_cost = 3 + attack = 2 + health = 3 + + faction = "Medical" + rarity = "Common" + card_type = "Unit" + +//MEDICAL END + +//ENGINEERING + +/datum/tcg_card/pack_1/engineer + name = "Station Engineer" + desc = "Station Engineers maintain the intricate and delicate web of machinery that keeps you and everyone else aboard your station alive. No pressure there then." + rules = "Tap this card: Reduce the first hit taken by an ally to zero." + icon_state = "engineer" + + mana_cost = 4 + attack = 2 + health = 2 + + faction = "Engineering" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/engi_hardsuit + name = "Nakamura Engineering's R.I.G.Suit" + desc = "Nakamura Engineering's R.I.G. is a hardsuit, specifically designed for engineers working in hostile enviroments. It features good armor and is rad-proof." + rules = "" + icon_state = "engineer_hardsuit" + + mana_cost = 2 + attack = 0 + health = 3 + + faction = "Engineering" + rarity = "Common" + card_type = "Equipment" + +/datum/tcg_card/pack_1/engineer_plasmaman + name = "Station Engineer (Plasmaman)" + desc = "The ever industrious plasmamen are well suited to engineering work due to their natural radiation resistance." + rules = "Immune to all spells except Security and Syndicate ones." + icon_state = "engineer_plasmeme" + + mana_cost = 5 + attack = 2 + health = 4 + + faction = "Engineering" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_1/atmos_tech + name = "Atmospheric Technician" + desc = "The Atmospheric Technicians are tasked with keeping the station's air clean breathable and most importantly devoid of plasma." + rules = "On Summon: Search your deck for an Engineering Spell card and add it to your hand. Shuffle your deck afterward." + icon_state = "atmos_tech" + + mana_cost = 4 + attack = 2 + health = 3 + + faction = "Engineering" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/atmos_hardsuit + name = "Nakamura Atmospherics's R.I.G.Suit" + desc = "Nakamura Atmospherics's R.I.G. is just an old modified Engineering R.I.G.Suit that lacks rad-protection. Some technicans painted it blue and now it's 'fireproof'." + rules = "Equipped creature gains immunity to engineering spells." + icon_state = "atmos_tech_hardsuit" + + mana_cost = 2 + attack = 0 + health = 2 + + faction = "Engineering" + rarity = "Rare" + card_type = "Equipment" + +//ENGINEERING END + +//CARGO + +/datum/tcg_card/pack_1/cargo_tech + name = "Cargo Technician" + desc = "The grunts of Cargo. Any reports that Cargo Technicians are frequently overcome by revolutionary fervour are exaggerated." + rules = "Once per turn: Give this card -1/0 and gain 1 mana." + icon_state = "cargo_tech" + + mana_cost = 2 + attack = 3 + health = 1 + + faction = "Cargo" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/shaft_miner + name = "Shaft Miner" + desc = "When the station needs materials these are the guys who risk their lives bravely pioneering the wastes of Indecipheres to bring them in." + rules = "Tap this card: Draw one card. If it's not a spell, discard it." + icon_state = "miner" + + mana_cost = 6 + attack = 6 + health = 4 + + faction = "Cargo" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_1/citrus + name = "Citrus" + desc = "Cargo's happy sloth pal. Known for his cute sweater and always getting in the way." + rules = "Taunt. Tap this card: Tap an opponent's card until the start of your next turn." + icon_state = "citrus" + + mana_cost = 2 + attack = 0 + health = 3 + + faction = "Cargo" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/quartermaster + name = "Quartermaster" + desc = "Every Nanotrasen station has a Quartermaster who controls the flow of cargo to and from the station and by extension to and from the hands of the crew. He's not given the distinction of being a head though. His job isn't hard enough." + rules = "Permanently tap this card. All cargo cards on your side gain +2/+2 until this card leaves the play." + icon_state = "quartermaster" + + mana_cost = 10 + attack = 4 + health = 4 + + faction = "Cargo" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_1/explorer + name = "Explorer" + desc = "The Nanotrasen Explorers Corps boldly goes where humanity has never gone before. Or would if they weren't buried under mounds of bureaucracy." + rules = "Tap this card: Flip a coin if heads gain 4 mana this turn, if tails tap this card for 2 turns." + icon_state = "explorer" + + mana_cost = 2 + attack = 3 + health = 3 + + faction = "Cargo" + rarity = "Legendary" + card_type = "Unit" + +//CARGO END + +//CENTCOM + +/datum/tcg_card/pack_1/intern + name = "Intern" + desc = "All Nanotrasen interns come with 3 things: A resume a desire to learn and vague promises that they're getting paid at some point. So don't be too rough on them." + rules = "First Strike. Greytide." + icon_state = "intern" + + mana_cost = 1 + attack = 1 + health = 1 + + faction = "Centcom" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/ert_command + name = "NT P.A.V. Suit (Command)" + desc = "Issued to members of Emergency Response Teams the P.A.V. Suit gives superior protection from any threat the galaxy can throw at it. This particular model is outfitted with a sidearm holster and a sleek blue finish." + rules = "While equipped give the equipped unit Squad Tactics and First Strike." + icon_state = "ert_command" + + mana_cost = 2 + attack = 2 + health = 2 + + faction = "Centcom" + rarity = "Epic" + card_type = "Equipment" + +/datum/tcg_card/pack_1/ert_sec + name = "NT P.A.V. Suit (Security)" + desc = "Issued to members of Emergency Response Teams the P.A.V. Suit gives superior protection from any threat the galaxy can throw at it. This particular model is outfitted with bulletproof padding and an intimidating red finish." + rules = "While equipped give the equipped unit Squad Tactics." + icon_state = "ert_sec" + + mana_cost = 2 + attack = 2 + health = 1 + + faction = "Centcom" + rarity = "Rare" + card_type = "Equipment" + +/datum/tcg_card/pack_1/ert_med + name = "NT P.A.V. Suit (Medical)" + desc = "Issued to members of Emergency Response Teams the P.A.V. Suit gives superior protection from any threat the galaxy can throw at it. This particular model is outfitted with a sterile coating and a calming white finish." + rules = "While equipped give the equipped unit Squad Tactics." + icon_state = "ert_med" + + mana_cost = 2 + attack = 1 + health = 2 + + faction = "Centcom" + rarity = "Common" + card_type = "Equipment" + +/datum/tcg_card/pack_1/ert_engi + name = "NT P.A.V. Suit (Engineering)" + desc = "Issued to members of Emergency Response Teams the P.A.V. Suit gives superior protection from any threat the galaxy can throw at it. This particular model is outfitted with a welding screen and a flashy yellow finish." + rules = "While equipped give the equipped unit Squad Tactics." + icon_state = "ert_engi" + + mana_cost = 1 + attack = 1 + health = 2 + + faction = "Centcom" + rarity = "Common" + card_type = "Equipment" + +/datum/tcg_card/pack_1/deathsquad + name = "Deathsquad Officer" + desc = "There were rumors about 'Deathsquads' killing station where something horrible happened, but we remind you that's it's just a lie." + rules = "Taunt. First Strike." + icon_state = "deathsquad" + + mana_cost = 8 + attack = 8 + health = 6 + + faction = "Centcom" + rarity = "Epic" + card_type = "Unit" + +//CENTCOM END + +//ANTAGONISTS + +/datum/tcg_card/pack_1/changeling + name = "Armored Changeling" + desc = "The strange creatures known as changelings have been known to develop natural armour as a defense mechanism when in combat." + rules = "Changeling." + icon_state = "changeling" + + mana_cost = 6 + attack = 2 + health = 8 + + faction = "Syndicate" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_1/chrono_legionare + name = "Chrono Legionare" + desc = "Currently in the earliest stages of development the Chrono Legionnaire project is expected to weaponise time itself." + rules = "If this card is destroyed or discarded flip 3 coins. If the result has 2 or more heads add this card back to your hand. Otherwise send it to your graveyard." + icon_state = "chrono_legionare" + + mana_cost = 4 + attack = 6 + health = 2 + + faction = "Syndicate" + rarity = "Epic" + card_type = "Unit" + +/datum/tcg_card/pack_1/abductor_armor + name = "Combat Abductor Armor" + desc = "Recovered from the strange alien species known as the Abductors this armour is made from an extremely tough yet flexible material that has been dubbed as Alien Alloy by researchers." + rules = "Give equipped unit immunity to spells for 3 turns. Unequipped after 3 turns." + icon_state = "abductor" + + mana_cost = 6 + attack = 1 + health = 2 + + faction = "Syndicate" + rarity = "Common" + card_type = "Equipment" + +/datum/tcg_card/pack_1/wizard + name = "Wizard" + desc = "A strange men(or golem) wearing blue robes. For some reason, he looks like a total nerd." + rules = "Flip a coin every turn. If tails, deal 2 damage to any enemy unit except Holy ones. If heads, deal 2 damage to self." + icon_state = "wizard" + + mana_cost = 8 + attack = 6 + health = 4 + + faction = "Syndicate" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_1/abductor_armor + name = "Wizard Federation Standard Issue Hardsuit" + desc = "Seemingly reverse engineered from captured engineering hardsuits the iconic Wizard Federation Hardsuit is a spectacular melding of technology and magic." + rules = "On Equip: The equipped creature cannot attack targets with Holy." + icon_state = "wizard_hardsuit" + + mana_cost = 1 + attack = 3 + health = 1 + + faction = "Syndicate" + rarity = "Rare" + card_type = "Equipment" + +/datum/tcg_card/pack_1/swarmer + name = "Swarmer" + desc = "Leading researchers theorise that Swarmers were designed as some kind of vanguard for an alien invasion force which seemingly has never materialised." + rules = "Greytide." + icon_state = "swarmer" + + mana_cost = 1 + attack = 1 + health = 1 + + faction = "Syndicate" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/swarmer_beacon + name = "Swarmer Beacon" + desc = "A strange device that can construct swarmers." + rules = "Every turn: Draw a card. If it's a Swarmer, play it for free. Else, discard it." + icon_state = "swarmer_beacon" + + mana_cost = 4 + attack = 0 + health = 1 + + faction = "Syndicate" + rarity = "Epic" + card_type = "Unit" + +/datum/tcg_card/pack_1/nukie + name = "Nuclear Operative" + desc = "The frontline grunts of the syndicate army Nuclear Operatives are typically well trained and equipped for their grim duty." + rules = "Squad Tactics." + icon_state = "nukie" + + mana_cost = 4 + attack = 4 + health = 2 + + faction = "Syndicate" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_1/nukie_elite + name = "Elite Syndicate Nuclear Stormtrooper" + desc = "The best of the best of the syndicate troops elite stormtroopers can be distinguished by their black armour. Shoot on sight ask questions later!" + rules = "Squad Tactics. Fury." + icon_state = "nukie_elite" + + mana_cost = 7 + attack = 5 + health = 5 + + faction = "Syndicate" + rarity = "Epic" + card_type = "Unit" + +/datum/tcg_card/pack_1/clockwork_cultist + name = "Ratvarian Clockwork Cuirass" + desc = "Fashioned from paranormally reinforced brass the Ratvar Cult's clockwork armour is as beautiful as it is heretical." + rules = "While equipped give the equipped unit Clockwork." + icon_state = "clockwork_cultist" + + mana_cost = 4 + attack = 2 + health = 2 + + faction = "Syndicate" + rarity = "Rare" + card_type = "Equipment" + +/datum/tcg_card/pack_1/revenant + name = "Revenant" + desc = "The revenant is a spirit of pure hatred kept alive by drawing the life force of its enemies." + rules = "When a unit on dies Revenant gains 1/0." + icon_state = "revenant" + + mana_cost = 3 + attack = 2 + health = 3 + + faction = "Syndicate" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/angry_slime + name = "Crazy Slime" + desc = "An agressive slime who seeks blood. You totally should extinguish him." + rules = "When attacking, search your deck for Crazy Slime and add it to your hand. Shuffle your deck afterwards." + icon_state = "angry_slime" + + mana_cost = 2 + attack = 1 + health = 1 + + faction = "Syndicate" + rarity = "Common" + card_type = "Unit" + +//ANTAGONISTS END + +//SPELLS + +/datum/tcg_card/pack_1/adrenals + name = "Adrenals" + desc = "A potent mixture of stimulants designed to enhance a soldier's ability in the field. Technically illegal in Terragov territory but since when has that stopped anyone?" + rules = "Grant +2/+1 to a friendly unit." + icon_state = "adrenals" + + mana_cost = 1 + + faction = "Medical" + rarity = "Common" + card_type = "Spell" + +/datum/tcg_card/pack_1/defib + name = "Defibrillator" + desc = "A device that allows to re-start hearts using electricity. It also can be used as a weapon!" + rules = "Resurrect a friendly unit with 1 HP." + icon_state = "defib" + + mana_cost = 4 + + faction = "Medical" + rarity = "Rare" + card_type = "Spell" + +/datum/tcg_card/pack_1/morphine + name = "Morphine" + desc = "A sedative chemical that puts everyone who uses it into sleep." + rules = "Tap an enemy card without activating it's effect for 1 turn." + icon_state = "morphine" + + mana_cost = 2 + + faction = "Medical" + rarity = "Common" + card_type = "Spell" + +/datum/tcg_card/pack_1/bluespace + name = "Bluespace Flux" + desc = "Despite being a revolutionary new technology bluespace still has some... kinks that need sorted out." + rules = "Active for 3 turns. Every player can pay 2 mana to draw an additional card from their deck." + icon_state = "bluespace" + + mana_cost = 5 + + faction = "Research" + rarity = "Common" + card_type = "Spell" + +/datum/tcg_card/pack_1/bag_of_holding + name = "Bag Of Greed" + desc = "BAG OF GREED ALLOWS ME TO DRAW TWO MORE CARDS. I WILL START MY TURN BY PLAYING BAG OF GREED WHICH ALLOWS ME TO DRAW TWO MORE CARDS. I WILL PLAY THE EVENT CARD BAG OF GREED WHICH ALLOWS ME TO DRAW TWO NEW CARDS." + rules = "Draw 2 cards from your deck." + icon_state = "bag_of_holding" + + mana_cost = 3 + + faction = "Research" + rarity = "Common" + card_type = "Spell" + +/datum/tcg_card/pack_1/malfunction + name = "Glitch in the System" + desc = "Even a meticulously maintained AI system will eventually develop errors. Many are benign but some may cause unforeseen problems..." + rules = "Remove Asimov from one of your cards." + icon_state = "malfunction" + + mana_cost = 1 + + faction = "Research" + rarity = "Common" + card_type = "Spell" + +/datum/tcg_card/pack_1/botanist_plant + name = "Comitted Botanist" + desc = "When you've grown the plants nurtured the plants and harvested the plants there's only one place to go from there... becoming the plant." + rules = "Only usable when Botanist is on the field. This turn all service cards cost 2 mana less(but not below 1)." + icon_state = "botanist_plant" + + mana_cost = 4 + + faction = "Service" + rarity = "Rare" + card_type = "Spell" + +/datum/tcg_card/pack_1/gaia + name = "Ambrosia Gaia" + desc = "If Ambrosia is the gold of Botany the rare Gaia variety is the platinum. Almost nobody has seen this illusive plant with their own eyes." + rules = "During the draw phase you may sacrifice Ambrosia Gaia to gain 3 mana." + icon_state = "gaia" + + mana_cost = 0 + + faction = "Service" + rarity = "Legendary" + card_type = "Spell" + +/datum/tcg_card/pack_1/deep_fryer + name = "Deep Fryer" + desc = "God bless the United States of Space America." + rules = "Destroy an opponent's equipment card." + icon_state = "deep_fryer" + + mana_cost = 2 + + faction = "Service" + rarity = "Common" + card_type = "Spell" + +/datum/tcg_card/pack_1/bepis + name = "B.E.P.I.S." + desc = "God bless the United States of Space America." + rules = "Flip a coin. If heads, gain 2 mana. If tails, lose 2 mana." + icon_state = "bepis" + + mana_cost = 0 + + faction = "Cargo" + rarity = "Common" + card_type = "Spell" + +/datum/tcg_card/pack_1/economy_crash + name = "Economy Crash" + desc = "So cargo sold 20 canisters of miasma and now the galactic economy is experiencing what's known as 'a catastrophic collapse'." + rules = "All cards cost 1 more mana to play." + icon_state = "economy_crash" + + mana_cost = 2 + + faction = "Cargo" + rarity = "Common" + card_type = "Spell" + +/datum/tcg_card/pack_1/additional_supplies + name = "Additional Supplies" + desc = "Well, cargonia ordered 10 crates of buckshots and slugs. Looks like we need to dispose of them quickly." + rules = "For 3 turns, you draw an additional page every turn." + icon_state = "additional_supplies" + + mana_cost = 3 + + faction = "Cargo" + rarity = "Rare" + card_type = "Spell" + +/datum/tcg_card/pack_1/bsa_barrage + name = "BSA Barrage" + desc = "The officers at Centcom are well known for their ability to hit targets extremely accurately with their bluespace artillery especially when stupid pictures show up at their fax machine." + rules = "Destroy an opponent's unit. Deal 2 damage to all units on the field." + icon_state = "bsa_barrage" + + mana_cost = 4 + + faction = "Security" + rarity = "Rare" + card_type = "Spell" + +/datum/tcg_card/pack_1/reeducation + name = "Re-education" + desc = "Nobody ever seems to return from re-education. Probably best not to question it." + rules = "Deal 4 damage to an enemy's unit." + icon_state = "re-education" + + mana_cost = 2 + + faction = "Security" + rarity = "Common" + card_type = "Spell" + +/datum/tcg_card/pack_1/just_losses + name = "Justifiable Casualties" + desc = "The beat is hell. Officers die. The strongest they live." + rules = "Sacrifice two friendly creatures from the battlefield then summon a creature from your hand at no mana cost." + icon_state = "just_losses" + + mana_cost = 2 + + faction = "Security" + rarity = "Common" + card_type = "Spell" + +/datum/tcg_card/pack_1/sleeping_carp + name = "Sleeping Carp" + desc = "Created by the long-extinct Carp Monks of Space Tibet the Sleeping Carp style has been kept alive by dedicated practitioners and even found its way into the Syndicate's training regime." + rules = "Give a friendly unit +3/+1. Draw an additional card every turn while they are alive." + icon_state = "sleeping_carp" + + mana_cost = 6 + + faction = "Syndicate" + rarity = "Epic" + card_type = "Spell" + +/datum/tcg_card/pack_1/tough_choices + name = "Tough Choices" + desc = "Every Nanotrasen employee will at some point be forced to make a tough choice. Make sure you make the right one!" + rules = "Draw the top three cards from your deck. Summon one at no cost and discard the other two." + icon_state = "tough_choices" + + mana_cost = 2 + + faction = "Syndicate" + rarity = "Common" + card_type = "Spell" + +/datum/tcg_card/pack_1/nuclear_explosion + name = "Nuclear Explosion" + desc = "The Gorlex Marauders are well known for their nuclear weapons and their nuke first second third and fourth policy with regards to deploying them." + rules = "Kill all units on the battlefield." + icon_state = "nuclear_explosion" + + mana_cost = 5 + + faction = "Syndicate" + rarity = "Rare" + card_type = "Spell" + +/datum/tcg_card/pack_1/inducer + name = "Inducer" + desc = "The inducer is a marvelous piece of tech allowing the recharging of an internal cell without opening a machine." + rules = "Pay 3 lifeshards: Gain 3 mana this turn." + icon_state = "inducer" + + mana_cost = 0 + + faction = "Engineering" + rarity = "Rare" + card_type = "Spell" + +/datum/tcg_card/pack_1/plasmafire + name = "Atmospherics Incident" + desc = "Accidents happen." + rules = "For 3 turns, add -1/-1 to every unit." + icon_state = "plasmafire" + + mana_cost = 3 + + faction = "Engineering" + rarity = "Rare" + card_type = "Spell" + +/datum/tcg_card/pack_1/supermatter + name = "Supermatter" + desc = "A glowing crystal, made of hyper-pressurised plasma, widely known for it's radiation production." + rules = "Destroy an enemy's unit." + icon_state = "supermatter" + + mana_cost = 4 + + faction = "Engineering" + rarity = "Rare" + card_type = "Spell" diff --git a/code/modules/tcg/pack_nuclear.dm b/code/modules/tcg/pack_nuclear.dm new file mode 100644 index 0000000000..96ec174a4b --- /dev/null +++ b/code/modules/tcg/pack_nuclear.dm @@ -0,0 +1,483 @@ +/datum/tcg_card/pack_nuclear + pack = 'icons/obj/tcg/pack_nuclear.dmi' + +/datum/tcg_card/pack_nuclear/cayenne + name = "Cayenne" + desc = "A failed Syndicate experiment in weaponized space carp technology, it now serves as a lovable mascot." + rules = "Only playable when there are other Syndicate units on the field." + icon_state = "cayenne" + + mana_cost = 4 + attack = 4 + health = 3 + + faction = "Syndicate" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_nuclear/esword + name = "Energy Sword" + desc = "Hard-light sword that doesn't leave burns. Don't ask questions." + rules = "" + icon_state = "esword" + + mana_cost = 3 + attack = 2 + health = 0 + + faction = "Syndicate" + rarity = "Common" + card_type = "Equipment" + +/datum/tcg_card/pack_nuclear/stechkin + name = "Stechkin Pistol" + desc = "A small, easily concealable 10mm handgun. Has a threaded barrel for suppressors." + rules = "When equipping this card, flip it so opponent won't see it. Flip the card after the first attack." + icon_state = "stechkin" + + mana_cost = 2 + attack = 2 + health = 0 + + faction = "Syndicate" + rarity = "Common" + card_type = "Equipment" + +/datum/tcg_card/pack_nuclear/c20r + name = "C-20R SMG" + desc = "A bullpup two-round burst .45 SMG, designated 'C-20r'. Has a 'Scarborough Arms - Per falcis, per pravitas' buttstamp." + rules = "After attack, flip a coin. If heads, leave the weapon. If tails, unequip this card." + icon_state = "c20r" + + mana_cost = 4 + attack = 4 + health = 0 + + faction = "Syndicate" + rarity = "Rare" + card_type = "Equipment" + +/datum/tcg_card/pack_nuclear/l6saw + name = "L6 Saw LMG" + desc = "A heavily modified 1.95x129mm light machine gun, designated 'L6 SAW'. Has 'Aussec Armoury - 2531' engraved on the receiver below the designation." + rules = "After equipped unit dies, this card goes to the bottom of draw deck" + icon_state = "l6saw" + + mana_cost = 8 + attack = 6 + health = 0 + + faction = "Syndicate" + rarity = "Epic" + card_type = "Equipment" + +/datum/tcg_card/pack_nuclear/bulldog + name = "Bulldog Shotgun" + desc = "A semi-auto, mag-fed shotgun for combat in narrow corridors, nicknamed 'Bulldog' by boarding parties. Compatible only with specialized 8-round drum magazines." + rules = "After attack, deal 1 damage to enemy units next to the attacked one." + icon_state = "bulldog" + + mana_cost = 3 + attack = 3 + health = 0 + + faction = "Syndicate" + rarity = "Rare" + card_type = "Equipment" + +/datum/tcg_card/pack_nuclear/nuke_op_leader + name = "Nuclear Team Commander" + desc = "All commanders of elite nuclear teams are equipped with high-tier gear and weaponery. And, sometimes, gaming cards." + rules = "Squad Tactics. Give all Syndicate units on your side +1/0." + icon_state = "nuke_op_leader" + + mana_cost = 5 + attack = 3 + health = 4 + + faction = "Syndicate" + rarity = "Epic" + card_type = "Unit" + +/datum/tcg_card/pack_nuclear/nuke_op + name = "Nuclear Team Commander" + desc = "An unequipped nuclear operative, ready to buy some gear and go full ham!" + rules = "Squad Tactics. On summon: Search your deck for Syndicate equipment. Equip it on this unit. Shuffle it afterwards." + icon_state = "nuke_op" + + mana_cost = 3 + attack = 2 + health = 3 + + faction = "Syndicate" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_nuclear/dark_gygax + name = "Dark Gygax" + desc = "A lightweight exosuit, painted in a dark scheme. This model appears to have some modifications." + rules = "Squad Tactics." + icon_state = "dark_gygax" + + mana_cost = 6 + attack = 8 + health = 4 + + faction = "Syndicate" + rarity = "Epic" + card_type = "Unit" + +/datum/tcg_card/pack_nuclear/mauler + name = "Mauler" + desc = "Heavy-duty, combat exosuit, developed off of the existing Marauder model. A perfect killing machine equipped with best weaponery in the world." + rules = "Squad Tactics. Deadeye." + icon_state = "mauler" + + mana_cost = 8 + attack = 8 + health = 8 + + faction = "Syndicate" + rarity = "Legendary" + card_type = "Unit" + +/datum/tcg_card/pack_nuclear/saboteur + name = "Syndicate Saboteur Cyborg" + desc = "A streamlined engineering cyborg, equipped with covert modules. Allows to sabotage all the systems you want without being suspicious." + rules = "Block the first spell your opponent plays against your hero." + icon_state = "saboteur" + + mana_cost = 3 + attack = 1 + health = 3 + + faction = "Syndicate" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_nuclear/medic + name = "Syndicate Medical Cyborg" + desc = "A combat medical cyborg. Has limited offensive potential, but makes more than up for it with its support capabilities." + rules = "Each turn you can give one of your units 0/+1." + icon_state = "medic" + + mana_cost = 4 + attack = 1 + health = 2 + + faction = "Syndicate" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_nuclear/combat + name = "Syndicate Assault Cyborg" + desc = "A cyborg designed and programmed for systematic extermination of non-Syndicate personnel." + rules = "Squad Tactics. Fury." + icon_state = "combat" + + mana_cost = 5 + attack = 4 + health = 4 + + faction = "Syndicate" + rarity = "Epic" + card_type = "Unit" + +/datum/tcg_card/pack_nuclear/emag + name = "Cryptographic Sequencer" + desc = "It's a card with a magnetic strip attached to some circuitry." + rules = "Convert an enemy silicon unit to your side." + icon_state = "emag" + + mana_cost = 4 + + faction = "Syndicate" + rarity = "Common" + card_type = "Spell" + +/datum/tcg_card/pack_nuclear/bomb + name = "Syndicate Bomb" + desc = "A large and menacing device. Can be bolted down with a wrench." + rules = "Deal 6 damage to all units on the field after 2 turns." + icon_state = "bomb" + + mana_cost = 6 + + faction = "Syndicate" + rarity = "Rare" + card_type = "Spell" + +/datum/tcg_card/pack_nuclear/honkbomb + name = "H.O.N.K. Bomb" + desc = "A bomb filled to the brim with bananium and dehydrated clowns!" + rules = "Search your deck for up to 3 Clowns. Play them for free. Shuffle the deck afterwards." + icon_state = "honkbomb" + + mana_cost = 8 + + faction = "Syndicate" + rarity = "Epic" + card_type = "Spell" + +/datum/tcg_card/pack_nuclear/assault_pod + name = "Assault Pod" + desc = "Raining Steel. Nothing personnel, just disky." + rules = "Summon up to 3 units from your hand with 4 mana discount each." + icon_state = "assault_pod" + + mana_cost = 8 + + faction = "Syndicate" + rarity = "Epic" + card_type = "Spell" + +/datum/tcg_card/pack_nuclear/c4 + name = "C4" + desc = "A bunch of plastic explosives wired together." + rules = "Deal 2 damage to an enemy unit." + icon_state = "c4" + + mana_cost = 1 + + faction = "Syndicate" + rarity = "Common" + card_type = "Spell" + +/datum/tcg_card/pack_nuclear/emp + name = "EMP Grenade" + desc = "A modern-looking grenade which creates a powerful EMP upon activation. Do not eat." + rules = "Deal 2 damage to an enemy silicon unit." + icon_state = "emp" + + mana_cost = 0 + + faction = "Syndicate" + rarity = "Common" + card_type = "Spell" + +/datum/tcg_card/pack_nuclear/zombie + name = "Romerol Zombie" + desc = "A horrible abomination, resembling a dead human. Has green skin and red claws. Wait, is it blood dripping from them?" + rules = "After killing an enemy unit, search your deck for a Zombie and summon it for free." + icon_state = "zombie" + + mana_cost = 8 + attack = 4 + health = 3 + + faction = "Syndicate" + rarity = "Epic" + card_type = "Unit" + +/datum/tcg_card/pack_nuclear/north_star + name = "North Star Armbands" + desc = "The armbands of a deadly martial artist. Makes you pretty keen to put an end to evil in an extremely violent manner." + rules = "Equipped unit can attack twice per turn." + icon_state = "north_star" + + mana_cost = 4 + + faction = "Syndicate" + rarity = "Rare" + card_type = "Equipment" + +/datum/tcg_card/pack_nuclear/fastdetonation + name = "Big-Ass Red Button" + desc = "A menacing red button. What could it do?" + rules = "Activate all spells that require several turns to occur." + icon_state = "fastdetonation" + + mana_cost = 2 + + faction = "Syndicate" + rarity = "Common" + card_type = "Spell" + +/datum/tcg_card/pack_nuclear/rpg + name = "PML-9 Rocket Launcher" + desc = "A reusable rocket propelled grenade launcher. The words \"NT this way\" and an arrow have been written near the barrel." + rules = "When equipped unit attacks enemy units, flip a coin. If heads, destroy the unit. If tails, deal 1/2 damage instead of the full blow." + icon_state = "rpg" + + mana_cost = 8 + attack = 6 + + faction = "Syndicate" + rarity = "Legendary" + card_type = "Equipment" + +/datum/tcg_card/pack_nuclear/darkhonk + name = "Dark H.O.N.K. Mech" + desc = "Produced by \"Tyranny of Honk, INC\", this exosuit is designed as heavy clown-support. This one was painted black for maximum HONKing!" + rules = "Taunt. Squad Tactics. Blocker." + icon_state = "darkhonk" + + mana_cost = 8 + attack = 6 + health = 8 + + faction = "Syndicate" + rarity = "Epic" + card_type = "Unit" + +/datum/tcg_card/pack_nuclear/shielded_hardsuit + name = "Shielded Blood-red Hardsuit" + desc = "An advanced version of Gorlex Maradeurs' hardsuit with built-in energy shielding." + rules = "Give equipped unit First Strike." + icon_state = "shielded_hardsuit" + + mana_cost = 4 + attack = 0 + health = 4 + + faction = "Syndicate" + rarity = "Epic" + card_type = "Equipment" + +/datum/tcg_card/pack_nuclear/nuclear_disk + name = "Nuclear Authentication Disk" + desc = "Better keep this safe." + rules = "Give equipped unit Taunt. After the equipped unit dies, re-equip this card to the killer." + icon_state = "nuclear_disk" + + mana_cost = 0 + attack = 1 + health = 1 + + faction = "Syndicate" + rarity = "Epic" + card_type = "Equipment" + +/datum/tcg_card/pack_nuclear/buzzkill + name = "Buzzkill grenade" + desc = "A whole swarm of angry bees filled with deadly toxins. Nasty!" + rules = "Hivemind." + icon_state = "buzzkill" + + mana_cost = 4 + attack = 1 + health = 5 + + faction = "Syndicate" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_nuclear/syndicate_minibomb + name = "Syndicate Minibomb" + desc = "A syndicate manufactured explosive used to sow destruction and chaos." + rules = "Deal 3 damage to an enemy unit and units adjacent to it." + icon_state = "syndicate_minibomb" + + mana_cost = 3 + + faction = "Syndicate" + rarity = "Common" + card_type = "Spell" + +/datum/tcg_card/pack_nuclear/viscerator + name = "Viscerator" + desc = "A small yet deadly machine, designed to rip it's targets apart." + rules = "Gain +1/+1 for every other viscerator on field." + icon_state = "viscerator" + + mana_cost = 2 + attack = 3 + health = 1 + + faction = "Syndicate" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_nuclear/cqc + name = "CQC Manual" + desc = "A manual that teaches a single user tactical Close-Quarters Combat before self-destructing." + rules = "Give equipped unit Deadeye and First Strike." + icon_state = "cqc" + + mana_cost = 4 + attack = 4 + health = 3 + + faction = "Syndicate" + rarity = "Epic" + card_type = "Equipment" + +/datum/tcg_card/pack_nuclear/holoparasite + name = "Holoparasite" + desc = "A mysterious being that stands by its charge, ever vigilant." + rules = "On summon: \"Link\" this unit to another unit. Whenever this unit takes damage, instead, transfer all damage to the linked unit." + icon_state = "holoparasite" + + mana_cost = 6 + attack = 8 + health = 0 + + faction = "Syndicate" + rarity = "Legendary" + card_type = "Unit" + +/datum/tcg_card/pack_nuclear/rapier + name = "Rapier" + desc = "An elegant plastitanium rapier with a diamond tip and coated in a specialized knockout poison." + rules = "" + icon_state = "rapier" + + mana_cost = 2 + attack = 3 + health = 0 + + faction = "Syndicate" + rarity = "Rare" + card_type = "Equipment" + +/datum/tcg_card/pack_nuclear/sniper + name = "Sniper Rifle" + desc = "A long ranged weapon that does significant damage. No, you can't quickscope." + rules = "Give equipped unit Deadeye." + icon_state = "sniper" + + mana_cost = 6 + attack = 5 + health = 0 + + faction = "Syndicate" + rarity = "Epic" + card_type = "Equipment" + +/datum/tcg_card/pack_nuclear/honksword + name = "Bananium Sword" + desc = "An elegant weapon, for a more \"civilized\" age." + rules = "Equipped unit does not deal damage. Instead, it taps the attacked card without activating it's effects." + icon_state = "honksword" + + mana_cost = 3 + attack = 0 + health = 0 + + faction = "Syndicate" + rarity = "Common" + card_type = "Equipment" + +/datum/tcg_card/pack_nuclear/mustache + name = "Mustache Grenade" + desc = "A handsomely-attired teargas grenade." + rules = "Unequip all enemy units. Unequipped equipment cards must be discarded." + icon_state = "mustache" + + mana_cost = 5 + + faction = "Syndicate" + rarity = "Common" + card_type = "Spell" + +/datum/tcg_card/pack_nuclear/taeclowndo + name = "Tae-Clown-Do" + desc = "A pair of clown shoes, infused with bananium. Rumors say that these can teach their wearer the art of Tae-Clown-Do." + rules = "Flip a coin. If heads, your enemy skips a turn. If tails, you skip a turn instead." + icon_state = "taeclowndo" + + mana_cost = 3 + + faction = "Syndicate" + rarity = "Epic" + card_type = "Spell" diff --git a/code/modules/tcg/pack_star.dm b/code/modules/tcg/pack_star.dm new file mode 100644 index 0000000000..4b8e32e631 --- /dev/null +++ b/code/modules/tcg/pack_star.dm @@ -0,0 +1,304 @@ +/datum/tcg_card/pack_star + pack = 'icons/obj/tcg/pack_star.dmi' + +/datum/tcg_card/pack_star/golem + name = "Adamantine Golem" + desc = "An adamantine golem, immune to magic and being able to coordinate other golems, has a great power in combat." + rules = "Holy. Taunt." + icon_state = "golem" + + mana_cost = 4 + attack = 4 + health = 5 + + faction = "Unique" + rarity = "Rare" + card_type = "Unit" + +/obj/item/tcg_card/special/golem + datum_type = /datum/tcg_card/pack_star/golem + +/datum/tcg_card/pack_star/xenomaid + name = "Lusty Xenomorph Maid" + desc = "Just a lusty xenomorph maid, nothing to see here." + rules = "Blocker. Each turn, gain -1/-1." + icon_state = "xenomaid" + + mana_cost = 3 + attack = 6 + health = 6 + + faction = "Unique" + rarity = "Epic" + card_type = "Unit" + +/obj/item/tcg_card/special/xenomaid + datum_type = /datum/tcg_card/pack_star/xenomaid + +/datum/tcg_card/pack_star/morph + name = "Morph" + desc = "A revolting, pulsating pile of flesh that can mimic everything it sees." + rules = "On summon: Copy stats of an opponent's card." + icon_state = "morph" + + mana_cost = 4 + attack = 0 + health = 1 + + faction = "Unique" + rarity = "Common" + card_type = "Unit" + +/obj/item/tcg_card/special/morph + datum_type = /datum/tcg_card/pack_star/morph + +/datum/tcg_card/pack_star/demonic_miner + name = "Demonic Miner" + desc = "An soul of extremely geared miner, driven crazy or possessed by the demonic forces here, either way a terrifying enemy." + rules = "Each turn: Deal 1 damage to all the creatures on the field." + icon_state = "demonic_miner" + + mana_cost = 7 + attack = 4 + health = 5 + + faction = "Unique" + rarity = "Rare" + card_type = "Unit" + +/obj/item/tcg_card/special/demonic_miner + datum_type = /datum/tcg_card/pack_star/demonic_miner + +/datum/tcg_card/pack_star/wendigo + name = "Wendigo" + desc = "A mythological man-eating legendary creature, you probably aren't going to survive this." + rules = "" + icon_state = "wendigo" + + mana_cost = 6 + attack = 5 + health = 3 + + faction = "Unique" + rarity = "Common" + card_type = "Unit" + +/obj/item/tcg_card/special/wendigo + datum_type = /datum/tcg_card/pack_star/wendigo + +/datum/tcg_card/pack_star/honk + name = "H.O.N.K. Mech" + desc = "Produced by \"Tyranny of Honk, INC\", this exosuit is designed as heavy clown-support. Used to spread the fun and joy of life. HONK!" + rules = "Taunt." + icon_state = "honk" + + mana_cost = 8 + attack = 6 + health = 8 + + faction = "Unique" + rarity = "Epic" + card_type = "Unit" + +/obj/item/tcg_card/special/honk + datum_type = /datum/tcg_card/pack_star/honk + +/datum/tcg_card/pack_star/ratvar + name = "Clockwork Slab" + desc = "A link between clockwork servants and the Celestial Derelict. It contains information, recites scripture, and is Servant's most vital tool." + rules = "Equipped unit gains Clockwork and can't attack units with Holy." + icon_state = "ratvar" + + mana_cost = 2 + attack = 3 + health = 0 + + faction = "Unique" + rarity = "Common" + card_type = "Equipment" + +/obj/item/tcg_card/special/ratvar + datum_type = /datum/tcg_card/pack_star/ratvar + +/datum/tcg_card/pack_star/hierophant + name = "Hierophant Club" + desc = "The strange technology of this large club allows various nigh-magical feats. It used to beat you, but now you can set the beat." + rules = "Give equipped unit First Strike." + icon_state = "hierophant" + + mana_cost = 4 + attack = 2 + health = 0 + + faction = "Unique" + rarity = "Rare" + card_type = "Equipment" + +/obj/item/tcg_card/special/hierophant + datum_type = /datum/tcg_card/pack_star/hierophant + +/datum/tcg_card/pack_star/abductor + name = "Alien Gland" + desc = "A nausea-inducing hunk of twisting flesh and metal. These things are often found after people were abducted by grey-skinned aliens." + rules = "Each turn: Flip a coin. If heads, unit gain +1/+1. If tails, unit gains -2/-1." + icon_state = "abductor" + + mana_cost = 2 + attack = 0 + health = 0 + + faction = "Unique" + rarity = "Common" + card_type = "Equipment" + +/obj/item/tcg_card/special/abductor + datum_type = /datum/tcg_card/pack_star/abductor + +/datum/tcg_card/pack_star/space_carp + name = "Space Carp" + desc = "A failed weaponery experiment, looking like a ferocious, fang-bearing creature that resembles a fish." + rules = "" + icon_state = "space_carp" + + mana_cost = 1 + attack = 2 + health = 1 + + faction = "Unique" + rarity = "Common" + card_type = "Unit" + +/obj/item/tcg_card/special/space_carp + datum_type = /datum/tcg_card/pack_star/space_carp + +/datum/tcg_card/pack_star/spess_pirate + name = "Space Pirate" + desc = "Space Pirate does whatever he wants because he is free. Sadly, Space Rum insn't free." + rules = "On summon: Draw 2 cards. If there are no spells, discard them." + icon_state = "spess_pirate" + + mana_cost = 4 + attack = 3 + health = 2 + + faction = "Unique" + rarity = "Rare" + card_type = "Unit" + +/obj/item/tcg_card/special/spess_pirate + datum_type = /datum/tcg_card/pack_star/spess_pirate + +/datum/tcg_card/pack_star/gondola + name = "Gondola" + desc = "Gondola is the silent walker. Having no hands he embodies the Taoist principle of wu-wei (non-action) while his smiling facial expression shows his utter and complete acceptance of the world as it is. Its hide is extremely valuable." + rules = "Taunt. Holy." + icon_state = "gondola" + + mana_cost = 6 + attack = 0 + health = 6 + + faction = "Unique" + rarity = "Epic" + card_type = "Unit" + +/obj/item/tcg_card/special/gondola + datum_type = /datum/tcg_card/pack_star/gondola + +/datum/tcg_card/pack_star/phazon + name = "Phazon" + desc = "The pinnacle of scientific research and pride of Nanotrasen, Phazon uses cutting edge bluespace technology and expensive materials." + rules = "Whenever this unit takes damage, flip a coin. If heads, take no damage. If tails, take double damage." + icon_state = "phazon" + + mana_cost = 8 + attack = 5 + health = 7 + + faction = "Unique" + rarity = "Rare" + card_type = "Unit" + +/obj/item/tcg_card/special/phazon + datum_type = /datum/tcg_card/pack_star/phazon + +//Ultimate Exodia cards. I really, really doubt that someone will ever find them. + +/datum/tcg_card/exodia + pack = 'icons/obj/tcg/pack_star.dmi' + +/datum/tcg_card/exodia/exodia_singulo + name = "Singularity" + desc = "A monstrous gravitational singularity, pitch black(but not quiet) and very menacings." + rules = "This card doesn't leave field. At the end of each turn: Remove all the cards(except other Exodia cards) from the field." + icon_state = "exodia_singularity" + + mana_cost = 8 + + faction = "Exodia" + rarity = "Exodia" + card_type = "Spell" + +/datum/tcg_card/exodia/exodia_tesla + name = "Energy Orb" + desc = "An orb made out of hypercharged plasma. An ultimate bug zapper." + rules = "This card doesn't leave field. Every turn all units take 4 damage." + icon_state = "exodia_tesla" + + mana_cost = 8 + + faction = "Exodia" + rarity = "Exodia" + card_type = "Spell" + +/datum/tcg_card/exodia/exodia_narie + name = "Nar-Sie" + desc = "An avatar of the Nar-Sie, one of the Eldritch Gods." + rules = "This card doesn't leave field. Every turn all units take 1 damage and you restore 1 lifeshard." + icon_state = "exodia_narsie" + + mana_cost = 8 + + faction = "Exodia" + rarity = "Exodia" + card_type = "Spell" + +/datum/tcg_card/exodia/exodia_ratvar + name = "Ratvar" + desc = "Ratvar, the god of cogs and clockwork mechanisms, was trapped by Nar-Sie a long ago." + rules = "This card doesn't leave field. Every turn enemy hero recieves 2 lifeshard damage." + icon_state = "exodia_ratvar" + + mana_cost = 8 + + faction = "Exodia" + rarity = "Exodia" + card_type = "Spell" + +/datum/tcg_card/exodia/exodia + name = "Eldritch Horror" + desc = "The Eldritch Horror is a long forgotten demon that was the beginning of everything. Afterwards, his creations revolted and left him abadoned in endless void." + rules = "This card doesn't leave field. If all other 4 Exodia cards are on the field(Singularity, Energy Orb, Nar-Sie and Ratvar), the game is won." + icon_state = "exodia_eldritch" + + mana_cost = 8 + + faction = "Exodia" + rarity = "Unique" //No drop lads + card_type = "Spell" + +/obj/item/tcg_card/special/exodia_singulo + datum_type = /datum/tcg_card/exodia/exodia_singulo + +/obj/item/tcg_card/special/exodia_tesla + datum_type = /datum/tcg_card/exodia/exodia_tesla + +/obj/item/tcg_card/special/exodia_narie + datum_type = /datum/tcg_card/exodia/exodia_narie + +/obj/item/tcg_card/special/exodia_ratvar + datum_type = /datum/tcg_card/exodia/exodia_ratvar + +/obj/item/tcg_card/special/exodia + datum_type = /datum/tcg_card/exodia/exodia + diff --git a/code/modules/uplink/uplink_items/uplink_badass.dm b/code/modules/uplink/uplink_items/uplink_badass.dm index 43e5523bad..ec0ebf66d1 100644 --- a/code/modules/uplink/uplink_items/uplink_badass.dm +++ b/code/modules/uplink/uplink_items/uplink_badass.dm @@ -78,3 +78,16 @@ limited_stock = 1 cant_discount = TRUE include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) + +/datum/uplink_item/badass/gaming_cardpack + name = "TCG Card Operatives Bundle" + desc = "A bundle full of goodies required to work as a TCG Card Operative. A warm pajama, a mug of cocoa, a plushie and a two packs full of rare 2560 Core Set cards!" + item = /obj/item/storage/box/syndie_kit/sleepytime/cardpack + cost = 20 + include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) + +/datum/uplink_item/badass/cardpack + name = "TCG Nuclear Cardpack" + desc = "A cardpack filled with top-tier TCG cards." + item = /obj/item/cardpack/syndicate + cost = 4 diff --git a/code/modules/uplink/uplink_items/uplink_clothing.dm b/code/modules/uplink/uplink_items/uplink_clothing.dm index 6163e5722a..de15b16b68 100644 --- a/code/modules/uplink/uplink_items/uplink_clothing.dm +++ b/code/modules/uplink/uplink_items/uplink_clothing.dm @@ -104,3 +104,10 @@ desc = "An eyepatch that connects itself to your eye socket, enhancing your shooting to an impossible degree, allowing your bullets to ricochet far more often than usual." item = /obj/item/clothing/glasses/eyepatch/syndicate cost = 8 + +/datum/uplink_item/device_tools/ablative_armwraps + name = "Ablative Armwraps" + desc = "A pair of highly reinforced armwraps allowing the user to parry almost anything. Fully reflects projectiles, no downsides to failing, but is very hard to parry melee with." + cost = 6 + item = /obj/item/clothing/gloves/fingerless/ablative + exclude_modes = list(/datum/game_mode/nuclear) diff --git a/code/modules/uplink/uplink_items/uplink_dangerous.dm b/code/modules/uplink/uplink_items/uplink_dangerous.dm index 898b716775..a8ca068ad2 100644 --- a/code/modules/uplink/uplink_items/uplink_dangerous.dm +++ b/code/modules/uplink/uplink_items/uplink_dangerous.dm @@ -118,6 +118,18 @@ /datum/uplink_item/dangerous/doublesword/get_discount() return pick(4;0.8,2;0.65,1;0.5) +/datum/uplink_item/dangerous/hyperblade + name = "Hypereutactic Blade" + desc = "The result of two Dragon Tooth swords combining, you wouldn't want to see this coming at you down the hall! \ + Requires two hands to wield and it slows you down. You can also recolor it!" + item = /obj/item/dualsaber/hypereutactic + player_minimum = 25 + cost = 16 + exclude_modes = list(/datum/game_mode/nuclear/clown_ops, /datum/game_mode/traitor/internal_affairs) + +/datum/uplink_item/dangerous/hyperblade/get_discount() + return pick(4;0.8,2;0.65,1;0.5) + /datum/uplink_item/dangerous/sword name = "Energy Sword" desc = "The energy sword is an edged weapon with a blade of pure energy. The sword is small enough to be \ diff --git a/code/modules/uplink/uplink_items/uplink_stealth.dm b/code/modules/uplink/uplink_items/uplink_stealth.dm index 18a7707a88..1bd75fa2b1 100644 --- a/code/modules/uplink/uplink_items/uplink_stealth.dm +++ b/code/modules/uplink/uplink_items/uplink_stealth.dm @@ -102,6 +102,7 @@ along with slurred speech, aggression, and the ability to infect others with this agent." item = /obj/item/storage/box/syndie_kit/romerol cost = 25 + player_minimum = 25 cant_discount = TRUE exclude_modes = list(/datum/game_mode/nuclear) diff --git a/code/modules/vending/clothesmate.dm b/code/modules/vending/clothesmate.dm index 8d19d46530..fedaeff98c 100644 --- a/code/modules/vending/clothesmate.dm +++ b/code/modules/vending/clothesmate.dm @@ -21,6 +21,7 @@ /obj/item/clothing/suit/jacket/puffer/vest = 4, /obj/item/clothing/suit/jacket/puffer = 4, /obj/item/clothing/suit/hooded/cloak/david = 4, + /obj/item/clothing/neck/cancloak/polychromic = 4, /obj/item/clothing/suit/bomber = 5, /obj/item/clothing/under/suit/turtle/teal = 3, /obj/item/clothing/under/suit/turtle/grey = 3, @@ -31,7 +32,10 @@ /obj/item/clothing/under/suit/burgundy = 3, /obj/item/clothing/under/suit/charcoal = 3, /obj/item/clothing/under/suit/white = 3, + /obj/item/clothing/under/suit/tan = 3, + /obj/item/clothing/under/suit/charismatic_suit = 3, /obj/item/clothing/under/costume/kilt = 3, + /obj/item/clothing/suit/suspenders = 3, /obj/item/clothing/under/misc/overalls = 3, /obj/item/clothing/under/suit/sl = 3, /obj/item/clothing/accessory/sweater = 3, @@ -64,12 +68,14 @@ /obj/item/clothing/under/pants/black = 4, /obj/item/clothing/under/pants/tan = 4, /obj/item/clothing/under/pants/track = 3, + /obj/item/clothing/under/pants/polypants/polychromic = 4, /obj/item/clothing/accessory/suitjacket = 2, /obj/item/clothing/accessory/suitjacket/charcoal = 2, /obj/item/clothing/accessory/suitjacket/navy = 2, /obj/item/clothing/accessory/suitjacket/burgundy = 2, /obj/item/clothing/accessory/suitjacket/checkered = 2, /obj/item/clothing/suit/jacket/miljacket = 5, + /obj/item/clothing/suit/jacket/urbanjacket/polychromic = 5, /obj/item/clothing/under/suit/white_on_white/skirt = 2, /obj/item/clothing/under/rank/captain/suit/skirt = 2, /obj/item/clothing/under/rank/civilian/head_of_personnel/suit/skirt = 2, @@ -208,7 +214,9 @@ /obj/item/clothing/neck/necklace/dope = 5, /obj/item/clothing/suit/jacket/letterman_nanotrasen = 5, /obj/item/clothing/under/misc/corporateuniform = 5, - /obj/item/clothing/suit/hooded/wintercoat/polychromic = 5) + /obj/item/clothing/suit/hooded/wintercoat/polychromic = 5, + /obj/item/clothing/suit/toggle/wbreakpoly/polychromic = 5, + /obj/item/clothing/shoes/sneakers/poly/polychromic = 10) refill_canister = /obj/item/vending_refill/clothing default_price = PRICE_CHEAP extra_price = PRICE_BELOW_NORMAL diff --git a/code/modules/vending/games.dm b/code/modules/vending/games.dm index 6c29b412e7..cea9c5ae70 100644 --- a/code/modules/vending/games.dm +++ b/code/modules/vending/games.dm @@ -7,7 +7,9 @@ /obj/item/storage/dice = 10, /obj/item/toy/cards/deck/cas = 3, /obj/item/toy/cards/deck/cas/black = 3, - /obj/item/toy/cards/deck/unum = 3) + /obj/item/toy/cards/deck/unum = 3, + /obj/item/cardpack/series_one = 10, + /obj/item/tcgcard_binder = 5) contraband = list(/obj/item/dice/fudge = 9) premium = list(/obj/item/melee/skateboard/pro = 3, /obj/item/melee/skateboard/hoverboard = 1) diff --git a/code/modules/vending/kinkmate.dm b/code/modules/vending/kinkmate.dm index 2316682e68..28e5a950ad 100644 --- a/code/modules/vending/kinkmate.dm +++ b/code/modules/vending/kinkmate.dm @@ -31,6 +31,8 @@ /obj/item/autosurgeon/testicles = 3, /obj/item/storage/pill_bottle/penis_enlargement = 5, /obj/item/storage/pill_bottle/breast_enlargement = 5, + /obj/item/reagent_containers/glass/bottle/crocin = 5, + /obj/item/reagent_containers/glass/bottle/camphor = 5, /obj/item/storage/daki = 4 ) contraband = list( @@ -46,6 +48,7 @@ ) premium = list( /obj/item/clothing/accessory/skullcodpiece/fake = 3, + /obj/item/reagent_containers/glass/bottle/hexacrocin = 10, /obj/item/clothing/under/pants/chaps = 5 ) refill_canister = /obj/item/vending_refill/kink diff --git a/code/modules/vending/wardrobes.dm b/code/modules/vending/wardrobes.dm index e88cfe33a3..eebb07938b 100644 --- a/code/modules/vending/wardrobes.dm +++ b/code/modules/vending/wardrobes.dm @@ -207,6 +207,7 @@ product_ads = "You turn me TRUE, use defines!;0110001101101100011011110111010001101000011001010111001101101000011001010111001001100101" vend_reply = "Thank you for using the RoboDrobe!" products = list(/obj/item/clothing/glasses/hud/diagnostic = 3, + /obj/item/stack/medical/nanogel = 5, /obj/item/clothing/head/beret/robo = 3, /obj/item/clothing/under/rank/rnd/roboticist = 3, /obj/item/clothing/under/rank/rnd/roboticist/sleek = 3, diff --git a/code/modules/vore/eating/vorepanel.dm b/code/modules/vore/eating/vorepanel.dm index 6e3951e60a..5622ec0382 100644 --- a/code/modules/vore/eating/vorepanel.dm +++ b/code/modules/vore/eating/vorepanel.dm @@ -4,8 +4,8 @@ #define BELLIES_MAX 20 #define BELLIES_NAME_MIN 2 -#define BELLIES_NAME_MAX 12 -#define BELLIES_DESC_MAX 1024 +#define BELLIES_NAME_MAX 24 +#define BELLIES_DESC_MAX 4096 /mob/living/proc/insidePanel() set name = "Vore Panel" diff --git a/config/game_options.txt b/config/game_options.txt index 3c53d9fecb..7776d87d4e 100644 --- a/config/game_options.txt +++ b/config/game_options.txt @@ -675,3 +675,6 @@ TURF_DIRT_THRESHOLD 100 ## Default alpha of dirt on spawn DIRT_ALPHA_STARTING 127 + +## Allows pAI custom holoforms +PAI_CUSTOM_HOLOFORMS diff --git a/config/policy.txt b/config/policy.txt index 610acd2be8..502b525ad0 100644 --- a/config/policy.txt +++ b/config/policy.txt @@ -3,7 +3,10 @@ ## ON_CLONE - displayed after a successful cloning operation to the cloned person ## ON_DEFIB_INTACT - displayed after defibbing before memory loss time threshold ## ON_DEFIB_LATE - displayed after defibbing post memory loss time threshold -## +## SDGF - displayed on SDGF clone spawning +## SDGF_GOOD - displayed on SDGF clone spawning, if the clone is loyal +## SDGF_BAD - displayed on SDGF clone spawning, if the clone is not loyal +## PAI - displayed on PAI personality being loaded ## EXAMPLE: ## POLICYCONFIG ON_CLONE insert text here span classes are fully supported diff --git a/html/changelog.html b/html/changelog.html index 8582b8f0d1..c387dc4058 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -50,6 +50,433 @@ -->
+

02 March 2021

+

LetterN updated:

+
    +
  • colorpainter: let's not dispense null
  • +
+

SandPoot updated:

+
    +
  • Changelings will actually become the person they want to be when using "human form" ability(after having used last resort).
  • +
+ +

01 March 2021

+

SmArtKar updated:

+
    +
  • Fixes decks breaking your screen
  • +
  • Fixes binders not saving cards
  • +
  • Fixes binders not saving multiple cards of the same type
  • +
+

Vynzill updated:

+
    +
  • cursed rice hat right in front of the jungle gateway's entrance is now removed from this dimensional plane
  • +
+ +

28 February 2021

+

Putnam3145 updated:

+
    +
  • Polychromic windbreaker's alt-click message is now coherent
  • +
  • Toggleable suits now have an on_toggle proc to be overridden.
  • +
+

R3dtail updated:

+
    +
  • doubled max belly name length and quadrupled belly description length
  • +
+

SandPoot updated:

+
    +
  • Body rejuvenation surgery will loop until the patient is completely healed.
  • +
+

dzahlus updated:

+
    +
  • fixes toxinlovers dying from heretic stuff that should heal them instead
  • +
+ +

27 February 2021

+

Hatterhat updated:

+
    +
  • Lingfists (trait_mauler) now deal no stam damage and lost their 15(!!!) armor penetration.
  • +
+

Putnam3145 updated:

+
    +
  • Tablets now protect their contents from rads.
  • +
+

TheObserver-sys updated:

+
    +
  • Chems that should have been usable are now usable, try some cryoxadone on a plant today!!!
  • +
+

kappa-sama updated:

+
    +
  • cards and card binders are now small-class items
  • +
+

keronshb updated:

+
    +
  • 16 > 10 unlock cost for stronger abilities
  • +
  • Made nearly all other abilities for free.
  • +
+

kiwedespars updated:

+
    +
  • reverted the pr that absolutely gutted pugilism and made it worse than base unarmed, also gives it a second long stagger
  • +
  • removed the ability to parry while horizontal, because that's dumb and makes it easy to just time the parries right.
  • +
+

silicons updated:

+
    +
  • chaplain arrythmic knives can no longer be abused for infinite speed.
  • +
+ +

26 February 2021

+

DeltaFire15 updated:

+
    +
  • All machine-frame based tool-use actions now have state-checking callbacks.
  • +
+ +

25 February 2021

+

DeltaFire15 updated:

+
    +
  • Traitor / Ling objective amount should now be correct again.
  • +
+ +

24 February 2021

+

SandPoot updated:

+
    +
  • Regular crowbars no longer open powered airlocks.
  • +
+

silicons updated:

+
    +
  • xeno cube makes hostile xenos now, and drops a sentinel instead of a drone.
  • +
+ +

23 February 2021

+

keronshb updated:

+
    +
  • Hyperblade to uplink with poplock
  • +
  • Removes combination of two Dragon Tooth Swords while keeping it for regular eutactics.
  • +
+

timothyteakettle updated:

+
    +
  • banning panel prioritises mobs with clients now when trying to find them if they're in the game
  • +
+ +

22 February 2021

+

Putnam3145 updated:

+
    +
  • (Hexa)crocin
  • +
  • (Hexa)camphor
  • +
  • Nymphomaniac quirk
  • +
  • All climaxes and arousals are now logged, as well as genital exposure.
  • +
+

SandPoot updated:

+
    +
  • Cyborg tablets and it's special app for self-management.
  • +
  • In the case of a doomsday device being created outside of an AI it will delete itself.
  • +
  • Some sprites for it have been added and the borg's hud light toggles been changed to only on-off (made by yours truly)
  • +
  • A lot of borg code was changed
  • +
  • Tools no longer use istype checks and actually check for their behavior.
  • +
+

Vynzill updated:

+
    +
  • cursed rice hat that's hard to find and obtain, along with a couple other hats
  • +
  • a replacement toy gun for donksoft lmg
  • +
  • gorillas to the jungle gateway, friendly, even when attacked.
  • +
  • couple mapping errors I noticed, most importantly a missing window in the chapel.
  • +
  • shotgun and donksoft lmg removed, captain coat nerfed armor values.
  • +
  • leaper healthpool from 450 to 550 hopefully making it more of a struggle, and gives it a name.
  • +
  • leaper pit is more wider. The hidden room south is now more obvious to find
  • +
+

dzahlus updated:

+
    +
  • Added pain emote to getting wounded
  • +
  • added a new pain emote sounds
  • +
+ +

21 February 2021

+

Hatterhat updated:

+
    +
  • Anomaly announcements and brand intelligence now always announce instead of having some ham-fisted chance of being a command report.
  • +
+

IronEleven updated:

+
    +
  • Raises Space Vine Population Requirement from 10 to 20
  • +
+

MrJWhit updated:

+
    +
  • Removes an unnecessary % on the seed extractor.
  • +
+

timothyteakettle updated:

+
    +
  • the query for checking mentors now gets properly deleted
  • +
  • vampires no longer burn in the chapel if they signed up as the chaplain
  • +
+ +

20 February 2021

+

Adelphon updated:

+
    +
  • polychromic pants
  • +
  • urban coat made polychromic
  • +
+

Chiirno updated:

+
    +
  • Synthflesh now unhusks with 100u instead of requiring 101u.
  • +
+

SmArtKar updated:

+
    +
  • Added some QoL changes to TCG
  • +
  • Fixed TCG cards not saving
  • +
+

TyrianTyrell updated:

+
    +
  • fixed the signed language so that you can actually use it, and that it's unusable when it's meant to be.
  • +
+

timothyteakettle updated:

+
    +
  • stops people using Message All on PDAs when their cartridge doesn't allow it
  • +
+ +

19 February 2021

+

Putnam3145 updated:

+
    +
  • Buzz Fuzz's addiction threshold is now a can and a sip as intended.
  • +
+

timothyteakettle updated:

+
    +
  • staring into pierced realities is now logged
  • +
+ +

18 February 2021

+

BlueWildrose updated:

+
    +
  • Admins now receive messages regarding certain holodeck actions.
  • +
+

Hatterhat updated:

+
    +
  • Free Golem Ship GPSes now start as disabled. Like they were supposed to.
  • +
+

LetterN updated:

+
    +
  • No more liver damage when you opt out of "hornychems"
  • +
+

SmArtKar updated:

+
    +
  • Added a new TCG card game
  • +
+

dzahlus updated:

+
    +
  • Removed maroon objective due to toxic gameplay behaviour
  • +
+

shellspeed1 updated:

+
    +
  • floor bots place plating before tiles now.
  • +
  • gets rid of another tile duplication issue.
  • +
+

silicons updated:

+
    +
  • priviledge --> privilege
  • +
+ +

16 February 2021

+

silicons updated:

+
    +
  • sprint removal entry added, UI will revert to old UI while this is active.
  • +
+ +

15 February 2021

+

Adelphon updated:

+
    +
  • polychromatic shoes
  • +
  • polychromatic windbreaker
  • +
  • polychromatic canvas cloak
  • +
  • digitigrade charismatic suit texture
  • +
+

DeltaFire15 updated:

+
    +
  • Kneecapped pugilist parries somewhat.
  • +
  • Slightly nerfed default unarmed parries.
  • +
  • Slightly nerfed traitor armwrap parries.
  • +
  • Pugilist parries now cannot perfectly defend against projectiles, as they were supposed to.
  • +
  • Some parrying numbers that one would think were in seconds didn't have the SECONDS. I added those.
  • +
  • Clock cultists now yell alot less when invoking scripture.
  • +
+

dzahlus updated:

+
    +
  • Added new emote
  • +
  • added a new emote sound
  • +
+

silicons updated:

+
    +
  • people on the ground hit less hard in unarmed combat. rng miss remove from punches.
  • +
  • chat highlighting no longer drops half your entered words.
  • +
+ +

14 February 2021

+

DeltaFire15 updated:

+
    +
  • The antag panel now correctly shows the names of cultist / clockcult datum subtypes.
  • +
  • Adding clock cultists via the admin panel now works correctly.
  • +
  • Xeno larvae should now be able to ventcrawl again.
  • +
+

Hatterhat updated:

+
    +
  • Repairing sensors on jumpsuits now requires a fully-intact jumpsuit. Find some cloth.
  • +
  • Durathread armor kits now require you to have a fully-repaired jumpsuit, first, with no attachments.
  • +
  • Durathread armor kits now no longer weave the entirety of the jumpsuit armor universe into having armor.
  • +
+

TyrianTyrell updated:

+
    +
  • added a define for multilingual granted languages, and changed the multilingual trait to use it.
  • +
+ +

13 February 2021

+

Hatterhat updated:

+
    +
  • Energy bolas now take 2.5 seconds to remove and dissipate on removal.
  • +
+

timothyteakettle updated:

+
    +
  • migration error to version 39+ of savefiles is now logged instead of messaging all online admins in the chat
  • +
+ +

12 February 2021

+

Hatterhat updated:

+
    +
  • The ATVs on SnowCabin.dmm have been replaced with snowmobiles.
  • +
+

MrJWhit updated:

+
    +
  • Random deltastation fixes.
  • +
  • Gives boxstation vault door actual vault door access
  • +
+

silicons updated:

+
    +
  • Voice of God - sleep removed, stun staggers instead, knockdown is faster but does not do stamina damage, vomit is faster but doesn't stun
  • +
+ +

11 February 2021

+

Adelphon updated:

+
    +
  • Charismatic Suit
  • +
  • Urban Jacket
  • +
+

DeltaFire15 updated:

+
    +
  • Added nanogel to the robodrobe.
  • +
+

Putnam3145 updated:

+
    +
  • Config to keep unreadied players from mode voting
  • +
+

dzahlus updated:

+
    +
  • fixes grenadelaunch.ogg being used where it shouldn't and makes mech weapons use correct sound
  • +
+

keronshb updated:

+
    +
  • 10 > 30 second for Warp Implant cooldown
  • +
  • Comments out power sink objective.
  • +
+

timothyteakettle updated:

+
    +
  • persistent blood should stop being invisible and alt clicking it shouldn't return the entire spritesheet
  • +
  • pickpocketing is now logged using log_combat
  • +
+

zeroisthebiggay updated:

+
    +
  • the aesthetic sterile mask no longer hides faces so you can cosplay egirls and keep flavortexts
  • +
+ +

09 February 2021

+

Chiirno updated:

+
    +
  • Adds clown waddle to clown shoes. Enhanced Clown Waddle Dampeners can be engaged in-hand with ctrl+click, _but why would you?_
  • +
+

MrJWhit updated:

+
    +
  • Re-adds theater disposal outlet, and makes dorms disposal able to have things sent to it on boxstation.
  • +
+

TyrianTyrell updated:

+
    +
  • made default tongue able to speak signed language.
  • +
+

timothyteakettle updated:

+
    +
  • sentient viruses can now infect synths and ipcs
  • +
+ +

07 February 2021

+

Thalpy updated:

+
    +
  • Dispenser: Adds the ability to store a small amount of reagents in the machine itself for dispensing. Reacting recipies cannot be stored. Size of storage increases with bin size.
  • +
  • Dispenser: Allows reagents to be color coded by pH
  • +
  • Dispenser: Each reagent displays it's pH on hover
  • +
  • Dispenser: Allows the user to toggle between buttons and a radial dial
  • +
  • Dispenser: When the dispencer is upgraded it can dispense 5/3/2/1 volumes based on rating refactor: Dispenser: as it was before. This does not break recorded recipes.
  • +
  • Adds a round function to some numbers so they're not huge
  • +
  • The Chem master can now get purity for all reagents when analysed
  • +
  • Synthissue fixes
  • +
  • buffers now have a strong and weak variant. Weak can be dispensed, and strong can be created. Strong buffers are 6x more effective.
  • +
  • Some buffer pH edge calculation fixes
  • +
+

TyrianTyrell updated:

+
    +
  • added a signed language, that can't be used over the radio but can be used if you're mute. also added the multilingual trait.
  • +
  • hopefully added an icon for the signed language.
  • +
  • changed how some traits function slightly.
  • +
+

dzahlus updated:

+
    +
  • tweaked a few sounds
  • +
  • added a new weapon sounds
  • +
  • removed old weapon sounds
  • +
  • changed some sound related code
  • +
+

silicons updated:

+
    +
  • syndicate ablative armwraps have been added.
  • +
+ +

05 February 2021

+

SmArtKar updated:

+
    +
  • The orbit menu now has an Auto-Observe button! No more sifting through the lame observe menu to snoop in people's backpacks! Also, orbit menu now refreshes.
  • +
  • KAs are no longer getting broken when fired by a circuit
  • +
+

keronshb updated:

+
    +
  • Force and damage > 15 from 18/25
  • +
  • Knockdown put down to 5 from 30
  • +
  • Armor pen down to 10 from 100.
  • +
  • Makes cell chargers, charge faster.
  • +
+

raspy-on-osu updated:

+
    +
  • alien royals can no longer ventcrawl
  • +
+

shellspeed1 updated:

+
    +
  • There actually needs to be people for zombies to happen now.
  • +
+

timothyteakettle updated:

+
    +
  • dwarf facial hair is no longer randomised
  • +
+ +

03 February 2021

+

Hatterhat updated:

+
    +
  • The green energy sabre's sprite now respects proper handedness.
  • +
+ +

02 February 2021

+

silicons updated:

+
    +
  • pais can now be carried around piggybacking/fireman
  • +
  • Meth and Nuka Cola once again, speed you up.
  • +
+ +

31 January 2021

+

Putnam3145 updated:

+
    +
  • fermichem explosion EMPs don't cover the entire station
  • +
+

30 January 2021

timothyteakettle updated: