diff --git a/.github/workflows/ci_suite.yml b/.github/workflows/ci_suite.yml index 622cd98514a..414f5d59ea0 100644 --- a/.github/workflows/ci_suite.yml +++ b/.github/workflows/ci_suite.yml @@ -287,7 +287,7 @@ jobs: completion_gate: # Serves as a non-moving target for branch rulesets if: always() && !cancelled() name: Completion Gate - needs: [ test_windows, compare_screenshots, compile_all_maps, run_linters ] + needs: [ test_windows, compare_screenshots, compile_all_maps, run_all_tests, run_alternate_tests, run_linters ] runs-on: ubuntu-latest steps: - name: Decide whether the needed jobs succeeded or failed diff --git a/_maps/RandomRuins/SpaceRuins/meatderelict.dmm b/_maps/RandomRuins/SpaceRuins/meatderelict.dmm index a4f95abdf0e..96959954e26 100644 --- a/_maps/RandomRuins/SpaceRuins/meatderelict.dmm +++ b/_maps/RandomRuins/SpaceRuins/meatderelict.dmm @@ -728,8 +728,8 @@ /obj/effect/turf_decal/siding/purple{ dir = 1 }, -/obj/item/ammo_casing/a357/spent, -/obj/item/ammo_casing/a357/spent, +/obj/item/ammo_casing/c357/spent, +/obj/item/ammo_casing/c357/spent, /turf/open/indestructible/white, /area/ruin/space/has_grav/powered/biooutpost) "oQ" = ( @@ -887,7 +887,7 @@ /obj/effect/turf_decal/siding/purple{ dir = 1 }, -/obj/item/ammo_casing/a357/spent, +/obj/item/ammo_casing/c357/spent, /turf/open/indestructible/white, /area/ruin/space/has_grav/powered/biooutpost) "rl" = ( @@ -1561,9 +1561,9 @@ /turf/open/indestructible/plating, /area/ruin/space/has_grav/powered/biooutpost) "DC" = ( -/obj/item/ammo_casing/a357/spent, -/obj/item/ammo_casing/a357/spent, -/obj/item/ammo_casing/a357/spent, +/obj/item/ammo_casing/c357/spent, +/obj/item/ammo_casing/c357/spent, +/obj/item/ammo_casing/c357/spent, /turf/open/indestructible/white, /area/ruin/space/has_grav/powered/biooutpost) "DJ" = ( diff --git a/_maps/RandomRuins/SpaceRuins/mimesvsclowns.dmm b/_maps/RandomRuins/SpaceRuins/mimesvsclowns.dmm index c98a43e89c2..7a76e71debf 100644 --- a/_maps/RandomRuins/SpaceRuins/mimesvsclowns.dmm +++ b/_maps/RandomRuins/SpaceRuins/mimesvsclowns.dmm @@ -6,7 +6,7 @@ /area/ruin) "dI" = ( /obj/item/grown/bananapeel, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 9; pixel_x = -13; pixel_y = 10 @@ -78,19 +78,19 @@ }, /obj/effect/decal/cleanable/blood/gibs, /obj/machinery/light/small/broken/directional/south, -/obj/item/ammo_casing/a357/spent, +/obj/item/ammo_casing/c357/spent, /turf/open/floor/iron/checker/airless, /area/ruin) "uc" = ( /obj/effect/decal/cleanable/blood/footprints{ dir = 4 }, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ pixel_x = -5; dir = 5; pixel_y = 6 }, -/obj/item/ammo_casing/a357/spent, +/obj/item/ammo_casing/c357/spent, /obj/item/gps/spaceruin, /turf/open/floor/plating/airless, /area/ruin) @@ -204,7 +204,7 @@ /obj/effect/mob_spawn/corpse/human/clown, /obj/effect/decal/cleanable/blood/footprints, /obj/effect/decal/cleanable/dirt, -/obj/item/ammo_casing/a357/spent, +/obj/item/ammo_casing/c357/spent, /turf/open/floor/plating/airless, /area/ruin) "Ij" = ( @@ -253,7 +253,7 @@ "Pq" = ( /obj/machinery/light/broken/directional/north, /obj/structure/reagent_dispensers/watertank, -/obj/item/ammo_casing/a357/spent, +/obj/item/ammo_casing/c357/spent, /turf/open/floor/iron/checker/airless, /area/ruin) "Qb" = ( diff --git a/_maps/RandomRuins/SpaceRuins/old_infiltrator.dmm b/_maps/RandomRuins/SpaceRuins/old_infiltrator.dmm index 4b42f668c33..85c2910d1fa 100644 --- a/_maps/RandomRuins/SpaceRuins/old_infiltrator.dmm +++ b/_maps/RandomRuins/SpaceRuins/old_infiltrator.dmm @@ -210,8 +210,8 @@ "nF" = ( /obj/item/radio/intercom/directional/south, /obj/effect/decal/cleanable/blood/old, -/obj/item/ammo_casing/a357/match, -/obj/item/ammo_casing/a357/match{ +/obj/item/ammo_casing/c357/match, +/obj/item/ammo_casing/c357/match{ pixel_y = -4; pixel_x = -7 }, @@ -306,7 +306,7 @@ /area/ruin/space/unpowered) "uS" = ( /obj/machinery/newscaster/directional/south, -/obj/item/ammo_casing/a357/match, +/obj/item/ammo_casing/c357/match, /turf/open/floor/mineral/plastitanium/red, /area/ruin/space/unpowered) "vi" = ( @@ -425,7 +425,7 @@ /turf/open/floor/mineral/plastitanium/red/airless, /area/ruin/space/unpowered) "Cv" = ( -/obj/item/ammo_casing/a357/match, +/obj/item/ammo_casing/c357/match, /turf/open/floor/mineral/plastitanium/red, /area/ruin/space/unpowered) "CC" = ( diff --git a/_maps/RandomRuins/SpaceRuins/russian_derelict.dmm b/_maps/RandomRuins/SpaceRuins/russian_derelict.dmm index d05c6135896..592b4253850 100644 --- a/_maps/RandomRuins/SpaceRuins/russian_derelict.dmm +++ b/_maps/RandomRuins/SpaceRuins/russian_derelict.dmm @@ -4146,14 +4146,14 @@ "Eb" = ( /obj/structure/cable, /obj/effect/mapping_helpers/burnt_floor, -/obj/item/ammo_casing/a357{ +/obj/item/ammo_casing/c357{ pixel_x = -6; pixel_y = 3 }, -/obj/item/ammo_casing/a357{ +/obj/item/ammo_casing/c357{ pixel_x = -5 }, -/obj/item/ammo_casing/a357{ +/obj/item/ammo_casing/c357{ pixel_x = 6; dir = 9; pixel_y = -3 @@ -5018,8 +5018,8 @@ /turf/open/floor/plating/airless, /area/space/nearstation) "IG" = ( -/obj/item/ammo_casing/a357, -/obj/item/ammo_casing/a357{ +/obj/item/ammo_casing/c357, +/obj/item/ammo_casing/c357{ pixel_x = 5; pixel_y = 6 }, @@ -6330,11 +6330,11 @@ /turf/open/floor/iron/airless, /area/ruin/space/ks13/hallway/aft) "Pv" = ( -/obj/item/ammo_casing/a357{ +/obj/item/ammo_casing/c357{ pixel_x = 4; pixel_y = -7 }, -/obj/item/ammo_casing/a357{ +/obj/item/ammo_casing/c357{ pixel_x = -5 }, /obj/structure/cable, @@ -6847,12 +6847,12 @@ "Sk" = ( /obj/structure/cable, /obj/effect/mapping_helpers/burnt_floor, -/obj/item/ammo_casing/a357{ +/obj/item/ammo_casing/c357{ pixel_x = 6; pixel_y = -4 }, -/obj/item/ammo_casing/a357, -/obj/item/ammo_casing/a357{ +/obj/item/ammo_casing/c357, +/obj/item/ammo_casing/c357{ pixel_x = -10; pixel_y = 7; dir = 9 @@ -7599,12 +7599,12 @@ /area/ruin/space/ks13/service/hydro) "VH" = ( /obj/effect/mapping_helpers/burnt_floor, -/obj/item/ammo_casing/a357{ +/obj/item/ammo_casing/c357{ pixel_x = 8; dir = 8; pixel_y = 6 }, -/obj/item/ammo_casing/a357{ +/obj/item/ammo_casing/c357{ pixel_x = 6; pixel_y = -4 }, diff --git a/_maps/RandomRuins/SpaceRuins/the_faceoff.dmm b/_maps/RandomRuins/SpaceRuins/the_faceoff.dmm index b31a11cba31..a358d59956e 100644 --- a/_maps/RandomRuins/SpaceRuins/the_faceoff.dmm +++ b/_maps/RandomRuins/SpaceRuins/the_faceoff.dmm @@ -1,15 +1,15 @@ //MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE "aj" = ( -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ pixel_x = 5; pixel_y = 12 }, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 8; pixel_x = -7; pixel_y = 6 }, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 4; pixel_x = 14; pixel_y = 14 @@ -45,40 +45,40 @@ /turf/template_noop, /area/template_noop) "bM" = ( -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 1; pixel_x = 9 }, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 1; pixel_x = -1; pixel_y = 5 }, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 8; pixel_x = -7; pixel_y = 6 }, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 8; pixel_x = 2; pixel_y = -5 }, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ pixel_x = 5; pixel_y = 2 }, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 4; pixel_x = 14; pixel_y = 14 }, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 8; pixel_x = 2; pixel_y = -5 }, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 8; pixel_x = 2; pixel_y = 12 @@ -168,7 +168,7 @@ /turf/open/floor/iron/dark/airless, /area/ruin/space) "eI" = ( -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 1; pixel_x = -1; pixel_y = 5 @@ -213,17 +213,17 @@ /turf/open/misc/asteroid/basalt/airless, /area/ruin/space) "gq" = ( -/obj/item/ammo_casing/a357/spent, +/obj/item/ammo_casing/c357/spent, /obj/structure/barricade/wooden, /turf/open/floor/iron/dark/airless, /area/ruin/space) "gx" = ( -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 8; pixel_x = -7; pixel_y = 6 }, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ pixel_x = 5; pixel_y = 2 }, @@ -280,41 +280,41 @@ /turf/open/floor/iron/dark/textured/airless, /area/ruin/space) "je" = ( -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 8; pixel_x = 10; pixel_y = 5 }, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 8; pixel_x = 2; pixel_y = 12 }, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 8; pixel_x = -2; pixel_y = -5 }, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ pixel_x = 5; pixel_y = 2 }, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 8; pixel_x = 2; pixel_y = 1 }, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ pixel_x = 2; pixel_y = 6; dir = 1 }, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 8; pixel_x = 2; pixel_y = -6 }, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 8; pixel_y = 13; pixel_x = -5 @@ -322,7 +322,7 @@ /turf/open/floor/mineral/plastitanium/red/airless, /area/ruin/space) "jX" = ( -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 1; pixel_x = 9; pixel_y = 9 @@ -354,7 +354,7 @@ /turf/open/floor/iron/dark/airless, /area/ruin/space) "mC" = ( -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 4; pixel_x = 14; pixel_y = 14 @@ -392,7 +392,7 @@ /turf/open/floor/iron/dark/airless, /area/ruin/space) "pl" = ( -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 8; pixel_x = 2; pixel_y = -5 @@ -434,11 +434,11 @@ /area/ruin/space) "qX" = ( /obj/effect/mapping_helpers/broken_floor, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ pixel_x = 2; pixel_y = 12 }, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 1; pixel_x = 9; pixel_y = 9 @@ -455,7 +455,7 @@ /area/ruin/space) "rU" = ( /obj/effect/mapping_helpers/broken_floor, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 1; pixel_x = 9 }, @@ -482,7 +482,7 @@ /area/ruin/space) "su" = ( /obj/effect/mapping_helpers/broken_floor, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 8; pixel_x = 2; pixel_y = 12 @@ -541,7 +541,7 @@ /turf/open/misc/asteroid/basalt/airless, /area/ruin/space) "vA" = ( -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 1; pixel_x = -1; pixel_y = 5 @@ -549,7 +549,7 @@ /turf/open/floor/iron/dark/airless, /area/ruin/space) "vZ" = ( -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 8; pixel_x = -2; pixel_y = -5 @@ -588,7 +588,7 @@ /turf/open/floor/mineral/plastitanium/airless, /area/ruin/space) "xi" = ( -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 4; pixel_x = 14; pixel_y = 14 @@ -726,7 +726,7 @@ /area/ruin/space) "Dm" = ( /obj/effect/decal/cleanable/dirt, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ pixel_x = 5; pixel_y = 12 }, @@ -786,7 +786,7 @@ /turf/open/misc/asteroid/basalt/airless, /area/ruin/space) "FQ" = ( -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ pixel_x = 5; pixel_y = 2 }, @@ -804,7 +804,7 @@ /turf/open/floor/iron/dark/airless, /area/ruin/space) "GA" = ( -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 4; pixel_x = 14; pixel_y = 14 @@ -822,7 +822,7 @@ /area/ruin/space) "HE" = ( /obj/structure/table/reinforced/plastitaniumglass, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ pixel_x = 2; pixel_y = 12 }, @@ -881,7 +881,7 @@ /turf/open/floor/mineral/plastitanium/airless, /area/ruin/space) "JP" = ( -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ pixel_x = 2; pixel_y = 12 }, @@ -897,11 +897,11 @@ /turf/open/floor/mineral/plastitanium/red/airless, /area/ruin/space) "Kd" = ( -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 1; pixel_x = 9 }, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 1; pixel_x = 9; pixel_y = 9 @@ -909,7 +909,7 @@ /turf/open/floor/iron/dark/airless, /area/ruin/space) "Kp" = ( -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 8; pixel_x = 10; pixel_y = 5 @@ -940,14 +940,14 @@ /turf/open/floor/iron/dark/textured/airless, /area/ruin/space) "LM" = ( -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ pixel_x = 2; pixel_y = 12 }, /turf/open/floor/iron/dark/airless, /area/ruin/space) "LX" = ( -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 8; pixel_x = 2; pixel_y = 12 @@ -973,7 +973,7 @@ /turf/open/floor/mineral/plastitanium/red/airless, /area/ruin/space) "Nc" = ( -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 8; pixel_x = 10; pixel_y = 5 @@ -1047,7 +1047,7 @@ /turf/open/floor/iron/dark/airless, /area/ruin/space) "TH" = ( -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 1; pixel_x = 9 }, @@ -1065,7 +1065,7 @@ /turf/open/floor/iron/dark/airless, /area/ruin/space) "Uy" = ( -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 8; pixel_x = -7; pixel_y = 6 @@ -1102,36 +1102,36 @@ /turf/open/floor/mineral/plastitanium/airless, /area/ruin/space) "Vn" = ( -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 4; pixel_x = 14; pixel_y = 14 }, -/obj/item/ammo_casing/a357/spent, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent, +/obj/item/ammo_casing/c357/spent{ dir = 8; pixel_x = 10; pixel_y = 5 }, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 1; pixel_x = 9 }, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 8; pixel_x = 10; pixel_y = 5 }, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 8; pixel_x = -7; pixel_y = 6 }, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ pixel_x = 2; pixel_y = 12 }, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 1; pixel_x = 9; pixel_y = 9 @@ -1152,7 +1152,7 @@ /turf/open/floor/mineral/plastitanium/airless, /area/ruin/space) "VB" = ( -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ pixel_x = 5; pixel_y = 2 }, @@ -1209,40 +1209,40 @@ /turf/open/floor/iron/dark/airless, /area/ruin/space) "Zg" = ( -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 8; pixel_x = 10; pixel_y = 5 }, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ pixel_x = 5; pixel_y = 7 }, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 8; pixel_x = -4; pixel_y = -7 }, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ pixel_x = 2; pixel_y = 12 }, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 1; pixel_x = -1; pixel_y = 8 }, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 8; pixel_x = -2; pixel_y = -4 }, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 8; pixel_x = -7; pixel_y = 8 }, -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ pixel_x = 5; pixel_y = -4 }, @@ -1259,7 +1259,7 @@ /turf/open/floor/mineral/plastitanium/airless, /area/ruin/space) "ZP" = ( -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ dir = 8; pixel_x = 2; pixel_y = 1 diff --git a/_maps/RandomZLevels/moonoutpost19.dmm b/_maps/RandomZLevels/moonoutpost19.dmm index a8f52784b34..c830fdc968f 100644 --- a/_maps/RandomZLevels/moonoutpost19.dmm +++ b/_maps/RandomZLevels/moonoutpost19.dmm @@ -4131,7 +4131,7 @@ /area/awaymission/moonoutpost19/arrivals/shed) "Bf" = ( /obj/effect/decal/cleanable/dirt, -/obj/item/ammo_casing/a357{ +/obj/item/ammo_casing/c357{ pixel_x = -2; pixel_y = -7 }, @@ -6467,7 +6467,7 @@ "QZ" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/cable, -/obj/item/ammo_casing/a357{ +/obj/item/ammo_casing/c357{ pixel_x = 11; pixel_y = 8 }, @@ -7514,7 +7514,7 @@ /obj/item/stack/ore/glass{ pixel_x = 8 }, -/obj/item/ammo_casing/a357{ +/obj/item/ammo_casing/c357{ pixel_x = -10; pixel_y = -7 }, diff --git a/_maps/deathmatch/arena_station.dmm b/_maps/deathmatch/arena_station.dmm index 50089df45e8..8009387c502 100644 --- a/_maps/deathmatch/arena_station.dmm +++ b/_maps/deathmatch/arena_station.dmm @@ -79,7 +79,7 @@ /obj/structure/closet/crate/cardboard, /obj/effect/turf_decal/tile/brown/fourcorners, /obj/item/mail/junkmail, -/obj/item/ammo_casing/a357, +/obj/item/ammo_casing/c357, /obj/item/reagent_containers/syringe/plasma, /turf/open/indestructible, /area/deathmatch) diff --git a/_maps/map_files/Birdshot/birdshot.dmm b/_maps/map_files/Birdshot/birdshot.dmm index 54d9bde3bc2..de9e1338f29 100644 --- a/_maps/map_files/Birdshot/birdshot.dmm +++ b/_maps/map_files/Birdshot/birdshot.dmm @@ -10872,7 +10872,10 @@ /obj/effect/turf_decal/tile/yellow{ dir = 1 }, -/obj/machinery/door/window/right/directional/east, +/obj/machinery/door/window/right/directional/east{ + name = "Engineering Deliveries"; + req_access = list("engineering") + }, /turf/open/floor/iron/smooth, /area/station/engineering/main) "ecn" = ( @@ -57400,6 +57403,9 @@ /obj/item/gun/energy/ionrifle{ pixel_y = 3 }, +/obj/item/gun/ballistic/automatic/battle_rifle{ + pixel_y = 5 + }, /obj/item/clothing/suit/hooded/ablative, /turf/open/floor/iron/dark/small, /area/station/ai_monitored/security/armory) diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index dcebb2cdce2..b0091430712 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -53109,6 +53109,9 @@ "nmT" = ( /obj/structure/rack, /obj/item/gun/energy/ionrifle, +/obj/item/gun/ballistic/automatic/battle_rifle{ + pixel_y = 3 + }, /obj/item/clothing/suit/hooded/ablative, /obj/item/gun/energy/temperature/security, /obj/structure/window/reinforced/spawner/directional/south, @@ -84090,10 +84093,10 @@ /obj/structure/disposalpipe/trunk{ dir = 4 }, -/obj/machinery/disposal/delivery_chute{ +/obj/effect/turf_decal/box/red, +/obj/structure/disposaloutlet{ dir = 8 }, -/obj/effect/turf_decal/box/red, /turf/open/floor/engine/xenobio, /area/station/science/xenobiology) "uYg" = ( diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm index 5c5129c900a..aa3df4dfd8a 100644 --- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm +++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm @@ -77464,6 +77464,9 @@ "wyF" = ( /obj/structure/rack, /obj/item/gun/energy/ionrifle, +/obj/item/gun/ballistic/automatic/battle_rifle{ + pixel_y = 3 + }, /obj/item/gun/energy/temperature/security, /obj/item/clothing/suit/hooded/ablative, /obj/effect/turf_decal/tile/red/half/contrasted{ diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index 0063ca41fdd..6b4adfe0d48 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -11421,6 +11421,9 @@ "eew" = ( /obj/structure/rack, /obj/item/gun/energy/ionrifle, +/obj/item/gun/ballistic/automatic/battle_rifle{ + pixel_y = 3 + }, /obj/item/gun/energy/temperature/security, /obj/item/clothing/suit/hooded/ablative, /obj/effect/turf_decal/tile/red/half/contrasted{ diff --git a/_maps/map_files/NebulaStation/NebulaStation.dmm b/_maps/map_files/NebulaStation/NebulaStation.dmm index 9e0fec80123..047b54e5fd4 100644 --- a/_maps/map_files/NebulaStation/NebulaStation.dmm +++ b/_maps/map_files/NebulaStation/NebulaStation.dmm @@ -10569,6 +10569,9 @@ "bDU" = ( /obj/structure/rack, /obj/item/gun/energy/ionrifle, +/obj/item/gun/ballistic/automatic/battle_rifle{ + pixel_y = 3 + }, /obj/item/clothing/suit/hooded/ablative, /obj/item/gun/energy/temperature/security, /obj/effect/turf_decal/bot/right, @@ -12767,6 +12770,7 @@ /turf/open/floor/iron/dark/textured, /area/station/engineering/atmos) "bUo" = ( +/obj/structure/cable, /turf/open/floor/iron/solarpanel/airless, /area/station/solars/port/aft) "bUs" = ( @@ -92156,7 +92160,8 @@ /area/station/security/checkpoint/science) "nKF" = ( /obj/item/toy/katana{ - icon_state = "supermatter_sword" + icon_state = "supermatter_sword"; + icon_angle = -45 }, /obj/structure/ladder, /turf/open/floor/plating, @@ -113586,7 +113591,7 @@ /turf/open/floor/engine/n2, /area/station/engineering/atmos) "qOe" = ( -/obj/item/ammo_casing/a357/spent{ +/obj/item/ammo_casing/c357/spent{ pixel_y = 6; pixel_x = 9 }, diff --git a/_maps/map_files/generic/CentCom.dmm b/_maps/map_files/generic/CentCom.dmm index 4aab72d4be6..8f24d290d17 100644 --- a/_maps/map_files/generic/CentCom.dmm +++ b/_maps/map_files/generic/CentCom.dmm @@ -62229,7 +62229,7 @@ xt xt xt xt -xt +PG xt Vd zm @@ -62486,7 +62486,7 @@ xt xt xt xt -rq +xt xt xt zl diff --git a/_maps/map_files/tramstation/tramstation.dmm b/_maps/map_files/tramstation/tramstation.dmm index 528a6dff60e..5701e877f72 100644 --- a/_maps/map_files/tramstation/tramstation.dmm +++ b/_maps/map_files/tramstation/tramstation.dmm @@ -7855,6 +7855,9 @@ /obj/structure/rack, /obj/item/clothing/suit/hooded/ablative, /obj/item/gun/energy/ionrifle, +/obj/item/gun/ballistic/automatic/battle_rifle{ + pixel_y = 3 + }, /obj/item/gun/energy/temperature/security, /obj/structure/reagent_dispensers/wall/peppertank/directional/north, /obj/effect/turf_decal/tile/neutral/fourcorners, diff --git a/_maps/map_files/wawastation/wawastation.dmm b/_maps/map_files/wawastation/wawastation.dmm index 75d1b066c6e..01d06908ce8 100644 --- a/_maps/map_files/wawastation/wawastation.dmm +++ b/_maps/map_files/wawastation/wawastation.dmm @@ -151,6 +151,9 @@ /obj/item/clothing/suit/hooded/ablative, /obj/item/gun/energy/temperature/security, /obj/item/gun/energy/ionrifle, +/obj/item/gun/ballistic/automatic/battle_rifle{ + pixel_y = 3 + }, /obj/effect/turf_decal/tile/red/half/contrasted{ dir = 1 }, @@ -4661,7 +4664,7 @@ /obj/structure/chair{ dir = 4 }, -/obj/item/ammo_casing/a357/spent, +/obj/item/ammo_casing/c357/spent, /obj/effect/decal/cleanable/dirt/dust, /turf/open/floor/iron/white/small, /area/station/science/lobby) @@ -21692,7 +21695,7 @@ /obj/effect/decal/cleanable/blood/tracks{ dir = 4 }, -/obj/item/ammo_casing/a357/spent, +/obj/item/ammo_casing/c357/spent, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 8 }, @@ -34884,7 +34887,7 @@ /area/station/engineering/atmos) "moT" = ( /obj/effect/turf_decal/siding/white, -/obj/item/ammo_casing/a357/spent, +/obj/item/ammo_casing/c357/spent, /turf/open/floor/iron/white/small, /area/station/science/lobby) "moU" = ( diff --git a/_maps/shuttles/emergency_lance.dmm b/_maps/shuttles/emergency_lance.dmm index d83294d00ac..2f62bc945bd 100644 --- a/_maps/shuttles/emergency_lance.dmm +++ b/_maps/shuttles/emergency_lance.dmm @@ -62,7 +62,7 @@ /area/shuttle/escape) "bV" = ( /obj/machinery/door/airlock/external/ruin{ - name = "Emegency Shuttle External Airlock" + name = "Emergency Shuttle External Airlock" }, /obj/effect/turf_decal/trimline/dark_blue/arrow_ccw{ dir = 8 @@ -125,7 +125,7 @@ /area/shuttle/escape) "dW" = ( /obj/machinery/door/airlock/external/ruin{ - name = "Emegency Shuttle External Airlock" + name = "Emergency Shuttle External Airlock" }, /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 8 @@ -287,7 +287,7 @@ /area/shuttle/escape) "jo" = ( /obj/machinery/door/airlock/external/ruin{ - name = "Emegency Shuttle External Airlock" + name = "Emergency Shuttle External Airlock" }, /obj/effect/turf_decal/trimline/dark_blue/arrow_ccw{ dir = 8 @@ -533,7 +533,7 @@ /area/shuttle/escape) "pu" = ( /obj/machinery/door/airlock/external/ruin{ - name = "Emegency Shuttle External Airlock" + name = "Emergency Shuttle External Airlock" }, /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 4 @@ -573,7 +573,7 @@ /area/shuttle/escape) "qe" = ( /obj/machinery/door/airlock/external/ruin{ - name = "Emegency Shuttle External Airlock" + name = "Emergency Shuttle External Airlock" }, /obj/effect/mapping_helpers/airlock/access/any/engineering/general, /obj/effect/mapping_helpers/airlock/cyclelink_helper{ @@ -609,7 +609,7 @@ /area/shuttle/escape) "rw" = ( /obj/machinery/door/airlock/external/ruin{ - name = "Emegency Shuttle External Airlock" + name = "Emergency Shuttle External Airlock" }, /obj/effect/mapping_helpers/airlock/access/any/engineering/general, /obj/effect/mapping_helpers/airlock/cyclelink_helper, @@ -682,7 +682,7 @@ /area/shuttle/escape) "uK" = ( /obj/machinery/door/airlock/external/ruin{ - name = "Emegency Shuttle External Airlock" + name = "Emergency Shuttle External Airlock" }, /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 4 @@ -868,7 +868,7 @@ /area/shuttle/escape) "Cx" = ( /obj/machinery/door/airlock/external/ruin{ - name = "Emegency Shuttle External Airlock" + name = "Emergency Shuttle External Airlock" }, /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 8 @@ -887,7 +887,7 @@ /area/shuttle/escape) "CR" = ( /obj/machinery/door/airlock/external/ruin{ - name = "Emegency Shuttle External Airlock" + name = "Emergency Shuttle External Airlock" }, /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 4 @@ -1199,7 +1199,7 @@ /area/shuttle/escape) "LD" = ( /obj/machinery/door/airlock/external/ruin{ - name = "Emegency Shuttle External Airlock" + name = "Emergency Shuttle External Airlock" }, /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 8 diff --git a/_maps/shuttles/emergency_raven.dmm b/_maps/shuttles/emergency_raven.dmm index 7e393756800..7eb255fc2d4 100644 --- a/_maps/shuttles/emergency_raven.dmm +++ b/_maps/shuttles/emergency_raven.dmm @@ -742,7 +742,7 @@ /area/shuttle/escape) "cd" = ( /obj/machinery/door/airlock/external/ruin{ - name = "Emegency Shuttle External Airlock" + name = "Emergency Shuttle External Airlock" }, /turf/open/floor/plating, /area/shuttle/escape) @@ -1456,7 +1456,7 @@ /area/shuttle/escape) "eo" = ( /obj/machinery/door/airlock/external/ruin{ - name = "Emegency Shuttle External Airlock" + name = "Emergency Shuttle External Airlock" }, /obj/docking_port/mobile/emergency{ name = "CentCom Raven Cruiser" diff --git a/_maps/templates/lazy_templates/nukie_base.dmm b/_maps/templates/lazy_templates/nukie_base.dmm index bb1d8bd4126..5178b0f9356 100644 --- a/_maps/templates/lazy_templates/nukie_base.dmm +++ b/_maps/templates/lazy_templates/nukie_base.dmm @@ -68,6 +68,17 @@ /obj/effect/turf_decal/siding/thinplating_new/light{ dir = 8 }, +/obj/structure/closet/syndicate/personal, +/obj/item/reagent_containers/cup/beaker/large, +/obj/item/reagent_containers/cup/beaker/large, +/obj/item/reagent_containers/cup/beaker/large, +/obj/item/reagent_containers/cup/beaker/large, +/obj/item/reagent_containers/cup/beaker/large, +/obj/item/reagent_containers/cup/beaker/large, +/obj/item/reagent_containers/cup/beaker/large, +/obj/item/reagent_containers/cup/beaker/large, +/obj/item/reagent_containers/cup/beaker/large, +/obj/item/reagent_containers/cup/beaker/large, /turf/open/floor/mineral/plastitanium, /area/centcom/syndicate_mothership/expansion_chemicalwarfare) "bo" = ( diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm index 2c20765d351..5cb838603c9 100644 --- a/code/__DEFINES/combat.dm +++ b/code/__DEFINES/combat.dm @@ -154,6 +154,13 @@ DEFINE_BITFIELD(status_flags, list( #define ATTACK_EFFECT_MECHTOXIN "mech_toxin" #define ATTACK_EFFECT_BOOP "boop" //Honk +/// Attack animation for sharp items +#define ATTACK_ANIMATION_SLASH "slash" +/// Attack animation for pointy items +#define ATTACK_ANIMATION_PIERCE "pierce" +/// Animation for blunt attacks +#define ATTACK_ANIMATION_BLUNT "blunt" + //the define for visible message range in combat #define SAMETILE_MESSAGE_RANGE 1 #define COMBAT_MESSAGE_RANGE 3 diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm index deb9188d76e..3569b9af1e6 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm @@ -244,6 +244,7 @@ ///from /mob/living/proc/check_block(): (atom/hit_by, damage, attack_text, attack_type, armour_penetration, damage_type) #define COMSIG_LIVING_CHECK_BLOCK "living_check_block" + #define FAILED_BLOCK NONE #define SUCCESSFUL_BLOCK (1<<0) ///Hit by successful disarm attack (mob/living/attacker, zone_targeted, item/weapon) diff --git a/code/__DEFINES/dcs/signals/signals_mod.dm b/code/__DEFINES/dcs/signals/signals_mod.dm index 58fd8ca689e..c08377d50db 100644 --- a/code/__DEFINES/dcs/signals/signals_mod.dm +++ b/code/__DEFINES/dcs/signals/signals_mod.dm @@ -45,3 +45,5 @@ #define COMSIG_MOD_TETHER_SNAP "mod_tether_snap" /// Called when a MOD module generats its worn overlay #define COMSIG_MODULE_GENERATE_WORN_OVERLAY "mod_module_generate_worn_overlay" +/// Called when the MOD control unit fetches its visor icon +#define COMSIG_MOD_GET_VISOR_OVERLAY "mod_get_visor_overlay" diff --git a/code/__DEFINES/hud.dm b/code/__DEFINES/hud.dm index 785d353982c..975b6037f6b 100644 --- a/code/__DEFINES/hud.dm +++ b/code/__DEFINES/hud.dm @@ -54,8 +54,10 @@ #define ui_combo "CENTER+4:24,SOUTH+1:7" //combo meter for martial arts //Lower right, persistent menu -#define ui_drop_throw "EAST-1:28,SOUTH+1:7" +#define ui_rest "EAST-1:28,SOUTH+1:7" +#define ui_drop_throw "EAST-1:28,SOUTH+1:24" #define ui_above_movement "EAST-2:26,SOUTH+1:7" +#define ui_above_movement_top "EAST-2:26, SOUTH+1:24" #define ui_above_intent "EAST-3:24, SOUTH+1:7" #define ui_movi "EAST-2:26,SOUTH:5" #define ui_acti "EAST-3:24,SOUTH:5" @@ -65,8 +67,7 @@ #define ui_crafting "EAST-4:22,SOUTH:5" #define ui_building "EAST-4:22,SOUTH:21" #define ui_language_menu "EAST-4:6,SOUTH:21" -#define ui_navigate_menu "EAST-4:22,SOUTH:5" -#define ui_floor_changer "EAST-3:24, SOUTH+1:3" +#define ui_navigate_menu "EAST-4:6,SOUTH:5" //Upper left (action buttons) #define ui_action_palette "WEST+0:23,NORTH-1:5" @@ -100,7 +101,11 @@ #define ui_living_healthdoll "EAST-1:28,CENTER-1:15" //Humans -#define ui_human_floor_changer "EAST-4:22, SOUTH+1:7" +#define ui_human_floor_changer "EAST-4:22,SOUTH:5" +#define ui_human_crafting "EAST-3:24,SOUTH+1:7" +#define ui_human_navigate "EAST-3:7,SOUTH+1:7" +#define ui_human_language "EAST-3:7,SOUTH+1:24" +#define ui_human_area "EAST-3:24,SOUTH+1:24" //Drones #define ui_drone_drop "CENTER+1:18,SOUTH:5" @@ -123,7 +128,7 @@ #define ui_borg_camera "CENTER+3:21,SOUTH:5" #define ui_borg_alerts "CENTER+4:21,SOUTH:5" #define ui_borg_language_menu "CENTER+4:19,SOUTH+1:6" -#define ui_borg_navigate_menu "CENTER+4:19,SOUTH+1:6" +#define ui_borg_navigate_menu "CENTER+4:3,SOUTH+1:6" #define ui_borg_floor_changer "EAST-1:28,SOUTH+1:39" //Aliens @@ -132,7 +137,7 @@ #define ui_alien_queen_finder "EAST,CENTER-3:15" #define ui_alien_storage_r "CENTER+1:18,SOUTH:5" #define ui_alien_language_menu "EAST-4:20,SOUTH:5" -#define ui_alien_navigate_menu "EAST-4:20,SOUTH:5" +#define ui_alien_navigate_menu "EAST-4:4,SOUTH:5" //AI #define ui_ai_core "BOTTOM:6,RIGHT-4" @@ -173,7 +178,7 @@ #define ui_pai_view_images "SOUTH:6,WEST+12" #define ui_pai_radio "SOUTH:6,WEST+13" #define ui_pai_language_menu "SOUTH+1:8,WEST+12:31" -#define ui_pai_navigate_menu "SOUTH+1:8,WEST+12:31" +#define ui_pai_navigate_menu "SOUTH+1:8,WEST+12:15" //Ghosts #define ui_ghost_spawners_menu "SOUTH:6,CENTER-3:24" @@ -182,8 +187,8 @@ #define ui_ghost_teleport "SOUTH:6,CENTER:24" #define ui_ghost_pai "SOUTH: 6, CENTER+1:24" #define ui_ghost_minigames "SOUTH: 6, CENTER+2:24" -#define ui_ghost_language_menu "SOUTH: 22, CENTER+3:22" -#define ui_ghost_floor_changer "SOUTH: 6, CENTER+3:23" +#define ui_ghost_language_menu "SOUTH: 6, CENTER+3:24" +#define ui_ghost_floor_changer "SOUTH: 6, CENTER+3:8" //Blobbernauts #define ui_blobbernaut_overmind_health "EAST-1:28,CENTER+0:19" diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index ffc42371844..cb338595b4d 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -255,8 +255,6 @@ GLOBAL_LIST_INIT(turfs_pass_meteor, typecacheof(list( #define ismecha(A) (istype(A, /obj/vehicle/sealed/mecha)) -#define ismopable(A) (A && ((PLANE_TO_TRUE(A.plane) == FLOOR_PLANE) ? (A.layer <= FLOOR_CLEAN_LAYER) : (A.layer <= GAME_CLEAN_LAYER))) //If something can be cleaned by floor-cleaning devices such as mops or clean bots - #define isorgan(A) (istype(A, /obj/item/organ)) #define isclothing(A) (istype(A, /obj/item/clothing)) diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers.dm index 2c5d8722f11..35dd5cc35ce 100644 --- a/code/__DEFINES/layers.dm +++ b/code/__DEFINES/layers.dm @@ -156,9 +156,7 @@ #define CATWALK_LAYER (14 + TOPDOWN_LAYER) #define LOWER_RUNE_LAYER (15 + TOPDOWN_LAYER) #define RUNE_LAYER (16 + TOPDOWN_LAYER) -/// [GAME_CLEAN_LAYER] but for floors. -/// Basically any layer below this (numerically) is "on" a floor for the purposes of washing -#define FLOOR_CLEAN_LAYER (21 + TOPDOWN_LAYER) +#define CLEANABLE_FLOOR_OBJECT_LAYER (21 + TOPDOWN_LAYER) //Placeholders in case the game plane and possibly other things between it and the floor plane are ever made into topdown planes @@ -185,9 +183,7 @@ #define BOT_PATH_LAYER 2.497 #define LOW_OBJ_LAYER 2.5 #define HIGH_PIPE_LAYER 2.54 -// Anything above this layer is not "on" a turf for the purposes of washing -// I hate this life of ours -#define GAME_CLEAN_LAYER 2.55 +#define CLEANABLE_OBJECT_LAYER 2.55 #define TRAM_STRUCTURE_LAYER 2.57 #define TRAM_FLOOR_LAYER 2.58 #define TRAM_WALL_LAYER 2.59 @@ -201,6 +197,7 @@ #define DOOR_HELPER_LAYER 2.72 //keep this above DOOR_ACCESS_HELPER_LAYER and OPEN_DOOR_LAYER since the others tend to have tiny sprites that tend to be covered up. #define PROJECTILE_HIT_THRESHHOLD_LAYER 2.75 //projectiles won't hit objects at or below this layer if possible #define TABLE_LAYER 2.8 +#define GIB_LAYER 2.85 // sit on top of tables, but below machines #define BELOW_OBJ_LAYER 2.9 #define LOW_ITEM_LAYER 2.95 //#define OBJ_LAYER 3 //For easy recordkeeping; this is a byond define diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index 3e53268a0d5..3d42c989479 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -1407,4 +1407,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai ///Trait given to atoms currently affected by projectile dampeners #define TRAIT_GOT_DAMPENED "got_dampened" +/// Apply to movables to say "hey, this movable is technically flat on the floor, so it'd be mopped up by a mop" +#define TRAIT_MOPABLE "mopable" + // END TRAIT DEFINES diff --git a/code/__HELPERS/cmp.dm b/code/__HELPERS/cmp.dm index efee782aaeb..aa13b74f0e1 100644 --- a/code/__HELPERS/cmp.dm +++ b/code/__HELPERS/cmp.dm @@ -215,3 +215,8 @@ var/position_a = fluids_priority.Find(initial(a.required_fluid_type)) var/position_b = fluids_priority.Find(initial(b.required_fluid_type)) return cmp_numeric_asc(position_a, position_b) || cmp_text_asc(initial(b.name), initial(a.name)) + +///Sorts stock parts based on tier +/proc/cmp_rped_sort(obj/item/first_item, obj/item/second_item) + ///even though stacks aren't stock parts, get_part_rating() is defined on the item level (see /obj/item/proc/get_part_rating()) and defaults to returning 0. + return second_item.get_part_rating() - first_item.get_part_rating() diff --git a/code/__HELPERS/construction.dm b/code/__HELPERS/construction.dm index 166a009f066..a0ebb3db034 100644 --- a/code/__HELPERS/construction.dm +++ b/code/__HELPERS/construction.dm @@ -46,9 +46,9 @@ return 0 /** - * Splits a stack. we don't use /obj/item/stack/proc/fast_split_stack because Byond complains that should only be called asynchronously. + * Splits a stack. we don't use /obj/item/stack/proc/split_stack because Byond complains that should only be called asynchronously. * This proc is also more faster because it doesn't deal with mobs, copying evidences or refreshing atom storages - * Has special internal uses for e.g. by the material container + * Has special internal uses for e.g. by the material container & RPED * * Arguments: * - [target][obj/item/stack]: the stack to split diff --git a/code/__HELPERS/hud.dm b/code/__HELPERS/hud.dm index 40a12767d28..d7d053c40bb 100644 --- a/code/__HELPERS/hud.dm +++ b/code/__HELPERS/hud.dm @@ -3,14 +3,10 @@ var/y_off = round((i-1) / 2) return"CENTER+[x_off]:16,SOUTH+[y_off]:5" -/proc/ui_equip_position(mob/M) - var/y_off = round((M.held_items.len-1) / 2) //values based on old equip ui position (CENTER: +/-16,SOUTH+1:5) - return "CENTER:-16,SOUTH+[y_off+1]:5" - /proc/ui_swaphand_position(mob/M, which = LEFT_HANDS) //values based on old swaphand ui positions (CENTER: +/-16,SOUTH+1:5) - var/x_off = which == LEFT_HANDS ? -1 : 0 + var/x_off = (which == LEFT_HANDS) ? -1 : null var/y_off = round((M.held_items.len-1) / 2) - return "CENTER+[x_off]:16,SOUTH+[y_off+1]:5" + return "CENTER[x_off]:16,SOUTH+[y_off+1]:5" /proc/ui_perk_position(perk_count) var/y_off = perk_count < 1 ? 0 : perk_count/2 diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index 357ff150415..b1ac9fdbac3 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -48,7 +48,6 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_CHASM_STOPPER" = TRAIT_CHASM_STOPPER, "TRAIT_COMBAT_MODE_SKIP_INTERACTION" = TRAIT_COMBAT_MODE_SKIP_INTERACTION, "TRAIT_DEL_ON_SPACE_DUMP" = TRAIT_DEL_ON_SPACE_DUMP, - "TRAIT_VALID_DNA_INFUSION" = TRAIT_VALID_DNA_INFUSION, "TRAIT_FROZEN" = TRAIT_FROZEN, "TRAIT_HAS_LABEL" = TRAIT_HAS_LABEL, "TRAIT_HEARING_SENSITIVE" = TRAIT_HEARING_SENSITIVE, @@ -57,34 +56,36 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_IRRADIATED" = TRAIT_IRRADIATED, "TRAIT_IS_AQUARIUM" = TRAIT_IS_AQUARIUM, "TRAIT_LAVA_IMMUNE" = TRAIT_LAVA_IMMUNE, + "TRAIT_MOPABLE" = TRAIT_MOPABLE, "TRAIT_MOVE_FLOATING" = TRAIT_MOVE_FLOATING, "TRAIT_MOVE_FLYING" = TRAIT_MOVE_FLYING, "TRAIT_MOVE_GROUND" = TRAIT_MOVE_GROUND, "TRAIT_MOVE_PHASING" = TRAIT_MOVE_PHASING, "TRAIT_MOVE_UPSIDE_DOWN" = TRAIT_MOVE_UPSIDE_DOWN, - "TRAIT_MOVE_VENTCRAWLING" = TRAIT_MOVE_VENTCRAWLING, "TRAIT_MOVE_UPSIDE_DOWN" = TRAIT_MOVE_UPSIDE_DOWN, + "TRAIT_MOVE_VENTCRAWLING" = TRAIT_MOVE_VENTCRAWLING, + "TRAIT_NOT_BARFABLE" = TRAIT_NOT_BARFABLE, + "TRAIT_NOT_ENGRAVABLE" = TRAIT_NOT_ENGRAVABLE, "TRAIT_NO_FLOATING_ANIM" = TRAIT_NO_FLOATING_ANIM, "TRAIT_NO_MANIFEST_CONTENTS_ERROR" = TRAIT_NO_MANIFEST_CONTENTS_ERROR, "TRAIT_NO_MISSING_ITEM_ERROR" = TRAIT_NO_MISSING_ITEM_ERROR, "TRAIT_NO_THROW_HITPUSH" = TRAIT_NO_THROW_HITPUSH, - "TRAIT_NOT_BARFABLE" = TRAIT_NOT_BARFABLE, - "TRAIT_NOT_ENGRAVABLE" = TRAIT_NOT_ENGRAVABLE, "TRAIT_ODD_CUSTOMIZABLE_FOOD_INGREDIENT" = TRAIT_ODD_CUSTOMIZABLE_FOOD_INGREDIENT, "TRAIT_ON_HIT_EFFECT" = TRAIT_ON_HIT_EFFECT, "TRAIT_RUNECHAT_HIDDEN" = TRAIT_RUNECHAT_HIDDEN, "TRAIT_SCARY_FISHERMAN" = TRAIT_SCARY_FISHERMAN, "TRAIT_SECLUDED_LOCATION" = TRAIT_SECLUDED_LOCATION, + "TRAIT_SILENT_REACTIONS" = TRAIT_SILENT_REACTIONS, "TRAIT_SNOWSTORM_IMMUNE" = TRAIT_SNOWSTORM_IMMUNE, "TRAIT_SPELLS_TRANSFER_TO_LOC" = TRAIT_SPELLS_TRANSFER_TO_LOC, "TRAIT_STOP_FISH_REPRODUCTION_AND_GROWTH" = TRAIT_STOP_FISH_REPRODUCTION_AND_GROWTH, "TRAIT_TELEKINESIS_CONTROLLED" = TRAIT_TELEKINESIS_CONTROLLED, "TRAIT_UNDERFLOOR" = TRAIT_UNDERFLOOR, "TRAIT_UNIQUE_IMMERSE" = TRAIT_UNIQUE_IMMERSE, + "TRAIT_VALID_DNA_INFUSION" = TRAIT_VALID_DNA_INFUSION, "TRAIT_WADDLING" = TRAIT_WADDLING, "TRAIT_WAS_RENAMED" = TRAIT_WAS_RENAMED, "TRAIT_WEATHER_IMMUNE" = TRAIT_WEATHER_IMMUNE, - "TRAIT_SILENT_REACTIONS" = TRAIT_SILENT_REACTIONS, ), /datum/controller/subsystem/economy = list( "TRAIT_MARKET_CRASHING" = TRAIT_MARKET_CRASHING, diff --git a/code/_onclick/hud/action_button.dm b/code/_onclick/hud/action_button.dm index 562266f51c0..5d092cbc1f6 100644 --- a/code/_onclick/hud/action_button.dm +++ b/code/_onclick/hud/action_button.dm @@ -110,32 +110,37 @@ last_hovored_ref = null if(!can_use(usr)) return + var/datum/hud/our_hud = usr.hud_used if(over_object == src) our_hud.hide_landings() return + if(istype(over_object, /atom/movable/screen/action_landing)) var/atom/movable/screen/action_landing/reserve = over_object reserve.hit_by(src) - our_hud.hide_landings() save_position() + our_hud.hide_landings() return - our_hud.hide_landings() if(istype(over_object, /atom/movable/screen/button_palette) || istype(over_object, /atom/movable/screen/palette_scroll)) our_hud.position_action(src, SCRN_OBJ_IN_PALETTE) save_position() + our_hud.hide_landings() return + if(istype(over_object, /atom/movable/screen/movable/action_button)) var/atom/movable/screen/movable/action_button/button = over_object our_hud.position_action_relative(src, button) save_position() + our_hud.hide_landings() return . = ..() our_hud.position_action(src, screen_loc) save_position() + our_hud.hide_landings() /atom/movable/screen/movable/action_button/proc/save_position() var/mob/user = our_hud.mymob @@ -290,6 +295,7 @@ /atom/movable/screen/button_palette/proc/set_hud(datum/hud/our_hud) src.our_hud = our_hud refresh_owner() + disable_landing() // If our hud already has elements, don't force hide us /atom/movable/screen/button_palette/update_name(updates) . = ..() @@ -311,6 +317,15 @@ icon_state = "[ui_name]_palette" +/atom/movable/screen/button_palette/proc/activate_landing() + // Reveal ourselves to the user + invisibility = INVISIBILITY_NONE + +/atom/movable/screen/button_palette/proc/disable_landing() + // If we have no elements in the palette, hide your ugly self please + if (!length(our_hud.palette_actions?.actions)) + invisibility = INVISIBILITY_ABSTRACT + /atom/movable/screen/button_palette/MouseEntered(location, control, params) . = ..() if(QDELETED(src)) diff --git a/code/_onclick/hud/alien.dm b/code/_onclick/hud/alien.dm index b9a0e3bf655..20e1e72f950 100644 --- a/code/_onclick/hud/alien.dm +++ b/code/_onclick/hud/alien.dm @@ -39,13 +39,13 @@ using = new /atom/movable/screen/swap_hand(null, src) using.icon = ui_style using.icon_state = "swap_1" - using.screen_loc = ui_swaphand_position(owner,1) + using.screen_loc = ui_swaphand_position(owner, 1) static_inventory += using using = new /atom/movable/screen/swap_hand(null, src) using.icon = ui_style using.icon_state = "swap_2" - using.screen_loc = ui_swaphand_position(owner,2) + using.screen_loc = ui_swaphand_position(owner, 2) static_inventory += using action_intent = new /atom/movable/screen/combattoggle/flashy(null, src) @@ -61,7 +61,6 @@ floor_change = new /atom/movable/screen/floor_changer(null, src) floor_change.icon = ui_style - floor_change.screen_loc = ui_above_intent static_inventory += floor_change using = new/atom/movable/screen/language_menu(null, src) @@ -77,11 +76,11 @@ using.screen_loc = ui_drop_throw static_inventory += using - using = new /atom/movable/screen/resist(null, src) - using.icon = ui_style - using.screen_loc = ui_above_movement - using.update_appearance() - hotkeybuttons += using + resist_icon = new /atom/movable/screen/resist(null, src) + resist_icon.icon = ui_style + resist_icon.screen_loc = ui_above_movement + resist_icon.update_appearance() + hotkeybuttons += resist_icon throw_icon = new /atom/movable/screen/throw_catch(null, src) throw_icon.icon = ui_style diff --git a/code/_onclick/hud/alien_larva.dm b/code/_onclick/hud/alien_larva.dm index bb2b9fcb14a..922953b01a3 100644 --- a/code/_onclick/hud/alien_larva.dm +++ b/code/_onclick/hud/alien_larva.dm @@ -12,7 +12,6 @@ floor_change = new /atom/movable/screen/floor_changer(null, src) floor_change.icon = ui_style - floor_change.screen_loc = ui_above_intent static_inventory += floor_change healths = new /atom/movable/screen/healths/alien(null, src) diff --git a/code/_onclick/hud/generic_dextrous.dm b/code/_onclick/hud/generic_dextrous.dm index 4048fd91b16..134f91a2b8d 100644 --- a/code/_onclick/hud/generic_dextrous.dm +++ b/code/_onclick/hud/generic_dextrous.dm @@ -3,11 +3,6 @@ ..() var/atom/movable/screen/using - using = new /atom/movable/screen/drop(null, src) - using.icon = ui_style - using.screen_loc = ui_drone_drop - static_inventory += using - pull_icon = new /atom/movable/screen/pull(null, src) pull_icon.icon = ui_style pull_icon.update_appearance() @@ -16,21 +11,20 @@ build_hand_slots() - using = new /atom/movable/screen/swap_hand(null, src) + using = new /atom/movable/screen/drop(null, src) using.icon = ui_style - using.icon_state = "swap_1_m" - using.screen_loc = ui_swaphand_position(owner,1) + using.screen_loc = ui_swaphand_position(owner, 1) static_inventory += using using = new /atom/movable/screen/swap_hand(null, src) using.icon = ui_style - using.icon_state = "swap_2" - using.screen_loc = ui_swaphand_position(owner,2) + using.icon_state = "act_swap" + using.screen_loc = ui_swaphand_position(owner, 2) static_inventory += using action_intent = new /atom/movable/screen/combattoggle/flashy(null, src) action_intent.icon = ui_style - action_intent.screen_loc = ui_combat_toggle + action_intent.screen_loc = ui_movi static_inventory += action_intent floor_change = new /atom/movable/screen/floor_changer(null, src) diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm index ab1e5fccfbb..ae1e619763f 100644 --- a/code/_onclick/hud/hud.dm +++ b/code/_onclick/hud/hud.dm @@ -40,6 +40,7 @@ GLOBAL_LIST_INIT(available_ui_styles, list( var/atom/movable/screen/pull_icon var/atom/movable/screen/rest_icon var/atom/movable/screen/throw_icon + var/atom/movable/screen/resist_icon var/atom/movable/screen/module_store_icon var/atom/movable/screen/floor_change @@ -505,12 +506,17 @@ GLOBAL_LIST_INIT(available_ui_styles, list( static_inventory += hand_box hand_box.update_appearance() - var/i = 1 - for(var/atom/movable/screen/swap_hand/SH in static_inventory) - SH.screen_loc = ui_swaphand_position(mymob, IS_RIGHT_INDEX(i) ? RIGHT_HANDS : LEFT_HANDS) - i++ - for(var/atom/movable/screen/human/equip/E in static_inventory) - E.screen_loc = ui_equip_position(mymob) + var/num_of_swaps = 0 + for(var/atom/movable/screen/swap_hand/swap_hands in static_inventory) + num_of_swaps += 1 + + var/hand_num = 1 + for(var/atom/movable/screen/swap_hand/swap_hands in static_inventory) + var/hand_ind = RIGHT_HANDS + if (num_of_swaps > 1) + hand_ind = IS_RIGHT_INDEX(hand_num) ? LEFT_HANDS : RIGHT_HANDS + swap_hands.screen_loc = ui_swaphand_position(mymob, hand_ind) + hand_num += 1 if(ismob(mymob) && mymob.hud_used == src) show_hud(hud_version) @@ -581,11 +587,13 @@ GLOBAL_LIST_INIT(available_ui_styles, list( /datum/hud/proc/generate_landings(atom/movable/screen/movable/action_button/button) listed_actions.generate_landing() palette_actions.generate_landing() + toggle_palette.activate_landing() /// Clears all currently visible landings /datum/hud/proc/hide_landings() listed_actions.clear_landing() palette_actions.clear_landing() + toggle_palette.disable_landing() // Updates any existing "owned" visuals, ensures they continue to be visible /datum/hud/proc/update_our_owner() diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm index 50954584a0d..918f5f62a32 100644 --- a/code/_onclick/hud/human.dm +++ b/code/_onclick/hud/human.dm @@ -4,6 +4,7 @@ /atom/movable/screen/human/toggle name = "toggle" icon_state = "toggle" + base_icon_state = "toggle" mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/human/toggle/Click() @@ -23,17 +24,11 @@ usr.client.screen += targetmob.hud_used.toggleable_inventory targetmob.hud_used.hidden_inventory_update(usr) + update_appearance() -/atom/movable/screen/human/equip - name = "equip" - icon_state = "act_equip" - mouse_over_pointer = MOUSE_HAND_POINTER - -/atom/movable/screen/human/equip/Click() - if(ismecha(usr.loc)) // stops inventory actions in a mech - return TRUE - var/mob/living/carbon/human/H = usr - H.quick_equip() +/atom/movable/screen/human/toggle/update_icon_state() + icon_state = "[base_icon_state][hud?.inventory_shown ? "_active" : ""]" + return ..() /atom/movable/screen/ling icon = 'icons/hud/screen_changeling.dmi' @@ -63,14 +58,17 @@ using = new /atom/movable/screen/language_menu(null, src) using.icon = ui_style + using.screen_loc = ui_human_language static_inventory += using using = new /atom/movable/screen/navigate(null, src) using.icon = ui_style + using.screen_loc = ui_human_navigate static_inventory += using using = new /atom/movable/screen/area_creator(null, src) using.icon = ui_style + using.screen_loc = ui_human_area static_inventory += using action_intent = new /atom/movable/screen/combattoggle/flashy(null, src) @@ -78,23 +76,17 @@ action_intent.screen_loc = ui_combat_toggle static_inventory += action_intent - floor_change = new /atom/movable/screen/floor_changer(null, src) + floor_change = new /atom/movable/screen/floor_changer/vertical(null, src) floor_change.icon = ui_style floor_change.screen_loc = ui_human_floor_changer static_inventory += floor_change - using = new /atom/movable/screen/mov_intent(null, src) using.icon = ui_style using.icon_state = (owner.move_intent == MOVE_INTENT_RUN ? "running" : "walking") using.screen_loc = ui_movi static_inventory += using - using = new /atom/movable/screen/drop(null, src) - using.icon = ui_style - using.screen_loc = ui_drop_throw - static_inventory += using - inv_box = new /atom/movable/screen/inventory(null, src) inv_box.name = "uniform" inv_box.icon = ui_style @@ -115,16 +107,15 @@ build_hand_slots() - using = new /atom/movable/screen/swap_hand(null, src) + using = new /atom/movable/screen/drop(null, src) using.icon = ui_style - using.icon_state = "swap_1" - using.screen_loc = ui_swaphand_position(owner,1) + using.screen_loc = ui_swaphand_position(owner, 1) static_inventory += using using = new /atom/movable/screen/swap_hand(null, src) using.icon = ui_style - using.icon_state = "swap_2" - using.screen_loc = ui_swaphand_position(owner,2) + using.icon_state = "act_swap" + using.screen_loc = ui_swaphand_position(owner, 2) static_inventory += using inv_box = new /atom/movable/screen/inventory(null, src) @@ -190,21 +181,16 @@ inv_box.slot_id = ITEM_SLOT_SUITSTORE static_inventory += inv_box - using = new /atom/movable/screen/resist(null, src) - using.icon = ui_style - using.screen_loc = ui_above_intent - hotkeybuttons += using + resist_icon = new /atom/movable/screen/resist(null, src) + resist_icon.icon = ui_style + resist_icon.screen_loc = ui_above_movement + hotkeybuttons += resist_icon using = new /atom/movable/screen/human/toggle(null, src) using.icon = ui_style using.screen_loc = ui_inventory static_inventory += using - using = new /atom/movable/screen/human/equip() - using.icon = ui_style - using.screen_loc = ui_equip_position(mymob) - static_inventory += using - inv_box = new /atom/movable/screen/inventory(null, src) inv_box.name = "gloves" inv_box.icon = ui_style @@ -266,7 +252,7 @@ rest_icon = new /atom/movable/screen/rest(null, src) rest_icon.icon = ui_style - rest_icon.screen_loc = ui_above_movement + rest_icon.screen_loc = ui_rest rest_icon.update_appearance() static_inventory += rest_icon @@ -287,7 +273,7 @@ pull_icon = new /atom/movable/screen/pull(null, src) pull_icon.icon = ui_style - pull_icon.screen_loc = ui_above_intent + pull_icon.screen_loc = ui_above_movement_top pull_icon.update_appearance() static_inventory += pull_icon diff --git a/code/_onclick/hud/new_player.dm b/code/_onclick/hud/new_player.dm index 01f79aa1476..594449575ea 100644 --- a/code/_onclick/hud/new_player.dm +++ b/code/_onclick/hud/new_player.dm @@ -259,12 +259,13 @@ icon = 'icons/hud/lobby/join.dmi' icon_state = "" //Default to not visible base_icon_state = "join_game" + enabled = null // set in init /atom/movable/screen/lobby/button/join/Initialize(mapload, datum/hud/hud_owner) . = ..() - set_button_status(FALSE) switch(SSticker.current_state) if(GAME_STATE_PREGAME, GAME_STATE_STARTUP) + set_button_status(FALSE) RegisterSignal(SSticker, COMSIG_TICKER_ENTER_SETTING_UP, PROC_REF(show_join_button)) if(GAME_STATE_SETTING_UP) set_button_status(TRUE) @@ -330,6 +331,7 @@ icon = 'icons/hud/lobby/observe.dmi' icon_state = "observe_disabled" base_icon_state = "observe" + enabled = null // set in init /atom/movable/screen/lobby/button/observe/Initialize(mapload, datum/hud/hud_owner) . = ..() diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index b72924fdbe5..fefd4ea889d 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -364,7 +364,7 @@ name = "change floor" icon = 'icons/hud/screen_midnight.dmi' icon_state = "floor_change" - screen_loc = ui_floor_changer + screen_loc = ui_above_intent mouse_over_pointer = MOUSE_HAND_POINTER var/vertical = FALSE @@ -439,10 +439,12 @@ name = "resist" icon = 'icons/hud/screen_midnight.dmi' icon_state = "act_resist" + base_icon_state = "act_resist" plane = HUD_PLANE mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/resist/Click() + flick("[base_icon_state]_on", src) if(isliving(usr)) var/mob/living/L = usr L.resist() @@ -464,7 +466,7 @@ var/mob/living/user = hud?.mymob if(!istype(user)) return ..() - icon_state = "[base_icon_state][user.resting ? 0 : null]" + icon_state = "[base_icon_state][user.resting ? "_on" : null]" return ..() /atom/movable/screen/storage @@ -537,7 +539,7 @@ /atom/movable/screen/throw_catch name = "throw/catch" icon = 'icons/hud/screen_midnight.dmi' - icon_state = "act_throw_off" + icon_state = "act_throw" mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/throw_catch/Click() diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 3d17d9abe89..70da5ac19de 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -444,21 +444,30 @@ else return clamp(w_class * 6, 10, 100) // Multiply the item's weight class by 6, then clamp the value between 10 and 100 -/mob/living/proc/send_item_attack_message(obj/item/I, mob/living/user, hit_area, def_zone) - if(!I.force && !length(I.attack_verb_simple) && !length(I.attack_verb_continuous)) +/mob/living/proc/send_item_attack_message(obj/item/weapon, mob/living/user, hit_area, def_zone) + if(!weapon.force && !length(weapon.attack_verb_simple) && !length(weapon.attack_verb_continuous)) return - var/message_verb_continuous = length(I.attack_verb_continuous) ? "[pick(I.attack_verb_continuous)]" : "attacks" - var/message_verb_simple = length(I.attack_verb_simple) ? "[pick(I.attack_verb_simple)]" : "attack" - var/message_hit_area = get_hit_area_message(hit_area) - var/attack_message_spectator = "[src] [message_verb_continuous][message_hit_area] with [I]!" - var/attack_message_victim = "Something [message_verb_continuous] you[message_hit_area] with [I]!" - var/attack_message_attacker = "You [message_verb_simple] [src][message_hit_area] with [I]!" + // Sanity in case one is null for some reason + var/picked_index = rand(max(length(weapon.attack_verb_simple), length(weapon.attack_verb_continuous))) + + var/message_verb_continuous = "attacks" + var/message_verb_simple = "attack" + var/message_hit_area = get_hit_area_message(hit_area) + // Sanity in case one is... longer than the other? + if (picked_index && length(weapon.attack_verb_continuous) >= picked_index) + message_verb_continuous = weapon.attack_verb_continuous[picked_index] + if (picked_index && length(weapon.attack_verb_simple) >= picked_index) + message_verb_simple = weapon.attack_verb_simple[picked_index] + + var/attack_message_spectator = "[src] [message_verb_continuous][message_hit_area] with [weapon]!" + var/attack_message_victim = "Something [message_verb_continuous] you[message_hit_area] with [weapon]!" + var/attack_message_attacker = "You [message_verb_simple] [src][message_hit_area] with [weapon]!" if(user in viewers(src, null)) - attack_message_spectator = "[user] [message_verb_continuous] [src][message_hit_area] with [I]!" - attack_message_victim = "[user] [message_verb_continuous] you[message_hit_area] with [I]!" + attack_message_spectator = "[user] [message_verb_continuous] [src][message_hit_area] with [weapon]!" + attack_message_victim = "[user] [message_verb_continuous] you[message_hit_area] with [weapon]!" if(user == src) - attack_message_victim = "You [message_verb_simple] yourself[message_hit_area] with [I]." + attack_message_victim = "You [message_verb_simple] yourself[message_hit_area] with [weapon]." visible_message(span_danger("[attack_message_spectator]"),\ span_userdanger("[attack_message_victim]"), null, COMBAT_MESSAGE_RANGE, user) if(is_blind()) diff --git a/code/controllers/subsystem/movement/newtonian_movement.dm b/code/controllers/subsystem/movement/newtonian_movement.dm index 41db87d722b..e4143669678 100644 --- a/code/controllers/subsystem/movement/newtonian_movement.dm +++ b/code/controllers/subsystem/movement/newtonian_movement.dm @@ -39,7 +39,7 @@ MOVEMENT_SUBSYSTEM_DEF(newtonian_movement) /datum/controller/subsystem/movement/newtonian_movement/proc/fire_moveloop(datum/move_loop/loop) // Loop isn't even running right now - if(!(loop.status & MOVELOOP_STATUS_QUEUED) || isnull(loop.queued_time)) + if(!(loop.status & MOVELOOP_STATUS_QUEUED)) return // Drop the loop, process it, and if its still valid - queue it again dequeue_loop(loop) diff --git a/code/datums/components/alternative_sharpness.dm b/code/datums/components/alternative_sharpness.dm new file mode 100644 index 00000000000..e32c3ccf45d --- /dev/null +++ b/code/datums/components/alternative_sharpness.dm @@ -0,0 +1,60 @@ +/// Allows items to have different sharpness for right click attacks +/datum/component/alternative_sharpness + /// Sharpness we change the attack to + var/alt_sharpness = NONE + /// Overrides for continuous attack verbs when performing an alt attack + var/verbs_continuous = null + /// Overrides for simple attack verbs when performing an alt attack + var/verbs_simple = null + /// Value by which we offset our force during the attack + var/force_mod = 0 + /// Are we currently performing an alt attack? + var/alt_attacking = FALSE + /// Trait required for us to trigger + var/required_trait = null + // Old values before we overrode them + var/base_continuous = null + var/base_simple = null + var/base_sharpness = NONE + +/datum/component/alternative_sharpness/Initialize(alt_sharpness, verbs_continuous = null, verbs_simple = null, force_mod = 0, required_trait = null) + if (!isitem(parent)) + return COMPONENT_INCOMPATIBLE + var/obj/item/weapon = parent + src.alt_sharpness = alt_sharpness + src.verbs_continuous = verbs_continuous + src.verbs_simple = verbs_simple + src.force_mod = force_mod + src.required_trait = required_trait + base_continuous = weapon.attack_verb_continuous + base_simple = weapon.attack_verb_simple + +/datum/component/alternative_sharpness/RegisterWithParent() + RegisterSignal(parent, COMSIG_ITEM_PRE_ATTACK_SECONDARY, PROC_REF(on_secondary_attack)) + +/datum/component/alternative_sharpness/proc/on_secondary_attack(obj/item/source, atom/target, mob/user, params) + SIGNAL_HANDLER + + if (alt_attacking || (required_trait && !HAS_TRAIT(source, required_trait))) + return + + alt_attacking = TRUE + source.force += force_mod + base_sharpness = source.sharpness + source.sharpness = alt_sharpness + if (!isnull(verbs_continuous)) + source.attack_verb_continuous = verbs_continuous + + if (!isnull(verbs_simple)) + source.attack_verb_simple = verbs_simple + + // I absolutely despise this but this is geniunely the best way to do this without creating and hooking up to a dozen signals and still risking failure edge cases + addtimer(CALLBACK(src, PROC_REF(disable_alt_attack)), 1) + +/datum/component/alternative_sharpness/proc/disable_alt_attack() + var/obj/item/weapon = parent + alt_attacking = FALSE + weapon.force -= force_mod + weapon.attack_verb_continuous = base_continuous + weapon.attack_verb_simple = base_simple + weapon.sharpness = base_sharpness diff --git a/code/datums/components/aquarium.dm b/code/datums/components/aquarium.dm index 184513a2e79..f207ecd9f55 100644 --- a/code/datums/components/aquarium.dm +++ b/code/datums/components/aquarium.dm @@ -189,7 +189,7 @@ /datum/component/aquarium/proc/on_click_alt(atom/movable/source, mob/living/user) SIGNAL_HANDLER - if(!user.can_perform_action(src)) + if(!user.can_perform_action(source)) return var/closing = HAS_TRAIT(parent, TRAIT_AQUARIUM_PANEL_OPEN) if(closing) diff --git a/code/datums/components/cleaner.dm b/code/datums/components/cleaner.dm index 7072f271c7a..035f0c054db 100644 --- a/code/datums/components/cleaner.dm +++ b/code/datums/components/cleaner.dm @@ -96,8 +96,8 @@ ADD_TRAIT(target, TRAIT_CURRENTLY_CLEANING, REF(src)) // We need to update our planes on overlay changes RegisterSignal(target, COMSIG_MOVABLE_Z_CHANGED, PROC_REF(cleaning_target_moved)) - var/mutable_appearance/low_bubble = mutable_appearance('icons/effects/effects.dmi', "bubbles", GAME_CLEAN_LAYER, target, GAME_PLANE) - var/mutable_appearance/high_bubble = mutable_appearance('icons/effects/effects.dmi', "bubbles", GAME_CLEAN_LAYER, target, ABOVE_GAME_PLANE) + var/mutable_appearance/low_bubble = mutable_appearance('icons/effects/effects.dmi', "bubbles", CLEANABLE_OBJECT_LAYER, target, GAME_PLANE) + var/mutable_appearance/high_bubble = mutable_appearance('icons/effects/effects.dmi', "bubbles", CLEANABLE_OBJECT_LAYER, target, ABOVE_GAME_PLANE) var/list/icon_offsets = target.get_oversized_icon_offsets() low_bubble.pixel_x = icon_offsets["x"] low_bubble.pixel_y = icon_offsets["y"] @@ -140,13 +140,13 @@ if(same_z_layer) return // First, get rid of the old overlay - var/mutable_appearance/old_low_bubble = mutable_appearance('icons/effects/effects.dmi', "bubbles", GAME_CLEAN_LAYER, old_turf, GAME_PLANE) - var/mutable_appearance/old_high_bubble = mutable_appearance('icons/effects/effects.dmi', "bubbles", GAME_CLEAN_LAYER, old_turf, ABOVE_GAME_PLANE) + var/mutable_appearance/old_low_bubble = mutable_appearance('icons/effects/effects.dmi', "bubbles", CLEANABLE_OBJECT_LAYER, old_turf, GAME_PLANE) + var/mutable_appearance/old_high_bubble = mutable_appearance('icons/effects/effects.dmi', "bubbles", CLEANABLE_OBJECT_LAYER, old_turf, ABOVE_GAME_PLANE) source.cut_overlay(old_low_bubble) source.cut_overlay(old_high_bubble) // Now, add the new one - var/mutable_appearance/new_low_bubble = mutable_appearance('icons/effects/effects.dmi', "bubbles", GAME_CLEAN_LAYER, new_turf, GAME_PLANE) - var/mutable_appearance/new_high_bubble = mutable_appearance('icons/effects/effects.dmi', "bubbles", GAME_CLEAN_LAYER, new_turf, ABOVE_GAME_PLANE) + var/mutable_appearance/new_low_bubble = mutable_appearance('icons/effects/effects.dmi', "bubbles", CLEANABLE_OBJECT_LAYER, new_turf, GAME_PLANE) + var/mutable_appearance/new_high_bubble = mutable_appearance('icons/effects/effects.dmi', "bubbles", CLEANABLE_OBJECT_LAYER, new_turf, ABOVE_GAME_PLANE) source.add_overlay(new_low_bubble) source.add_overlay(new_high_bubble) diff --git a/code/datums/components/combustible_flooder.dm b/code/datums/components/combustible_flooder.dm index 07df03671c1..c24fae55b84 100644 --- a/code/datums/components/combustible_flooder.dm +++ b/code/datums/components/combustible_flooder.dm @@ -57,7 +57,11 @@ message_admins(admin_message) if(delete_parent && !QDELETED(parent)) - qdel(parent) // For things with the explodable component like plasma mats this isn't necessary, but there's no harm. + if(isobj(parent)) + var/obj/obj_parent = parent + obj_parent.deconstruct(disassembled = FALSE) + else + qdel(parent) // For things with the explodable component like plasma mats this isn't necessary, but there's no harm. qdel(src) /// fire_act reaction. diff --git a/code/datums/components/crafting/crafting.dm b/code/datums/components/crafting/crafting.dm index ca8c8fdc62f..04a53ce3a3a 100644 --- a/code/datums/components/crafting/crafting.dm +++ b/code/datums/components/crafting/crafting.dm @@ -1,16 +1,23 @@ -/datum/component/personal_crafting/Initialize() +/datum/component/personal_crafting + /// Custom screen_loc for our element + var/screen_loc_override + +/datum/component/personal_crafting/Initialize(screen_loc_override) + src.screen_loc_override = screen_loc_override if(ismob(parent)) RegisterSignal(parent, COMSIG_MOB_CLIENT_LOGIN, PROC_REF(create_mob_button)) -/datum/component/personal_crafting/proc/create_mob_button(mob/user, client/CL) +/datum/component/personal_crafting/proc/create_mob_button(mob/user, client/user_client) SIGNAL_HANDLER - var/datum/hud/H = user.hud_used - var/atom/movable/screen/craft/C = new() - C.icon = H.ui_style - H.static_inventory += C - CL.screen += C - RegisterSignal(C, COMSIG_SCREEN_ELEMENT_CLICK, PROC_REF(component_ui_interact)) + var/datum/hud/hud = user.hud_used + var/atom/movable/screen/craft/craft_ui = new() + craft_ui.icon = hud.ui_style + if (screen_loc_override) + craft_ui.screen_loc = screen_loc_override + hud.static_inventory += craft_ui + user_client.screen += craft_ui + RegisterSignal(craft_ui, COMSIG_SCREEN_ELEMENT_CLICK, PROC_REF(component_ui_interact)) #define COOKING TRUE #define CRAFTING FALSE diff --git a/code/datums/components/explodable.dm b/code/datums/components/explodable.dm index 9dc8db3bbc4..db77f865fd7 100644 --- a/code/datums/components/explodable.dm +++ b/code/datums/components/explodable.dm @@ -147,18 +147,20 @@ return // If we don't do this and this doesn't delete it can lock the MC into only processing Input, Timers, and Explosions. var/atom/bomb = parent - var/log = TRUE - if(light_impact_range < 1) - log = FALSE + var/do_log = light_impact_range >= 1 exploding = TRUE - explosion(bomb, devastation_range, heavy_impact_range, light_impact_range, flame_range, flash_range, log, uncapped) //epic explosion time + explosion(bomb, devastation_range, heavy_impact_range, light_impact_range, flame_range, flash_range, do_log, uncapped) //epic explosion time switch(delete_after) if(EXPLODABLE_DELETE_SELF) qdel(src) if(EXPLODABLE_DELETE_PARENT) - qdel(bomb) + if(isobj(bomb)) + var/obj/obj_bomb = bomb + obj_bomb.deconstruct(disassembled = FALSE) + else + qdel(bomb) else addtimer(CALLBACK(src, PROC_REF(reset_exploding)), 0.1 SECONDS) diff --git a/code/datums/components/food_storage.dm b/code/datums/components/food_storage.dm index 843f611e5ff..32fb27c7b72 100644 --- a/code/datums/components/food_storage.dm +++ b/code/datums/components/food_storage.dm @@ -4,7 +4,7 @@ /datum/component/food_storage /// Reference to what we have in our food. - var/obj/item/stored_item + VAR_FINAL/obj/item/stored_item /// The amount of volume the food has on creation - Used for probabilities var/initial_volume = 10 /// Minimum size items that can be inserted @@ -13,16 +13,14 @@ var/bad_chance_of_discovery = 0 /// What are the odds we see the stored item before we bite it? var/good_chance_of_discovery = 100 - /// The stored item was found out somehow. - var/discovered = FALSE /datum/component/food_storage/Initialize(_minimum_weight_class = WEIGHT_CLASS_SMALL, _bad_chance = 0, _good_chance = 100) RegisterSignal(parent, COMSIG_ATOM_ITEM_INTERACTION_SECONDARY, PROC_REF(try_inserting_item)) + RegisterSignal(parent, COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM, PROC_REF(on_requesting_context_from_item)) RegisterSignal(parent, COMSIG_CLICK_CTRL, PROC_REF(try_removing_item)) RegisterSignal(parent, COMSIG_FOOD_EATEN, PROC_REF(consume_food_storage)) - RegisterSignal(parent, COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM, PROC_REF(on_requesting_context_from_item)) - + RegisterSignals(parent, list(COMSIG_FOOD_CONSUMED, COMSIG_OBJ_DECONSTRUCT), PROC_REF(storage_consumed)) var/atom/food = parent initial_volume = food.reagents.total_volume @@ -33,12 +31,19 @@ food.flags_1 |= HAS_CONTEXTUAL_SCREENTIPS_1 -/datum/component/food_storage/Destroy(force) - if(stored_item) - stored_item.forceMove(stored_item.drop_location()) - stored_item.dropped() - stored_item = null - . = ..() +/datum/component/food_storage/UnregisterFromParent() + UnregisterSignal(parent, list( + COMSIG_ATOM_ITEM_INTERACTION_SECONDARY, + COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM, + COMSIG_CLICK_CTRL, + COMSIG_FOOD_CONSUMED, + COMSIG_FOOD_EATEN, + COMSIG_OBJ_DECONSTRUCT, + )) + if(QDELING(parent) || QDELETED(stored_item)) + return + stored_item.forceMove(stored_item.drop_location()) + stored_item = null /** Begins the process of inserted an item. * @@ -60,19 +65,17 @@ return NONE if(inserted_item.w_class > minimum_weight_class) - to_chat(user, span_warning("\The [inserted_item.name] won't fit in \the [parent].")) + to_chat(user, span_warning("[inserted_item] won't fit in [parent].")) return ITEM_INTERACT_BLOCKING if(!QDELETED(stored_item)) - to_chat(user, span_warning("There's something in \the [parent].")) - return ITEM_INTERACT_BLOCKING - - if(HAS_TRAIT(inserted_item, TRAIT_NODROP)) - to_chat(user, span_warning("\the [inserted_item] is stuck to your hand, you can't put into \the [parent]!")) + to_chat(user, span_warning("There's something in [parent].")) return ITEM_INTERACT_BLOCKING - user.visible_message(span_notice("[user.name] begins inserting [inserted_item.name] into \the [parent]."), \ - span_notice("You start to insert the [inserted_item.name] into \the [parent].")) + user.visible_message( + span_notice("[user] begins inserting [inserted_item] into [parent]."), + span_notice("You start to insert the [inserted_item] into [parent]."), + ) INVOKE_ASYNC(src, PROC_REF(insert_item), inserted_item, user) return ITEM_INTERACT_SUCCESS @@ -89,14 +92,11 @@ var/atom/food = parent - if(QDELETED(stored_item)) - return CLICK_ACTION_BLOCKING - if(!food.can_interact(user)) return CLICK_ACTION_BLOCKING - user.visible_message(span_notice("[user.name] begins tearing at \the [parent]."), \ - span_notice("You start to rip into \the [parent].")) + user.visible_message(span_notice("[user] begins tearing at [parent]."), \ + span_notice("You start to rip into [parent].")) INVOKE_ASYNC(src, PROC_REF(begin_remove_item), user) return CLICK_ACTION_SUCCESS @@ -110,9 +110,12 @@ /datum/component/food_storage/proc/insert_item(obj/item/inserted_item, mob/user) if(!do_after(user, 1.5 SECONDS, target = parent)) return + if(!user.temporarilyRemoveItemFromInventory(inserted_item)) + to_chat(user, span_warning("You can't seem to insert [inserted_item] into [parent].")) + return var/atom/food = parent - to_chat(user, span_notice("You slip [inserted_item.name] inside \the [parent].")) + to_chat(user, span_notice("You slip [inserted_item] inside [parent].")) inserted_item.forceMove(food) user.log_message("inserted [inserted_item] into [parent].", LOG_ATTACK) food.add_fingerprint(user) @@ -126,19 +129,22 @@ * user - person removing the item. */ /datum/component/food_storage/proc/begin_remove_item(mob/user) - if(do_after(user, 10 SECONDS, target = parent)) - remove_item(user) + if(!do_after(user, 10 SECONDS, target = parent)) + return + if(QDELETED(stored_item)) + to_chat(user, span_warning("There's nothing in [parent].")) + return + remove_item(user) /** * Removes the stored item, putting it in user's hands or on the ground, then updates the reference. */ /datum/component/food_storage/proc/remove_item(mob/user) if(user.put_in_hands(stored_item)) - user.visible_message(span_warning("[user.name] slowly pulls [stored_item.name] out of \the [parent]."), \ - span_warning("You slowly pull [stored_item.name] out of \the [parent].")) + user.visible_message(span_warning("[user] slowly pulls [stored_item] out of [parent]."), \ + span_warning("You slowly pull [stored_item] out of [parent].")) else - stored_item.dropped() - stored_item.visible_message(span_warning("[stored_item.name] falls out of \the [parent].")) + stored_item.visible_message(span_warning("[stored_item] falls out of [parent].")) update_stored_item() @@ -167,9 +173,10 @@ /// Chance of finding the held item = bad chance - 50 good_chance_of_discovery = bad_chance_of_discovery - 50 + var/discovered = FALSE if(prob(good_chance_of_discovery)) //finding the item, without biting it discovered = TRUE - to_chat(target, span_warning("It feels like there's something in \the [parent]...!")) + to_chat(target, span_warning("It feels like there's something in [parent]...!")) else if(prob(bad_chance_of_discovery)) //finding the item, BY biting it user.log_message("just fed [key_name(target)] \a [stored_item] which was hidden in [parent].", LOG_ATTACK) @@ -179,6 +186,14 @@ if(!QDELETED(stored_item) && discovered) INVOKE_ASYNC(src, PROC_REF(remove_item), user) +/// When fully consumed, just drop the item out on the ground. +/datum/component/food_storage/proc/storage_consumed(datum/source, mob/living/target, mob/living/user) + SIGNAL_HANDLER + if(QDELETED(stored_item)) + return + stored_item.forceMove(stored_item.drop_location()) + stored_item = null + /** Updates the reference of the stored item. * * Checks the food's contents for if an alternate item was placed into the food. diff --git a/code/datums/components/jetpack.dm b/code/datums/components/jetpack.dm index 1a44da7eb6d..c7ff096029b 100644 --- a/code/datums/components/jetpack.dm +++ b/code/datums/components/jetpack.dm @@ -110,6 +110,7 @@ RegisterSignal(user, COMSIG_MOVABLE_PRE_MOVE, PROC_REF(pre_move_react)) RegisterSignal(user, COMSIG_MOB_CLIENT_MOVE_NOGRAV, PROC_REF(on_client_move)) RegisterSignal(user, COMSIG_MOB_ATTEMPT_HALT_SPACEMOVE, PROC_REF(on_pushoff)) + RegisterSignal(user, COMSIG_MOVABLE_DRIFT_BLOCK_INPUT, PROC_REF(on_input_block)) last_stabilization_tick = world.time START_PROCESSING(SSnewtonian_movement, src) if (effect_type) @@ -164,6 +165,17 @@ var/max_drift_force = MOVE_DELAY_TO_DRIFT(user.cached_multiplicative_slowdown) user.drift_handler.stabilize_drift(user.client.intended_direction ? dir2angle(user.client.intended_direction) : null, user.client.intended_direction ? max_drift_force : 0, stabilization_force * (seconds_per_tick * 1 SECONDS)) +/datum/component/jetpack/proc/on_input_block(mob/source) + SIGNAL_HANDLER + + if (!should_trigger(source)) + return + + if (!check_on_move.Invoke(TRUE)) + return + + return DRIFT_ALLOW_INPUT + /datum/component/jetpack/proc/on_client_move(mob/source, list/move_args) SIGNAL_HANDLER @@ -179,11 +191,10 @@ var/max_drift_force = MOVE_DELAY_TO_DRIFT(source.cached_multiplicative_slowdown) var/applied_force = drift_force var/move_dir = source.client.intended_direction - // We're not moving anywhere, try to see if we can simulate pushing off a wall - if (isnull(source.drift_handler)) - var/atom/movable/backup = source.get_spacemove_backup(move_dir, FALSE) - if (backup && !(backup.dir & move_dir)) - applied_force = max_drift_force + // Try to see if we can simulate pushing off a wall + var/atom/movable/backup = source.get_spacemove_backup(move_dir, FALSE, include_floors = TRUE) + if (backup && !(backup.dir & move_dir)) + applied_force = max_drift_force // We don't want to force the loop to fire before stabilizing if we're going to, otherwise its effects will be delayed until the next tick which is jank var/force_stabilize = FALSE diff --git a/code/datums/components/leanable.dm b/code/datums/components/leanable.dm index b95fd734ad0..b823cf5ec50 100644 --- a/code/datums/components/leanable.dm +++ b/code/datums/components/leanable.dm @@ -2,26 +2,21 @@ /datum/component/leanable /// How much will mobs that lean onto this object be offset var/leaning_offset = 11 - /// List of click modifiers that are required to be present for leaning to trigger - var/list/click_mods = null - /// Callback called for additional checks if a lean is valid - var/datum/callback/lean_check = null - /// Whenever this object can be leaned on from the same turf as its' own. Do not use without a custom lean_check! - var/same_turf = FALSE /// List of mobs currently leaning on our parent var/list/leaning_mobs = list() -/datum/component/leanable/Initialize(leaning_offset = 11, list/click_mods = null, datum/callback/lean_check = null, same_turf = FALSE) +/datum/component/leanable/Initialize(mob/living/leaner, leaning_offset = 11) . = ..() src.leaning_offset = leaning_offset - src.click_mods = click_mods - src.lean_check = lean_check - src.same_turf = same_turf + mousedrop_receive(parent, leaner, leaner) /datum/component/leanable/RegisterWithParent() RegisterSignal(parent, COMSIG_MOUSEDROPPED_ONTO, PROC_REF(mousedrop_receive)) RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved)) +/datum/component/leanable/UnregisterFromParent() + UnregisterSignal(parent, list(COMSIG_MOUSEDROPPED_ONTO, COMSIG_MOVABLE_MOVED)) + /datum/component/leanable/Destroy(force) for (var/mob/living/leaner as anything in leaning_mobs) leaner.stop_leaning() @@ -30,17 +25,13 @@ /datum/component/leanable/proc/on_moved(datum/source) SIGNAL_HANDLER + for (var/mob/living/leaner as anything in leaning_mobs) leaner.stop_leaning() /datum/component/leanable/proc/mousedrop_receive(atom/source, atom/movable/dropped, mob/user, params) if (dropped != user) return - if (islist(click_mods)) - var/list/modifiers = params2list(params) - for (var/modifier in click_mods) - if (!LAZYACCESS(modifiers, modifier)) - return if (!iscarbon(dropped) && !iscyborg(dropped)) return var/mob/living/leaner = dropped @@ -49,9 +40,7 @@ if (HAS_TRAIT_FROM(leaner, TRAIT_UNDENSE, LEANING_TRAIT)) return var/turf/checked_turf = get_step(leaner, REVERSE_DIR(leaner.dir)) - if (checked_turf != get_turf(source) && (!same_turf || get_turf(source) != get_turf(leaner))) - return - if (!isnull(lean_check) && !lean_check.Invoke(dropped, params)) + if (checked_turf != get_turf(source)) return leaner.start_leaning(source, leaning_offset) leaning_mobs += leaner @@ -63,6 +52,13 @@ leaning_mobs -= source UnregisterSignal(source, list(COMSIG_LIVING_STOPPED_LEANING, COMSIG_QDELETING)) +/** + * Makes the mob lean on an atom + * Arguments + * + * * atom/lean_target - the target the mob is trying to lean on + * * leaning_offset - pixel offset to apply on the mob when leaning + */ /mob/living/proc/start_leaning(atom/lean_target, leaning_offset) var/new_x = lean_target.pixel_x + base_pixel_x + body_position_pixel_x_offset var/new_y = lean_target.pixel_y + base_pixel_y + body_position_pixel_y_offset @@ -95,6 +91,7 @@ /// You fall on your face if you get teleported while leaning /mob/living/proc/teleport_away_while_leaning() SIGNAL_HANDLER + // Make sure we unregister signal handlers and reset animation stop_leaning() // -1000 aura @@ -103,6 +100,7 @@ /mob/living/proc/stop_leaning() SIGNAL_HANDLER + UnregisterSignal(src, list( COMSIG_MOB_CLIENT_PRE_MOVE, COMSIG_LIVING_DISARM_HIT, @@ -117,5 +115,6 @@ /mob/living/proc/lean_dir_changed(atom/source, old_dir, new_dir) SIGNAL_HANDLER + if (old_dir != new_dir) INVOKE_ASYNC(src, PROC_REF(stop_leaning)) diff --git a/code/datums/components/mutant_hands.dm b/code/datums/components/mutant_hands.dm index 66e19852ae7..b3478d41f31 100644 --- a/code/datums/components/mutant_hands.dm +++ b/code/datums/components/mutant_hands.dm @@ -147,6 +147,7 @@ icon = 'icons/effects/blood.dmi' icon_state = "bloodhand_left" base_icon_state = "bloodhand" + icon_angle = 90 item_flags = ABSTRACT | DROPDEL | HAND_ITEM resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF diff --git a/code/datums/drift_handler.dm b/code/datums/drift_handler.dm index dc47f28819b..dcf0771d8a5 100644 --- a/code/datums/drift_handler.dm +++ b/code/datums/drift_handler.dm @@ -36,7 +36,6 @@ RegisterSignal(drifting_loop, COMSIG_MOVELOOP_PREPROCESS_CHECK, PROC_REF(before_move)) RegisterSignal(drifting_loop, COMSIG_MOVELOOP_POSTPROCESS, PROC_REF(after_move)) RegisterSignal(drifting_loop, COMSIG_QDELETING, PROC_REF(loop_death)) - RegisterSignal(parent, COMSIG_MOB_ATTEMPT_HALT_SPACEMOVE, PROC_REF(attempt_halt)) if(drifting_loop.status & MOVELOOP_STATUS_RUNNING) drifting_start(drifting_loop) // There's a good chance it'll autostart, gotta catch that @@ -208,28 +207,28 @@ if(world.time < block_inputs_until) return COMSIG_MOB_CLIENT_BLOCK_PRE_MOVE -/datum/drift_handler/proc/attempt_halt(mob/source, movement_dir, continuous_move, atom/backup) - SIGNAL_HANDLER - - if ((backup.density || !backup.CanPass(source, get_dir(backup, source))) && (get_dir(source, backup) == movement_dir || source.loc == backup.loc)) +/datum/drift_handler/proc/attempt_halt(movement_dir, continuous_move, atom/backup) + if ((backup.density || !backup.CanPass(parent, get_dir(backup, parent))) && (get_dir(parent, backup) == movement_dir || parent.loc == backup.loc)) if (drift_force >= INERTIA_FORCE_THROW_FLOOR) - source.throw_at(backup, 1, floor(1 + (drift_force - INERTIA_FORCE_THROW_FLOOR) / INERTIA_FORCE_PER_THROW_FORCE), spin = FALSE) - return + parent.throw_at(backup, 1, floor(1 + (drift_force - INERTIA_FORCE_THROW_FLOOR) / INERTIA_FORCE_PER_THROW_FORCE), spin = FALSE) + return FALSE if (drift_force < INERTIA_FORCE_SPACEMOVE_GRAB || isnull(drifting_loop)) - return + return FALSE - if (!isnull(source.client) && source.client.intended_direction) - if ((source.client.intended_direction & movement_dir) && !(get_dir(source, backup) & movement_dir)) - return + if (ismob(parent)) + var/mob/source_user = parent + if (!isnull(source_user.client) && source_user.client.intended_direction) + if ((source_user.client.intended_direction & movement_dir) && !(get_dir(source_user, backup) & movement_dir)) + return FALSE - if (drift_force <= INERTIA_FORCE_SPACEMOVE_REDUCTION / source.inertia_force_weight) - glide_to_halt(get_loop_delay(source)) - return COMPONENT_PREVENT_SPACEMOVE_HALT + if (drift_force <= INERTIA_FORCE_SPACEMOVE_REDUCTION / parent.inertia_force_weight) + glide_to_halt(get_loop_delay(parent)) + return TRUE - drift_force -= INERTIA_FORCE_SPACEMOVE_REDUCTION / source.inertia_force_weight - drifting_loop.set_delay(get_loop_delay(source)) - return COMPONENT_PREVENT_SPACEMOVE_HALT + drift_force -= INERTIA_FORCE_SPACEMOVE_REDUCTION / parent.inertia_force_weight + drifting_loop.set_delay(get_loop_delay(parent)) + return TRUE /datum/drift_handler/proc/get_loop_delay(atom/movable/movable) return (DEFAULT_INERTIA_SPEED / ((1 - INERTIA_SPEED_COEF) + drift_force * INERTIA_SPEED_COEF)) * movable.inertia_move_multiplier diff --git a/code/datums/elements/weapon_description.dm b/code/datums/elements/weapon_description.dm index eda7ca59b49..64d044fb74a 100644 --- a/code/datums/elements/weapon_description.dm +++ b/code/datums/elements/weapon_description.dm @@ -73,9 +73,9 @@ // Doesn't show the base notes for items that have the override notes variable set to true if(!source.override_notes) - if (source.sharpness & SHARP_EDGED) + if (source.get_sharpness() & SHARP_EDGED) readout += "It's sharp and could cause bleeding wounds." - if (source.sharpness & SHARP_POINTY) + if (source.get_sharpness() & SHARP_POINTY) readout += "It's pointy and could cause piercing wounds." // Make sure not to divide by 0 on accident if(source.force > 0) diff --git a/code/datums/keybinding/living.dm b/code/datums/keybinding/living.dm index f3d9cbf2989..f3b14c58dfa 100644 --- a/code/datums/keybinding/living.dm +++ b/code/datums/keybinding/living.dm @@ -16,10 +16,20 @@ . = ..() if(.) return - var/mob/living/L = user.mob - L.resist() + var/mob/living/owner = user.mob + owner.resist() + if (owner.hud_used?.resist_icon) + owner.hud_used.resist_icon.icon_state = "[owner.hud_used.resist_icon.base_icon_state]_on" return TRUE +/datum/keybinding/living/resist/up(client/user) + . = ..() + if(.) + return + var/mob/living/owner = user.mob + if (owner.hud_used?.resist_icon) + owner.hud_used.resist_icon.icon_state = owner.hud_used.resist_icon.base_icon_state + /datum/keybinding/living/look_up hotkey_keys = list("P") name = "look up" diff --git a/code/datums/looping_sounds/_looping_sound.dm b/code/datums/looping_sounds/_looping_sound.dm index d0ad6544ca6..1dc2e69f2ca 100644 --- a/code/datums/looping_sounds/_looping_sound.dm +++ b/code/datums/looping_sounds/_looping_sound.dm @@ -174,7 +174,7 @@ if(!each_once) . = play_from while(!isfile(.) && !isnull(.)) - . = pick_weight(.) + . = pick_weight_recursive(.) return . if(in_order) @@ -192,7 +192,7 @@ // Tree is a list of lists containign files // If an entry in the tree goes to 0 length, we cut it from the list tree += list(.) - . = pick_weight(.) + . = pick_weight_recursive(.) if(!isfile(.)) return diff --git a/code/datums/looping_sounds/machinery_sounds.dm b/code/datums/looping_sounds/machinery_sounds.dm index c4648a929b3..92f78074c98 100644 --- a/code/datums/looping_sounds/machinery_sounds.dm +++ b/code/datums/looping_sounds/machinery_sounds.dm @@ -1,13 +1,17 @@ /datum/looping_sound/showering start_sound = 'sound/machines/shower/shower_start.ogg' start_length = 2 - mid_sounds = list('sound/machines/shower/shower_mid1.ogg' = 1, 'sound/machines/shower/shower_mid2.ogg' = 1, 'sound/machines/shower/shower_mid3.ogg' = 1) + mid_sounds = list( + 'sound/machines/shower/shower_mid1.ogg', + 'sound/machines/shower/shower_mid2.ogg', + 'sound/machines/shower/shower_mid3.ogg', + ) mid_length = 10 end_sound = 'sound/machines/shower/shower_end.ogg' volume = 20 /datum/looping_sound/supermatter - mid_sounds = list('sound/machines/sm/loops/calm.ogg' = 1) + mid_sounds = list('sound/machines/sm/loops/calm.ogg') mid_length = 60 volume = 40 extra_range = 25 @@ -16,14 +20,14 @@ vary = TRUE /datum/looping_sound/destabilized_crystal - mid_sounds = list('sound/machines/sm/loops/delamming.ogg' = 1) + mid_sounds = list('sound/machines/sm/loops/delamming.ogg') mid_length = 60 volume = 55 extra_range = 15 vary = TRUE /datum/looping_sound/hypertorus - mid_sounds = list('sound/machines/hypertorus/loops/hypertorus_nominal.ogg' = 1) + mid_sounds = list('sound/machines/hypertorus/loops/hypertorus_nominal.ogg') mid_length = 60 volume = 55 extra_range = 15 @@ -32,35 +36,41 @@ /datum/looping_sound/generator start_sound = 'sound/machines/generator/generator_start.ogg' start_length = 4 - mid_sounds = list('sound/machines/generator/generator_mid1.ogg' = 1, 'sound/machines/generator/generator_mid2.ogg' = 1, 'sound/machines/generator/generator_mid3.ogg' = 1) + mid_sounds = list( + 'sound/machines/generator/generator_mid1.ogg', + 'sound/machines/generator/generator_mid2.ogg', + 'sound/machines/generator/generator_mid3.ogg', + ) mid_length = 4 end_sound = 'sound/machines/generator/generator_end.ogg' volume = 40 - /datum/looping_sound/deep_fryer start_sound = 'sound/machines/fryer/deep_fryer_immerse.ogg' //my immersions start_length = 10 - mid_sounds = list('sound/machines/fryer/deep_fryer_1.ogg' = 1, 'sound/machines/fryer/deep_fryer_2.ogg' = 1) + mid_sounds = list( + 'sound/machines/fryer/deep_fryer_1.ogg', + 'sound/machines/fryer/deep_fryer_2.ogg', + ) mid_length = 2 end_sound = 'sound/machines/fryer/deep_fryer_emerge.ogg' volume = 15 /datum/looping_sound/clock - mid_sounds = list('sound/ambience/misc/ticking_clock.ogg' = 1) + mid_sounds = list('sound/ambience/misc/ticking_clock.ogg') mid_length = 40 volume = 50 ignore_walls = FALSE /datum/looping_sound/grill - mid_sounds = list('sound/machines/grill/grillsizzle.ogg' = 1) + mid_sounds = list('sound/machines/grill/grillsizzle.ogg') mid_length = 18 volume = 50 /datum/looping_sound/oven start_sound = 'sound/machines/oven/oven_loop_start.ogg' //my immersions start_length = 12 - mid_sounds = list('sound/machines/oven/oven_loop_mid.ogg' = 1) + mid_sounds = list('sound/machines/oven/oven_loop_mid.ogg') mid_length = 13 end_sound = 'sound/machines/oven/oven_loop_end.ogg' volume = 100 @@ -68,19 +78,25 @@ /datum/looping_sound/deep_fryer mid_length = 2 - mid_sounds = list('sound/machines/fryer/deep_fryer_1.ogg' = 1, 'sound/machines/fryer/deep_fryer_2.ogg' = 1) + mid_sounds = list( + 'sound/machines/fryer/deep_fryer_1.ogg', + 'sound/machines/fryer/deep_fryer_2.ogg', + ) volume = 30 /datum/looping_sound/microwave start_sound = 'sound/machines/microwave/microwave-start.ogg' start_length = 10 - mid_sounds = list('sound/machines/microwave/microwave-mid1.ogg' = 10, 'sound/machines/microwave/microwave-mid2.ogg' = 1) + mid_sounds = list( + 'sound/machines/microwave/microwave-mid1.ogg' = 10, + 'sound/machines/microwave/microwave-mid2.ogg' = 1, + ) mid_length = 10 end_sound = 'sound/machines/microwave/microwave-end.ogg' volume = 90 /datum/looping_sound/lathe_print - mid_sounds = list('sound/machines/lathe/lathe_print.ogg' = 1) + mid_sounds = list('sound/machines/lathe/lathe_print.ogg') mid_length = 20 volume = 50 vary = TRUE @@ -90,19 +106,19 @@ /datum/looping_sound/jackpot mid_length = 11 - mid_sounds = list('sound/machines/roulette/roulettejackpot.ogg' = 1) + mid_sounds = list('sound/machines/roulette/roulettejackpot.ogg') volume = 85 vary = TRUE /datum/looping_sound/server mid_sounds = list( - 'sound/machines/tcomms/tcomms_mid1.ogg' = 1, - 'sound/machines/tcomms/tcomms_mid2.ogg' = 1, - 'sound/machines/tcomms/tcomms_mid3.ogg' = 1, - 'sound/machines/tcomms/tcomms_mid4.ogg' = 1, - 'sound/machines/tcomms/tcomms_mid5.ogg' = 1, - 'sound/machines/tcomms/tcomms_mid6.ogg' = 1, - 'sound/machines/tcomms/tcomms_mid7.ogg' = 1, + 'sound/machines/tcomms/tcomms_mid1.ogg', + 'sound/machines/tcomms/tcomms_mid2.ogg', + 'sound/machines/tcomms/tcomms_mid3.ogg', + 'sound/machines/tcomms/tcomms_mid4.ogg', + 'sound/machines/tcomms/tcomms_mid5.ogg', + 'sound/machines/tcomms/tcomms_mid6.ogg', + 'sound/machines/tcomms/tcomms_mid7.ogg', ) mid_length = 1.8 SECONDS extra_range = -8 @@ -116,7 +132,10 @@ start_sound = 'sound/machines/computer/computer_start.ogg' start_length = 7.2 SECONDS start_volume = 10 - mid_sounds = list('sound/machines/computer/computer_mid1.ogg' = 1, 'sound/machines/computer/computer_mid2.ogg' = 1) + mid_sounds = list( + 'sound/machines/computer/computer_mid1.ogg', + 'sound/machines/computer/computer_mid2.ogg', + ) mid_length = 1.8 SECONDS end_sound = 'sound/machines/computer/computer_end.ogg' end_volume = 10 @@ -141,7 +160,12 @@ falloff_exponent = 20 /datum/looping_sound/firealarm - mid_sounds = list('sound/machines/fire_alarm/FireAlarm1.ogg' = 1,'sound/machines/fire_alarm/FireAlarm2.ogg' = 1,'sound/machines/fire_alarm/FireAlarm3.ogg' = 1,'sound/machines/fire_alarm/FireAlarm4.ogg' = 1) + mid_sounds = list( + 'sound/machines/fire_alarm/FireAlarm1.ogg', + 'sound/machines/fire_alarm/FireAlarm2.ogg', + 'sound/machines/fire_alarm/FireAlarm3.ogg', + 'sound/machines/fire_alarm/FireAlarm4.ogg', + ) mid_length = 2.4 SECONDS volume = 30 @@ -151,30 +175,30 @@ falloff_exponent = 5 /datum/looping_sound/boiling - mid_sounds = list('sound/effects/bubbles/bubbles2.ogg' = 1) + mid_sounds = list('sound/effects/bubbles/bubbles2.ogg') mid_length = 7 SECONDS volume = 25 /datum/looping_sound/typing mid_sounds = list( - 'sound/machines/terminal/terminal_button01.ogg' = 1, - 'sound/machines/terminal/terminal_button02.ogg' = 1, - 'sound/machines/terminal/terminal_button03.ogg' = 1, - 'sound/machines/terminal/terminal_button04.ogg' = 1, - 'sound/machines/terminal/terminal_button05.ogg' = 1, - 'sound/machines/terminal/terminal_button06.ogg' = 1, - 'sound/machines/terminal/terminal_button07.ogg' = 1, - 'sound/machines/terminal/terminal_button08.ogg' = 1, + 'sound/machines/terminal/terminal_button01.ogg', + 'sound/machines/terminal/terminal_button02.ogg', + 'sound/machines/terminal/terminal_button03.ogg', + 'sound/machines/terminal/terminal_button04.ogg', + 'sound/machines/terminal/terminal_button05.ogg', + 'sound/machines/terminal/terminal_button06.ogg', + 'sound/machines/terminal/terminal_button07.ogg', + 'sound/machines/terminal/terminal_button08.ogg', ) mid_length = 0.3 SECONDS /datum/looping_sound/soup mid_sounds = list( - 'sound/effects/soup_boil/soup_boil1.ogg' = 1, - 'sound/effects/soup_boil/soup_boil2.ogg' = 1, - 'sound/effects/soup_boil/soup_boil3.ogg' = 1, - 'sound/effects/soup_boil/soup_boil4.ogg' = 1, - 'sound/effects/soup_boil/soup_boil5.ogg' = 1, + 'sound/effects/soup_boil/soup_boil1.ogg', + 'sound/effects/soup_boil/soup_boil2.ogg', + 'sound/effects/soup_boil/soup_boil3.ogg', + 'sound/effects/soup_boil/soup_boil4.ogg', + 'sound/effects/soup_boil/soup_boil5.ogg', ) mid_length = 3 SECONDS volume = 80 @@ -182,3 +206,19 @@ end_volume = 60 extra_range = MEDIUM_RANGE_SOUND_EXTRARANGE falloff_exponent = 4 + +/datum/looping_sound/cryo_cell + mid_sounds = list( + 'sound/machines/cryo/cryo_1.ogg', + 'sound/machines/cryo/cryo_2.ogg', + 'sound/machines/cryo/cryo_3.ogg', + 'sound/machines/cryo/cryo_4.ogg', + 'sound/machines/cryo/cryo_5.ogg', + 'sound/machines/cryo/cryo_6.ogg', + 'sound/machines/cryo/cryo_7.ogg', + 'sound/machines/cryo/cryo_8.ogg', + 'sound/machines/cryo/cryo_9.ogg', + 'sound/machines/cryo/cryo_10.ogg', + ) + mid_length = 5 SECONDS + volume = 50 diff --git a/code/datums/martial/sleeping_carp.dm b/code/datums/martial/sleeping_carp.dm index d2142b02a8b..b5ff49037e6 100644 --- a/code/datums/martial/sleeping_carp.dm +++ b/code/datums/martial/sleeping_carp.dm @@ -254,6 +254,7 @@ icon = 'icons/obj/weapons/staff.dmi' icon_state = "bostaff0" base_icon_state = "bostaff" + icon_angle = -135 lefthand_file = 'icons/mob/inhands/weapons/staves_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi' block_chance = 50 diff --git a/code/datums/mutations/tongue_spike.dm b/code/datums/mutations/tongue_spike.dm index c6a48a32a14..663dcd2541a 100644 --- a/code/datums/mutations/tongue_spike.dm +++ b/code/datums/mutations/tongue_spike.dm @@ -45,6 +45,7 @@ desc = "Hardened biomass, shaped into a spike. Very pointy!" icon = 'icons/obj/weapons/thrown.dmi' icon_state = "tonguespike" + icon_angle = 45 force = 2 throwforce = 25 throw_speed = 4 diff --git a/code/datums/storage/subtypes/rped.dm b/code/datums/storage/subtypes/rped.dm index 9931cff7372..a54d52ca359 100644 --- a/code/datums/storage/subtypes/rped.dm +++ b/code/datums/storage/subtypes/rped.dm @@ -6,7 +6,6 @@ #define MAX_STACK_PICKUP 30 /datum/storage/rped - allow_quick_empty = TRUE allow_quick_gather = TRUE max_slots = 50 max_total_storage = 100 @@ -14,7 +13,7 @@ numerical_stacking = TRUE /** - * as of now only these stack components are required to build machines like[thermomaachine,crystallizer,electrolyzer] + * as of now only these stack components are required to build machines like[thermomachine,crystallizer,electrolyzer] * so we limit the rped to pick up only these stack types so players dont cheat and use this as a general storage medium */ var/static/list/allowed_material_types = list( @@ -33,11 +32,20 @@ ) /datum/storage/rped/can_insert(obj/item/to_insert, mob/user, messages = TRUE, force = FALSE) - . = ..() - if(!.) - return . + //only stock parts permited + if(to_insert.get_part_rating()) + return ..() + + //some exceptions to non stock parts + var/static/list/obj/item/exceptions = list( + /obj/item/stack, + /obj/item/circuitboard/machine, + /obj/item/circuitboard/computer, + ) + + return is_type_in_list(to_insert, exceptions) ? ..() : FALSE - //we check how much of glass,plasteel & cable the user can insert +/datum/storage/rped/attempt_insert(obj/item/to_insert, mob/user, override, force, messages) if(isstack(to_insert)) //user tried to insert invalid stacktype if(!is_type_in_list(to_insert, allowed_material_types) && !is_type_in_list(to_insert, allowed_bluespace_types)) @@ -53,60 +61,58 @@ //if yes count total bluespace stuff is the RPED and then compare the total amount to the value the user is trying to insert if(is_type_in_list(stack_content, allowed_bluespace_types)) present_amount += stack_content.amount + //count other normal stack stuff - else if(istype(to_insert,stack_content.type)) + else if(the_stack.merge_type == stack_content.merge_type) present_amount = stack_content.amount break - //no more storage for this specific stack type - if(MAX_STACK_PICKUP - present_amount == 0) - return FALSE + var/available = MAX_STACK_PICKUP - present_amount - //we want the user to insert the exact stack amount which is available so we dont have to bother subtracting & leaving left overs for the user - var/available = MAX_STACK_PICKUP-present_amount - if(available - the_stack.amount < 0) + //no more storage for this specific stack type + if(!available) return FALSE - else if(istype(to_insert, /obj/item/circuitboard/machine) || istype(to_insert, /obj/item/circuitboard/computer)) - return TRUE + var/obj/item/stack/target = the_stack + if(the_stack.amount > available) //take in only a portion of the stack that can fit in our quota + target = fast_split_stack(the_stack, available) + target.copy_evidences(the_stack) - //check normal insertion of other stock parts - else if(!to_insert.get_part_rating()) - return FALSE + . = ..(target, user, override, force, messages) + if(!. && target != the_stack) //in case of failure merge back the split amount into the original + the_stack.add(target.amount) + qdel(target) - return . - -/datum/storage/rped/mass_empty(datum/source, mob/user) - if(!allow_quick_empty) return - remove_lowest_tier(user.drop_location()) + return ..() -/** - * Searches through everything currently in storage, calculates the lowest tier of parts inside of it, - * and then dumps out every part that has the equal tier of parts. Likely a worse implementation of remove_all. - * - * Arguments - * * atom/dump_loc - where we're placing the item - */ -/datum/storage/rped/proc/remove_lowest_tier(atom/dump_loc = parent.drop_location()) +/datum/storage/rped/mass_empty(datum/source, mob/user) var/list/obj/item/parts_list = list() - var/current_lowest_tier = INFINITY - for(var/obj/item/thing in real_location) parts_list += thing + if(!parts_list.len) + return - if(parts_list.len > 0) - parts_list = reverse_range(sortTim(parts_list, GLOBAL_PROC_REF(cmp_rped_sort))) - current_lowest_tier = parts_list[1].get_part_rating() - if(ismob(parent.loc)) - parent.balloon_alert(parent.loc, "dropping lowest rated parts...") - for(var/obj/item/part in parts_list) - if(part.get_part_rating() != current_lowest_tier) - break - if(!attempt_remove(part, dump_loc, silent = TRUE)) - continue - part.pixel_x = part.base_pixel_x + rand(-8, 8) - part.pixel_y = part.base_pixel_y + rand(-8, 8) + var/current_lowest_tier = INFINITY + parts_list = reverse_range(sortTim(parts_list, GLOBAL_PROC_REF(cmp_rped_sort))) + current_lowest_tier = parts_list[1].get_part_rating() + if(ismob(parent.loc)) + parent.balloon_alert(parent.loc, "dropping lowest rated parts...") + + var/dump_loc = user.drop_location() + for(var/obj/item/part in parts_list) + if(part.get_part_rating() != current_lowest_tier) + break + if(!attempt_remove(part, dump_loc, silent = TRUE)) + continue + part.pixel_x = part.base_pixel_x + rand(-8, 8) + part.pixel_y = part.base_pixel_y + rand(-8, 8) + +///bluespace variant +/datum/storage/rped/bluespace + max_slots = 400 + max_total_storage = 800 + max_specific_storage = WEIGHT_CLASS_GIGANTIC #undef MAX_STACK_PICKUP diff --git a/code/datums/wounds/pierce.dm b/code/datums/wounds/pierce.dm index bb4bc85d8e9..4bf2664fb34 100644 --- a/code/datums/wounds/pierce.dm +++ b/code/datums/wounds/pierce.dm @@ -17,6 +17,8 @@ /// How much blood we start losing when this wound is first applied var/initial_flow + /// How much our blood_flow will naturally decrease per second, even without gauze + var/clot_rate /// If gauzed, what percent of the internal bleeding actually clots of the total absorption rate var/gauzed_clot_rate @@ -72,8 +74,10 @@ return BLOOD_FLOW_STEADY if(HAS_TRAIT(victim, TRAIT_BLOODY_MESS)) return BLOOD_FLOW_INCREASING - if(limb.current_gauze) + if(limb.current_gauze || clot_rate > 0) return BLOOD_FLOW_DECREASING + if(clot_rate < 0) + return BLOOD_FLOW_INCREASING return BLOOD_FLOW_STEADY /datum/wound/pierce/bleed/handle_process(seconds_per_tick, times_fired) @@ -92,10 +96,16 @@ if(HAS_TRAIT(victim, TRAIT_BLOODY_MESS)) adjust_blood_flow(0.25 * seconds_per_tick) // old heparin used to just add +2 bleed stacks per tick, this adds 0.5 bleed flow to all open cuts which is probably even stronger as long as you can cut them first + //gauze always reduces blood flow, even for non bleeders if(limb.current_gauze) + if(clot_rate > 0) + adjust_blood_flow(-clot_rate * seconds_per_tick) var/gauze_power = limb.current_gauze.absorption_rate limb.seep_gauze(gauze_power * seconds_per_tick) adjust_blood_flow(-gauze_power * gauzed_clot_rate * seconds_per_tick) + //otherwise, only clot if it's a bleeder + else if(limb.can_bleed()) + adjust_blood_flow(-clot_rate * seconds_per_tick) /datum/wound/pierce/bleed/adjust_blood_flow(adjust_by, minimum) . = ..() @@ -174,12 +184,13 @@ cauterization, or in extreme circumstances, exposure to extreme cold or vaccuum. \ Follow with food and a rest period." treat_text_short = "Apply bandaging or suturing." - examine_desc = "has a small, circular hole, gently bleeding" + examine_desc = "has a small, torn hole, gently bleeding" occur_text = "spurts out a thin stream of blood" sound_effect = 'sound/effects/wounds/pierce1.ogg' severity = WOUND_SEVERITY_MODERATE initial_flow = 1.5 gauzed_clot_rate = 0.8 + clot_rate = 0.03 internal_bleeding_chance = 30 internal_bleeding_coefficient = 1.25 threshold_penalty = 20 @@ -189,6 +200,11 @@ simple_treat_text = "Bandaging the wound will reduce blood loss, help the wound close by itself quicker, and speed up the blood recovery period. The wound itself can be slowly sutured shut." homemade_treat_text = "Tea stimulates the body's natural healing systems, slightly fastening clotting. The wound itself can be rinsed off on a sink or shower as well. Other remedies are unnecessary." +/datum/wound/pierce/bleed/moderate/update_descriptions() + if(!limb.can_bleed()) + examine_desc = "has a small, torn hole" + occur_text = "splits a small hole open" + /datum/wound_pregen_data/flesh_pierce/breakage abstract = FALSE @@ -196,13 +212,35 @@ threshold_minimum = 30 -/datum/wound/pierce/bleed/moderate/update_descriptions() +/datum/wound_pregen_data/flesh_pierce/breakage/get_weight(obj/item/bodypart/limb, woundtype, damage, attack_direction, damage_source) + if (isprojectile(damage_source)) + return 0 + return weight + +/datum/wound/pierce/bleed/moderate/projectile + name = "Minor Skin Penetration" + desc = "Patient's skin has been pierced through, causing severe bruising and minor internal bleeding in affected area." + treat_text = "Apply bandaging or suturing to the wound, make use of blood clotting agents, \ + cauterization, or in extreme circumstances, exposure to extreme cold or vaccuum. \ + Follow with food and a rest period." + examine_desc = "has a small, circular hole, gently bleeding" + clot_rate = 0 + +/datum/wound/pierce/bleed/moderate/projectile/update_descriptions() if(!limb.can_bleed()) examine_desc = "has a small, circular hole" occur_text = "splits a small hole open" +/datum/wound_pregen_data/flesh_pierce/breakage/projectile + wound_path_to_generate = /datum/wound/pierce/bleed/moderate/projectile + +/datum/wound_pregen_data/flesh_pierce/breakage/projectile/get_weight(obj/item/bodypart/limb, woundtype, damage, attack_direction, damage_source) + if (!isprojectile(damage_source)) + return 0 + return weight + /datum/wound/pierce/bleed/severe - name = "Open Puncture" + name = "Open Stab Puncture" desc = "Patient's internal tissue is penetrated, causing sizeable internal bleeding and reduced limb stability." treat_text = "Swiftly apply bandaging or suturing to the wound, make use of blood clotting agents or saline-glucose, \ cauterization, or in extreme circumstances, exposure to extreme cold or vaccuum. \ @@ -214,6 +252,7 @@ severity = WOUND_SEVERITY_SEVERE initial_flow = 2.25 gauzed_clot_rate = 0.6 + clot_rate = 0.02 internal_bleeding_chance = 60 internal_bleeding_coefficient = 1.5 threshold_penalty = 35 @@ -223,6 +262,10 @@ simple_treat_text = "Bandaging the wound is essential, and will reduce blood loss. Afterwards, the wound can be sutured shut, preferably while the patient is resting and/or grasping their wound." homemade_treat_text = "Bed sheets can be ripped up to make makeshift gauze. Flour, table salt, or salt mixed with water can be applied directly to stem the flow, though unmixed salt will irritate the skin and worsen natural healing. Resting and grabbing your wound will also reduce bleeding." +/datum/wound/pierce/bleed/severe/update_descriptions() + if(!limb.can_bleed()) + occur_text = "tears a hole open" + /datum/wound_pregen_data/flesh_pierce/open_puncture abstract = FALSE @@ -230,9 +273,23 @@ threshold_minimum = 50 -/datum/wound/pierce/bleed/severe/update_descriptions() - if(!limb.can_bleed()) - occur_text = "tears a hole open" +/datum/wound_pregen_data/flesh_pierce/open_puncture/get_weight(obj/item/bodypart/limb, woundtype, damage, attack_direction, damage_source) + if (isprojectile(damage_source)) + return 0 + return weight + +/datum/wound/pierce/bleed/severe/projectile + name = "Open Bullet Puncture" + examine_desc = "is pierced clear through, with bits of tissue obscuring the cleanly torn hole" + clot_rate = 0 + +/datum/wound_pregen_data/flesh_pierce/open_puncture/projectile + wound_path_to_generate = /datum/wound/pierce/bleed/severe/projectile + +/datum/wound_pregen_data/flesh_pierce/open_puncture/projectile/get_weight(obj/item/bodypart/limb, woundtype, damage, attack_direction, damage_source) + if (!isprojectile(damage_source)) + return 0 + return weight /datum/wound/pierce/bleed/severe/eye name = "Eyeball Puncture" diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index fe3646cd062..7c2840afde1 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -1137,6 +1137,7 @@ pulledby.stop_pulling() var/same_loc = oldloc == destination + var/movement_successful = TRUE var/area/old_area = get_area(oldloc) var/area/destarea = get_area(destination) var/movement_dir = get_dir(src, destination) @@ -1145,7 +1146,13 @@ loc = destination - if(!same_loc) + if(!same_loc && loc == oldloc) + // when attempting to move an atom A into an atom B which already contains A, BYOND seems + // to silently refuse to move A to the new loc. This can really break stuff (see #77067) + stack_trace("Attempt to move [src] to [destination] was rejected by BYOND, possibly due to cyclic contents") + movement_successful = FALSE + + if(movement_successful && !same_loc) if(is_multi_tile && isturf(destination)) var/list/new_locs = block( destination, @@ -1174,7 +1181,7 @@ if(destarea && old_area != destarea) destarea.Entered(src, old_area) - . = TRUE + . = movement_successful //If no destination, move the atom into nullspace (don't do this unless you know what you're doing) else @@ -1491,9 +1498,16 @@ return -/atom/movable/proc/do_attack_animation(atom/attacked_atom, visual_effect_icon, obj/item/used_item, no_effect, fov_effect = TRUE) +/atom/movable/proc/do_attack_animation(atom/attacked_atom, visual_effect_icon, obj/item/used_item, no_effect, fov_effect = TRUE, item_animation_override = null) if(!no_effect && (visual_effect_icon || used_item)) - do_item_attack_animation(attacked_atom, visual_effect_icon, used_item) + var/animation_type = item_animation_override || ATTACK_ANIMATION_BLUNT + if (used_item && !item_animation_override) + switch(used_item.get_sharpness()) + if (SHARP_EDGED) + animation_type = ATTACK_ANIMATION_SLASH + if (SHARP_POINTY) + animation_type = ATTACK_ANIMATION_PIERCE + do_item_attack_animation(attacked_atom, visual_effect_icon, used_item, animation_type = animation_type) if(attacked_atom == src) return //don't do an animation if attacking self diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm index 656ece7f8ee..0a7a8298aa3 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -493,7 +493,6 @@ ///internal proc that removes all static power usage from the current area /obj/machinery/proc/unset_static_power() - PRIVATE_PROC(TRUE) SHOULD_NOT_OVERRIDE(TRUE) var/old_usage = static_power_usage @@ -1020,21 +1019,16 @@ return TRUE /obj/machinery/proc/exchange_parts(mob/user, obj/item/storage/part_replacer/replacer_tool) - if(!istype(replacer_tool)) + if(!istype(replacer_tool) || !component_parts) return FALSE - var/shouldplaysound = FALSE - if(!component_parts) - return FALSE - - if(!panel_open && !replacer_tool.works_from_distance) + var/works_from_distance = istype(replacer_tool, /obj/item/storage/part_replacer/bluespace) + if(!panel_open && !works_from_distance) to_chat(user, display_parts(user)) - if(shouldplaysound) - replacer_tool.play_rped_sound() return FALSE var/obj/item/circuitboard/machine/machine_board = locate(/obj/item/circuitboard/machine) in component_parts - if(replacer_tool.works_from_distance) + if(works_from_distance) to_chat(user, display_parts(user)) if(!machine_board) return FALSE @@ -1045,6 +1039,7 @@ * completly ignoring the tier 4 component inside * we also ignore stack components inside the RPED cause we dont exchange that */ + var/shouldplaysound = FALSE var/list/part_list = replacer_tool.get_sorted_parts(ignore_stacks = TRUE) if(!part_list.len) return FALSE @@ -1075,7 +1070,7 @@ if(!istype(secondary_part, required_type)) continue // If it's a corrupt or rigged cell, attempting to send it through Bluespace could have unforeseen consequences. - if(istype(secondary_part, /obj/item/stock_parts/power_store/cell) && replacer_tool.works_from_distance) + if(istype(secondary_part, /obj/item/stock_parts/power_store/cell) && works_from_distance) var/obj/item/stock_parts/power_store/cell/checked_cell = secondary_part // If it's rigged or corrupted, max the charge. Then explode it. if(checked_cell.rigged || checked_cell.corrupted) diff --git a/code/game/machinery/computer/buildandrepair.dm b/code/game/machinery/computer/buildandrepair.dm index 3e947d33d7b..45a21eafef8 100644 --- a/code/game/machinery/computer/buildandrepair.dm +++ b/code/game/machinery/computer/buildandrepair.dm @@ -125,8 +125,6 @@ if(add_cabling(user, cable, time = 0)) if(!no_sound) replacer.play_rped_sound() - if(replacer.works_from_distance) - user.Beam(src, icon_state = "rped_upgrade", time = 0.5 SECONDS) no_sound = TRUE return install_parts_from_part_replacer(user, replacer, no_sound = no_sound) // Recursive call to handle the next part @@ -140,8 +138,6 @@ if(add_glass(user, glass_sheets, time = 0)) if(!no_sound) replacer.play_rped_sound() - if(replacer.works_from_distance) - user.Beam(src, icon_state = "rped_upgrade", time = 0.5 SECONDS) return TRUE return FALSE diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm index f0b3434ec85..b90302111ab 100644 --- a/code/game/machinery/constructable_frame.dm +++ b/code/game/machinery/constructable_frame.dm @@ -112,6 +112,16 @@ return install_board(user, tool, by_hand = TRUE) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING return NONE +/obj/structure/frame/ranged_item_interaction(mob/living/user, obj/item/tool, list/modifiers) + . = NONE + + if(!istype(tool, /obj/item/storage/part_replacer/bluespace)) + return + + . = item_interaction(user, tool, modifiers) + if(. & ITEM_INTERACT_ANY_BLOCKER) + user.Beam(tool, icon_state = "rped_upgrade", time = 0.5 SECONDS) + /** * Installs the passed circuit board into the frame * @@ -173,7 +183,7 @@ if(QDELETED(target_board) || QDELETED(src) || QDELETED(user) || !(target_board in replacer) || !user.is_holding(replacer)) return FALSE // User still within range? - var/close_enough = replacer.works_from_distance || user.Adjacent(src) + var/close_enough = istype(replacer, /obj/item/storage/part_replacer/bluespace) || user.Adjacent(src) if(!close_enough) return FALSE @@ -182,8 +192,6 @@ install_parts_from_part_replacer(user, replacer, no_sound = TRUE) if(!no_sound) replacer.play_rped_sound() - if(replacer.works_from_distance) - user.Beam(src, icon_state = "rped_upgrade", time = 0.5 SECONDS) return TRUE return FALSE diff --git a/code/game/machinery/dna_infuser/organ_sets/carp_organs.dm b/code/game/machinery/dna_infuser/organ_sets/carp_organs.dm index 9a873b5e373..221881c6ea5 100644 --- a/code/game/machinery/dna_infuser/organ_sets/carp_organs.dm +++ b/code/game/machinery/dna_infuser/organ_sets/carp_organs.dm @@ -98,6 +98,7 @@ name = "carp tooth" desc = "Looks sharp. Sharp enough to poke someone's eye out. Holy fuck it's big." icon_state = "carptooth" + icon_angle = -45 ///carp brain. you need to occasionally go to a new zlevel. think of it as... walking your dog! /obj/item/organ/brain/carp diff --git a/code/game/machinery/dna_infuser/organ_sets/goliath_organs.dm b/code/game/machinery/dna_infuser/organ_sets/goliath_organs.dm index 5a06aa8e8c2..e4315c4a5e2 100644 --- a/code/game/machinery/dna_infuser/organ_sets/goliath_organs.dm +++ b/code/game/machinery/dna_infuser/organ_sets/goliath_organs.dm @@ -99,6 +99,7 @@ icon = 'icons/obj/weapons/goliath_hammer.dmi' icon_state = "goliath_hammer" inhand_icon_state = "goliath_hammer" + icon_angle = -90 lefthand_file = 'icons/mob/inhands/weapons/goliath_hammer_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/goliath_hammer_righthand.dmi' item_flags = ABSTRACT | DROPDEL diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 7cbd5126ca4..1be4325638d 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -1172,13 +1172,15 @@ return TRUE -/obj/machinery/door/airlock/try_to_crowbar(obj/item/I, mob/living/user, forced = FALSE) - if(I.tool_behaviour == TOOL_CROWBAR && should_try_removing_electronics() && !operating) +/obj/machinery/door/airlock/try_to_crowbar(obj/item/tool, mob/living/user, forced = FALSE) + if(!isnull(tool) && tool.tool_behaviour == TOOL_CROWBAR && should_try_removing_electronics() && !operating) user.visible_message(span_notice("[user] removes the electronics from the airlock assembly."), \ span_notice("You start to remove electronics from the airlock assembly...")) - if(I.use_tool(src, user, 40, volume = 100)) + + if(tool.use_tool(src, user, 40, volume = 100)) deconstruct(TRUE, user) return + if(seal) to_chat(user, span_warning("Remove the seal first!")) return @@ -1188,37 +1190,48 @@ if(welded) to_chat(user, span_warning("It's welded, it won't budge!")) return - if(hasPower()) - if(forced) - var/check_electrified = isElectrified() //setting this so we can check if the mob got shocked during the do_after below - if(check_electrified && shock(user,100)) - return //it's like sticking a fork in a power socket - if(!density)//already open - return + if(!hasPower()) + if(operating) + return - if(!prying_so_hard) - var/time_to_open = 50 - playsound(src, 'sound/machines/airlock/airlock_alien_prying.ogg', 100, TRUE) //is it aliens or just the CE being a dick? - prying_so_hard = TRUE - if(I.use_tool(src, user, time_to_open, volume = 100)) - if(check_electrified && shock(user, 100)) - prying_so_hard = FALSE - return - open(BYPASS_DOOR_CHECKS) - take_damage(25, BRUTE, 0, 0) // Enough to sometimes spark - if(density && !open(BYPASS_DOOR_CHECKS)) - to_chat(user, span_warning("Despite your attempts, [src] refuses to open.")) - prying_so_hard = FALSE - return + if(istype(tool, /obj/item/fireaxe) && !HAS_TRAIT(tool, TRAIT_WIELDED)) //being fireaxe'd + to_chat(user, span_warning("You need to be wielding [tool] to do that!")) + return + + INVOKE_ASYNC(src, density ? PROC_REF(open) : PROC_REF(close), BYPASS_DOOR_CHECKS) + return + + if(!forced) to_chat(user, span_warning("The airlock's motors resist your efforts to force it!")) return - if(!operating) - if(istype(I, /obj/item/fireaxe) && !HAS_TRAIT(I, TRAIT_WIELDED)) //being fireaxe'd - to_chat(user, span_warning("You need to be wielding [I] to do that!")) - return - INVOKE_ASYNC(src, density ? PROC_REF(open) : PROC_REF(close), BYPASS_DOOR_CHECKS) + var/check_electrified = isElectrified() //setting this so we can check if the mob got shocked during the do_after below + if(check_electrified && shock(user,100)) + return //it's like sticking a fork in a power socket + + if(!density)//already open + return + + if(prying_so_hard) + return + + var/time_to_open = 5 SECONDS + playsound(src, 'sound/machines/airlock/airlock_alien_prying.ogg', 100, TRUE) //is it aliens or just the CE being a dick? + prying_so_hard = TRUE + + if(!tool.use_tool(src, user, time_to_open, volume = 100)) + prying_so_hard = FALSE + return + + if(check_electrified && shock(user, 100)) + prying_so_hard = FALSE + return + + open(BYPASS_DOOR_CHECKS) + take_damage(25, BRUTE, 0, 0) // Enough to sometimes spark + if(density && !open(BYPASS_DOOR_CHECKS)) + to_chat(user, span_warning("Despite your attempts, [src] refuses to open.")) /obj/machinery/door/airlock/open(forced = DEFAULT_DOOR_CHECKS) if(cycle_pump && !operating && !welded && !seal && locked && density) @@ -2227,7 +2240,7 @@ if(!hasPower()) to_chat(user, span_notice("You begin unlocking the airlock safety mechanism...")) if(do_after(user, 15 SECONDS, target = src)) - try_to_crowbar(src, user, TRUE) + try_to_crowbar(null, user, TRUE) return TRUE else // always open from the space side diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm index b238f341668..5de6b4d61d3 100644 --- a/code/game/machinery/doors/firedoor.dm +++ b/code/game/machinery/doors/firedoor.dm @@ -548,7 +548,7 @@ if(welded || operating) return - var/atom/crowbar_owner = acting_object.loc //catchs mechs and any other non-mob using a crowbar + var/atom/crowbar_owner = acting_object?.loc || user // catches mechs and any other non-mob using a crowbar if(density) being_held_open = TRUE diff --git a/code/game/machinery/machine_frame.dm b/code/game/machinery/machine_frame.dm index d39d0652324..0f02d2ee3a7 100644 --- a/code/game/machinery/machine_frame.dm +++ b/code/game/machinery/machine_frame.dm @@ -259,8 +259,7 @@ if(play_sound && !no_sound) replacer.play_rped_sound() - if(replacer.works_from_distance) - user.Beam(src, icon_state = "rped_upgrade", time = 0.5 SECONDS) + return TRUE /obj/structure/frame/machine/can_be_unfasten_wrench(mob/user, silent) diff --git a/code/game/machinery/porta_turret/portable_turret.dm b/code/game/machinery/porta_turret/portable_turret.dm index 32e29a2e5dd..d1f785f9b53 100644 --- a/code/game/machinery/porta_turret/portable_turret.dm +++ b/code/game/machinery/porta_turret/portable_turret.dm @@ -483,13 +483,17 @@ DEFINE_BITFIELD(turret_flags, list( else if(iscarbon(A)) var/mob/living/carbon/C = A - //If not emagged, only target carbons that can use items - if(mode != TURRET_LETHAL && (C.stat || C.handcuffed || !(C.mobility_flags & MOBILITY_USE))) - continue - - //If emagged, target all but dead carbons - if(mode == TURRET_LETHAL && C.stat == DEAD) - continue + switch(mode) + //If not emagged, only target carbons that can use items + if(TURRET_STUN) + if(!(C.mobility_flags & MOBILITY_USE)) + continue + if(HAS_TRAIT(C, TRAIT_INCAPACITATED)) + continue + //If emagged, target all but dead carbons + if(TURRET_LETHAL) + if(C.stat == DEAD) + continue //if the target is a human and not in our faction, analyze threat level if(ishuman(C) && !in_faction(C)) @@ -840,6 +844,7 @@ DEFINE_BITFIELD(turret_flags, list( return TRUE /obj/machinery/porta_turret/ai + scan_range = /obj/projectile/energy/electrode/ai_turrets::range + 1 turret_flags = TURRET_FLAG_SHOOT_CRIMINALS | TURRET_FLAG_SHOOT_ANOMALOUS | TURRET_FLAG_SHOOT_HEADS /obj/machinery/porta_turret/ai/assess_perp(mob/living/carbon/human/perp) diff --git a/code/game/machinery/recharger.dm b/code/game/machinery/recharger.dm index 7454f185511..226e19bfe84 100755 --- a/code/game/machinery/recharger.dm +++ b/code/game/machinery/recharger.dm @@ -17,6 +17,7 @@ /obj/item/melee/baton/security, /obj/item/ammo_box/magazine/recharge, /obj/item/modular_computer, + /obj/item/gun/ballistic/automatic/battle_rifle, )) /obj/machinery/recharger/RefreshParts() @@ -55,6 +56,11 @@ var/obj/item/ammo_box/magazine/recharge/power_pack = charging . += span_notice("- \The [charging]'s cell is at [PERCENT(power_pack.stored_ammo.len/power_pack.max_ammo)]%.") return + if(istype(charging, /obj/item/gun/ballistic/automatic/battle_rifle)) + var/obj/item/gun/ballistic/automatic/battle_rifle/recalibrating_gun = charging + . += span_notice("- \The [charging]'s system degradation is at stage [recalibrating_gun.degradation_stage] of [recalibrating_gun.degradation_stage_max]%.") + . += span_notice("- \The [charging]'s degradation buffer is at [PERCENT(recalibrating_gun.shots_before_degradation/recalibrating_gun.max_shots_before_degradation)]%.") + return . += span_notice("- \The [charging] is not reporting a power level.") /obj/machinery/recharger/Entered(atom/movable/arrived, atom/old_loc, list/atom/old_locs) @@ -158,6 +164,23 @@ using_power = TRUE update_appearance() return + + if(istype(charging, /obj/item/gun/ballistic/automatic/battle_rifle)) + var/obj/item/gun/ballistic/automatic/battle_rifle/recalibrating_gun = charging + + if(recalibrating_gun.degradation_stage) + recalibrating_gun.attempt_recalibration(FALSE) + use_energy(active_power_usage * recharge_coeff * seconds_per_tick) + using_power = TRUE + + else if(recalibrating_gun.shots_before_degradation < recalibrating_gun.max_shots_before_degradation) + recalibrating_gun.attempt_recalibration(TRUE, 1 * recharge_coeff) + use_energy(active_power_usage * recharge_coeff * seconds_per_tick) + using_power = TRUE + + update_appearance() + return + if(!using_power && !finished_recharging) //Inserted thing is at max charge/ammo, notify those around us finished_recharging = TRUE playsound(src, 'sound/machines/ping.ogg', 30, TRUE) diff --git a/code/game/objects/effects/decals/cleanable.dm b/code/game/objects/effects/decals/cleanable.dm index 21eff5028b5..14e56b3ed69 100644 --- a/code/game/objects/effects/decals/cleanable.dm +++ b/code/game/objects/effects/decals/cleanable.dm @@ -1,6 +1,6 @@ /obj/effect/decal/cleanable gender = PLURAL - layer = FLOOR_CLEAN_LAYER + layer = CLEANABLE_FLOOR_OBJECT_LAYER var/list/random_icon_states = null ///I'm sorry but cleanable/blood code is ass, and so is blood_DNA var/blood_state = "" @@ -15,6 +15,9 @@ var/datum/reagent/decal_reagent ///The amount of reagent this decal holds, if decal_reagent is defined var/reagent_amount = 0 + /// If TRUE, gains TRAIT_MOPABLE on init - thus this cleanable will cleaned if its turf is cleaned + /// Set to FALSE for things that hang high on the walls or things which generally shouldn't be mopped up + var/is_mopped = TRUE /// Creates a cleanable decal on a turf /// Use this if your decal is one of one, and thus we should not spawn it if it's there already @@ -40,6 +43,9 @@ handle_merge_decal(C) return INITIALIZE_HINT_QDEL + if(is_mopped) + ADD_TRAIT(src, TRAIT_MOPABLE, INNATE_TRAIT) + if(LAZYLEN(diseases)) var/list/datum/disease/diseases_to_add = list() for(var/datum/disease/D in diseases) diff --git a/code/game/objects/effects/decals/cleanable/aliens.dm b/code/game/objects/effects/decals/cleanable/aliens.dm index bc7923ac0ed..f2543f33c86 100644 --- a/code/game/objects/effects/decals/cleanable/aliens.dm +++ b/code/game/objects/effects/decals/cleanable/aliens.dm @@ -24,10 +24,12 @@ icon = 'icons/effects/blood.dmi' icon_state = "xgib1" plane = GAME_PLANE - layer = BELOW_OBJ_LAYER + layer = GIB_LAYER random_icon_states = list("xgib1", "xgib2", "xgib3", "xgib4", "xgib5", "xgib6") mergeable_decal = FALSE + is_mopped = TRUE // probably shouldn't be, but janitor powercreep + /obj/effect/decal/cleanable/xenoblood/xgibs/Initialize(mapload) . = ..() RegisterSignal(src, COMSIG_MOVABLE_PIPE_EJECTING, PROC_REF(on_pipe_eject)) diff --git a/code/game/objects/effects/decals/cleanable/humans.dm b/code/game/objects/effects/decals/cleanable/humans.dm index 38a7624a504..3a5c29c5572 100644 --- a/code/game/objects/effects/decals/cleanable/humans.dm +++ b/code/game/objects/effects/decals/cleanable/humans.dm @@ -75,6 +75,7 @@ plane = GAME_PLANE vis_flags = VIS_INHERIT_PLANE alpha = 180 + is_mopped = FALSE /obj/effect/decal/cleanable/blood/splatter/over_window/NeverShouldHaveComeHere(turf/here_turf) return isgroundlessturf(here_turf) @@ -116,7 +117,7 @@ desc = "They look bloody and gruesome." icon = 'icons/effects/blood.dmi' icon_state = "gib1" - layer = BELOW_OBJ_LAYER + layer = GIB_LAYER plane = GAME_PLANE random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6") mergeable_decal = FALSE @@ -126,6 +127,8 @@ decal_reagent = /datum/reagent/consumable/liquidgibs reagent_amount = 5 + is_mopped = TRUE // probably shouldn't be, but janitor powercreep + /obj/effect/decal/cleanable/blood/gibs/Initialize(mapload, list/datum/disease/diseases) . = ..() AddElement(/datum/element/squish_sound) @@ -361,6 +364,7 @@ GLOBAL_LIST_EMPTY(bloody_footprints_cache) random_icon_states = list("hitsplatter1", "hitsplatter2", "hitsplatter3") plane = GAME_PLANE layer = ABOVE_WINDOW_LAYER + is_mopped = FALSE /// The turf we just came from, so we can back up when we hit a wall var/turf/prev_loc /// The cached info about the blood diff --git a/code/game/objects/effects/decals/cleanable/misc.dm b/code/game/objects/effects/decals/cleanable/misc.dm index caf7428ef01..65d22c8d856 100644 --- a/code/game/objects/effects/decals/cleanable/misc.dm +++ b/code/game/objects/effects/decals/cleanable/misc.dm @@ -11,7 +11,7 @@ icon = 'icons/obj/debris.dmi' icon_state = "ash" plane = GAME_PLANE - layer = GAME_CLEAN_LAYER + layer = CLEANABLE_OBJECT_LAYER mergeable_decal = FALSE beauty = -50 decal_reagent = /datum/reagent/ash @@ -153,6 +153,7 @@ resistance_flags = FLAMMABLE beauty = -100 clean_type = CLEAN_TYPE_HARD_DECAL + is_mopped = FALSE /obj/effect/decal/cleanable/cobweb/cobweb2 icon_state = "cobweb2" @@ -164,7 +165,7 @@ icon = 'icons/effects/effects.dmi' icon_state = "molten" plane = GAME_PLANE - layer = GAME_CLEAN_LAYER + layer = CLEANABLE_OBJECT_LAYER mergeable_decal = FALSE beauty = -150 clean_type = CLEAN_TYPE_HARD_DECAL @@ -251,7 +252,7 @@ desc = "A pile of chemicals. You can't quite tell what's inside it." gender = NEUTER plane = GAME_PLANE - layer = GAME_CLEAN_LAYER + layer = CLEANABLE_OBJECT_LAYER icon = 'icons/obj/debris.dmi' icon_state = "ash" @@ -330,7 +331,7 @@ icon = 'icons/obj/debris.dmi' icon_state = "paper_shreds" plane = GAME_PLANE - layer = GAME_CLEAN_LAYER + layer = CLEANABLE_OBJECT_LAYER /obj/effect/decal/cleanable/wrapping/pinata name = "pinata shreds" @@ -349,7 +350,7 @@ icon = 'icons/obj/debris.dmi' icon_state = "garbage" plane = GAME_PLANE - layer = GAME_CLEAN_LAYER + layer = CLEANABLE_OBJECT_LAYER beauty = -150 clean_type = CLEAN_TYPE_HARD_DECAL @@ -567,7 +568,9 @@ mergeable_decal = FALSE beauty = -10 plane = GAME_PLANE - layer = BELOW_OBJ_LAYER + layer = GIB_LAYER + clean_type = CLEAN_TYPE_HARD_DECAL + is_mopped = FALSE /obj/effect/decal/cleanable/rubble/Initialize(mapload) . = ..() diff --git a/code/game/objects/effects/decals/cleanable/robots.dm b/code/game/objects/effects/decals/cleanable/robots.dm index 3f2957a9c9e..7406cd910a1 100644 --- a/code/game/objects/effects/decals/cleanable/robots.dm +++ b/code/game/objects/effects/decals/cleanable/robots.dm @@ -6,7 +6,7 @@ icon = 'icons/mob/silicon/robots.dmi' icon_state = "gib1" plane = GAME_PLANE - layer = BELOW_OBJ_LAYER + layer = GIB_LAYER random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6", "gib7") blood_state = BLOOD_STATE_OIL bloodiness = BLOOD_AMOUNT_PER_DECAL @@ -14,6 +14,8 @@ beauty = -50 clean_type = CLEAN_TYPE_BLOOD + is_mopped = TRUE // probably shouldn't be, but janitor powercreep + /obj/effect/decal/cleanable/robot_debris/Initialize(mapload) . = ..() RegisterSignal(src, COMSIG_MOVABLE_PIPE_EJECTING, PROC_REF(on_pipe_eject)) diff --git a/code/game/objects/effects/decals/crayon.dm b/code/game/objects/effects/decals/crayon.dm index e27e6f91337..2e60cfb8bda 100644 --- a/code/game/objects/effects/decals/crayon.dm +++ b/code/game/objects/effects/decals/crayon.dm @@ -15,7 +15,7 @@ if(isclosedturf(loc) && loc.density) // allows for wall graffiti to be seen SET_PLANE_IMPLICIT(src, GAME_PLANE) - layer = GAME_CLEAN_LAYER + layer = CLEANABLE_OBJECT_LAYER if(e_name) name = e_name if(desc_override) diff --git a/code/game/objects/effects/forcefields.dm b/code/game/objects/effects/forcefields.dm index dc51e5079f4..bc9f8a0bfd6 100644 --- a/code/game/objects/effects/forcefields.dm +++ b/code/game/objects/effects/forcefields.dm @@ -84,7 +84,7 @@ icon = 'icons/effects/eldritch.dmi' icon_state = "cosmic_carpet" anchored = TRUE - layer = BELOW_OBJ_LAYER + layer = GIB_LAYER density = FALSE can_atmos_pass = ATMOS_PASS_NO initial_duration = 30 SECONDS diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index c613bdaaf73..99b8fef92c4 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -22,6 +22,9 @@ ///Icon file for right inhand overlays var/righthand_file = 'icons/mob/inhands/items_righthand.dmi' + /// Angle of the icon, used for piercing and slashing attack animations, clockwise from *east-facing* sprites + var/icon_angle = 0 + ///Icon file for mob worn overlays. var/icon/worn_icon ///Icon state for mob worn overlays, if null the normal icon_state will be used. @@ -178,7 +181,7 @@ ///for flags such as [GLASSESCOVERSEYES] var/flags_cover = 0 var/heat = 0 - ///All items with sharpness of SHARP_EDGED or higher will automatically get the butchering component. + /// All items with sharpness of SHARP_EDGED or higher will automatically get the butchering component. var/sharpness = NONE ///How a tool acts when you use it on something, such as wirecutters cutting wires while multitools measure power @@ -1594,44 +1597,162 @@ // This is instant on byond's end, but to our clients this looks like a quick drop animate(src, alpha = old_alpha, pixel_x = old_x, pixel_y = old_y, transform = old_transform, time = 3, easing = CUBIC_EASING) -/atom/movable/proc/do_item_attack_animation(atom/attacked_atom, visual_effect_icon, obj/item/used_item) - var/image/attack_image - if(visual_effect_icon) - attack_image = image(icon = 'icons/effects/effects.dmi', icon_state = visual_effect_icon) - else if(used_item) - attack_image = image(icon = used_item) +/atom/movable/proc/do_item_attack_animation(atom/attacked_atom, visual_effect_icon, obj/item/used_item, animation_type = ATTACK_ANIMATION_BLUNT) + if (visual_effect_icon) + var/image/attack_image = image(icon = 'icons/effects/effects.dmi', icon_state = visual_effect_icon) attack_image.plane = attacked_atom.plane + 1 - // Scale the icon. attack_image.transform *= 0.4 // The icon should not rotate. attack_image.appearance_flags = APPEARANCE_UI + var/atom/movable/flick_visual/attack = attacked_atom.flick_overlay_view(attack_image, 1 SECONDS) + var/matrix/copy_transform = new(transform) + animate(attack, alpha = 175, transform = copy_transform.Scale(0.75), time = 0.3 SECONDS) + animate(time = 0.1 SECONDS) + animate(alpha = 0, time = 0.3 SECONDS, easing = CIRCULAR_EASING|EASE_OUT) + return - // Set the direction of the icon animation. - var/direction = get_dir(src, attacked_atom) - if(direction & NORTH) - attack_image.pixel_y = -12 - else if(direction & SOUTH) - attack_image.pixel_y = 12 - - if(direction & EAST) - attack_image.pixel_x = -14 - else if(direction & WEST) - attack_image.pixel_x = 14 - - if(!direction) // Attacked self?! - attack_image.pixel_y = 12 - attack_image.pixel_x = 5 * (prob(50) ? 1 : -1) - - if(!attack_image) + if (isnull(used_item)) return + var/image/attack_image = image(icon = used_item) + attack_image.plane = attacked_atom.plane + 1 + // Scale the icon. + attack_image.transform *= 0.5 + // The icon should not rotate. + attack_image.appearance_flags = APPEARANCE_UI + var/atom/movable/flick_visual/attack = attacked_atom.flick_overlay_view(attack_image, 1 SECONDS) var/matrix/copy_transform = new(transform) + var/x_sign = 0 + var/y_sign = 0 + var/direction = get_dir(src, attacked_atom) + if (direction & NORTH) + y_sign = -1 + else if (direction & SOUTH) + y_sign = 1 + + if (direction & EAST) + x_sign = -1 + else if (direction & WEST) + x_sign = 1 + + // Attacking self, or something on the same turf as us + if (!direction) + y_sign = 1 + // Not a fan of this, but its the "cleanest" way to animate this + x_sign = 0.25 * (prob(50) ? 1 : -1) + // For piercing attacks + direction = SOUTH + // And animate the attack! - animate(attack, alpha = 175, transform = copy_transform.Scale(0.75), pixel_x = 0, pixel_y = 0, pixel_z = 0, time = 0.3 SECONDS) - animate(time = 0.1 SECONDS) - animate(alpha = 0, time = 0.3 SECONDS, easing = CIRCULAR_EASING|EASE_OUT) + switch (animation_type) + if (ATTACK_ANIMATION_BLUNT) + attack.pixel_x = 14 * x_sign + attack.pixel_y = 12 * y_sign + animate(attack, alpha = 175, transform = copy_transform.Scale(0.75), pixel_x = 4 * x_sign, pixel_y = 3 * y_sign, time = 0.2 SECONDS) + animate(time = 0.1 SECONDS) + animate(alpha = 0, time = 0.1 SECONDS, easing = CIRCULAR_EASING|EASE_OUT) + + if (ATTACK_ANIMATION_PIERCE) + var/attack_angle = dir2angle(direction) + rand(-7, 7) + // Deducting 90 because we're assuming that icon_angle of 0 means an east-facing sprite + var/anim_angle = attack_angle - 90 - used_item.icon_angle + var/angle_mult = 1 + if (x_sign && y_sign) + angle_mult = 1.4 + attack.pixel_x = 22 * x_sign * angle_mult + attack.pixel_y = 18 * y_sign * angle_mult + attack.transform = attack.transform.Turn(anim_angle) + copy_transform = copy_transform.Turn(anim_angle) + animate( + attack, + pixel_x = (22 * x_sign - 12 * sin(attack_angle)) * angle_mult, + pixel_y = (18 * y_sign - 8 * cos(attack_angle)) * angle_mult, + time = 0.1 SECONDS, + easing = CUBIC_EASING|EASE_IN, + ) + animate( + attack, + alpha = 175, + transform = copy_transform.Scale(0.75), + pixel_x = (22 * x_sign + 26 * sin(attack_angle)) * angle_mult, + pixel_y = (18 * y_sign + 22 * cos(attack_angle)) * angle_mult, + time = 0.3 SECONDS, + easing = CUBIC_EASING|EASE_OUT, + ) + animate( + alpha = 0, + pixel_x = -3 * -(x_sign + sin(attack_angle)), + pixel_y = -2 * -(y_sign + cos(attack_angle)), + time = 0.1 SECONDS, + easing = CIRCULAR_EASING|EASE_OUT + ) + + if (ATTACK_ANIMATION_SLASH) + attack.pixel_x = 18 * x_sign + attack.pixel_y = 14 * y_sign + var/x_rot_sign = 0 + var/y_rot_sign = 0 + var/attack_dir = (prob(50) ? 1 : -1) + var/anim_angle = dir2angle(direction) - 90 - used_item.icon_angle + + if (x_sign) + y_rot_sign = attack_dir + if (y_sign) + x_rot_sign = attack_dir + + // Animations are flipped, so flip us too! + if (x_sign > 0 || y_sign < 0) + attack_dir *= -1 + + // We're swinging diagonally, use separate logic + var/anim_dir = attack_dir + if (x_sign && y_sign) + if (attack_dir < 0) + x_rot_sign = -x_sign * 1.4 + y_rot_sign = 0 + else + x_rot_sign = 0 + y_rot_sign = -y_sign * 1.4 + + // Flip us if we've been flipped *unless* we're flipped due to both axis + if ((x_sign < 0 && y_sign > 0) || (x_sign > 0 && y_sign < 0)) + anim_dir *= -1 + + attack.pixel_x += 10 * x_rot_sign + attack.pixel_y += 8 * y_rot_sign + attack.transform = attack.transform.Turn(anim_angle - 45 * anim_dir) + copy_transform = copy_transform.Scale(0.75) + animate(attack, alpha = 175, time = 0.3 SECONDS, flags = ANIMATION_PARALLEL) + animate(time = 0.1 SECONDS) + animate(alpha = 0, time = 0.1 SECONDS, easing = CIRCULAR_EASING|EASE_OUT) + + animate(attack, transform = copy_transform.Turn(anim_angle + 45 * anim_dir), time = 0.3 SECONDS, flags = ANIMATION_PARALLEL) + + var/x_return = 10 * -x_rot_sign + var/y_return = 8 * -y_rot_sign + + if (!x_rot_sign) + x_return = 18 * x_sign + if (!y_rot_sign) + y_return = 14 * y_sign + + var/angle_mult = 1 + if (x_sign && y_sign) + angle_mult = 1.4 + if (attack_dir > 0) + x_return = 8 * x_sign + y_return = 14 * y_sign + else + x_return = 18 * x_sign + y_return = 6 * y_sign + + animate(attack, pixel_x = 4 * x_sign * angle_mult, time = 0.2 SECONDS, easing = CIRCULAR_EASING | EASE_IN, flags = ANIMATION_PARALLEL) + animate(pixel_x = x_return, time = 0.2 SECONDS, easing = CIRCULAR_EASING | EASE_OUT) + + animate(attack, pixel_y = 3 * y_sign * angle_mult, time = 0.2 SECONDS, easing = CIRCULAR_EASING | EASE_IN, flags = ANIMATION_PARALLEL) + animate(pixel_y = y_return, time = 0.2 SECONDS, easing = CIRCULAR_EASING | EASE_OUT) /// Common proc used by painting tools like spraycans and palettes that can access the entire 24 bits color space. /obj/item/proc/pick_painting_tool_color(mob/user, default_color) diff --git a/code/game/objects/items/boxcutter.dm b/code/game/objects/items/boxcutter.dm index 58be269bacd..5452cd013fb 100644 --- a/code/game/objects/items/boxcutter.dm +++ b/code/game/objects/items/boxcutter.dm @@ -5,6 +5,7 @@ icon_state = "boxcutter" inhand_icon_state = "boxcutter" base_icon_state = "boxcutter" + icon_angle = -90 lefthand_file = 'icons/mob/inhands/equipment/boxcutter_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/boxcutter_righthand.dmi' inhand_icon_state = null diff --git a/code/game/objects/items/broom.dm b/code/game/objects/items/broom.dm index 32636b1a99c..a48dfa1b94c 100644 --- a/code/game/objects/items/broom.dm +++ b/code/game/objects/items/broom.dm @@ -7,6 +7,7 @@ icon = 'icons/obj/service/janitor.dmi' icon_state = "broom0" base_icon_state = "broom" + icon_angle = 135 lefthand_file = 'icons/mob/inhands/equipment/custodial_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/custodial_righthand.dmi' force = 8 diff --git a/code/game/objects/items/chainsaw.dm b/code/game/objects/items/chainsaw.dm index 8045646b075..509a3a63856 100644 --- a/code/game/objects/items/chainsaw.dm +++ b/code/game/objects/items/chainsaw.dm @@ -5,6 +5,7 @@ desc = "A versatile power tool. Useful for limbing trees and delimbing humans." icon = 'icons/obj/weapons/chainsaw.dmi' icon_state = "chainsaw" + icon_angle = 180 lefthand_file = 'icons/mob/inhands/weapons/chainsaw_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/chainsaw_righthand.dmi' obj_flags = CONDUCTS_ELECTRICITY diff --git a/code/game/objects/items/courtroom.dm b/code/game/objects/items/courtroom.dm index 8baba284314..c8907cbe936 100644 --- a/code/game/objects/items/courtroom.dm +++ b/code/game/objects/items/courtroom.dm @@ -7,6 +7,7 @@ desc = "Order, order! No bombs in my courthouse." icon = 'icons/obj/weapons/hammer.dmi' icon_state = "gavelhammer" + icon_angle = -135 force = 5 throwforce = 6 w_class = WEIGHT_CLASS_SMALL diff --git a/code/game/objects/items/debug_items.dm b/code/game/objects/items/debug_items.dm index fb6400fc7b3..9af69c33d7f 100644 --- a/code/game/objects/items/debug_items.dm +++ b/code/game/objects/items/debug_items.dm @@ -34,6 +34,7 @@ icon = 'icons/obj/weapons/club.dmi' icon_state = "hypertool" inhand_icon_state = "hypertool" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' toolspeed = 0.1 diff --git a/code/game/objects/items/devices/multitool.dm b/code/game/objects/items/devices/multitool.dm index 4d538f46184..bc3a12a4fe5 100644 --- a/code/game/objects/items/devices/multitool.dm +++ b/code/game/objects/items/devices/multitool.dm @@ -16,6 +16,7 @@ icon = 'icons/obj/devices/tool.dmi' icon_state = "multitool" inhand_icon_state = "multitool" + icon_angle = -90 lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' force = 5 @@ -292,6 +293,7 @@ desc = "Optimised version of a regular multitool. Streamlines processes handled by its internal microchip." icon = 'icons/obj/items_cyborg.dmi' icon_state = "toolkit_engiborg_multitool" + icon_angle = 0 toolspeed = 0.5 #undef PROXIMITY_NEAR diff --git a/code/game/objects/items/devices/scanners/scanner_wand.dm b/code/game/objects/items/devices/scanners/scanner_wand.dm index 18dfc820039..bba046bd2fe 100644 --- a/code/game/objects/items/devices/scanners/scanner_wand.dm +++ b/code/game/objects/items/devices/scanners/scanner_wand.dm @@ -3,6 +3,7 @@ icon = 'icons/obj/devices/scanner.dmi' icon_state = "scanner_wand" inhand_icon_state = "healthanalyzer" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' desc = "A wand that medically scans people. Inserting it into a medical kiosk makes it able to perform a health scan on the patient." diff --git a/code/game/objects/items/devices/traitordevices.dm b/code/game/objects/items/devices/traitordevices.dm index d8b7c1999ae..341231d767a 100644 --- a/code/game/objects/items/devices/traitordevices.dm +++ b/code/game/objects/items/devices/traitordevices.dm @@ -329,7 +329,7 @@ effective or pretty fucking useless. /obj/item/jammer name = "radio jammer" - desc = "Device used to disrupt nearby radio communication. Alternate function creates a powerful distruptor wave which disables all nearby listening devices." + desc = "Device used to disrupt nearby radio communication. Alternate function creates a powerful disruptor wave which disables all nearby listening devices." icon = 'icons/obj/devices/syndie_gadget.dmi' icon_state = "jammer" var/active = FALSE @@ -342,7 +342,7 @@ effective or pretty fucking useless. register_context() /obj/item/jammer/add_context(atom/source, list/context, obj/item/held_item, mob/user) - context[SCREENTIP_CONTEXT_LMB] = "Release distruptor wave" + context[SCREENTIP_CONTEXT_LMB] = "Release disruptor wave" context[SCREENTIP_CONTEXT_RMB] = "Toggle" return CONTEXTUAL_SCREENTIP_SET @@ -352,8 +352,8 @@ effective or pretty fucking useless. user.balloon_alert(user, "on cooldown!") return - user.balloon_alert(user, "distruptor wave released!") - to_chat(user, span_notice("You release a distruptor wave, disabling all nearby radio devices.")) + user.balloon_alert(user, "disruptor wave released!") + to_chat(user, span_notice("You release a disruptor wave, disabling all nearby radio devices.")) for (var/atom/potential_owner in view(7, user)) disable_radios_on(potential_owner) COOLDOWN_START(src, jam_cooldown, jam_cooldown_duration) @@ -379,8 +379,8 @@ effective or pretty fucking useless. user.balloon_alert(user, "out of reach!") return - interacting_with.balloon_alert(user, "radio distrupted!") - to_chat(user, span_notice("You release a directed distruptor wave, disabling all radio devices on [interacting_with].")) + interacting_with.balloon_alert(user, "radio disrupted!") + to_chat(user, span_notice("You release a directed disruptor wave, disabling all radio devices on [interacting_with].")) disable_radios_on(interacting_with) return ITEM_INTERACT_SUCCESS diff --git a/code/game/objects/items/dice.dm b/code/game/objects/items/dice.dm index aa98d325a7d..ef1e4ebdee4 100644 --- a/code/game/objects/items/dice.dm +++ b/code/game/objects/items/dice.dm @@ -89,6 +89,7 @@ result = rigged_value . = result + playsound(src, 'sound/items/dice_roll.ogg', 50, TRUE) var/fake_result = roll(sides)//Daredevil isn't as good as he used to be var/comment = "" diff --git a/code/game/objects/items/dualsaber.dm b/code/game/objects/items/dualsaber.dm index 7f2e54984ca..dd5ef68f0d3 100644 --- a/code/game/objects/items/dualsaber.dm +++ b/code/game/objects/items/dualsaber.dm @@ -2,13 +2,14 @@ * Double-Bladed Energy Swords - Cheridan */ /obj/item/dualsaber + name = "double-bladed energy sword" + desc = "Handle with care." icon = 'icons/obj/weapons/transforming_energy.dmi' icon_state = "dualsaber0" inhand_icon_state = "dualsaber0" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' - name = "double-bladed energy sword" - desc = "Handle with care." force = 3 throwforce = 5 throw_speed = 3 @@ -73,7 +74,9 @@ set_light_on(FALSE) /obj/item/dualsaber/get_sharpness() - return HAS_TRAIT(src, TRAIT_WIELDED) && sharpness + if (!HAS_TRAIT(src, TRAIT_WIELDED)) + return NONE + return ..() /obj/item/dualsaber/update_icon_state() icon_state = inhand_icon_state = HAS_TRAIT(src, TRAIT_WIELDED) ? "dualsaber[saber_color][HAS_TRAIT(src, TRAIT_WIELDED)]" : "dualsaber0" diff --git a/code/game/objects/items/extinguisher.dm b/code/game/objects/items/extinguisher.dm index b4150ecb72f..a3b2422af61 100644 --- a/code/game/objects/items/extinguisher.dm +++ b/code/game/objects/items/extinguisher.dm @@ -5,6 +5,7 @@ icon_state = "fire_extinguisher0" worn_icon_state = "fire_extinguisher" inhand_icon_state = "fire_extinguisher" + icon_angle = 90 hitsound = 'sound/items/weapons/smash.ogg' pickup_sound = 'sound/items/handling/gas_tank/gas_tank_pick_up.ogg' drop_sound = 'sound/items/handling/gas_tank/gas_tank_drop.ogg' diff --git a/code/game/objects/items/fireaxe.dm b/code/game/objects/items/fireaxe.dm index 162af703ad2..3b6727d6923 100644 --- a/code/game/objects/items/fireaxe.dm +++ b/code/game/objects/items/fireaxe.dm @@ -4,13 +4,13 @@ GLOBAL_DATUM(bridge_axe, /obj/item/fireaxe) * Fireaxe */ /obj/item/fireaxe // DEM AXES MAN, marker -Agouri + name = "fire axe" + desc = "Truly, the weapon of a madman. Who would think to fight fire with an axe?" icon = 'icons/obj/weapons/fireaxe.dmi' icon_state = "fireaxe0" base_icon_state = "fireaxe" lefthand_file = 'icons/mob/inhands/weapons/axes_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/axes_righthand.dmi' - name = "fire axe" - desc = "Truly, the weapon of a madman. Who would think to fight fire with an axe?" force = 5 throwforce = 15 demolition_mod = 1.25 @@ -73,10 +73,11 @@ GLOBAL_DATUM(bridge_axe, /obj/item/fireaxe) * Bone Axe */ /obj/item/fireaxe/boneaxe // Blatant imitation of the fireaxe, but made out of bone. - icon_state = "bone_axe0" - base_icon_state = "bone_axe" name = "bone axe" desc = "A large, vicious axe crafted out of several sharpened bone plates and crudely tied together. Made of monsters, by killing monsters, for killing monsters." + icon_state = "bone_axe0" + base_icon_state = "bone_axe" + icon_angle = 180 force_unwielded = 5 force_wielded = 23 @@ -84,10 +85,11 @@ GLOBAL_DATUM(bridge_axe, /obj/item/fireaxe) * Metal Hydrogen Axe */ /obj/item/fireaxe/metal_h2_axe - icon_state = "metalh2_axe0" - base_icon_state = "metalh2_axe" name = "metallic hydrogen axe" desc = "A lightweight crowbar with an extreme sharp fire axe head attached. It trades its heft as a weapon by making it easier to carry around when holstered to suits without having to sacrifice your backpack." + icon_state = "metalh2_axe0" + base_icon_state = "metalh2_axe" + icon_angle = -45 force_unwielded = 5 force_wielded = 15 demolition_mod = 2 @@ -97,10 +99,10 @@ GLOBAL_DATUM(bridge_axe, /obj/item/fireaxe) //boarding axe /obj/item/fireaxe/boardingaxe - icon_state = "boarding_axe0" - base_icon_state = "boarding_axe" name = "boarding axe" desc = "A hulking cleaver that feels like a burden just looking at it. Seems excellent at halving obstacles like windows, airlocks, barricades and people." + icon_state = "boarding_axe0" + base_icon_state = "boarding_axe" force_unwielded = 5 force_wielded = 30 demolition_mod = 3 diff --git a/code/game/objects/items/food/bread.dm b/code/game/objects/items/food/bread.dm index 48e7a2a21b1..3a41514413c 100644 --- a/code/game/objects/items/food/bread.dm +++ b/code/game/objects/items/food/bread.dm @@ -420,6 +420,7 @@ /obj/item/food/baguette/combat block_sound = 'sound/items/weapons/parry.ogg' sharpness = SHARP_EDGED + icon_angle = -45 /// Force when wielded as a sword by a mime var/active_force = 20 /// Block chance when wielded as a sword by a mime diff --git a/code/game/objects/items/grenades/_grenade.dm b/code/game/objects/items/grenades/_grenade.dm index 780311fa4d1..664a31c2262 100644 --- a/code/game/objects/items/grenades/_grenade.dm +++ b/code/game/objects/items/grenades/_grenade.dm @@ -159,7 +159,7 @@ if(istype(user)) user.add_mob_memory(/datum/memory/bomb_planted, antagonist = src) active = TRUE - icon_state = initial(icon_state) + "_active" + icon_state = (base_icon_state || initial(icon_state)) + "_active" SEND_SIGNAL(src, COMSIG_GRENADE_ARMED, det_time, delayoverride) addtimer(CALLBACK(src, PROC_REF(detonate)), isnull(delayoverride)? det_time : delayoverride) @@ -255,7 +255,7 @@ if(det_time == 0) det_time = "Instant" else - det_time = num2text(det_time * 0.1) + det_time = num2text(det_time * 0.1) var/old_selection = possible_fuse_time.Find(det_time) //Position of det_time in the list if(old_selection >= possible_fuse_time.len) diff --git a/code/game/objects/items/grenades/flashbang.dm b/code/game/objects/items/grenades/flashbang.dm index 2300d2c6717..2bc9401c774 100644 --- a/code/game/objects/items/grenades/flashbang.dm +++ b/code/game/objects/items/grenades/flashbang.dm @@ -54,6 +54,7 @@ /obj/item/grenade/stingbang name = "stingbang" icon_state = "timeg_locked" + base_icon_state = "timeg" inhand_icon_state = "flashbang" lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi' @@ -64,6 +65,8 @@ /obj/item/grenade/stingbang/mega name = "mega stingbang" + icon_state = "timeg_mega_locked" + base_icon_state = "timeg_mega" shrapnel_type = /obj/projectile/bullet/pellet/stingball/mega shrapnel_radius = 12 @@ -122,6 +125,7 @@ name = "rotfrag grenade" desc = "A grenade that generates more shrapnel the more you rotate it in your hand after pulling the pin. This one releases shrapnel shards." icon_state = "timeg_locked" + base_icon_state = "timeg" inhand_icon_state = "flashbang" lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi' diff --git a/code/game/objects/items/hand_items.dm b/code/game/objects/items/hand_items.dm index befd9a619a3..d5c2a58dcd8 100644 --- a/code/game/objects/items/hand_items.dm +++ b/code/game/objects/items/hand_items.dm @@ -515,7 +515,7 @@ to_chat(taker, span_nicegreen("[offerer] gives you \a [blown_kiss][cheek_kiss ? " on the cheek" : ""]!")) offerer.face_atom(taker) taker.face_atom(offerer) - offerer.do_item_attack_animation(taker, used_item=src) + offerer.do_item_attack_animation(taker, used_item = src) //We're still firing a shot here because I don't want to deal with some weird edgecase where direct impacting them with the projectile causes it to freak out because there's no angle or something blown_kiss.original = taker blown_kiss.fired_from = offerer diff --git a/code/game/objects/items/inspector.dm b/code/game/objects/items/inspector.dm index 7783dcff072..d1092c34326 100644 --- a/code/game/objects/items/inspector.dm +++ b/code/game/objects/items/inspector.dm @@ -8,7 +8,9 @@ */ /obj/item/inspector name = "\improper N-spect scanner" - desc = "Central Command standard issue inspection device. Can perform either wide area scans that central command can use to verify the security of the station, or detailed scan. Can scan people for contraband on their person or items being contraband." + desc = "Central Command standard issue inspection device. \ + Performs wide area scan reports for inspectors to use to verify the security and integrity of the station. \ + Can additionally be used for precision scans to determine if an item contains, or is itself, contraband." icon = 'icons/obj/devices/scanner.dmi' icon_state = "inspector" worn_icon_state = "salestagger" @@ -88,14 +90,16 @@ /obj/item/inspector/examine(mob/user) . = ..() + . += span_info("Use in-hand to scan the local area, creating an encrypted security inspection.") + . += span_info("Use on an item to scan if it contains, or is, contraband.") if(!cell_cover_open) - . += "Its cell cover is closed. It looks like it could be pried out, but doing so would require an appropriate tool." + . += span_notice("Its cell cover is closed. It looks like it could be pried out, but doing so would require an appropriate tool.") return - . += "Its cell cover is open, exposing the cell slot. It looks like it could be pried in, but doing so would require an appropriate tool." + . += span_notice("Its cell cover is open, exposing the cell slot. It looks like it could be pried in, but doing so would require an appropriate tool.") if(!cell) - . += "The slot for a cell is empty." + . += span_notice("The slot for a cell is empty.") else - . += "\The [cell] is firmly in place. [span_info("Ctrl-click with an empty hand to remove it.")]" + . += span_notice("\The [cell] is firmly in place. Ctrl-click with an empty hand to remove it.") /obj/item/inspector/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) if(!user.Adjacent(interacting_with)) diff --git a/code/game/objects/items/kitchen.dm b/code/game/objects/items/kitchen.dm index 6689ec41a9a..40bcd25d735 100644 --- a/code/game/objects/items/kitchen.dm +++ b/code/game/objects/items/kitchen.dm @@ -22,6 +22,7 @@ name = "fork" desc = "Pointy." icon_state = "fork" + icon_angle = -90 force = 4 w_class = WEIGHT_CLASS_TINY throwforce = 0 @@ -107,6 +108,7 @@ name = "Kitchen Toolset" icon = 'icons/obj/items_cyborg.dmi' icon_state = "sili_knife" + icon_angle = 0 desc = "A breakthrough in synthetic engineering, this tool is a knife programmed to dull when not used for cooking purposes, and can exchange the blade for a rolling pin" force = 0 throwforce = 0 @@ -161,6 +163,7 @@ icon_state = "rolling_pin" worn_icon_state = "rolling_pin" inhand_icon_state = "rolling_pin" + icon_angle = -45 force = 8 throwforce = 5 throw_speed = 3 @@ -194,6 +197,7 @@ desc = "Just be careful your food doesn't melt the spoon first." icon_state = "spoon" base_icon_state = "spoon" + icon_angle = -90 w_class = WEIGHT_CLASS_TINY obj_flags = CONDUCTS_ELECTRICITY force = 2 @@ -335,6 +339,7 @@ icon_state = "ladle" base_icon_state = "ladle" inhand_icon_state = "spoon" + icon_angle = 90 custom_price = PAYCHECK_LOWER * 4 spoon_sip_size = 3 // just a taste diff --git a/code/game/objects/items/knives.dm b/code/game/objects/items/knives.dm index e089a5bc55d..fc7836bbc04 100644 --- a/code/game/objects/items/knives.dm +++ b/code/game/objects/items/knives.dm @@ -7,6 +7,7 @@ righthand_file = 'icons/mob/inhands/equipment/kitchen_righthand.dmi' inhand_icon_state = "knife" worn_icon_state = "knife" + icon_angle = -90 desc = "The original knife, it is said that all other knives are only copies of this one." obj_flags = CONDUCTS_ELECTRICITY force = 10 @@ -17,13 +18,15 @@ throw_speed = 3 throw_range = 6 custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 6) - attack_verb_continuous = list("slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts") - attack_verb_simple = list("slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut") + attack_verb_continuous = list("slashes", "slices", "tears", "lacerates", "rips", "dices", "cuts") + attack_verb_simple = list("slash", "slice", "tear", "lacerate", "rip", "dice", "cut") sharpness = SHARP_EDGED armor_type = /datum/armor/item_knife wound_bonus = 5 bare_wound_bonus = 15 tool_behaviour = TOOL_KNIFE + var/list/alt_continuous = list("stabs", "pierces", "shanks") + var/list/alt_simple = list("stab", "pierce", "shank") /datum/armor/item_knife fire = 50 @@ -33,6 +36,9 @@ . = ..() AddElement(/datum/element/eyestab) set_butchering() + alt_continuous = string_list(alt_continuous) + alt_simple = string_list(alt_simple) + make_stabby() ///Adds the butchering component, used to override stats for special cases /obj/item/knife/proc/set_butchering() @@ -43,6 +49,10 @@ ) //bonus chance increases depending on force +///Adds alt sharpness component, used for overrides +/obj/item/knife/proc/make_stabby() + AddComponent(/datum/component/alternative_sharpness, SHARP_POINTY, alt_continuous, alt_simple) + /obj/item/knife/suicide_act(mob/living/user) user.visible_message(pick(span_suicide("[user] is slitting [user.p_their()] wrists with the [src.name]! It looks like [user.p_theyre()] trying to commit suicide."), \ span_suicide("[user] is slitting [user.p_their()] throat with the [src.name]! It looks like [user.p_theyre()] trying to commit suicide."), \ @@ -56,6 +66,7 @@ icon_state = "bone_blade" inhand_icon_state = "bone_blade" worn_icon_state = "bone_blade" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/64x64_lefthand.dmi' righthand_file = 'icons/mob/inhands/64x64_righthand.dmi' inhand_x_dimension = 64 @@ -72,6 +83,7 @@ icon = 'icons/obj/weapons/khopesh.dmi' icon_state = "bloodletter" worn_icon_state = "render" + icon_angle = -45 w_class = WEIGHT_CLASS_NORMAL /// Bleed stacks applied when an organic mob target is hit var/bleed_stacks_per_hit = 3 @@ -90,9 +102,10 @@ /obj/item/knife/butcher name = "butcher's cleaver" + desc = "A huge thing used for chopping and chopping up meat. This includes clowns and clown by-products." icon_state = "butch" inhand_icon_state = "butch" - desc = "A huge thing used for chopping and chopping up meat. This includes clowns and clown by-products." + icon_angle = -45 obj_flags = CONDUCTS_ELECTRICITY force = 15 throwforce = 10 @@ -103,12 +116,16 @@ custom_price = PAYCHECK_CREW * 5 wound_bonus = 15 +/obj/item/knife/butcher/make_stabby() + return + /obj/item/knife/hunting name = "hunting knife" - icon = 'icons/obj/weapons/stabby.dmi' desc = "Despite its name, it's mainly used for cutting meat from dead prey rather than actual hunting." + icon = 'icons/obj/weapons/stabby.dmi' inhand_icon_state = "huntingknife" icon_state = "huntingknife" + icon_angle = 180 wound_bonus = 10 /obj/item/knife/hunting/set_butchering() @@ -118,12 +135,16 @@ bonus_modifier = force + 10, \ ) +/obj/item/knife/hunting/make_stabby() + return + /obj/item/knife/combat name = "combat knife" + desc = "A military combat utility survival knife." icon = 'icons/obj/weapons/stabby.dmi' icon_state = "buckknife" worn_icon_state = "buckknife" - desc = "A military combat utility survival knife." + icon_angle = -45 embed_type = /datum/embed_data/combat_knife force = 20 throwforce = 20 @@ -141,6 +162,9 @@ . = ..() AddComponent(/datum/component/knockoff, 90, list(BODY_ZONE_PRECISE_MOUTH), slot_flags) //90% to knock off when wearing a mask +/obj/item/knife/combat/make_stabby() + AddComponent(/datum/component/alternative_sharpness, SHARP_POINTY, alt_continuous, alt_simple, -5) + /obj/item/knife/combat/dropped(mob/living/user, slot) . = ..() if(user.get_item_by_slot(ITEM_SLOT_MASK) == src && !user.has_status_effect(/datum/status_effect/choke) && prob(20)) @@ -158,36 +182,33 @@ /obj/item/knife/combat/survival name = "survival knife" - icon = 'icons/obj/weapons/stabby.dmi' + desc = "A hunting grade survival knife." icon_state = "survivalknife" worn_icon_state = "survivalknife" embed_type = /datum/embed_data/combat_knife/weak - desc = "A hunting grade survival knife." force = 15 throwforce = 15 /obj/item/knife/combat/root name = "cahn'root dagger" - icon = 'icons/obj/weapons/stabby.dmi' + desc = "A root dagger, deceptively sharp. Perfect to hide and stab someone with, or make a couple and throw them at enemies." icon_state = "rootdagger" worn_icon_state = "root_dagger" lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' inhand_icon_state = "rootshiv" embed_type = /datum/embed_data/combat_knife/weak - desc = "A root dagger, deceptively sharp. Perfect to hide and stab someone with, or make a couple and throw them at enemies." force = 15 throwforce = 15 /obj/item/knife/combat/bone name = "bone dagger" + desc = "A sharpened bone. The bare minimum in survival." inhand_icon_state = "bone_dagger" - icon = 'icons/obj/weapons/stabby.dmi' icon_state = "bone_dagger" worn_icon_state = "bone_dagger" lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' - desc = "A sharpened bone. The bare minimum in survival." embed_type = /datum/embed_data/combat_knife/weak obj_flags = parent_type::obj_flags & ~CONDUCTS_ELECTRICITY force = 15 @@ -199,20 +220,21 @@ /obj/item/knife/combat/cyborg name = "cyborg knife" + desc = "A cyborg-mounted plasteel knife. Extremely sharp and durable." icon = 'icons/obj/items_cyborg.dmi' icon_state = "knife_cyborg" worn_icon_state = "knife_cyborg" //error sprite - this shouldn't have been dropped - desc = "A cyborg-mounted plasteel knife. Extremely sharp and durable." slot_flags = NONE //you can't put this in your mouth /obj/item/knife/shiv name = "glass shiv" + desc = "A makeshift glass shiv." icon = 'icons/obj/weapons/stabby.dmi' icon_state = "shiv" inhand_icon_state = "shiv" + icon_angle = -65 lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' - desc = "A makeshift glass shiv." obj_flags = parent_type::obj_flags & ~CONDUCTS_ELECTRICITY force = 8 throwforce = 12 @@ -221,11 +243,14 @@ armor_type = /datum/armor/none custom_materials = list(/datum/material/glass = SMALL_MATERIAL_AMOUNT * 4) +/obj/item/knife/shiv/make_stabby() + AddComponent(/datum/component/alternative_sharpness, SHARP_POINTY, alt_continuous, alt_simple, -3) + /obj/item/knife/shiv/plasma name = "plasma shiv" + desc = "A makeshift plasma glass shiv." icon_state = "plasmashiv" inhand_icon_state = "plasmashiv" - desc = "A makeshift plasma glass shiv." force = 9 throwforce = 13 armor_type = /datum/armor/shiv_plasma @@ -242,9 +267,9 @@ /obj/item/knife/shiv/titanium name = "titanium shiv" + desc = "A makeshift titanium-infused glass shiv." icon_state = "titaniumshiv" inhand_icon_state = "titaniumshiv" - desc = "A makeshift titanium-infused glass shiv." throwforce = 14 throw_range = 7 wound_bonus = 10 @@ -262,9 +287,9 @@ /obj/item/knife/shiv/plastitanium name = "plastitanium shiv" + desc = "A makeshift titanium-infused plasma glass shiv." icon_state = "plastitaniumshiv" inhand_icon_state = "plastitaniumshiv" - desc = "A makeshift titanium-infused plasma glass shiv." force = 10 throwforce = 15 throw_speed = 4 @@ -285,9 +310,10 @@ /obj/item/knife/shiv/carrot name = "carrot shiv" + desc = "Unlike other carrots, you should probably keep this far away from your eyes." icon_state = "carrotshiv" inhand_icon_state = "carrotshiv" - desc = "Unlike other carrots, you should probably keep this far away from your eyes." + icon_angle = -45 custom_materials = null /obj/item/knife/shiv/carrot/suicide_act(mob/living/carbon/user) @@ -296,15 +322,17 @@ /obj/item/knife/shiv/parsnip name = "parsnip shiv" + desc = "Truly putting 'snip' in the 'parsnip', and it's not sub-par either!" icon_state = "parsnipshiv" inhand_icon_state = "parsnipshiv" - desc = "Truly putting 'snip' in the 'parsnip', and it's not sub-par either!" + icon_angle = -45 custom_materials = null /obj/item/knife/shiv/root name = "cahn'root shiv" + desc = "A root sharpened into a shiv. A root source of someone's stab wounds soon, most likely." icon_state = "rootshiv" inhand_icon_state = "rootshiv" - desc = "A root sharpened into a shiv. A root source of someone's stab wounds soon, most likely." + icon_angle = -45 custom_materials = null diff --git a/code/game/objects/items/maintenance_loot.dm b/code/game/objects/items/maintenance_loot.dm index 9d1c4fe676b..1bba4f5b651 100644 --- a/code/game/objects/items/maintenance_loot.dm +++ b/code/game/objects/items/maintenance_loot.dm @@ -8,6 +8,7 @@ icon = 'icons/obj/maintenance_loot.dmi' icon_state = "lead_pipe" inhand_icon_state = "lead_pipe" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' //wow, lore diff --git a/code/game/objects/items/melee/baton.dm b/code/game/objects/items/melee/baton.dm index 775612026b1..03df0514038 100644 --- a/code/game/objects/items/melee/baton.dm +++ b/code/game/objects/items/melee/baton.dm @@ -6,6 +6,7 @@ icon_state = "classic_baton" inhand_icon_state = "classic_baton" worn_icon_state = "classic_baton" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi' slot_flags = ITEM_SLOT_BELT @@ -306,6 +307,7 @@ desc = "A compact yet robust personal defense weapon. Can be concealed when folded." icon = 'icons/obj/weapons/baton.dmi' icon_state = "telebaton" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' inhand_icon_state = null @@ -396,6 +398,7 @@ icon = 'icons/obj/weapons/baton.dmi' icon_state = "contractor_baton" worn_icon_state = "contractor_baton" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' slot_flags = ITEM_SLOT_BELT @@ -431,6 +434,7 @@ icon_state = "stunbaton" inhand_icon_state = "baton" worn_icon_state = "baton" + icon_angle = -45 force = 10 wound_bonus = 0 attack_verb_continuous = list("beats") @@ -724,6 +728,7 @@ icon_state = "stunprod" inhand_icon_state = "prod" worn_icon_state = null + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' w_class = WEIGHT_CLASS_HUGE diff --git a/code/game/objects/items/melee/energy.dm b/code/game/objects/items/melee/energy.dm index f78eec38987..a386375b827 100644 --- a/code/game/objects/items/melee/energy.dm +++ b/code/game/objects/items/melee/energy.dm @@ -1,5 +1,6 @@ /obj/item/melee/energy icon = 'icons/obj/weapons/transforming_energy.dmi' + icon_angle = -45 max_integrity = 200 armor_type = /datum/armor/melee_energy attack_verb_continuous = list("hits", "taps", "pokes") @@ -63,8 +64,8 @@ sharpness_on = active_sharpness, \ hitsound_on = active_hitsound, \ w_class_on = active_w_class, \ - attack_verb_continuous_on = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts"), \ - attack_verb_simple_on = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut"), \ + attack_verb_continuous_on = list("attacks", "slashes", "slices", "tears", "lacerates", "rips", "dices", "cuts"), \ + attack_verb_simple_on = list("attack", "slash", "slice", "tear", "lacerate", "rip", "dice", "cut"), \ ) RegisterSignal(src, COMSIG_TRANSFORMING_ON_TRANSFORM, PROC_REF(on_transform)) @@ -190,6 +191,14 @@ block_chance = 50 block_sound = 'sound/items/weapons/block_blade.ogg' embed_type = /datum/embed_data/esword + var/list/alt_continuous = list("stabs", "pierces", "impales") + var/list/alt_simple = list("stab", "pierce", "impale") + +/obj/item/melee/energy/sword/Initialize(mapload) + . = ..() + alt_continuous = string_list(alt_continuous) + alt_simple = string_list(alt_simple) + AddComponent(/datum/component/alternative_sharpness, SHARP_POINTY, alt_continuous, alt_simple, -10, TRAIT_TRANSFORM_ACTIVE) /obj/item/melee/energy/sword/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK, damage_type = BRUTE) if(!HAS_TRAIT(src, TRAIT_TRANSFORM_ACTIVE)) @@ -322,8 +331,8 @@ lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' hitsound = 'sound/items/weapons/blade1.ogg' - attack_verb_continuous = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts") - attack_verb_simple = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut") + attack_verb_continuous = list("attacks", "slashes", "slices", "tears", "lacerates", "rips", "dices", "cuts") + attack_verb_simple = list("attack", "slash", "slice", "tear", "lacerate", "rip", "dice", "cut") force = 30 throwforce = 1 // Throwing or dropping the item deletes it. throw_speed = 3 @@ -333,10 +342,15 @@ w_class = WEIGHT_CLASS_BULKY /// Our linked spark system that emits from our sword. var/datum/effect_system/spark_spread/spark_system + var/list/alt_continuous = list("stabs", "pierces", "impales") + var/list/alt_simple = list("stab", "pierce", "impale") //Most of the other special functions are handled in their own files. aka special snowflake code so kewl /obj/item/melee/energy/blade/Initialize(mapload) . = ..() + alt_continuous = string_list(alt_continuous) + alt_simple = string_list(alt_simple) + AddComponent(/datum/component/alternative_sharpness, SHARP_POINTY, alt_continuous, alt_simple, -10) spark_system = new /datum/effect_system/spark_spread() spark_system.set_up(5, 0, src) spark_system.attach(src) @@ -356,3 +370,4 @@ icon_state = "lightblade" inhand_icon_state = "lightblade" base_icon_state = "lightblade" + icon_angle = 0 diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm index d8b69c53be8..237815016b6 100644 --- a/code/game/objects/items/melee/misc.dm +++ b/code/game/objects/items/melee/misc.dm @@ -9,6 +9,7 @@ icon_state = "chain" inhand_icon_state = "chain" worn_icon_state = "whip" + icon_angle = -90 lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' obj_flags = CONDUCTS_ELECTRICITY @@ -34,18 +35,24 @@ icon = 'icons/obj/weapons/changeling_items.dmi' icon_state = "arm_blade" inhand_icon_state = "arm_blade" + icon_angle = 180 lefthand_file = 'icons/mob/inhands/antag/changeling_lefthand.dmi' righthand_file = 'icons/mob/inhands/antag/changeling_righthand.dmi' w_class = WEIGHT_CLASS_HUGE force = 20 throwforce = 10 hitsound = 'sound/items/weapons/bladeslice.ogg' - attack_verb_continuous = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts") - attack_verb_simple = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut") + attack_verb_continuous = list("attacks", "slashes", "slices", "tears", "lacerates", "rips", "dices", "cuts") + attack_verb_simple = list("attack", "slash", "slice", "tear", "lacerate", "rip", "dice", "cut") sharpness = SHARP_EDGED + var/list/alt_continuous = list("stabs", "pierces", "impales") + var/list/alt_simple = list("stab", "pierce", "impale") /obj/item/melee/synthetic_arm_blade/Initialize(mapload) . = ..() + alt_continuous = string_list(alt_continuous) + alt_simple = string_list(alt_simple) + AddComponent(/datum/component/alternative_sharpness, SHARP_POINTY, alt_continuous, alt_simple, -5) AddComponent(/datum/component/butchering, \ speed = 6 SECONDS, \ effectiveness = 80, \ @@ -58,6 +65,7 @@ icon = 'icons/psychonaut/obj/weapons/sword.dmi' icon_state = "sabre_red" inhand_icon_state = "sabre_red" + icon_angle = -45 lefthand_file = 'icons/psychonaut/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/psychonaut/mob/inhands/weapons/swords_righthand.dmi' obj_flags = CONDUCTS_ELECTRICITY | UNIQUE_RENAME @@ -171,6 +179,7 @@ icon = 'icons/obj/weapons/sword.dmi' icon_state = "parsnip_sabre" inhand_icon_state = "parsnip_sabre" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' force = 15 @@ -212,6 +221,7 @@ icon_state = "beesword" inhand_icon_state = "stinger" worn_icon_state = "stinger" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' slot_flags = ITEM_SLOT_BELT @@ -248,6 +258,7 @@ icon = 'icons/obj/weapons/sword.dmi' icon_state = "supermatter_sword_balanced" inhand_icon_state = "supermatter_sword" + icon_angle = -90 lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' slot_flags = null @@ -304,6 +315,7 @@ ..() balanced = 0 icon_state = "supermatter_sword" + icon_angle = -45 /obj/item/melee/supermatter_sword/ex_act(severity, target) visible_message( @@ -361,6 +373,7 @@ icon = 'icons/obj/weapons/whip.dmi' icon_state = "whip" inhand_icon_state = "chain" + icon_angle = -90 lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' worn_icon_state = "whip" @@ -385,6 +398,7 @@ icon_state = "roastingstick" inhand_icon_state = null worn_icon_state = "tele_baton" + icon_angle = -45 slot_flags = ITEM_SLOT_BELT w_class = WEIGHT_CLASS_SMALL item_flags = NONE @@ -510,6 +524,7 @@ icon_state = "default" inhand_icon_state = "default" worn_icon_state = "default_worn" + icon_angle = -45 greyscale_config = /datum/greyscale_config/cleric_mace greyscale_config_inhand_left = /datum/greyscale_config/cleric_mace_lefthand diff --git a/code/game/objects/items/mop.dm b/code/game/objects/items/mop.dm index b2bd6d55d5c..2896ce06301 100644 --- a/code/game/objects/items/mop.dm +++ b/code/game/objects/items/mop.dm @@ -4,6 +4,7 @@ icon = 'icons/obj/service/janitor.dmi' icon_state = "mop" inhand_icon_state = "mop" + icon_angle = 135 lefthand_file = 'icons/mob/inhands/equipment/custodial_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/custodial_righthand.dmi' force = 8 diff --git a/code/game/objects/items/pitchfork.dm b/code/game/objects/items/pitchfork.dm index 1ece740d4a6..99f714f09f3 100644 --- a/code/game/objects/items/pitchfork.dm +++ b/code/game/objects/items/pitchfork.dm @@ -8,6 +8,7 @@ icon = 'icons/obj/weapons/spear.dmi' icon_state = "pitchfork0" base_icon_state = "pitchfork" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/polearms_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/polearms_righthand.dmi' name = "pitchfork" diff --git a/code/game/objects/items/powerfist.dm b/code/game/objects/items/powerfist.dm index 77810ff3a89..871a6d2d3b2 100644 --- a/code/game/objects/items/powerfist.dm +++ b/code/game/objects/items/powerfist.dm @@ -12,6 +12,7 @@ icon = 'icons/obj/antags/syndicate_tools.dmi' icon_state = "powerfist" inhand_icon_state = "powerfist" + icon_angle = 180 lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' obj_flags = CONDUCTS_ELECTRICITY diff --git a/code/game/objects/items/religion.dm b/code/game/objects/items/religion.dm index 963274f26f2..61385378736 100644 --- a/code/game/objects/items/religion.dm +++ b/code/game/objects/items/religion.dm @@ -337,6 +337,7 @@ desc = "It's a stick..?" icon = 'icons/obj/weapons/staff.dmi' icon_state = "godstaff-red" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/staves_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi' var/conversion_color = "#ffffff" @@ -427,8 +428,14 @@ force = 24 armour_penetration = 10 +/obj/item/claymore/weak/make_stabby() + AddComponent(/datum/component/alternative_sharpness, SHARP_POINTY, alt_continuous, alt_simple, -9) + /obj/item/claymore/weak/ceremonial desc = "A rusted claymore, once at the heart of a powerful scottish clan struck down and oppressed by tyrants, it has been passed down the ages as a symbol of defiance." force = 15 block_chance = 30 armour_penetration = 5 + +/obj/item/claymore/weak/ceremonial/make_stabby() + AddComponent(/datum/component/alternative_sharpness, SHARP_POINTY, alt_continuous, alt_simple, -5) diff --git a/code/game/objects/items/shrapnel.dm b/code/game/objects/items/shrapnel.dm index 701a0a819d0..a4adc353db3 100644 --- a/code/game/objects/items/shrapnel.dm +++ b/code/game/objects/items/shrapnel.dm @@ -4,6 +4,7 @@ weak_against_armour = TRUE icon = 'icons/obj/debris.dmi' icon_state = "large" + icon_angle = -45 w_class = WEIGHT_CLASS_TINY item_flags = DROPDEL sharpness = SHARP_EDGED diff --git a/code/game/objects/items/spear.dm b/code/game/objects/items/spear.dm index 6ad49bf836f..2ac99231d73 100644 --- a/code/game/objects/items/spear.dm +++ b/code/game/objects/items/spear.dm @@ -1,11 +1,12 @@ //spears /obj/item/spear + name = "spear" + desc = "A haphazardly-constructed yet still deadly weapon of ancient design." icon = 'icons/obj/weapons/spear.dmi' icon_state = "spearglass0" lefthand_file = 'icons/mob/inhands/weapons/polearms_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/polearms_righthand.dmi' - name = "spear" - desc = "A haphazardly-constructed yet still deadly weapon of ancient design." + icon_angle = -45 force = 10 w_class = WEIGHT_CLASS_BULKY slot_flags = ITEM_SLOT_BACK @@ -18,7 +19,7 @@ hitsound = 'sound/items/weapons/bladeslice.ogg' attack_verb_continuous = list("attacks", "pokes", "jabs", "tears", "lacerates", "gores") attack_verb_simple = list("attack", "poke", "jab", "tear", "lacerate", "gore") - sharpness = SHARP_EDGED // i know the whole point of spears is that they're pointy, but edged is more devastating at the moment so + sharpness = SHARP_POINTY max_integrity = 200 armor_type = /datum/armor/item_spear wound_bonus = -15 diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm index 7c922d6687d..e5514380bf8 100644 --- a/code/game/objects/items/stacks/medical.dm +++ b/code/game/objects/items/stacks/medical.dm @@ -32,6 +32,10 @@ var/sanitization /// How much we add to flesh_healing for burn wounds on application var/flesh_regeneration + /// Verb used when applying this object to someone + var/apply_verb = "treating" + /// Whether this item can be used on dead bodies + var/works_on_dead = FALSE /obj/item/stack/medical/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) if(!isliving(interacting_with)) @@ -90,8 +94,8 @@ var/heal_zone = check_zone(user.zone_selected) if(!try_heal_checks(patient, user, heal_zone)) return FALSE - SSblackbox.record_feedback("nested tally", "medical_item_used", 1, list(type, auto_change_zone ? "auto" : "manual")) - patient.balloon_alert(user, "treating [parse_zone(heal_zone)]...") + SSblackbox.record_feedback("nested tally", "medical_item_used", 1, list("[auto_change_zone ? "auto" : "manual"]", "[type]")) + patient.balloon_alert(user, "[apply_verb] [parse_zone(heal_zone)]...") INVOKE_ASYNC(src, PROC_REF(try_heal), patient, user, heal_zone, FALSE, iscarbon(patient) && auto_change_zone) // auto change is useless for non-carbons return TRUE @@ -114,7 +118,6 @@ /obj/item/stack/medical/proc/try_heal(mob/living/patient, mob/living/user, healed_zone, silent = FALSE, auto_change_zone = TRUE) if(patient == user) if(!silent) - user.balloon_alert(user, "treating [parse_zone(healed_zone)]...") user.visible_message( span_notice("[user] starts to apply [src] on [user.p_them()]self..."), span_notice("You begin applying [src] on yourself..."), @@ -134,7 +137,6 @@ else if(other_delay) if(!silent) - patient.balloon_alert(user, "treating [parse_zone(healed_zone)]...") user.visible_message( span_notice("[user] starts to apply [src] on [patient]."), span_notice("You begin applying [src] on [patient]..."), @@ -181,7 +183,7 @@ var/preferred_target = check_zone(user.zone_selected) if(try_heal_checks(patient, user, preferred_target, silent = TRUE)) if(preferred_target != healed_zone) - patient.balloon_alert(user, "treating [parse_zone(preferred_target)]...") + patient.balloon_alert(user, "[apply_verb] [parse_zone(preferred_target)]...") try_heal(patient, user, preferred_target, TRUE, auto_change_zone) return @@ -211,7 +213,7 @@ var/next_picked = (preferred_target in other_affected_limbs) ? preferred_target : other_affected_limbs[1] if(next_picked != last_zone) - user.balloon_alert(user, "treating [parse_zone(next_picked)]...") + patient.balloon_alert(user, "[apply_verb] [parse_zone(next_picked)]...") try_heal(patient, user, next_picked, silent = TRUE, auto_change_zone = TRUE) /obj/item/stack/medical/proc/try_heal_manual_target(mob/living/carbon/patient, mob/living/user) @@ -223,7 +225,7 @@ var/new_zone = check_zone(user.zone_selected) if(!try_heal_checks(patient, user, new_zone)) return - patient.balloon_alert(user, "treating [parse_zone(new_zone)]...") + patient.balloon_alert(user, "[apply_verb] [parse_zone(new_zone)]...") try_heal(patient, user, new_zone, silent = TRUE, auto_change_zone = FALSE) /// Checks if the passed patient can be healed by the passed user @@ -233,10 +235,14 @@ /// Checks a bunch of stuff to see if we can heal the patient, including can_heal /// Gives a feedback if we can't ultimatly heal the patient (unless silent is TRUE) /obj/item/stack/medical/proc/try_heal_checks(mob/living/patient, mob/living/user, healed_zone, silent = FALSE) + if(!(healed_zone in GLOB.all_body_zones)) + stack_trace("Invalid zone ([healed_zone || "null"]) passed to try_heal_checks.") + healed_zone = BODY_ZONE_CHEST + if(!can_heal(patient, user, healed_zone, silent)) // has its own feedback return FALSE - if(patient.stat == DEAD) + if(!works_on_dead && patient.stat == DEAD) if(!silent) patient.balloon_alert(user, "[patient.p_theyre()] dead!") return FALSE @@ -343,6 +349,7 @@ other_delay = 2 SECONDS grind_results = list(/datum/reagent/medicine/c2/libital = 10) merge_type = /obj/item/stack/medical/bruise_pack + apply_verb = "applying to" /obj/item/stack/medical/bruise_pack/suicide_act(mob/living/user) user.visible_message(span_suicide("[user] is bludgeoning [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit suicide!")) @@ -365,6 +372,8 @@ splint_factor = 0.7 burn_cleanliness_bonus = 0.35 merge_type = /obj/item/stack/medical/gauze + apply_verb = "wrapping" + works_on_dead = TRUE var/obj/item/bodypart/gauzed_bodypart /obj/item/stack/medical/gauze/Destroy(force) @@ -403,7 +412,7 @@ return FALSE // gauze is only relevant for wounds, which are handled in the wounds themselves -/obj/item/stack/medical/gauze/try_heal(mob/living/patient, mob/living/user, silent, healed_zone, auto_change_zone) +/obj/item/stack/medical/gauze/try_heal(mob/living/patient, mob/living/user, healed_zone, silent, auto_change_zone) var/obj/item/bodypart/limb = patient.get_bodypart(healed_zone) var/treatment_delay = (user == patient ? self_delay : other_delay) var/any_scanned = FALSE @@ -436,8 +445,6 @@ visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE, ) - patient.balloon_alert(user, "wrapping [parse_zone(healed_zone)]...") - if(!do_after(user, treatment_delay, target = patient)) return @@ -510,6 +517,7 @@ stop_bleeding = 0.6 grind_results = list(/datum/reagent/medicine/spaceacillin = 2) merge_type = /obj/item/stack/medical/suture + apply_verb = "suturing" /obj/item/stack/medical/suture/emergency name = "emergency suture" @@ -546,6 +554,7 @@ sanitization = 0.25 grind_results = list(/datum/reagent/medicine/c2/lenturi = 10) merge_type = /obj/item/stack/medical/ointment + apply_verb = "applying to" /obj/item/stack/medical/ointment/suicide_act(mob/living/user) user.visible_message(span_suicide("[user] is squeezing [src] into [user.p_their()] mouth! [user.p_do(TRUE)]n't [user.p_they()] know that stuff is toxic?")) @@ -581,7 +590,7 @@ return ..() icon_state = "regen_mesh_closed" -/obj/item/stack/medical/mesh/try_heal_checks(mob/living/patient, mob/living/user, silent = FALSE) +/obj/item/stack/medical/mesh/try_heal_checks(mob/living/patient, mob/living/user, healed_zone, silent = FALSE) if(!is_open) if(!silent) balloon_alert(user, "open it first!") @@ -643,6 +652,11 @@ heal_burn = 3 grind_results = list(/datum/reagent/consumable/aloejuice = 1) merge_type = /obj/item/stack/medical/aloe + apply_verb = "applying to" + +/obj/item/stack/medical/aloe/Initialize(mapload, new_amount, merge, list/mat_override, mat_amt) + . = ..() + AddComponent(/datum/component/bakeable, /obj/item/food/badrecipe, rand(10 SECONDS, 15 SECONDS), FALSE) /obj/item/stack/medical/aloe/fresh amount = 2 @@ -663,6 +677,7 @@ grind_results = list(/datum/reagent/bone_dust = 10, /datum/reagent/carbon = 10) novariants = TRUE merge_type = /obj/item/stack/medical/bone_gel + apply_verb = "applying to" /obj/item/stack/medical/bone_gel/get_surgery_tool_overlay(tray_extended) return "gel" + (tray_extended ? "" : "_out") @@ -715,6 +730,8 @@ mob_throw_hit_sound = 'sound/misc/moist_impact.ogg' hitsound = 'sound/misc/moist_impact.ogg' merge_type = /obj/item/stack/medical/poultice + apply_verb = "applying to" + works_on_dead = TRUE /obj/item/stack/medical/poultice/post_heal_effects(amount_healed, mob/living/carbon/healed_mob, mob/living/user) . = ..() @@ -736,6 +753,7 @@ self_delay = 3 SECONDS other_delay = 1 SECONDS grind_results = list(/datum/reagent/medicine/c2/libital = 2) + apply_verb = "applying to" /obj/item/stack/medical/bandage/makeshift name = "makeshift bandage" diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm index 709465314bc..db7f1732979 100644 --- a/code/game/objects/items/stacks/sheets/glass.dm +++ b/code/game/objects/items/stacks/sheets/glass.dm @@ -290,6 +290,7 @@ GLOBAL_LIST_INIT(plastitaniumglass_recipes, list( desc = "A nasty looking shard of glass." icon = 'icons/obj/debris.dmi' icon_state = "large" + icon_angle = -45 w_class = WEIGHT_CLASS_TINY force = 5 throwforce = 10 diff --git a/code/game/objects/items/storage/belt.dm b/code/game/objects/items/storage/belt.dm index cb7957929d2..4e8f53ba85c 100644 --- a/code/game/objects/items/storage/belt.dm +++ b/code/game/objects/items/storage/belt.dm @@ -718,7 +718,7 @@ atom_storage.set_holdable(list( /obj/item/ammo_casing/strilka310, /obj/item/ammo_casing/shotgun, - /obj/item/ammo_casing/a357, + /obj/item/ammo_casing/c357, /obj/item/ammo_casing/junk, )) diff --git a/code/game/objects/items/storage/uplink_kits.dm b/code/game/objects/items/storage/uplink_kits.dm index 3f813e50b45..d945a3fd711 100644 --- a/code/game/objects/items/storage/uplink_kits.dm +++ b/code/game/objects/items/storage/uplink_kits.dm @@ -461,7 +461,7 @@ /obj/item/storage/box/syndie_kit/chemical/Initialize(mapload) . = ..() - atom_storage.max_slots = 14 + atom_storage.max_slots = 15 /obj/item/storage/box/syndie_kit/chemical/PopulateContents() new /obj/item/reagent_containers/cup/bottle/polonium(src) @@ -469,6 +469,7 @@ new /obj/item/reagent_containers/cup/bottle/fentanyl(src) new /obj/item/reagent_containers/cup/bottle/formaldehyde(src) new /obj/item/reagent_containers/cup/bottle/spewium(src) + new /obj/item/reagent_containers/cup/bottle/syndol(src) new /obj/item/reagent_containers/cup/bottle/cyanide(src) new /obj/item/reagent_containers/cup/bottle/histamine(src) new /obj/item/reagent_containers/cup/bottle/initropidril(src) diff --git a/code/game/objects/items/syndie_spraycan.dm b/code/game/objects/items/syndie_spraycan.dm index 5690ecb7a28..bc1910595d4 100644 --- a/code/game/objects/items/syndie_spraycan.dm +++ b/code/game/objects/items/syndie_spraycan.dm @@ -171,7 +171,7 @@ /// Timer until the rune can be cleaned up off the floor var/protected_timer -/obj/effect/decal/cleanable/traitor_rune/traitor/Destroy() +/obj/effect/decal/cleanable/traitor_rune/Destroy() deltimer(protected_timer) QDEL_NULL(demoraliser) return ..() diff --git a/code/game/objects/items/tanks/tanks.dm b/code/game/objects/items/tanks/tanks.dm index 100f8a3319e..241fb28d11f 100644 --- a/code/game/objects/items/tanks/tanks.dm +++ b/code/game/objects/items/tanks/tanks.dm @@ -16,6 +16,7 @@ icon = 'icons/obj/canisters.dmi' icon_state = "generic" inhand_icon_state = "generic_tank" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/equipment/tanks_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/tanks_righthand.dmi' obj_flags = CONDUCTS_ELECTRICITY diff --git a/code/game/objects/items/tanks/watertank.dm b/code/game/objects/items/tanks/watertank.dm index 1c23937d2b5..eba0bc82054 100644 --- a/code/game/objects/items/tanks/watertank.dm +++ b/code/game/objects/items/tanks/watertank.dm @@ -290,6 +290,9 @@ /obj/item/extinguisher/mini/nozzle/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) if(AttemptRefill(interacting_with, user)) return NONE + return ..() + +/obj/item/extinguisher/mini/nozzle/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) if(nozzle_mode == EXTINGUISHER) return ..() diff --git a/code/game/objects/items/tongs.dm b/code/game/objects/items/tongs.dm index 81f71c6b345..ec72133a257 100644 --- a/code/game/objects/items/tongs.dm +++ b/code/game/objects/items/tongs.dm @@ -6,6 +6,7 @@ icon_state = "tongs" base_icon_state = "tongs" inhand_icon_state = "fork" // close enough + icon_angle = -45 attack_verb_continuous = list("pinches", "tongs", "nips") attack_verb_simple = list("pinch", "tong", "nip") /// What are we holding in our tongs? diff --git a/code/game/objects/items/tools/crowbar.dm b/code/game/objects/items/tools/crowbar.dm index 38ca59038f0..9081277ad94 100644 --- a/code/game/objects/items/tools/crowbar.dm +++ b/code/game/objects/items/tools/crowbar.dm @@ -4,6 +4,7 @@ icon = 'icons/obj/tools.dmi' icon_state = "crowbar" inhand_icon_state = "crowbar" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' usesound = 'sound/items/tools/crowbar.ogg' @@ -77,6 +78,7 @@ w_class = WEIGHT_CLASS_NORMAL icon = 'icons/obj/weapons/hammer.dmi' icon_state = "clawhammer" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/hammers_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/hammers_righthand.dmi' inhand_icon_state = "clawhammer" @@ -112,6 +114,7 @@ icon_state = "jaws" inhand_icon_state = "jawsoflife" worn_icon_state = "jawsoflife" + icon_angle = 180 lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT*2.25, /datum/material/silver = SHEET_MATERIAL_AMOUNT*1.25, /datum/material/titanium = SHEET_MATERIAL_AMOUNT*1.75) @@ -192,6 +195,7 @@ icon = 'icons/obj/items_cyborg.dmi' icon_state = "toolkit_engiborg_crowbar" worn_icon_state = "toolkit_engiborg_crowbar" //error sprite - this shouldn't have been dropped + icon_angle = 0 usesound = 'sound/items/tools/jaws_pry.ogg' force = 10 toolspeed = 0.5 @@ -203,6 +207,7 @@ base_icon_state = "mechremoval" inhand_icon_state = null icon = 'icons/obj/mechremoval.dmi' + icon_angle = -65 w_class = WEIGHT_CLASS_HUGE slot_flags = NONE toolspeed = 1.25 diff --git a/code/game/objects/items/tools/spess_knife.dm b/code/game/objects/items/tools/spess_knife.dm index 3550f4df5ae..f1148fbd397 100644 --- a/code/game/objects/items/tools/spess_knife.dm +++ b/code/game/objects/items/tools/spess_knife.dm @@ -8,6 +8,7 @@ worn_icon_state = "spess_knife" inside_belt_icon_state = "spess_knife" inhand_icon_state = "spess_knife" + icon_angle = -90 lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' w_class = WEIGHT_CLASS_TINY diff --git a/code/game/objects/items/tools/wrench.dm b/code/game/objects/items/tools/wrench.dm index 564403acf0e..25f7e75593f 100644 --- a/code/game/objects/items/tools/wrench.dm +++ b/code/game/objects/items/tools/wrench.dm @@ -5,6 +5,7 @@ icon_state = "wrench" inhand_icon_state = "wrench" worn_icon_state = "wrench" + icon_angle = -135 lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' obj_flags = CONDUCTS_ELECTRICITY @@ -43,6 +44,7 @@ desc = "A polarized wrench. It causes anything placed between the jaws to turn." icon = 'icons/obj/antags/abductor.dmi' inside_belt_icon_state = "wrench_alien" + icon_angle = -135 custom_materials = list(/datum/material/iron =SHEET_MATERIAL_AMOUNT * 2.5, /datum/material/silver = SHEET_MATERIAL_AMOUNT*1.25, /datum/material/plasma =HALF_SHEET_MATERIAL_AMOUNT, /datum/material/titanium =SHEET_MATERIAL_AMOUNT, /datum/material/diamond =SHEET_MATERIAL_AMOUNT) usesound = 'sound/effects/empulse.ogg' toolspeed = 0.1 @@ -89,6 +91,7 @@ desc = "An advanced robotic wrench, powered by internal hydraulics. Twice as fast as the handheld version." icon = 'icons/obj/items_cyborg.dmi' icon_state = "toolkit_engiborg_wrench" + icon_angle = 0 toolspeed = 0.5 /obj/item/wrench/combat @@ -97,6 +100,7 @@ icon_state = "wrench_combat" inhand_icon_state = "wrench_combat" inside_belt_icon_state = "wrench_combat" + icon_angle = -90 attack_verb_continuous = list("devastates", "brutalizes", "commits a war crime against", "obliterates", "humiliates") attack_verb_simple = list("devastate", "brutalize", "commit a war crime against", "obliterate", "humiliate") tool_behaviour = null @@ -132,4 +136,5 @@ desc = "A wrench designed to grab into airlock's bolting system and raise it regardless of the airlock's power status." icon_state = "bolter_wrench" inhand_icon_state = "bolter_wrench" + icon_angle = -90 w_class = WEIGHT_CLASS_NORMAL diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index 3b67c096c54..f3630424a65 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -565,6 +565,7 @@ desc = "A cheap, plastic replica of an energy sword. Realistic sounds! Ages 8 and up." icon_state = "e_sword" inhand_icon_state = "e_sword" + icon_angle = -45 icon = 'icons/obj/weapons/transforming_energy.dmi' lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' @@ -682,6 +683,7 @@ icon = 'icons/obj/toys/toy.dmi' icon_state = "foamblade" inhand_icon_state = "arm_blade" + icon_angle = -180 lefthand_file = 'icons/mob/inhands/antag/changeling_lefthand.dmi' righthand_file = 'icons/mob/inhands/antag/changeling_righthand.dmi' attack_verb_continuous = list("pricks", "absorbs", "gores") @@ -781,6 +783,7 @@ icon_state = "katana" inhand_icon_state = "katana" worn_icon_state = "katana" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' obj_flags = CONDUCTS_ELECTRICITY @@ -788,9 +791,17 @@ force = 5 throwforce = 5 w_class = WEIGHT_CLASS_NORMAL - attack_verb_continuous = list("attacks", "slashes", "stabs", "slices") - attack_verb_simple = list("attack", "slash", "stab", "slice") + attack_verb_continuous = list("attacks", "slashes", "slices") + attack_verb_simple = list("attack", "slash", "slice") hitsound = 'sound/items/weapons/bladeslice.ogg' + var/list/alt_continuous = list("stabs", "pierces", "impales") + var/list/alt_simple = list("stab", "pierce", "impale") + +/obj/item/toy/katana/Initialize(mapload) + . = ..() + alt_continuous = string_list(alt_continuous) + alt_simple = string_list(alt_simple) + AddComponent(/datum/component/alternative_sharpness, SHARP_POINTY, alt_continuous, alt_simple) /* * Snap pops @@ -1121,6 +1132,7 @@ icon = 'icons/obj/weapons/khopesh.dmi' icon_state = "render" inhand_icon_state = "cultdagger" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' w_class = WEIGHT_CLASS_SMALL diff --git a/code/game/objects/items/v8_engine.dm b/code/game/objects/items/v8_engine.dm index c75f1ebc13a..20b7dd406a5 100644 --- a/code/game/objects/items/v8_engine.dm +++ b/code/game/objects/items/v8_engine.dm @@ -48,6 +48,7 @@ icon = 'icons/obj/weapons/sword.dmi' icon_state = "house_edge0" inhand_icon_state = "house_edge0" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' w_class = WEIGHT_CLASS_HUGE diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm index a731772b090..bc34783a853 100644 --- a/code/game/objects/items/weaponry.dm +++ b/code/game/objects/items/weaponry.dm @@ -3,6 +3,7 @@ name = "banhammer" icon = 'icons/obj/weapons/hammer.dmi' icon_state = "toyhammer" + icon_angle = -45 slot_flags = ITEM_SLOT_BELT throwforce = 0 force = 1 @@ -47,6 +48,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 icon = 'icons/obj/weapons/hammer.dmi' icon_state = "balloon_mallet" inhand_icon_state = "balloon_mallet" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/hammers_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/hammers_righthand.dmi' siemens_coefficient = 0 @@ -88,6 +90,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 icon = 'icons/obj/weapons/sword.dmi' icon_state = "sord" inhand_icon_state = "sord" + icon_angle = -35 lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' slot_flags = ITEM_SLOT_BELT @@ -109,6 +112,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 icon = 'icons/obj/weapons/sword.dmi' icon_state = "claymore" inhand_icon_state = "claymore" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' hitsound = 'sound/items/weapons/bladeslice.ogg' @@ -117,14 +121,16 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 force = 40 throwforce = 10 w_class = WEIGHT_CLASS_NORMAL - attack_verb_continuous = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts") - attack_verb_simple = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut") + attack_verb_continuous = list("attacks", "slashes", "slices", "tears", "lacerates", "rips", "dices", "cuts") + attack_verb_simple = list("attack", "slash", "slice", "tear", "lacerate", "rip", "dice", "cut") block_chance = 50 block_sound = 'sound/items/weapons/parry.ogg' sharpness = SHARP_EDGED max_integrity = 200 armor_type = /datum/armor/item_claymore resistance_flags = FIRE_PROOF + var/list/alt_continuous = list("stabs", "pierces", "impales") + var/list/alt_simple = list("stab", "pierce", "impale") /datum/armor/item_claymore fire = 100 @@ -132,11 +138,18 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 /obj/item/claymore/Initialize(mapload) . = ..() + alt_continuous = string_list(alt_continuous) + alt_simple = string_list(alt_simple) + make_stabby() AddComponent(/datum/component/butchering, \ speed = 4 SECONDS, \ effectiveness = 105, \ ) +// Applies alt sharpness component, for overrides +/obj/item/claymore/proc/make_stabby() + AddComponent(/datum/component/alternative_sharpness, SHARP_POINTY, alt_continuous, alt_simple, -15) + /obj/item/claymore/suicide_act(mob/living/user) user.visible_message(span_suicide("[user] is falling on [src]! It looks like [user.p_theyre()] trying to commit suicide!")) return BRUTELOSS @@ -356,6 +369,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 icon_state = "katana" inhand_icon_state = "katana" worn_icon_state = "katana" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' obj_flags = CONDUCTS_ELECTRICITY @@ -364,14 +378,22 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 throwforce = 10 w_class = WEIGHT_CLASS_HUGE hitsound = 'sound/items/weapons/bladeslice.ogg' - attack_verb_continuous = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts") - attack_verb_simple = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut") + attack_verb_continuous = list("attacks", "slashes", "slices", "tears", "lacerates", "rips", "dices", "cuts") + attack_verb_simple = list("attack", "slash", "slice", "tear", "lacerate", "rip", "dice", "cut") block_chance = 50 block_sound = 'sound/items/weapons/parry.ogg' sharpness = SHARP_EDGED max_integrity = 200 armor_type = /datum/armor/item_katana resistance_flags = FIRE_PROOF + var/list/alt_continuous = list("stabs", "pierces", "impales") + var/list/alt_simple = list("stab", "pierce", "impale") + +/obj/item/katana/Initialize(mapload) + . = ..() + alt_continuous = string_list(alt_continuous) + alt_simple = string_list(alt_simple) + AddComponent(/datum/component/alternative_sharpness, SHARP_POINTY, alt_continuous, alt_simple, -15) /datum/armor/item_katana fire = 100 @@ -438,6 +460,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 icon_state = "carpenter_hammer" inhand_icon_state = "carpenter_hammer" worn_icon_state = "clawhammer" //plaecholder + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/hammers_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/hammers_righthand.dmi' desc = "Uncanny looking hammer." @@ -475,6 +498,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 icon = 'icons/obj/weapons/sword.dmi' icon_state = "switchblade" base_icon_state = "switchblade" + icon_angle = -90 lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' desc = "A sharp, concealable, spring-loaded knife." @@ -491,6 +515,8 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 resistance_flags = FIRE_PROOF /// Whether the switchblade starts extended or not. var/start_extended = FALSE + var/list/alt_continuous = list("stabs", "pierces", "shanks") + var/list/alt_simple = list("stab", "pierce", "shank") /obj/item/switchblade/get_all_tool_behaviours() return list(TOOL_KNIFE) @@ -512,10 +538,14 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 sharpness_on = SHARP_EDGED, \ hitsound_on = 'sound/items/weapons/bladeslice.ogg', \ w_class_on = WEIGHT_CLASS_NORMAL, \ - attack_verb_continuous_on = list("slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts"), \ - attack_verb_simple_on = list("slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut"), \ + attack_verb_continuous_on = list("slashes", "slices", "tears", "lacerates", "rips", "dices", "cuts"), \ + attack_verb_simple_on = list("slash", "slice", "tear", "lacerate", "rip", "dice", "cut"), \ ) + alt_continuous = string_list(alt_continuous) + alt_simple = string_list(alt_simple) + AddComponent(/datum/component/alternative_sharpness, SHARP_POINTY, alt_continuous, alt_simple, -5, TRAIT_TRANSFORM_ACTIVE) + RegisterSignal(src, COMSIG_TRANSFORMING_ON_TRANSFORM, PROC_REF(on_transform)) /obj/item/switchblade/proc/on_transform(obj/item/source, mob/user, active) @@ -567,6 +597,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 base_icon_state = "bambostaff" inhand_icon_state = "bambostaff0" worn_icon_state = "bambostaff0" + icon_angle = -135 lefthand_file = 'icons/mob/inhands/weapons/staves_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi' @@ -589,6 +620,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 icon = 'icons/obj/weapons/staff.dmi' icon_state = "cane" inhand_icon_state = "stick" + icon_angle = 135 lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' force = 5 @@ -630,6 +662,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 icon = 'icons/obj/weapons/staff.dmi' icon_state = "crutch_med" inhand_icon_state = "crutch_med" + icon_angle = 45 lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' force = 12 @@ -682,6 +715,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 desc = "Traditionally used by the blind to help them see. Folds down to be easier to transport." icon_state = "cane_white" inhand_icon_state = "cane_white" + icon_angle = 45 lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' force = 1 @@ -756,6 +790,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 icon = 'icons/obj/weapons/staff.dmi' icon_state = "cane" inhand_icon_state = "stick" + icon_angle = 135 lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' force = 3 @@ -788,6 +823,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 desc = "For the beating to death of lizards with their own tails." icon = 'icons/obj/weapons/club.dmi' icon_state = "tailclub" + icon_angle = -25 force = 14 throwforce = 1 // why are you throwing a club do you even weapon throw_speed = 1 @@ -895,6 +931,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 icon = 'icons/obj/weapons/bat.dmi' icon_state = "baseball_bat" inhand_icon_state = "baseball_bat" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' force = 12 @@ -1045,6 +1082,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 icon = 'icons/obj/service/hydroponics/equipment.dmi' icon_state = "flyswatter" inhand_icon_state = "flyswatter" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' force = 1 @@ -1135,6 +1173,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 icon = 'icons/obj/weapons/club.dmi' icon_state = "gohei" inhand_icon_state = "gohei" + icon_angle = -65 lefthand_file = 'icons/mob/inhands/weapons/staves_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi' @@ -1145,6 +1184,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 icon_state = "swordon" inhand_icon_state = "swordon" worn_icon_state = "swordon" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' w_class = WEIGHT_CLASS_BULKY @@ -1155,8 +1195,16 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 force = 14 throwforce = 12 hitsound = 'sound/items/weapons/bladeslice.ogg' - attack_verb_continuous = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts") - attack_verb_simple = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut") + attack_verb_continuous = list("attacks", "slashes", "slices", "tears", "lacerates", "rips", "dices", "cuts") + attack_verb_simple = list("attack", "slash", "slice", "tear", "lacerate", "rip", "dice", "cut") + var/list/alt_continuous = list("stabs", "pierces", "impales") + var/list/alt_simple = list("stab", "pierce", "impale") + +/obj/item/melee/moonlight_greatsword/Initialize(mapload) + . = ..() + alt_continuous = string_list(alt_continuous) + alt_simple = string_list(alt_simple) + AddComponent(/datum/component/alternative_sharpness, SHARP_POINTY, alt_continuous, alt_simple) //High Frequency Blade @@ -1167,6 +1215,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 icon = 'icons/obj/weapons/sword.dmi' icon_state = "hfrequency0" worn_icon_state = "hfrequency0" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' force = 10 diff --git a/code/game/objects/items/wizard_weapons.dm b/code/game/objects/items/wizard_weapons.dm index e5750c06bb2..9cbbce1a4c8 100644 --- a/code/game/objects/items/wizard_weapons.dm +++ b/code/game/objects/items/wizard_weapons.dm @@ -4,6 +4,7 @@ icon = 'icons/obj/weapons/hammer.dmi' icon_state = "singularity_hammer0" base_icon_state = "singularity_hammer" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/hammers_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/hammers_righthand.dmi' worn_icon_state = "singularity_hammer" @@ -77,6 +78,7 @@ icon_state = "mjollnir0" base_icon_state = "mjollnir" worn_icon_state = "mjollnir" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/hammers_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/hammers_righthand.dmi' obj_flags = CONDUCTS_ELECTRICITY diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index 91991bec3a7..7a58e3ef486 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -69,18 +69,29 @@ GLOBAL_LIST_EMPTY(objects_by_id_tag) return var/total_force = (attacking_item.force * attacking_item.demolition_mod) + var/damage = take_damage(total_force, attacking_item.damtype, MELEE, TRUE, get_dir(src, user), attacking_item.armour_penetration) - var/damage = take_damage(total_force, attacking_item.damtype, MELEE, 1, get_dir(src, user)) + // Sanity in case one is null for some reason + var/picked_index = rand(max(length(attacking_item.attack_verb_simple), length(attacking_item.attack_verb_continuous))) - var/damage_verb = "hit" + var/message_verb_continuous = "attacks" + var/message_verb_simple = "attack" + // Sanity in case one is... longer than the other? + if (picked_index && length(attacking_item.attack_verb_continuous) >= picked_index) + message_verb_continuous = attacking_item.attack_verb_continuous[picked_index] + if (picked_index && length(attacking_item.attack_verb_simple) >= picked_index) + message_verb_simple = attacking_item.attack_verb_simple[picked_index] + + if(attacking_item.demolition_mod > 1 && prob(damage * 5)) + message_verb_simple = "pulverise" + message_verb_continuous = "pulverises" - if(attacking_item.demolition_mod > 1 && damage) - damage_verb = "pulverise" if(attacking_item.demolition_mod < 1) - damage_verb = "ineffectively pierce" + message_verb_simple = "ineffectively " + message_verb_simple + message_verb_continuous = "ineffectively " + message_verb_continuous - user.visible_message(span_danger("[user] [damage_verb][plural_s(damage_verb)] [src] with [attacking_item][damage ? "." : ", [no_damage_feedback]!"]"), \ - span_danger("You [damage_verb] [src] with [attacking_item][damage ? "." : ", [no_damage_feedback]!"]"), null, COMBAT_MESSAGE_RANGE) + user.visible_message(span_danger("[user] [message_verb_continuous] [src] with [attacking_item][damage ? "." : ", [no_damage_feedback]!"]"), \ + span_danger("You [message_verb_simple] [src] with [attacking_item][damage ? "." : ", [no_damage_feedback]!"]"), null, COMBAT_MESSAGE_RANGE) log_combat(user, src, "attacked", attacking_item) /obj/assume_air(datum/gas_mixture/giver) diff --git a/code/game/objects/structures/beds_chairs/chair.dm b/code/game/objects/structures/beds_chairs/chair.dm index 38aadbb2662..8cc1012995d 100644 --- a/code/game/objects/structures/beds_chairs/chair.dm +++ b/code/game/objects/structures/beds_chairs/chair.dm @@ -317,6 +317,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/chair/stool/bar, 0) icon = 'icons/obj/chairs.dmi' icon_state = "chair_toppled" inhand_icon_state = "chair" + icon_angle = 180 lefthand_file = 'icons/mob/inhands/items/chairs_lefthand.dmi' righthand_file = 'icons/mob/inhands/items/chairs_righthand.dmi' w_class = WEIGHT_CLASS_HUGE diff --git a/code/game/objects/structures/lavaland/geyser.dm b/code/game/objects/structures/lavaland/geyser.dm index 6a8dc8e31cd..9a546e8154d 100644 --- a/code/game/objects/structures/lavaland/geyser.dm +++ b/code/game/objects/structures/lavaland/geyser.dm @@ -121,6 +121,7 @@ icon = 'icons/obj/watercloset.dmi' icon_state = "plunger" worn_icon_state = "plunger" + icon_angle = 90 slot_flags = ITEM_SLOT_MASK flags_inv = HIDESNOUT diff --git a/code/game/objects/structures/showcase.dm b/code/game/objects/structures/showcase.dm index 2158a88a6b6..c0f19da6dbd 100644 --- a/code/game/objects/structures/showcase.dm +++ b/code/game/objects/structures/showcase.dm @@ -127,8 +127,8 @@ /obj/structure/showcase/katana name = "seppuku katana" - density = 0 desc = "Welp, only one way to recover your honour." + density = 0 icon = 'icons/obj/weapons/sword.dmi' icon_state = "katana" diff --git a/code/game/objects/structures/shower.dm b/code/game/objects/structures/shower.dm index 9f7660b05e6..ce6c987ba10 100644 --- a/code/game/objects/structures/shower.dm +++ b/code/game/objects/structures/shower.dm @@ -344,11 +344,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/shower, (-16)) return mode == SHOWER_MODE_FOREVER ? 0 : PROCESS_KILL // Wash up. - wash_atom(loc) - for(var/atom/movable/movable_content as anything in loc) - if(!ismopable(movable_content)) // Mopables will be cleaned anyways by the turf wash above - wash_atom(movable_content) // Reagent exposure is handled in wash_atom - + wash_atom(loc, TRUE) reagents.remove_all(SHOWER_SPRAY_VOLUME) /obj/machinery/shower/on_deconstruction(disassembled = TRUE) diff --git a/code/game/objects/structures/water_structures/sink.dm b/code/game/objects/structures/water_structures/sink.dm index 1cd3f7d7aaa..3a6dfbb2a2c 100644 --- a/code/game/objects/structures/water_structures/sink.dm +++ b/code/game/objects/structures/water_structures/sink.dm @@ -73,10 +73,13 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sink, (-14)) if(busy) to_chat(user, span_warning("Someone's already washing here!")) return + var/selected_area = user.parse_zone_with_bodypart(user.zone_selected) - var/washing_face = 0 + var/washing_face = FALSE if(selected_area in list(BODY_ZONE_HEAD, BODY_ZONE_PRECISE_MOUTH, BODY_ZONE_PRECISE_EYES)) - washing_face = 1 + washing_face = TRUE + + playsound(src, 'sound/machines/sink-faucet.ogg', 50) user.visible_message(span_notice("[user] starts washing [user.p_their()] [washing_face ? "face" : "hands"]..."), \ span_notice("You start washing your [washing_face ? "face" : "hands"]...")) busy = TRUE @@ -206,6 +209,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sink, (-14)) if(!user.combat_mode || (O.item_flags & NOBLUDGEON)) to_chat(user, span_notice("You start washing [O]...")) + playsound(src, 'sound/machines/sink-faucet.ogg', 50) busy = TRUE if(!do_after(user, 4 SECONDS, target = src)) busy = FALSE diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 71c3ef9b671..9924713d939 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -82,12 +82,11 @@ /obj/structure/window/mouse_drop_receive(atom/dropping, mob/user, params) . = ..() - if (added_leaning || (flags_1 & ON_BORDER_1)) + if (flags_1 & ON_BORDER_1) return - /// For performance reasons and to cut down on init times we are "lazy-loading" the leaning component when someone drags their sprite onto us, and then calling dragging code again to trigger the component - AddComponent(/datum/component/leanable, 11) - added_leaning = TRUE - dropping.base_mouse_drop_handler(src, null, null, params) + + //Adds the component only once. We do it here & not in Initialize() because there are tons of windows & we don't want to add to their init times + LoadComponent(/datum/component/leanable, dropping) /obj/structure/window/examine(mob/user) . = ..() diff --git a/code/game/say.dm b/code/game/say.dm index d8cb91c4ea4..1e5b4bce450 100644 --- a/code/game/say.dm +++ b/code/game/say.dm @@ -165,7 +165,7 @@ GLOBAL_LIST_INIT(freqtospan, list( if(istype(dialect) && dialect.display_icon(src)) languageicon = "[dialect.get_icon()] " - messagepart = " [say_emphasis(messagepart)]" + messagepart = " [messagepart]" return "[spanpart1][spanpart2][freqpart][languageicon][compose_track_href(speaker, namepart)][namepart][compose_job(speaker, message_language, raw_message, radio_freq)][endspanpart][messagepart]" @@ -223,8 +223,14 @@ GLOBAL_LIST_INIT(freqtospan, list( if(copytext_char(input, -2) == "!!") spans |= SPAN_YELL - var/spanned = attach_spans(input, spans) - return "[say_mod], \"[spanned]\"" + /* all inputs should be fully figured out past this point */ + + var/processed_input = say_emphasis(input) //This MUST be done first so that we don't get clipped by spans + processed_input = attach_spans(processed_input, spans) + + var/processed_say_mod = say_emphasis(say_mod) + + return "[processed_say_mod], \"[processed_input]\"" /// Transforms the speech emphasis mods from [/atom/movable/proc/say_emphasis] into the appropriate HTML tags. Includes escaping. #define ENCODE_HTML_EMPHASIS(input, char, html, varname) \ @@ -235,8 +241,8 @@ GLOBAL_LIST_INIT(freqtospan, list( /atom/movable/proc/say_emphasis(input) ENCODE_HTML_EMPHASIS(input, "\\|", "i", italics) ENCODE_HTML_EMPHASIS(input, "\\+", "b", bold) - ENCODE_HTML_EMPHASIS(input, "_", "u", underline) - var/static/regex/remove_escape_backlashes = regex("\\\\(_|\\+|\\|)", "g") // Removes backslashes used to escape text modification. + ENCODE_HTML_EMPHASIS(input, "\\_", "u", underline) + var/static/regex/remove_escape_backlashes = regex("\\\\(\\_|\\+|\\|)", "g") // Removes backslashes used to escape text modification. input = remove_escape_backlashes.Replace_char(input, "$1") return input diff --git a/code/game/turfs/closed/walls.dm b/code/game/turfs/closed/walls.dm index 99ea3327d6c..402d24c6c83 100644 --- a/code/game/turfs/closed/walls.dm +++ b/code/game/turfs/closed/walls.dm @@ -51,13 +51,8 @@ underlays += underlay_appearance /turf/closed/wall/mouse_drop_receive(atom/dropping, mob/user, params) - . = ..() - if (added_leaning) - return - /// For performance reasons and to cut down on init times we are "lazy-loading" the leaning component when someone drags their sprite onto us, and then calling dragging code again to trigger the component - AddComponent(/datum/component/leanable, 11) - added_leaning = TRUE - dropping.base_mouse_drop_handler(src, null, null, params) + //Adds the component only once. We do it here & not in Initialize() because there are tons of walls & we don't want to add to their init times + LoadComponent(/datum/component/leanable, dropping) /turf/closed/wall/atom_destruction(damage_flag) . = ..() diff --git a/code/game/turfs/open/_open.dm b/code/game/turfs/open/_open.dm index c30073b9907..b0c3bb9c883 100644 --- a/code/game/turfs/open/_open.dm +++ b/code/game/turfs/open/_open.dm @@ -340,11 +340,7 @@ for(var/atom/theatom as anything in src) SEND_SIGNAL(theatom, COMSIG_ATOM_EXPOSED_WATER) - wash(CLEAN_WASH) - for(var/atom/movable/movable_content as anything in src) - if(ismopable(movable_content)) // Will have already been washed by the wash call above at this point. - continue - movable_content.wash(CLEAN_WASH) + wash(CLEAN_WASH, TRUE) return TRUE /turf/open/handle_slip(mob/living/slipper, knockdown_amount, obj/slippable, lube, paralyze_amount, force_drop) diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 318bb5ebb4c..b3cf3761e1d 100755 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -702,19 +702,14 @@ GLOBAL_LIST_EMPTY(station_turfs) var/reac_volume = reagents[reagent] . |= reagent.expose_turf(src, reac_volume) -/** - * Called when this turf is being washed. Washing a turf will also wash any mopable floor decals - */ -/turf/wash(clean_types) +// When our turf is washed, we may wash everything on top of the turf +// By default we will only wash mopable things (like blood or vomit) +// but you may optionally pass in all_contents = TRUE to wash everything +/turf/wash(clean_types, all_contents = FALSE) . = ..() - - for(var/am in src) - if(am == src) - continue - var/atom/movable/movable_content = am - if(!ismopable(movable_content)) - continue - movable_content.wash(clean_types) + for(var/atom/movable/to_clean as anything in src) + if(all_contents || HAS_TRAIT(to_clean, TRAIT_MOPABLE)) + to_clean.wash(clean_types) /turf/set_density(new_value) var/old_density = density diff --git a/code/modules/admin/permissionedit.dm b/code/modules/admin/permissionedit.dm index 73987622202..6bd97dcaa20 100644 --- a/code/modules/admin/permissionedit.dm +++ b/code/modules/admin/permissionedit.dm @@ -140,9 +140,14 @@ ADMIN_VERB(edit_admin_permissions, R_PERMISSIONS, "Permissions Panel", "Edit adm permissions_assets.send(usr.client) var/admin_key = href_list["key"] var/admin_ckey = ckey(admin_key) - var/datum/admins/D = GLOB.admin_datums[admin_ckey] - var/use_db + var/task = href_list["editrights"] + var/datum/admins/target_admin_datum = GLOB.admin_datums[admin_ckey] + if(!target_admin_datum) + target_admin_datum = GLOB.deadmins[admin_ckey] + if (!target_admin_datum && task != "add") + return + var/use_db var/skip var/legacy_only if(task == "activate" || task == "deactivate" || task == "sync" || task == "verify") @@ -152,7 +157,7 @@ ADMIN_VERB(edit_admin_permissions, R_PERMISSIONS, "Permissions Panel", "Edit adm to_chat(usr, "Editing the rank of this admin is blocked by server configuration.", confidential = TRUE) return if(!CONFIG_GET(flag/admin_legacy_system) && CONFIG_GET(flag/protect_legacy_ranks) && task == "permissions") - if((D.ranks & GLOB.protected_ranks).len > 0) + if((target_admin_datum.ranks & GLOB.protected_ranks).len > 0) to_chat(usr, "Editing the flags of this rank is blocked by server configuration.", confidential = TRUE) return if(CONFIG_GET(flag/load_legacy_ranks_only) && (task == "add" || task == "rank" || task == "permissions")) @@ -173,16 +178,11 @@ ADMIN_VERB(edit_admin_permissions, R_PERMISSIONS, "Permissions Panel", "Edit adm use_db = FALSE if(QDELETED(usr)) return - if(task != "add") - D = GLOB.admin_datums[admin_ckey] - if(!D) - D = GLOB.deadmins[admin_ckey] - if(!D) - return - if((task != "sync") && !check_if_greater_rights_than_holder(D)) - message_admins("[key_name_admin(usr)] attempted to change the rank of [admin_key] without sufficient rights.") - log_admin("[key_name(usr)] attempted to change the rank of [admin_key] without sufficient rights.") - return + + if(target_admin_datum && (task != "sync" && task != "verify") && !check_if_greater_rights_than_holder(target_admin_datum)) + message_admins("[key_name_admin(usr)] attempted to change the rank of [admin_key] without sufficient rights.") + log_admin("[key_name(usr)] attempted to change the rank of [admin_key] without sufficient rights.") + return switch(task) if("add") admin_ckey = add_admin(admin_ckey, admin_key, use_db) @@ -194,24 +194,24 @@ ADMIN_VERB(edit_admin_permissions, R_PERMISSIONS, "Permissions Panel", "Edit adm change_admin_rank(admin_ckey, admin_key, use_db, null, legacy_only) if("remove") - remove_admin(admin_ckey, admin_key, use_db, D) + remove_admin(admin_ckey, admin_key, use_db, target_admin_datum) if("rank") - change_admin_rank(admin_ckey, admin_key, use_db, D, legacy_only) + change_admin_rank(admin_ckey, admin_key, use_db, target_admin_datum, legacy_only) if("permissions") - change_admin_flags(admin_ckey, admin_key, D) + change_admin_flags(admin_ckey, admin_key, target_admin_datum) if("activate") - force_readmin(admin_key, D) + force_readmin(admin_key, target_admin_datum) if("deactivate") - force_deadmin(admin_key, D) + force_deadmin(admin_key, target_admin_datum) if("sync") - sync_lastadminrank(admin_ckey, admin_key, D) + sync_lastadminrank(admin_ckey, admin_key, target_admin_datum) if("verify") var/msg = "has authenticated [admin_ckey]" message_admins("[key_name_admin(usr)] [msg]") log_admin("[key_name(usr)] [msg]") - D.bypass_2fa = TRUE - D.associate(GLOB.directory[admin_ckey]) + target_admin_datum.bypass_2fa = TRUE + target_admin_datum.associate(GLOB.directory[admin_ckey]) edit_admin_permissions() /datum/admins/proc/add_admin(admin_ckey, admin_key, use_db) diff --git a/code/modules/antagonists/abductor/equipment/gear/abductor_items.dm b/code/modules/antagonists/abductor/equipment/gear/abductor_items.dm index d70dc3f0e67..b2900b810f3 100644 --- a/code/modules/antagonists/abductor/equipment/gear/abductor_items.dm +++ b/code/modules/antagonists/abductor/equipment/gear/abductor_items.dm @@ -29,6 +29,7 @@ desc = "A dual-mode tool for retrieving specimens and scanning appearances. Scanning can be done through cameras." icon_state = "gizmo_scan" inhand_icon_state = "silencer" + icon_angle = -45 var/mode = GIZMO_SCAN var/datum/weakref/marked_target_weakref var/obj/machinery/abductor/console/console @@ -105,6 +106,7 @@ desc = "A compact device used to shut down communications equipment." icon_state = "silencer" inhand_icon_state = "gizmo" + icon_angle = -45 /obj/item/abductor/silencer/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) if(!AbductorCheck(user)) @@ -145,6 +147,7 @@ or to send a command to a test subject with a charged gland." icon_state = "mind_device_message" inhand_icon_state = "silencer" + icon_angle = -45 var/mode = MIND_DEVICE_MESSAGE /obj/item/abductor/mind_device/attack_self(mob/user) @@ -297,6 +300,7 @@ Congratulations! You are now trained for invasive xenobiology research!"} righthand_file = 'icons/mob/inhands/antag/abductor_righthand.dmi' icon_state = "wonderprodStun" inhand_icon_state = "wonderprod" + icon_angle = -45 force = 7 wound_bonus = FALSE @@ -549,6 +553,7 @@ Congratulations! You are now trained for invasive xenobiology research!"} name = "alien scalpel" desc = "It's a gleaming sharp knife made out of silvery-green metal." icon = 'icons/obj/antags/abductor.dmi' + icon_angle = 180 surgical_tray_overlay = "scalpel_alien" toolspeed = 0.25 @@ -557,6 +562,7 @@ Congratulations! You are now trained for invasive xenobiology research!"} desc = "You've never seen this before." icon = 'icons/obj/antags/abductor.dmi' surgical_tray_overlay = "hemostat_alien" + icon_angle = 180 toolspeed = 0.25 /obj/item/retractor/alien @@ -564,6 +570,7 @@ Congratulations! You are now trained for invasive xenobiology research!"} desc = "You're not sure if you want the veil pulled back." icon = 'icons/obj/antags/abductor.dmi' surgical_tray_overlay = "retractor_alien" + icon_angle = 180 toolspeed = 0.25 /obj/item/circular_saw/alien @@ -571,6 +578,7 @@ Congratulations! You are now trained for invasive xenobiology research!"} desc = "Do the aliens also lose this, and need to find an alien hatchet?" icon = 'icons/obj/antags/abductor.dmi' surgical_tray_overlay = "saw_alien" + icon_angle = 180 toolspeed = 0.25 /obj/item/surgicaldrill/alien @@ -578,6 +586,7 @@ Congratulations! You are now trained for invasive xenobiology research!"} desc = "Maybe alien surgeons have finally found a use for the drill." icon = 'icons/obj/antags/abductor.dmi' surgical_tray_overlay = "drill_alien" + icon_angle = 180 toolspeed = 0.25 /obj/item/cautery/alien @@ -586,6 +595,7 @@ Congratulations! You are now trained for invasive xenobiology research!"} Unless..." icon = 'icons/obj/antags/abductor.dmi' surgical_tray_overlay = "cautery_alien" + icon_angle = 180 toolspeed = 0.25 /obj/item/clothing/head/helmet/abductor @@ -620,6 +630,7 @@ Congratulations! You are now trained for invasive xenobiology research!"} desc = "Effectively just a Space Swiss Army Knife. Contains a multitude of integrated tools. Right-click it to switch which toolset is active." icon_state = "omnitool" inhand_icon_state = "silencer" + icon_angle = -45 toolspeed = 0.25 tool_behaviour = null usesound = 'sound/items/pshoom/pshoom.ogg' diff --git a/code/modules/antagonists/changeling/powers/mutations.dm b/code/modules/antagonists/changeling/powers/mutations.dm index 874141237a9..c1721cc57e6 100644 --- a/code/modules/antagonists/changeling/powers/mutations.dm +++ b/code/modules/antagonists/changeling/powers/mutations.dm @@ -188,6 +188,7 @@ icon = 'icons/obj/weapons/changeling_items.dmi' icon_state = "arm_blade" inhand_icon_state = "arm_blade" + icon_angle = 180 lefthand_file = 'icons/mob/inhands/antag/changeling_lefthand.dmi' righthand_file = 'icons/mob/inhands/antag/changeling_righthand.dmi' item_flags = NEEDS_PERMIT | ABSTRACT | DROPDEL @@ -197,14 +198,16 @@ throw_range = 0 throw_speed = 0 hitsound = 'sound/items/weapons/bladeslice.ogg' - attack_verb_continuous = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts") - attack_verb_simple = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut") + attack_verb_continuous = list("attacks", "slashes", "slices", "tears", "lacerates", "rips", "dices", "cuts") + attack_verb_simple = list("attack", "slash", "slice", "tear", "lacerate", "rip", "dice", "cut") sharpness = SHARP_EDGED wound_bonus = 10 bare_wound_bonus = 10 armour_penetration = 35 var/can_drop = FALSE var/fake = FALSE + var/list/alt_continuous = list("stabs", "pierces", "impales") + var/list/alt_simple = list("stab", "pierce", "impale") /obj/item/melee/arm_blade/Initialize(mapload,silent,synthetic) . = ..() @@ -213,6 +216,9 @@ loc.visible_message(span_warning("A grotesque blade forms around [loc.name]\'s arm!"), span_warning("Our arm twists and mutates, transforming it into a deadly blade."), span_hear("You hear organic matter ripping and tearing!")) if(synthetic) can_drop = TRUE + alt_continuous = string_list(alt_continuous) + alt_simple = string_list(alt_simple) + AddComponent(/datum/component/alternative_sharpness, SHARP_POINTY, alt_continuous, alt_simple, -5) AddComponent(/datum/component/butchering, \ speed = 6 SECONDS, \ effectiveness = 80, \ @@ -276,6 +282,7 @@ icon = 'icons/obj/weapons/changeling_items.dmi' icon_state = "tentacle" inhand_icon_state = "tentacle" + icon_angle = 180 lefthand_file = 'icons/mob/inhands/antag/changeling_lefthand.dmi' righthand_file = 'icons/mob/inhands/antag/changeling_righthand.dmi' item_flags = NEEDS_PERMIT | ABSTRACT | DROPDEL | NOBLUDGEON @@ -356,26 +363,31 @@ chain = firer.Beam(src, icon_state = "tentacle", emissive = FALSE) ..() -/obj/projectile/tentacle/proc/reset_throw(mob/living/carbon/human/H) - if(H.throw_mode) - H.throw_mode_off(THROW_MODE_TOGGLE) //Don't annoy the changeling if he doesn't catch the item +/obj/projectile/tentacle/proc/reset_throw(mob/living/carbon/human/user) + if(user.throw_mode) + user.throw_mode_off(THROW_MODE_TOGGLE) //Don't annoy the changeling if he doesn't catch the item -/obj/projectile/tentacle/proc/tentacle_grab(mob/living/carbon/human/H, mob/living/carbon/C) - if(H.Adjacent(C)) - if(H.get_active_held_item() && !H.get_inactive_held_item()) - H.swap_hand() - if(H.get_active_held_item()) +/obj/projectile/tentacle/proc/tentacle_grab(mob/living/carbon/human/user, mob/living/carbon/victim) + if(!user.Adjacent(victim)) + return + + if(user.get_active_held_item() && !user.get_inactive_held_item()) + user.swap_hand() + + if(user.get_active_held_item()) + return + + victim.grabbedby(user) + victim.grippedby(user, instant = TRUE) //instant aggro grab + + for(var/obj/item/weapon in user.held_items) + if(weapon.get_sharpness()) + victim.visible_message(span_danger("[user] impales [victim] with [user.p_their()] [weapon.name]!"), span_userdanger("[user] impales you with [user.p_their()] [weapon.name]!")) + victim.apply_damage(weapon.force, BRUTE, BODY_ZONE_CHEST, attacking_item = weapon) + user.do_item_attack_animation(victim, used_item = weapon, animation_type = ATTACK_ANIMATION_PIERCE) + user.add_mob_blood(victim) + playsound(get_turf(user),weapon.hitsound,75,TRUE) return - C.grabbedby(H) - C.grippedby(H, instant = TRUE) //instant aggro grab - for(var/obj/item/I in H.held_items) - if(I.get_sharpness()) - C.visible_message(span_danger("[H] impales [C] with [H.p_their()] [I.name]!"), span_userdanger("[H] impales you with [H.p_their()] [I.name]!")) - C.apply_damage(I.force, BRUTE, BODY_ZONE_CHEST, attacking_item = I) - H.do_item_attack_animation(C, used_item = I) - H.add_mob_blood(C) - playsound(get_turf(H),I.hitsound,75,TRUE) - return /obj/projectile/tentacle/on_hit(atom/movable/target, blocked = 0, pierce_hit) if(!isliving(firer) || !ismovable(target)) diff --git a/code/modules/antagonists/cult/cult_items.dm b/code/modules/antagonists/cult/cult_items.dm index c332b2266ce..6d7bee5d583 100644 --- a/code/modules/antagonists/cult/cult_items.dm +++ b/code/modules/antagonists/cult/cult_items.dm @@ -14,6 +14,7 @@ icon_state = "render" inhand_icon_state = "cultdagger" worn_icon_state = "render" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' inhand_x_dimension = 32 @@ -61,6 +62,7 @@ Striking a noncultist, however, will tear their flesh."} icon_state = "cultblade" inhand_icon_state = "cultblade" worn_icon_state = "cultblade" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/64x64_lefthand.dmi' righthand_file = 'icons/mob/inhands/64x64_righthand.dmi' inhand_x_dimension = 64 @@ -75,10 +77,12 @@ Striking a noncultist, however, will tear their flesh."} bare_wound_bonus = 20 hitsound = 'sound/items/weapons/bladeslice.ogg' block_sound = 'sound/items/weapons/parry.ogg' - attack_verb_continuous = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "rends") - attack_verb_simple = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "rend") + attack_verb_continuous = list("attacks", "slashes", "slices", "tears", "lacerates", "rips", "dices", "rends") + attack_verb_simple = list("attack", "slash", "slice", "tear", "lacerate", "rip", "dice", "rend") /// If TRUE, it can be used at will by anyone, non-cultists included var/free_use = FALSE + var/list/alt_continuous = list("stabs", "pierces", "impales") + var/list/alt_simple = list("stab", "pierce", "impale") /obj/item/melee/cultblade/Initialize(mapload) . = ..() @@ -86,6 +90,9 @@ Striking a noncultist, however, will tear their flesh."} speed = 4 SECONDS, \ effectiveness = 100, \ ) + alt_continuous = string_list(alt_continuous) + alt_simple = string_list(alt_simple) + AddComponent(/datum/component/alternative_sharpness, SHARP_POINTY, alt_continuous, alt_simple, -5) ADD_TRAIT(src, TRAIT_CONTRABAND, INNATE_TRAIT) /obj/item/melee/cultblade/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK, damage_type = BRUTE) @@ -1131,6 +1138,7 @@ Striking a noncultist, however, will tear their flesh."} icon_state = "occultpoleaxe0" base_icon_state = "occultpoleaxe" inhand_icon_state = "occultpoleaxe0" + icon_angle = -45 w_class = WEIGHT_CLASS_HUGE force = 17 throwforce = 40 diff --git a/code/modules/antagonists/cult/cult_structure_archives.dm b/code/modules/antagonists/cult/cult_structure_archives.dm index d4867659651..050fe7361a5 100644 --- a/code/modules/antagonists/cult/cult_structure_archives.dm +++ b/code/modules/antagonists/cult/cult_structure_archives.dm @@ -49,8 +49,9 @@ /obj/structure/destructible/cult/item_dispenser/archives/succcess_message(mob/living/user, obj/item/spawned_item) to_chat(user, span_cult_italic("You summon [spawned_item] from [src]!")) -// Preset for the library that doesn't spawn runed metal on destruction. +// Preset for the library that doesn't spawn runed metal on destruction, or glow. /obj/structure/destructible/cult/item_dispenser/archives/library + icon_state = "tomealtar_off" debris = list() #undef CULT_BLINDFOLD diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm index af7254119dd..f4b424e4f20 100644 --- a/code/modules/antagonists/cult/runes.dm +++ b/code/modules/antagonists/cult/runes.dm @@ -82,6 +82,7 @@ Runes can either be invoked by one's self or with many different cultists. Each var/image/I = image(icon = 'icons/effects/blood.dmi', icon_state = null, loc = src) I.override = TRUE add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/silicons, "cult_runes", I) + ADD_TRAIT(src, TRAIT_MOPABLE, INNATE_TRAIT) /obj/effect/rune/examine(mob/user) . = ..() diff --git a/code/modules/antagonists/heretic/items/heretic_blades.dm b/code/modules/antagonists/heretic/items/heretic_blades.dm index 7b608223a98..1cee767dc96 100644 --- a/code/modules/antagonists/heretic/items/heretic_blades.dm +++ b/code/modules/antagonists/heretic/items/heretic_blades.dm @@ -5,6 +5,7 @@ icon = 'icons/obj/weapons/khopesh.dmi' icon_state = "eldritch_blade" inhand_icon_state = "eldritch_blade" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/64x64_lefthand.dmi' righthand_file = 'icons/mob/inhands/64x64_righthand.dmi' inhand_x_dimension = 64 @@ -21,8 +22,8 @@ demolition_mod = 0.8 hitsound = 'sound/items/weapons/bladeslice.ogg' armour_penetration = 35 - attack_verb_continuous = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "rends") - attack_verb_simple = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "rend") + attack_verb_continuous = list("attacks", "slashes", "slices", "tears", "lacerates", "rips", "dices", "rends") + attack_verb_simple = list("attack", "slash", "slice", "tear", "lacerate", "rip", "dice", "rend") var/after_use_message = "" /obj/item/melee/sickly_blade/examine(mob/user) diff --git a/code/modules/antagonists/heretic/magic/cosmic_runes.dm b/code/modules/antagonists/heretic/magic/cosmic_runes.dm index be8f103678e..7eee200dd4a 100644 --- a/code/modules/antagonists/heretic/magic/cosmic_runes.dm +++ b/code/modules/antagonists/heretic/magic/cosmic_runes.dm @@ -69,6 +69,7 @@ var/image/silicon_image = image(icon = 'icons/obj/service/hand_of_god_structures.dmi', icon_state = null, loc = src) silicon_image.override = TRUE add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/silicons, "cosmic", silicon_image) + ADD_TRAIT(src, TRAIT_MOPABLE, INNATE_TRAIT) /obj/effect/cosmic_rune/attack_paw(mob/living/user, list/modifiers) return attack_hand(user, modifiers) diff --git a/code/modules/antagonists/heretic/rust_effect.dm b/code/modules/antagonists/heretic/rust_effect.dm index 9af6c4f6d89..294fe42cff1 100644 --- a/code/modules/antagonists/heretic/rust_effect.dm +++ b/code/modules/antagonists/heretic/rust_effect.dm @@ -13,3 +13,4 @@ pixel_x = rand(-6, 6) icon_state = "small_rune_[rand(1, 12)]" update_appearance() + ADD_TRAIT(src, TRAIT_MOPABLE, INNATE_TRAIT) diff --git a/code/modules/antagonists/heretic/structures/carving_knife.dm b/code/modules/antagonists/heretic/structures/carving_knife.dm index f3d37b87682..eb8a3a4769b 100644 --- a/code/modules/antagonists/heretic/structures/carving_knife.dm +++ b/code/modules/antagonists/heretic/structures/carving_knife.dm @@ -5,6 +5,7 @@ but only few can evoke the dangers that lurk beneath reality." icon = 'icons/obj/antags/eldritch.dmi' icon_state = "rune_carver" + icon_angle = -45 obj_flags = CONDUCTS_ELECTRICITY sharpness = SHARP_EDGED w_class = WEIGHT_CLASS_SMALL @@ -12,8 +13,8 @@ force = 10 throwforce = 20 hitsound = 'sound/items/weapons/bladeslice.ogg' - attack_verb_continuous = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "rends") - attack_verb_simple = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "rend") + attack_verb_continuous = list("attacks", "slashes", "slices", "tears", "lacerates", "rips", "dices", "rends") + attack_verb_simple = list("attack", "slash", "slice", "tear", "lacerate", "rip", "dice", "rend") actions_types = list(/datum/action/item_action/rune_shatter) embed_type = /datum/embed_data/rune_carver @@ -25,6 +26,14 @@ var/list/datum/weakref/current_runes = list() /// Turfs that you cannot draw carvings on var/static/list/blacklisted_turfs = typecacheof(list(/turf/open/space, /turf/open/openspace, /turf/open/lava)) + var/list/alt_continuous = list("stabs", "pierces", "impales") + var/list/alt_simple = list("stab", "pierce", "impale") + +/obj/item/melee/rune_carver/Initialize(mapload) + . = ..() + alt_continuous = string_list(alt_continuous) + alt_simple = string_list(alt_simple) + AddComponent(/datum/component/alternative_sharpness, SHARP_POINTY, alt_continuous, alt_simple) /datum/embed_data/rune_carver ignore_throwspeed_threshold = TRUE diff --git a/code/modules/antagonists/heretic/transmutation_rune.dm b/code/modules/antagonists/heretic/transmutation_rune.dm index a2bf4af77f4..ee25b0a18fd 100644 --- a/code/modules/antagonists/heretic/transmutation_rune.dm +++ b/code/modules/antagonists/heretic/transmutation_rune.dm @@ -17,6 +17,7 @@ var/image/silicon_image = image(icon = 'icons/effects/eldritch.dmi', icon_state = null, loc = src) silicon_image.override = TRUE add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/silicons, "heretic_rune", silicon_image) + ADD_TRAIT(src, TRAIT_MOPABLE, INNATE_TRAIT) /obj/effect/heretic_rune/examine(mob/user) . = ..() diff --git a/code/modules/antagonists/nightmare/nightmare_equipment.dm b/code/modules/antagonists/nightmare/nightmare_equipment.dm index 52a687f9ac7..1d356d3dd9d 100644 --- a/code/modules/antagonists/nightmare/nightmare_equipment.dm +++ b/code/modules/antagonists/nightmare/nightmare_equipment.dm @@ -6,6 +6,7 @@ icon = 'icons/obj/weapons/changeling_items.dmi' icon_state = "arm_blade" inhand_icon_state = "arm_blade" + icon_angle = 180 force = 25 armour_penetration = 35 lefthand_file = 'icons/mob/inhands/antag/changeling_lefthand.dmi' diff --git a/code/modules/antagonists/ninja/energy_katana.dm b/code/modules/antagonists/ninja/energy_katana.dm index efd99355091..c26cb44d39c 100644 --- a/code/modules/antagonists/ninja/energy_katana.dm +++ b/code/modules/antagonists/ninja/energy_katana.dm @@ -17,6 +17,7 @@ icon_state = "energy_katana" inhand_icon_state = "energy_katana" worn_icon_state = "energy_katana" + icon_angle = 35 lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' force = 30 @@ -28,8 +29,8 @@ pickup_sound = 'sound/items/unsheath.ogg' drop_sound = 'sound/items/sheath.ogg' block_sound = 'sound/items/weapons/block_blade.ogg' - attack_verb_continuous = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts") - attack_verb_simple = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut") + attack_verb_continuous = list("attacks", "slashes", "slices", "tears", "lacerates", "rips", "dices", "cuts") + attack_verb_simple = list("attack", "slash", "slice", "tear", "lacerate", "rip", "dice", "cut") slot_flags = ITEM_SLOT_BACK|ITEM_SLOT_BELT sharpness = SHARP_EDGED max_integrity = 200 diff --git a/code/modules/antagonists/voidwalker/voidwalker_void_eater.dm b/code/modules/antagonists/voidwalker/voidwalker_void_eater.dm index f88c09188cf..5367a5cd89c 100644 --- a/code/modules/antagonists/voidwalker/voidwalker_void_eater.dm +++ b/code/modules/antagonists/voidwalker/voidwalker_void_eater.dm @@ -7,6 +7,7 @@ icon = 'icons/obj/weapons/voidwalker_items.dmi' icon_state = "tentacle" inhand_icon_state = "tentacle" + icon_angle = 180 force = 25 armour_penetration = 35 lefthand_file = 'icons/mob/inhands/antag/voidwalker_lefthand.dmi' diff --git a/code/modules/antagonists/wizard/equipment/artefact.dm b/code/modules/antagonists/wizard/equipment/artefact.dm index 465765c75a3..9b0b16ef9f6 100644 --- a/code/modules/antagonists/wizard/equipment/artefact.dm +++ b/code/modules/antagonists/wizard/equipment/artefact.dm @@ -10,6 +10,7 @@ icon_state = "bone_blade" inhand_icon_state = "bone_blade" worn_icon_state = "bone_blade" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/64x64_lefthand.dmi' righthand_file = 'icons/mob/inhands/64x64_righthand.dmi' inhand_x_dimension = 64 @@ -401,6 +402,7 @@ desc = "This scepter allows you to conjure, force push and detonate Runic Vendors. It can hold up to 3 charges that can be recovered with a simple magical channeling. A modern spin on the old Geomancy spells." icon_state = "vendor_staff" inhand_icon_state = "vendor_staff" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/staves_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi' icon = 'icons/obj/weapons/guns/magic.dmi' diff --git a/code/modules/antagonists/wizard/grand_ritual/grand_rune.dm b/code/modules/antagonists/wizard/grand_ritual/grand_rune.dm index dfda45ec488..33ae8f2c871 100644 --- a/code/modules/antagonists/wizard/grand_ritual/grand_rune.dm +++ b/code/modules/antagonists/wizard/grand_ritual/grand_rune.dm @@ -79,6 +79,7 @@ silicon_image.override = TRUE add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/silicons, "wizard_rune", silicon_image) announce_rune() + ADD_TRAIT(src, TRAIT_MOPABLE, INNATE_TRAIT) /// I cast Summon Security /obj/effect/grand_rune/proc/announce_rune() diff --git a/code/modules/art/statues.dm b/code/modules/art/statues.dm index eeb0cfa9cb4..a6a15c97732 100644 --- a/code/modules/art/statues.dm +++ b/code/modules/art/statues.dm @@ -265,6 +265,7 @@ icon = 'icons/obj/art/statue.dmi' icon_state = "chisel" inhand_icon_state = "screwdriver_nuke" + icon_angle = -90 lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' obj_flags = CONDUCTS_ELECTRICITY diff --git a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm index 97b9741701f..65a587578e5 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm @@ -101,6 +101,8 @@ var/datum/gas_machine_connector/internal_connector /// Check if the machine has been turned on var/on = FALSE + /// The sound loop that can be heard when the generator is processing. + var/datum/looping_sound/cryo_cell/soundloop /datum/armor/unary_cryo_cell energy = 100 @@ -119,6 +121,7 @@ occupant_vis = new(mapload, src) vis_contents += occupant_vis internal_connector = new(loc, src, dir, CELL_VOLUME * 0.5) + soundloop = new(src) register_context() @@ -130,6 +133,7 @@ QDEL_NULL(radio) QDEL_NULL(beaker) QDEL_NULL(internal_connector) + QDEL_NULL(soundloop) return ..() @@ -378,10 +382,14 @@ /obj/machinery/cryo_cell/begin_processing() . = ..() SSair.start_processing_machine(src) + if(soundloop) + soundloop.start() /obj/machinery/cryo_cell/end_processing() . = ..() SSair.stop_processing_machine(src) + if(soundloop) + soundloop.stop() /obj/machinery/cryo_cell/on_set_is_operational(old_value) //Turned off diff --git a/code/modules/atmospherics/machinery/components/unary_devices/machine_connector.dm b/code/modules/atmospherics/machinery/components/unary_devices/machine_connector.dm index 157cbae9af0..e852fccdc31 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/machine_connector.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/machine_connector.dm @@ -57,8 +57,12 @@ /** * Called when the machine has been moved, reconnect to the pipe network */ -/datum/gas_machine_connector/proc/moved_connected_machine() +/datum/gas_machine_connector/proc/moved_connected_machine(obj/machinery/source, atom/old_loc, movement_dir, forced, list/old_locs, momentum_change = TRUE) SIGNAL_HANDLER + if(forced) // Called from parent doing abstract_move() + gas_connector.abstract_move(get_turf(connected_machine)) + return // No side-effects means no disconnections + gas_connector.forceMove(get_turf(connected_machine)) reconnect_connector() diff --git a/code/modules/cargo/goodies.dm b/code/modules/cargo/goodies.dm index 0b6451e5698..5abf8f2dd27 100644 --- a/code/modules/cargo/goodies.dm +++ b/code/modules/cargo/goodies.dm @@ -32,6 +32,27 @@ access_view = ACCESS_WEAPONS contains = list(/obj/item/ammo_box/c38/match/bouncy) +/datum/supply_pack/goody/dumdum38br + name = ".38 DumDum Magazine Single-Pack" + desc = "Contains one magazine of .38 DumDum ammunition, good for embedding in soft targets." + cost = PAYCHECK_CREW * 2 + access_view = ACCESS_WEAPONS + contains = list(/obj/item/ammo_box/magazine/m38/dumdum) + +/datum/supply_pack/goody/match38br + name = ".38 Match Grade Magazine Single-Pack" + desc = "Contains one magazine of match grade .38 ammunition, perfect for showing off trickshots." + cost = PAYCHECK_CREW * 2 + access_view = ACCESS_WEAPONS + contains = list(/obj/item/ammo_box/magazine/m38/match) + +/datum/supply_pack/goody/rubber + name = ".38 Rubber Magazine Single-Pack" + desc = "Contains one magazine of bouncy rubber .38 ammunition, for when you want to bounce your shots off anything and everything." + cost = PAYCHECK_CREW * 1.5 + access_view = ACCESS_WEAPONS + contains = list(/obj/item/ammo_box/magazine/m38/match/bouncy) + /datum/supply_pack/goody/mars_single name = "Colt Detective Special Single-Pack" desc = "The HoS took your gun and your badge? No problem! Just pay the absurd taxation fee and you too can be reunited with the lethal power of a .38!" diff --git a/code/modules/cargo/packs/general.dm b/code/modules/cargo/packs/general.dm index e294d1bd4a1..5f3a4645933 100644 --- a/code/modules/cargo/packs/general.dm +++ b/code/modules/cargo/packs/general.dm @@ -137,9 +137,9 @@ /datum/supply_pack/misc/funeral - name = "Funeral Supply crate" + name = "Funeral Supplies Crate" desc = "At the end of the day, someone's gonna want someone dead. Give them a proper send-off with these \ - funeral supplies! Contains a coffin with burial garmets and flowers." + funeral supplies! Contains a coffin with burial garments and flowers." cost = CARGO_CRATE_VALUE * 1.6 access_view = ACCESS_CHAPEL_OFFICE contains = list(/obj/item/clothing/under/misc/burial, @@ -165,7 +165,7 @@ /datum/supply_pack/misc/religious_supplies name = "Religious Supplies Crate" desc = "Keep your local chaplain happy and well-supplied, lest they call down judgement upon your \ - cargo bay. Contains two bottles of holywater, bibles, chaplain robes, and burial garmets." + cargo bay. Contains two bottles of holy water, bibles, chaplain robes, and burial garments." cost = CARGO_CRATE_VALUE * 6 // it costs so much because the Space Church needs funding to build a cathedral access_view = ACCESS_CHAPEL_OFFICE contains = list(/obj/item/reagent_containers/cup/glass/bottle/holywater = 2, diff --git a/code/modules/cargo/packs/security.dm b/code/modules/cargo/packs/security.dm index 1823ef5174f..b233ecd78dd 100644 --- a/code/modules/cargo/packs/security.dm +++ b/code/modules/cargo/packs/security.dm @@ -248,6 +248,30 @@ crate_name = "disabler smg crate" crate_type = /obj/structure/closet/crate/secure/plasma +/datum/supply_pack/security/armory/battle_rifle + name = "NT BR-38 Crate" + desc = "An experimental energy-based ballistc battle rifle. Only available to \ + Nanotrasen stations for security purposes. DO NOT RESELL TO OUTSIDE COMPANIES. \ + Contains three NT BR-38 rifles and three magazines containing .38 Standard." + cost = CARGO_CRATE_VALUE * 100 + contains = list( + /obj/item/gun/ballistic/automatic/battle_rifle = 2, + /obj/item/ammo_box/magazine/m38 = 4, + ) + crate_name = "battle rifle crate" + +/datum/supply_pack/security/armory/br_mag + name = "NT BR-38 Magazine Crate" + desc = "Six .38 magazines, able to fit into the NT BR-38. Contains \ + two standard magazines, two Hot Shot magazines and two Iceblox magazines." + cost = CARGO_CRATE_VALUE * 7 + contains = list( + /obj/item/ammo_box/magazine/m38 = 2, + /obj/item/ammo_box/magazine/m38/hotshot = 2, + /obj/item/ammo_box/magazine/m38/iceblox =2, + ) + crate_name = ".38 magazine crate" + /datum/supply_pack/security/armory/exileimp name = "Exile Implants Crate" desc = "Contains five Exile implants." diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm index 05a0451be9e..560a61c9683 100644 --- a/code/modules/clothing/suits/armor.dm +++ b/code/modules/clothing/suits/armor.dm @@ -354,7 +354,7 @@ /obj/item/clothing/suit/armor/balloon_vest/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK, damage_type = BRUTE) if(isitem(hitby)) var/obj/item/item_hit = hitby - if(item_hit.sharpness) + if(item_hit.get_sharpness()) pop() if(istype(hitby, /obj/projectile/bullet)) diff --git a/code/modules/fishing/fish/_fish.dm b/code/modules/fishing/fish/_fish.dm index 0c09afb90cd..8f838ea339b 100644 --- a/code/modules/fishing/fish/_fish.dm +++ b/code/modules/fishing/fish/_fish.dm @@ -10,6 +10,7 @@ icon = 'icons/obj/aquarium/fish.dmi' lefthand_file = 'icons/mob/inhands/fish_lefthand.dmi' righthand_file = 'icons/mob/inhands/fish_righthand.dmi' + icon_angle = 180 force = 6 throwforce = 6 throw_range = 8 diff --git a/code/modules/fishing/fishing_rod.dm b/code/modules/fishing/fishing_rod.dm index a4b1e5924f8..5fcfdd07ff3 100644 --- a/code/modules/fishing/fishing_rod.dm +++ b/code/modules/fishing/fishing_rod.dm @@ -5,6 +5,7 @@ desc = "You can fish with this." icon = 'icons/obj/fishing.dmi' icon_state = "fishing_rod" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/equipment/fishing_rod_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/fishing_rod_righthand.dmi' inhand_icon_state = "rod" @@ -140,7 +141,7 @@ var/list/block = list() var/get_percent = HAS_MIND_TRAIT(user, TRAIT_EXAMINE_DEEPER_FISH) block += span_info("You think you can cast it up to [get_cast_range()] tiles away.") - block += get_stat_info(get_percent, difficulty_modifier, "Fishing will be", "easier", "harder", "with this fishing rod") + block += get_stat_info(get_percent, difficulty_modifier * 0.01, "Fishing will be", "easier", "harder", "with this fishing rod", offset = 0) block += get_stat_info(get_percent, experience_multiplier, "You will gain experience", "faster", "slower") block += get_stat_info(get_percent, completion_speed_mult, "You should complete the minigame", "faster", "slower") block += get_stat_info(get_percent, bait_speed_mult, "Reeling is", "faster", "slower") @@ -148,6 +149,7 @@ block += get_stat_info(get_percent, bounciness_mult, "This fishing rod is ", "bouncier", "less bouncy", "than a normal one", less_is_better = TRUE) block += get_stat_info(get_percent, gravity_mult, "The lure will sink", "faster", "slower", span_info = TRUE) + list_clear_nulls(block) . += examine_block(block.Join("\n")) if(get_percent && (material_flags & MATERIAL_EFFECTS) && length(custom_materials)) @@ -172,15 +174,16 @@ . += examine_block(block.Join("\n")) ///Used in examine_more to reduce all the copypasta when getting more information about the various stats of the fishing rod. -/obj/item/fishing_rod/proc/get_stat_info(get_percent, value, prefix, easier, harder, suffix = "with this fishing rod", span_info = FALSE, less_is_better = FALSE) +/obj/item/fishing_rod/proc/get_stat_info(get_percent, value, prefix, easier, harder, suffix = "with this fishing rod", span_info = FALSE, less_is_better = FALSE, offset = 1) if(value == 1) return - var/percent = get_percent ? "[abs(value)]% " : "" - var/harder_easier = value > 1 ? easier : harder + value -= offset + var/percent = get_percent ? "[abs(value * 100)]% " : "" + var/harder_easier = value > 0 ? easier : harder . = "[prefix] [percent][harder_easier] [suffix]." if(span_info) return span_info(.) - if(less_is_better ? value < 1 : value > 1) + if(less_is_better ? value < 0 : value > 0) return span_nicegreen(.) return span_danger(.) diff --git a/code/modules/hallucination/delusions.dm b/code/modules/hallucination/delusions.dm index 0760d05ff46..da12f117803 100644 --- a/code/modules/hallucination/delusions.dm +++ b/code/modules/hallucination/delusions.dm @@ -230,6 +230,22 @@ return ..() +/datum/hallucination/delusion/preset/seccies + dynamic_delusion = TRUE + random_hallucination_weight = 0 + delusion_name = "Security" + affects_others = TRUE + affects_us = FALSE + +/datum/hallucination/delusion/preset/seccies/make_delusion_image(mob/over_who) + delusion_appearance = get_dynamic_human_appearance( + outfit_path = /datum/outfit/job/security, + bloody_slots = prob(5) ? ALL : NONE, + r_hand = prob(15) ? /obj/item/melee/baton/security/loaded : null, + l_hand = prob(15) ? /obj/item/melee/baton/security/loaded : null, + ) + return ..() + /// Hallucination used by the nightmare vision goggles to turn everyone except you into mares /datum/hallucination/delusion/preset/mare delusion_icon_file = 'icons/obj/clothing/masks.dmi' diff --git a/code/modules/hallucination/stray_bullet.dm b/code/modules/hallucination/stray_bullet.dm index b670cd869e9..33462d2ab43 100644 --- a/code/modules/hallucination/stray_bullet.dm +++ b/code/modules/hallucination/stray_bullet.dm @@ -218,32 +218,6 @@ afflicted.adjustStaminaLoss(20) afflicted.adjust_eye_blur(4 SECONDS) -/obj/projectile/hallucination/taser - name = "electrode" - damage_type = BURN - hal_icon_state = "spark" - color = COLOR_YELLOW - hal_fire_sound = 'sound/items/weapons/taser.ogg' - hal_hitsound = 'sound/items/weapons/taserhit.ogg' - hal_hitsound_wall = null - hal_impact_effect = null - hal_impact_effect_wall = null - -/obj/projectile/hallucination/taser/apply_effect_to_hallucinator(mob/living/afflicted) - afflicted.Paralyze(10 SECONDS) - afflicted.adjust_stutter(40 SECONDS) - if(HAS_TRAIT(afflicted, TRAIT_HULK)) - afflicted.say(pick( - ";RAAAAAAAARGH!", - ";HNNNNNNNNNGGGGGGH!", - ";GWAAAAAAAARRRHHH!", - "NNNNNNNNGGGGGGGGHH!", - ";AAAAAAARRRGH!"), - forced = "hulk (hallucinating)", - ) - else if(!afflicted.check_stun_immunity(CANKNOCKDOWN)) - addtimer(CALLBACK(afflicted, TYPE_PROC_REF(/mob/living/carbon, do_jitter_animation), 20), 0.5 SECONDS) - /obj/projectile/hallucination/disabler name = "disabler beam" damage_type = STAMINA diff --git a/code/modules/hydroponics/hydroitemdefines.dm b/code/modules/hydroponics/hydroitemdefines.dm index 1b81661d245..0ffc3372042 100644 --- a/code/modules/hydroponics/hydroitemdefines.dm +++ b/code/modules/hydroponics/hydroitemdefines.dm @@ -424,6 +424,7 @@ icon = 'icons/obj/service/hydroponics/equipment.dmi' icon_state = "cultivator" inhand_icon_state = "cultivator" + icon_angle = -135 lefthand_file = 'icons/mob/inhands/equipment/hydroponics_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/hydroponics_righthand.dmi' obj_flags = CONDUCTS_ELECTRICITY @@ -442,6 +443,7 @@ /obj/item/cultivator/rake name = "rake" icon_state = "rake" + icon_angle = -45 w_class = WEIGHT_CLASS_NORMAL attack_verb_continuous = list("slashes", "slices", "bashes", "claws") attack_verb_simple = list("slash", "slice", "bash", "claw") @@ -473,6 +475,7 @@ name = "cyborg cultivator" icon = 'icons/obj/items_cyborg.dmi' icon_state = "sili_cultivator" + icon_angle = 0 /obj/item/hatchet name = "hatchet" @@ -480,6 +483,7 @@ icon = 'icons/obj/service/hydroponics/equipment.dmi' icon_state = "hatchet" inhand_icon_state = "hatchet" + icon_angle = -135 lefthand_file = 'icons/mob/inhands/equipment/hydroponics_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/hydroponics_righthand.dmi' obj_flags = CONDUCTS_ELECTRICITY @@ -523,6 +527,7 @@ name = "cyborg hatchet" icon = 'icons/obj/items_cyborg.dmi' icon_state = "sili_hatchet" + icon_angle = 0 /obj/item/scythe name = "scythe" @@ -530,6 +535,7 @@ icon = 'icons/obj/service/hydroponics/equipment.dmi' icon_state = "scythe0" inhand_icon_state = "scythe0" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/polearms_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/polearms_righthand.dmi' force = 15 @@ -594,6 +600,7 @@ icon_state = "secateurs" inhand_icon_state = null worn_icon_state = "cutters" + icon_angle = -135 lefthand_file = 'icons/mob/inhands/equipment/hydroponics_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/hydroponics_righthand.dmi' obj_flags = CONDUCTS_ELECTRICITY @@ -621,6 +628,7 @@ name = "cyborg secateurs" icon = 'icons/obj/items_cyborg.dmi' icon_state = "sili_secateur" + icon_angle = 0 /obj/item/geneshears name = "botanogenetic plant shears" diff --git a/code/modules/jobs/job_types/chaplain/chaplain_nullrod.dm b/code/modules/jobs/job_types/chaplain/chaplain_nullrod.dm index 7a26e2bd959..ac5d2a4b323 100644 --- a/code/modules/jobs/job_types/chaplain/chaplain_nullrod.dm +++ b/code/modules/jobs/job_types/chaplain/chaplain_nullrod.dm @@ -108,6 +108,7 @@ icon_state = "claymore_gold" inhand_icon_state = "claymore_gold" worn_icon_state = "claymore_gold" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' w_class = WEIGHT_CLASS_BULKY @@ -116,9 +117,17 @@ block_sound = 'sound/items/weapons/parry.ogg' sharpness = SHARP_EDGED hitsound = 'sound/items/weapons/bladeslice.ogg' - attack_verb_continuous = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts") - attack_verb_simple = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut") + attack_verb_continuous = list("attacks", "slashes", "slices", "tears", "lacerates", "rips", "dices", "cuts") + attack_verb_simple = list("attack", "slash", "slice", "tear", "lacerate", "rip", "dice", "cut") menu_description = "A sharp claymore which provides a low chance of blocking incoming melee attacks. Can be worn on the back or belt." + var/list/alt_continuous = list("stabs", "pierces", "impales") + var/list/alt_simple = list("stab", "pierce", "impale") + +/obj/item/nullrod/claymore/Initialize(mapload) + . = ..() + alt_continuous = string_list(alt_continuous) + alt_simple = string_list(alt_simple) + AddComponent(/datum/component/alternative_sharpness, SHARP_POINTY, alt_continuous, alt_simple, -3) /obj/item/nullrod/claymore/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK, damage_type = BRUTE) if(attack_type == PROJECTILE_ATTACK || attack_type == LEAP_ATTACK) @@ -132,6 +141,7 @@ icon_state = "cultblade" inhand_icon_state = "cultblade" worn_icon_state = "cultblade" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/64x64_lefthand.dmi' righthand_file = 'icons/mob/inhands/64x64_righthand.dmi' inhand_x_dimension = 64 @@ -192,6 +202,7 @@ icon_state = "e_sword_on_blue" inhand_icon_state = "e_sword_on_blue" worn_icon_state = "swordblue" + icon_angle = -45 slot_flags = ITEM_SLOT_BELT hitsound = 'sound/items/weapons/blade1.ogg' block_sound = 'sound/items/weapons/block_blade.ogg' @@ -221,6 +232,7 @@ icon_state = "hfrequency0" inhand_icon_state = "hfrequency1" worn_icon_state = "hfrequency0" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' w_class = WEIGHT_CLASS_BULKY @@ -231,6 +243,14 @@ attack_verb_simple = list("chop", "slice", "cut", "zandatsu") hitsound = 'sound/items/weapons/rapierhit.ogg' menu_description = "A sharp blade which partially penetrates armor. Very effective at butchering bodies. Can be worn on the back." + var/list/alt_continuous = list("stabs", "pierces", "impales") + var/list/alt_simple = list("stab", "pierce", "impale") + +/obj/item/nullrod/vibro/Initialize(mapload) + . = ..() + alt_continuous = string_list(alt_continuous) + alt_simple = string_list(alt_simple) + AddComponent(/datum/component/alternative_sharpness, SHARP_POINTY, alt_continuous, alt_simple, -3) /obj/item/nullrod/vibro/Initialize(mapload) . = ..() @@ -258,6 +278,7 @@ icon = 'icons/obj/weapons/sword.dmi' icon_state = "talking_sword" inhand_icon_state = "talking_sword" + icon_angle = 45 lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' worn_icon_state = "talking_sword" @@ -320,6 +341,7 @@ icon = 'icons/obj/weapons/staff.dmi' icon_state = "godstaff-red" inhand_icon_state = "godstaff-red" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/staves_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi' w_class = WEIGHT_CLASS_HUGE @@ -352,6 +374,7 @@ icon_state = "sord" inhand_icon_state = "sord" worn_icon_state = "sord" + icon_angle = -35 lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' force = 4.13 @@ -376,6 +399,7 @@ icon_state = "hammeron" inhand_icon_state = "hammeron" worn_icon_state = "hammeron" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/hammers_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/hammers_righthand.dmi' w_class = WEIGHT_CLASS_BULKY @@ -443,13 +467,14 @@ icon = 'icons/obj/weapons/khopesh.dmi' icon_state = "clownrender" inhand_icon_state = "cultdagger" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' worn_icon_state = "render" hitsound = 'sound/items/bikehorn.ogg' sharpness = SHARP_EDGED - attack_verb_continuous = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts") - attack_verb_simple = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut") + attack_verb_continuous = list("attacks", "slashes", "slices", "tears", "lacerates", "rips", "dices", "cuts") + attack_verb_simple = list("attack", "slash", "slice", "tear", "lacerate", "rip", "dice", "cut") menu_description = "A sharp dagger. Fits in pockets. Can be worn on the belt. Honk." // Pride-struck Hammer - Transfers reagents in your body to those you hit. @@ -463,6 +488,7 @@ icon_state = "pride" inhand_icon_state = "pride" worn_icon_state = "pride" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/hammers_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/hammers_righthand.dmi' force = 16 @@ -495,6 +521,7 @@ icon_state = "chain" inhand_icon_state = "chain" worn_icon_state = "whip" + icon_angle = -90 lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' slot_flags = ITEM_SLOT_BELT @@ -536,6 +563,7 @@ icon = 'icons/obj/weapons/changeling_items.dmi' icon_state = "arm_blade" inhand_icon_state = "arm_blade" + icon_angle = 180 lefthand_file = 'icons/mob/inhands/antag/changeling_lefthand.dmi' righthand_file = 'icons/mob/inhands/antag/changeling_righthand.dmi' slot_flags = null @@ -604,6 +632,7 @@ base_icon_state = "bostaff" inhand_icon_state = "bostaff0" worn_icon_state = "bostaff0" + icon_angle = -135 lefthand_file = 'icons/mob/inhands/weapons/staves_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi' menu_description = "A staff which provides a medium-low chance of blocking incoming melee attacks and deals less damage, unless dual-wielded. Can be worn on the back." @@ -632,20 +661,26 @@ icon = 'icons/obj/weapons/sword.dmi' icon_state = "crysknife" inhand_icon_state = "crysknife" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' w_class = WEIGHT_CLASS_HUGE sharpness = SHARP_EDGED slot_flags = null hitsound = 'sound/items/weapons/bladeslice.ogg' - attack_verb_continuous = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts") - attack_verb_simple = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut") + attack_verb_continuous = list("attacks", "slashes", "slices", "tears", "lacerates", "rips", "dices", "cuts") + attack_verb_simple = list("attack", "slash", "slice", "tear", "lacerate", "rip", "dice", "cut") item_flags = SLOWS_WHILE_IN_HAND menu_description = "A sharp knife. Randomly speeds or slows its user at a regular intervals. Capable of butchering bodies. Cannot be worn anywhere." + var/list/alt_continuous = list("stabs", "pierces", "impales") + var/list/alt_simple = list("stab", "pierce", "impale") /obj/item/nullrod/tribal_knife/Initialize(mapload) . = ..() START_PROCESSING(SSobj, src) + alt_continuous = string_list(alt_continuous) + alt_simple = string_list(alt_simple) + AddComponent(/datum/component/alternative_sharpness, SHARP_POINTY, alt_continuous, alt_simple, -3) AddComponent(/datum/component/butchering, \ speed = 5 SECONDS, \ effectiveness = 100, \ @@ -670,6 +705,7 @@ icon = 'icons/obj/weapons/spear.dmi' icon_state = "pitchfork0" inhand_icon_state = "pitchfork0" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/polearms_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/polearms_righthand.dmi' worn_icon_state = "pitchfork0" @@ -707,6 +743,7 @@ icon_state = "hypertool" inhand_icon_state = "hypertool" worn_icon_state = "hypertool" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' slot_flags = ITEM_SLOT_BELT @@ -725,6 +762,7 @@ icon = 'icons/obj/weapons/spear.dmi' icon_state = "ratvarian_spear" inhand_icon_state = "ratvarian_spear" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/antag/clockwork_lefthand.dmi' righthand_file = 'icons/mob/inhands/antag/clockwork_righthand.dmi' slot_flags = ITEM_SLOT_BELT @@ -744,6 +782,7 @@ icon = 'icons/obj/weapons/spear.dmi' icon_state = "ratvarian_spear" inhand_icon_state = "ratvarian_spear" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/antag/clockwork_lefthand.dmi' righthand_file = 'icons/mob/inhands/antag/clockwork_righthand.dmi' slot_flags = ITEM_SLOT_BELT @@ -767,6 +806,7 @@ icon_state = "nullsword" inhand_icon_state = "nullsword" worn_icon_state = "nullsword" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' w_class = WEIGHT_CLASS_BULKY @@ -775,14 +815,23 @@ bare_wound_bonus = 30 slot_flags = ITEM_SLOT_BELT block_sound = 'sound/items/weapons/parry.ogg' - sharpness = SHARP_POINTY + sharpness = SHARP_EDGED hitsound = 'sound/items/weapons/bladeslice.ogg' - attack_verb_continuous = list("attacks", "punctures", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts") - attack_verb_simple = list("attack", "puncture", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut") + attack_verb_continuous = list("attacks", "slashes", "slices", "tears", "lacerates", "rips", "dices", "cuts") + attack_verb_simple = list("attack", "slashes", "slice", "tear", "lacerate", "rip", "dice", "cut") menu_description = "A blade that deals variable, low amounts of damage, but does easily inflict wounds. \ The stronger your swinging arm is, the stronger the blade is, though only slightly. \ Against debilitated targets, can also deal additional sneak attack damage with a very high wound chance." + var/list/alt_continuous = list("stabs", "pierces", "impales", "punctures") + var/list/alt_simple = list("stab", "pierce", "impale", "puncture") + +/obj/item/nullrod/nullblade/Initialize(mapload) + . = ..() + alt_continuous = string_list(alt_continuous) + alt_simple = string_list(alt_simple) + AddComponent(/datum/component/alternative_sharpness, SHARP_POINTY, alt_continuous, alt_simple) + /obj/item/nullrod/nullblade/melee_attack_chain(mob/user, atom/target, params) //Track our actual force separately var/old_force = force diff --git a/code/modules/jobs/job_types/chaplain/chaplain_vorpal_scythe.dm b/code/modules/jobs/job_types/chaplain/chaplain_vorpal_scythe.dm index ce4a30efa92..df2e4f277b7 100644 --- a/code/modules/jobs/job_types/chaplain/chaplain_vorpal_scythe.dm +++ b/code/modules/jobs/job_types/chaplain/chaplain_vorpal_scythe.dm @@ -30,6 +30,7 @@ If the scythe isn't empowered when you sheath it, you take a heap of damage and icon_state = "vorpalscythe" inhand_icon_state = "vorpalscythe" worn_icon_state = null + icon_angle = -35 // Scythes look better when slightly angled lefthand_file = 'icons/mob/inhands/64x64_lefthand.dmi' righthand_file = 'icons/mob/inhands/64x64_righthand.dmi' inhand_x_dimension = 64 diff --git a/code/modules/library/book.dm b/code/modules/library/book.dm index 0a190b94662..3a95bf56aaa 100644 --- a/code/modules/library/book.dm +++ b/code/modules/library/book.dm @@ -196,7 +196,7 @@ if(!user.combat_mode) return FALSE //special check for wirecutter's because they don't have a sharp edge - if((carving_item.sharpness & SHARP_EDGED) || (carving_item.tool_behaviour == TOOL_WIRECUTTER)) + if((carving_item.get_sharpness() & SHARP_EDGED) || (carving_item.tool_behaviour == TOOL_WIRECUTTER)) balloon_alert(user, "carving out...") if(!do_after(user, 3 SECONDS, target = src)) balloon_alert(user, "interrupted!") diff --git a/code/modules/mapfluff/ruins/spaceruin_code/caravanambush.dm b/code/modules/mapfluff/ruins/spaceruin_code/caravanambush.dm index d6b2d9ffaa7..c531ae75e0d 100644 --- a/code/modules/mapfluff/ruins/spaceruin_code/caravanambush.dm +++ b/code/modules/mapfluff/ruins/spaceruin_code/caravanambush.dm @@ -4,6 +4,7 @@ icon_state = "wrench_caravan" desc = "A prototype of a new wrench design, allegedly the red color scheme makes it go faster." name = "experimental wrench" + icon_angle = -90 toolspeed = 0.3 /obj/item/screwdriver/caravan diff --git a/code/modules/mapfluff/ruins/spaceruin_code/meatderelict.dm b/code/modules/mapfluff/ruins/spaceruin_code/meatderelict.dm index 2b221664148..440f7ad0578 100644 --- a/code/modules/mapfluff/ruins/spaceruin_code/meatderelict.dm +++ b/code/modules/mapfluff/ruins/spaceruin_code/meatderelict.dm @@ -125,6 +125,7 @@ /obj/lightning_thrower/Destroy() . = ..() + clear_signals() signal_turfs = null STOP_PROCESSING(SSprocessing, src) @@ -132,6 +133,8 @@ var/list/dirs = throw_diagonals ? GLOB.diagonals : GLOB.cardinals throw_diagonals = !throw_diagonals playsound(src, 'sound/effects/magic/lightningbolt.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE, ignore_walls = FALSE) + if(length(signal_turfs)) + clear_signals() for(var/direction in dirs) var/victim_turf = get_step(src, direction) if(isclosedturf(victim_turf)) @@ -143,8 +146,7 @@ shock_victim(null, victim) addtimer(CALLBACK(src, PROC_REF(clear_signals)), shock_duration) -/obj/lightning_thrower/proc/clear_signals(datum/source) - SIGNAL_HANDLER +/obj/lightning_thrower/proc/clear_signals() for(var/turf in signal_turfs) UnregisterSignal(turf, COMSIG_ATOM_ENTERED) signal_turfs -= turf diff --git a/code/modules/mapfluff/ruins/spaceruin_code/meateor.dm b/code/modules/mapfluff/ruins/spaceruin_code/meateor.dm index 88b9e9f9503..d348ad6ac19 100644 --- a/code/modules/mapfluff/ruins/spaceruin_code/meateor.dm +++ b/code/modules/mapfluff/ruins/spaceruin_code/meateor.dm @@ -100,7 +100,7 @@ stored_organ = pick_weight(allowed_organs) /obj/structure/meateor_fluff/flesh_pod/attackby(obj/item/attacking_item, mob/user, params) - if (attacking_item.sharpness & SHARP_EDGED) + if (attacking_item.get_sharpness() & SHARP_EDGED) cut_open(user) return return ..() diff --git a/code/modules/mining/equipment/kinetic_crusher.dm b/code/modules/mining/equipment/kinetic_crusher.dm index c5bdfa9daa2..09982715f23 100644 --- a/code/modules/mining/equipment/kinetic_crusher.dm +++ b/code/modules/mining/equipment/kinetic_crusher.dm @@ -6,15 +6,16 @@ * a good tradeoff and a decent playstyle. */ /obj/item/kinetic_crusher + name = "proto-kinetic crusher" + desc = "An early design of the proto-kinetic accelerator, it is little more than a combination of various mining tools cobbled together, \ + forming a high-tech club. While it is an effective mining tool, it did little to aid any but the most skilled and/or \ + suicidal miners against local fauna." icon = 'icons/obj/mining.dmi' icon_state = "crusher" inhand_icon_state = "crusher0" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/hammers_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/hammers_righthand.dmi' - name = "proto-kinetic crusher" - desc = "An early design of the proto-kinetic accelerator, it is little more than a combination of various mining tools cobbled together, \ - forming a high-tech club. While it is an effective mining tool, it did little to aid any but the most skilled and/or \ - suicidal miners against local fauna." resistance_flags = FIRE_PROOF force = 0 //You can't hit stuff unless wielded w_class = WEIGHT_CLASS_BULKY @@ -51,6 +52,17 @@ ) //technically it's huge and bulky, but this provides an incentive to use it AddComponent(/datum/component/two_handed, force_unwielded=0, force_wielded=20) + register_context() + +/obj/item/kinetic_crusher/add_context(atom/source, list/context, obj/item/held_item, mob/user) + . = ..() + if(!held_item) + context[SCREENTIP_CONTEXT_RMB] = "Detach trophy" + return CONTEXTUAL_SCREENTIP_SET + + if(istype(held_item) && held_item.tool_behaviour == TOOL_CROWBAR) + context[SCREENTIP_CONTEXT_LMB] = "Detach all trophies" + return CONTEXTUAL_SCREENTIP_SET /obj/item/kinetic_crusher/Destroy() QDEL_LIST(trophies) @@ -85,6 +97,46 @@ crusher_trophy.remove_from(src, user) return ITEM_INTERACT_SUCCESS +// adapted from kinetic accelerator attack_hand_secodary +/obj/item/kinetic_crusher/attack_hand_secondary(mob/user, list/modifiers) + . = ..() + if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN) + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + + if(!LAZYLEN(trophies)) + return SECONDARY_ATTACK_CONTINUE_CHAIN + + var/list/display_names = list() + var/list/items = list() + for(var/trophies_length in 1 to length(trophies)) + var/obj/item/crusher_trophy/trophy = trophies[trophies_length] + display_names[trophy.name] = REF(trophy) + var/image/item_image = image(icon = trophy.icon, icon_state = trophy.icon_state) + if(length(trophy.overlays)) + item_image.copy_overlays(trophy) + items["[trophy.name]"] = item_image + + var/pick = show_radial_menu(user, src, items, custom_check = CALLBACK(src, PROC_REF(check_menu), user), radius = 36, require_near = TRUE, tooltips = TRUE) + if(!pick) + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + + var/trophy_reference = display_names[pick] + var/obj/item/crusher_trophy/trophy_to_remove = locate(trophy_reference) in trophies + if(!istype(trophy_to_remove)) + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + trophy_to_remove.remove_from(src, user) + if(!user.put_in_hands(trophy_to_remove)) + trophy_to_remove.forceMove(drop_location()) + + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + +/obj/item/kinetic_crusher/proc/check_menu(mob/living/carbon/human/user) + if(!istype(user)) + return FALSE + if(user.incapacitated) + return FALSE + return TRUE + /obj/item/kinetic_crusher/pre_attack(atom/A, mob/living/user, params) . = ..() if(.) diff --git a/code/modules/mining/equipment/mining_tools.dm b/code/modules/mining/equipment/mining_tools.dm index 06f8ec1828d..23d59fbfb71 100644 --- a/code/modules/mining/equipment/mining_tools.dm +++ b/code/modules/mining/equipment/mining_tools.dm @@ -4,6 +4,7 @@ icon = 'icons/obj/mining.dmi' icon_state = "pickaxe" inhand_icon_state = "pickaxe" + icon_angle = -45 obj_flags = CONDUCTS_ELECTRICITY slot_flags = ITEM_SLOT_BELT | ITEM_SLOT_BACK force = 15 @@ -65,6 +66,7 @@ name = "mining drill" icon_state = "handdrill" inhand_icon_state = "handdrill" + icon_angle = 0 slot_flags = ITEM_SLOT_BELT toolspeed = 0.6 //available from roundstart, faster than a pickaxe. usesound = 'sound/items/weapons/drill.ogg' @@ -121,6 +123,7 @@ icon = 'icons/obj/mining.dmi' icon_state = "shovel" inhand_icon_state = "shovel" + icon_angle = 135 lefthand_file = 'icons/mob/inhands/equipment/mining_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/mining_righthand.dmi' obj_flags = CONDUCTS_ELECTRICITY @@ -157,6 +160,7 @@ desc = "A small tool for digging and moving dirt." icon_state = "spade" inhand_icon_state = "spade" + icon_angle = -135 lefthand_file = 'icons/mob/inhands/equipment/hydroponics_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/hydroponics_righthand.dmi' force = 5 @@ -167,6 +171,7 @@ name = "cyborg spade" icon = 'icons/obj/items_cyborg.dmi' icon_state = "sili_shovel" + icon_angle = 0 toolspeed = 0.6 worn_icon_state = null @@ -212,6 +217,7 @@ icon = 'icons/obj/mining.dmi' icon_state = "trench_tool" inhand_icon_state = "trench_tool" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/equipment/mining_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/mining_righthand.dmi' obj_flags = CONDUCTS_ELECTRICITY @@ -301,6 +307,7 @@ desc = "A gigantic wrench made illegal because of its many incidents involving this tool." icon_state = "giant_wrench" icon = 'icons/obj/weapons/giant_wrench.dmi' + icon_angle = 0 inhand_icon_state = null lefthand_file = 'icons/mob/inhands/64x64_lefthand.dmi' righthand_file = 'icons/mob/inhands/64x64_righthand.dmi' diff --git a/code/modules/mining/lavaland/megafauna_loot.dm b/code/modules/mining/lavaland/megafauna_loot.dm index 3b33119aa24..cfe087a8ab3 100644 --- a/code/modules/mining/lavaland/megafauna_loot.dm +++ b/code/modules/mining/lavaland/megafauna_loot.dm @@ -46,6 +46,7 @@ desc = "The strange technology of this large club allows various nigh-magical teleportation feats. It used to beat you, but now you can set the beat." icon_state = "hierophant_club_ready_beacon" inhand_icon_state = "hierophant_club_ready_beacon" + icon_angle = -135 icon = 'icons/obj/mining_zones/artefacts.dmi' lefthand_file = 'icons/mob/inhands/64x64_lefthand.dmi' righthand_file = 'icons/mob/inhands/64x64_righthand.dmi' @@ -649,6 +650,7 @@ icon = 'icons/obj/weapons/sword.dmi' icon_state = "spectral" inhand_icon_state = "spectral" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' obj_flags = CONDUCTS_ELECTRICITY @@ -658,17 +660,22 @@ throwforce = 1 hitsound = 'sound/effects/ghost2.ogg' block_sound = 'sound/items/weapons/parry.ogg' - attack_verb_continuous = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "rends") - attack_verb_simple = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "rend") + attack_verb_continuous = list("attacks", "slashes", "slices", "tears", "lacerates", "rips", "dices", "rends") + attack_verb_simple = list("attack", "slash", "slice", "tear", "lacerate", "rip", "dice", "rend") resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF var/summon_cooldown = 0 var/list/mob/dead/observer/spirits + var/list/alt_continuous = list("stabs", "pierces", "impales") + var/list/alt_simple = list("stab", "pierce", "impale") /obj/item/melee/ghost_sword/Initialize(mapload) . = ..() spirits = list() START_PROCESSING(SSobj, src) SSpoints_of_interest.make_point_of_interest(src) + alt_continuous = string_list(alt_continuous) + alt_simple = string_list(alt_simple) + AddComponent(/datum/component/alternative_sharpness, SHARP_POINTY, alt_continuous, alt_simple) AddComponent(\ /datum/component/butchering, \ speed = 15 SECONDS, \ @@ -784,6 +791,7 @@ desc = "The ability to fill the emergency shuttle with lava. What more could you want out of life?" icon_state = "lavastaff" inhand_icon_state = "lavastaff" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/staves_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi' icon = 'icons/obj/weapons/guns/magic.dmi' @@ -985,6 +993,7 @@ desc = "An ancient staff retrieved from the remains of Legion. The wind stirs as you move it." icon_state = "staffofstorms" inhand_icon_state = "staffofstorms" + icon_angle = -45 icon = 'icons/obj/weapons/guns/magic.dmi' lefthand_file = 'icons/mob/inhands/weapons/staves_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi' diff --git a/code/modules/mining/lavaland/tendril_loot.dm b/code/modules/mining/lavaland/tendril_loot.dm index bb36b6d9102..31c4c1177ac 100644 --- a/code/modules/mining/lavaland/tendril_loot.dm +++ b/code/modules/mining/lavaland/tendril_loot.dm @@ -73,6 +73,7 @@ righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi' icon_state = "asclepius_dormant" inhand_icon_state = "asclepius_dormant" + icon_angle = -45 var/activated = FALSE /obj/item/rod_of_asclepius/Initialize(mapload) @@ -990,6 +991,7 @@ Even with the weapon destroyed, all the pieces containing the creature have coagulated back together to find a new host." icon = 'icons/obj/mining_zones/artefacts.dmi' icon_state = "cursed_katana" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' force = 15 @@ -998,8 +1000,8 @@ block_sound = 'sound/items/weapons/parry.ogg' sharpness = SHARP_EDGED w_class = WEIGHT_CLASS_HUGE - attack_verb_continuous = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts") - attack_verb_simple = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut") + attack_verb_continuous = list("attacks", "slashes", "slices", "tears", "lacerates", "rips", "dices", "cuts") + attack_verb_simple = list("attack", "slash", "slice", "tear", "lacerate", "rip", "dice", "cut") hitsound = 'sound/items/weapons/bladeslice.ogg' resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | FREEZE_PROOF var/shattered = FALSE @@ -1012,9 +1014,14 @@ ATTACK_CLOAK = list(COMBO_STEPS = list(LEFT_ATTACK, RIGHT_ATTACK, LEFT_ATTACK, RIGHT_ATTACK), COMBO_PROC = PROC_REF(cloak)), ATTACK_SHATTER = list(COMBO_STEPS = list(RIGHT_ATTACK, LEFT_ATTACK, RIGHT_ATTACK, LEFT_ATTACK), COMBO_PROC = PROC_REF(shatter)), ) + var/list/alt_continuous = list("stabs", "pierces", "impales") + var/list/alt_simple = list("stab", "pierce", "impale") /obj/item/cursed_katana/Initialize(mapload) . = ..() + alt_continuous = string_list(alt_continuous) + alt_simple = string_list(alt_simple) + AddComponent(/datum/component/alternative_sharpness, SHARP_POINTY, alt_continuous, alt_simple) AddComponent( \ /datum/component/combo_attacks, \ combos = combo_list, \ @@ -1078,6 +1085,7 @@ user.visible_message(span_warning("[user] does a wide slice!"), span_notice("You do a wide slice!")) playsound(src, 'sound/items/weapons/bladeslice.ogg', 50, TRUE) + user.do_item_attack_animation(target, used_item = src, animation_type = ATTACK_ANIMATION_SLASH) var/turf/user_turf = get_turf(user) var/dir_to_target = get_dir(user_turf, get_turf(target)) var/static/list/cursed_katana_slice_angles = list(0, -45, 45, -90, 90) //so that the animation animates towards the target clicked and not towards a side target @@ -1117,6 +1125,7 @@ user.visible_message(span_warning("[user] cuts [target]'s tendons!"), span_notice("You tendon cut [target]!")) to_chat(target, span_userdanger("Your tendons have been cut by [user]!")) + user.do_item_attack_animation(target, used_item = src, animation_type = ATTACK_ANIMATION_SLASH) target.apply_damage(damage = 15, sharpness = SHARP_EDGED, wound_bonus = 15) user.do_attack_animation(target, ATTACK_EFFECT_DISARM) playsound(src, 'sound/items/weapons/rapierhit.ogg', 50, TRUE) diff --git a/code/modules/mob/dead/observer/orbit.dm b/code/modules/mob/dead/observer/orbit.dm index d2823eae2b5..5e77627e00d 100644 --- a/code/modules/mob/dead/observer/orbit.dm +++ b/code/modules/mob/dead/observer/orbit.dm @@ -104,7 +104,7 @@ GLOBAL_DATUM_INIT(orbit_menu, /datum/orbit_menu, new) if(isliving(mob_poi)) serialized += get_living_data(mob_poi) - var/list/antag_data = get_antag_data(mob_poi.mind) + var/list/antag_data = get_antag_data(mob_poi.mind, user?.client?.holder) if(length(antag_data)) serialized += antag_data antagonists += list(serialized) @@ -151,11 +151,11 @@ GLOBAL_DATUM_INIT(orbit_menu, /datum/orbit_menu, new) /// Helper function to get threat type, group, overrides for job and icon -/datum/orbit_menu/proc/get_antag_data(datum/mind/poi_mind) as /list +/datum/orbit_menu/proc/get_antag_data(datum/mind/poi_mind, is_admin) as /list var/list/serialized = list() for(var/datum/antagonist/antag as anything in poi_mind.antag_datums) - if(!antag.show_to_ghosts) + if(!antag.show_to_ghosts && !is_admin) continue serialized["antag"] = antag.name diff --git a/code/modules/mob/living/basic/drone/drone_tools.dm b/code/modules/mob/living/basic/drone/drone_tools.dm index 8408738bf6a..dfb05a8d3a9 100644 --- a/code/modules/mob/living/basic/drone/drone_tools.dm +++ b/code/modules/mob/living/basic/drone/drone_tools.dm @@ -34,6 +34,7 @@ icon = 'icons/obj/items_cyborg.dmi' icon_state = "toolkit_engiborg_crowbar" inhand_icon_state = "crowbar" + icon_angle = 0 item_flags = NO_MAT_REDEMPTION /obj/item/screwdriver/drone @@ -61,6 +62,7 @@ icon = 'icons/obj/items_cyborg.dmi' icon_state = "toolkit_engiborg_wrench" inhand_icon_state = "wrench" + icon_angle = 0 item_flags = NO_MAT_REDEMPTION /obj/item/weldingtool/drone @@ -84,6 +86,7 @@ desc = "A multitool built into your chassis." icon = 'icons/obj/items_cyborg.dmi' icon_state = "toolkit_engiborg_multitool" + icon_angle = 0 item_flags = NO_MAT_REDEMPTION toolspeed = 0.5 diff --git a/code/modules/mob/living/basic/lavaland/brimdemon/brimdemon_loot.dm b/code/modules/mob/living/basic/lavaland/brimdemon/brimdemon_loot.dm index 014cfb626be..9b1916c9ac0 100644 --- a/code/modules/mob/living/basic/lavaland/brimdemon/brimdemon_loot.dm +++ b/code/modules/mob/living/basic/lavaland/brimdemon/brimdemon_loot.dm @@ -21,7 +21,7 @@ icon_state = "brimdust" icon = 'icons/obj/mining.dmi' plane = GAME_PLANE - layer = GAME_CLEAN_LAYER + layer = CLEANABLE_OBJECT_LAYER mergeable_decal = FALSE /obj/effect/decal/cleanable/brimdust/Initialize(mapload) diff --git a/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat.dm b/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat.dm index eae137787ed..07ad70a29e3 100644 --- a/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat.dm +++ b/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat.dm @@ -179,10 +179,12 @@ if(SEND_SIGNAL(target, COMSIG_RAT_INTERACT, src) & COMPONENT_RAT_INTERACTED) return FALSE - if(isnull(mind) || !combat_mode) + if(isnull(mind) || combat_mode) return TRUE - poison_target(target) + if(poison_target(target)) + return FALSE + return TRUE /// Checks if we are allowed to attack this mob. Will return TRUE if we are potentially allowed to attack, but if we end up in a case where we should NOT attack, return FALSE. @@ -204,10 +206,17 @@ return TRUE -/// Attempts to add rat spit to a target, effectively poisoning it to whoever eats it. Yuckers. +/** + * Attempts to add rat spit to a target, effectively poisoning it to whoever eats it. Yuckers. + * Returns TRUE if the target is valid for adding rat spit + * Returns FALSE if the target is invalid for adding rat spit + * Arguments + * + * * atom/lean_target - the target we try to add the spit to + */ /mob/living/basic/regal_rat/proc/poison_target(atom/target) if(isnull(target.reagents) || !target.is_injectable(src, allowmobs = TRUE)) - return + return FALSE visible_message( span_warning("[src] starts licking [target] passionately!"), @@ -216,10 +225,11 @@ ) if (!do_after(src, 2 SECONDS, target, interaction_key = REGALRAT_INTERACTION)) - return + return TRUE // don't return false here because they tried to lick and the do_after was interrupted, otherwise cancelling the do_after will make them hit the target. target.reagents.add_reagent(/datum/reagent/rat_spit, rand(1,3), no_react = TRUE) balloon_alert(src, "licked") + return TRUE /** * Conditionally "eat" cheese object and heal, if injured. diff --git a/code/modules/mob/living/brain/brain_item.dm b/code/modules/mob/living/brain/brain_item.dm index dedecacc6ab..b32517875e4 100644 --- a/code/modules/mob/living/brain/brain_item.dm +++ b/code/modules/mob/living/brain/brain_item.dm @@ -471,9 +471,9 @@ /obj/item/organ/brain/felinid //A bit smaller than average brain_size = 0.8 -/obj/item/organ/brain/lizard //A bit smaller than average +/obj/item/organ/brain/lizard name = "lizard brain" - desc = "This juicy piece of meat has a oversized brain stem and cerebellum, with not much of a limbic system to speak of at all. You would expect it's owner to be pretty cold blooded." + desc = "This juicy piece of meat has a oversized brain stem and cerebellum, with not much of a limbic system to speak of at all. You would expect its owner to be pretty cold blooded." organ_traits = list(TRAIT_TACKLING_TAILED_DEFENDER) /obj/item/organ/brain/abductor diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 6e0f6716778..66b4ad2cfd0 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -77,7 +77,7 @@ if(!hurt) return - if(victim.check_block(src, 0, "[name]", LEAP_ATTACK)) + if(. == SUCCESSFUL_BLOCK || victim.check_block(src, 0, "[name]", LEAP_ATTACK)) blocked = TRUE take_bodypart_damage(10 + 5 * extra_speed, check_armor = TRUE, wound_bonus = extra_speed * 5) @@ -120,7 +120,7 @@ return throw_mode = THROW_MODE_DISABLED if(hud_used) - hud_used.throw_icon.icon_state = "act_throw_off" + hud_used.throw_icon.icon_state = "act_throw" SEND_SIGNAL(src, COMSIG_LIVING_THROW_MODE_TOGGLE, throw_mode) diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index 2c5d2df0517..ee06686faaf 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -84,19 +84,28 @@ return TRUE return ..() -/mob/living/carbon/send_item_attack_message(obj/item/I, mob/living/user, hit_area, def_zone) - if(!I.force && !length(I.attack_verb_simple) && !length(I.attack_verb_continuous)) +/mob/living/carbon/send_item_attack_message(obj/item/weapon, mob/living/user, hit_area, def_zone) + if(!weapon.force && !length(weapon.attack_verb_simple) && !length(weapon.attack_verb_continuous)) return var/obj/item/bodypart/hit_bodypart = get_bodypart(def_zone) if(isnull(hit_bodypart)) // ?? return ..() - var/message_verb_continuous = length(I.attack_verb_continuous) ? "[pick(I.attack_verb_continuous)]" : "attacks" - var/message_verb_simple = length(I.attack_verb_simple) ? "[pick(I.attack_verb_simple)]" : "attack" + // Sanity in case one is null for some reason + var/picked_index = rand(max(length(weapon.attack_verb_simple), length(weapon.attack_verb_continuous))) + + var/message_verb_continuous = "attacks" + var/message_verb_simple = "attack" + var/message_hit_area = get_hit_area_message(hit_area) + // Sanity in case one is... longer than the other? + if (picked_index && length(weapon.attack_verb_continuous) >= picked_index) + message_verb_continuous = weapon.attack_verb_continuous[picked_index] + if (picked_index && length(weapon.attack_verb_simple) >= picked_index) + message_verb_simple = weapon.attack_verb_simple[picked_index] var/extra_wound_details = "" - if(I.damtype == BRUTE && hit_bodypart.can_dismember()) + if(weapon.damtype == BRUTE && hit_bodypart.can_dismember()) var/mangled_state = hit_bodypart.get_mangled_state() @@ -111,24 +120,21 @@ var/dismemberable = ((hit_bodypart.dismemberable_by_wound()) || hit_bodypart.dismemberable_by_total_damage()) if (dismemberable) extra_wound_details = ", threatening to sever it entirely" - else if((has_interior && (has_exterior && exterior_ready_to_dismember) && I.get_sharpness())) + else if((has_interior && (has_exterior && exterior_ready_to_dismember) && weapon.get_sharpness())) var/bone_text = hit_bodypart.get_internal_description() - extra_wound_details = ", [I.get_sharpness() == SHARP_EDGED ? "slicing" : "piercing"] through to the [bone_text]" - else if(has_exterior && ((has_interior && interior_ready_to_dismember) && I.get_sharpness())) + extra_wound_details = ", [weapon.get_sharpness() == SHARP_EDGED ? "slicing" : "piercing"] through to the [bone_text]" + else if(has_exterior && ((has_interior && interior_ready_to_dismember) && weapon.get_sharpness())) var/tissue_text = hit_bodypart.get_external_description() - extra_wound_details = ", [I.get_sharpness() == SHARP_EDGED ? "slicing" : "piercing"] at the remaining [tissue_text]" - - var/message_hit_area = "" - if(hit_area) - message_hit_area = " in the [hit_area]" - var/attack_message_spectator = "[src] [message_verb_continuous][message_hit_area] with [I][extra_wound_details]!" - var/attack_message_victim = "You're [message_verb_continuous][message_hit_area] with [I][extra_wound_details]!" - var/attack_message_attacker = "You [message_verb_simple] [src][message_hit_area] with [I][extra_wound_details]!" + extra_wound_details = ", [weapon.get_sharpness() == SHARP_EDGED ? "slicing" : "piercing"] at the remaining [tissue_text]" + + var/attack_message_spectator = "[src] [message_verb_continuous][message_hit_area] with [weapon][extra_wound_details]!" + var/attack_message_victim = "You're [message_verb_continuous][message_hit_area] with [weapon][extra_wound_details]!" + var/attack_message_attacker = "You [message_verb_simple] [src][message_hit_area] with [weapon][extra_wound_details]!" if(user in viewers(src, null)) - attack_message_spectator = "[user] [message_verb_continuous] [src][message_hit_area] with [I][extra_wound_details]!" - attack_message_victim = "[user] [message_verb_continuous] you[message_hit_area] with [I][extra_wound_details]!" + attack_message_spectator = "[user] [message_verb_continuous] [src][message_hit_area] with [weapon][extra_wound_details]!" + attack_message_victim = "[user] [message_verb_continuous] you[message_hit_area] with [weapon][extra_wound_details]!" if(user == src) - attack_message_victim = "You [message_verb_simple] yourself[message_hit_area] with [I][extra_wound_details]!" + attack_message_victim = "You [message_verb_simple] yourself[message_hit_area] with [weapon][extra_wound_details]!" visible_message(span_danger("[attack_message_spectator]"),\ span_userdanger("[attack_message_victim]"), null, COMBAT_MESSAGE_RANGE, user) if(user != src) diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm index c13ac14b100..56c687df7bb 100644 --- a/code/modules/mob/living/carbon/carbon_defines.dm +++ b/code/modules/mob/living/carbon/carbon_defines.dm @@ -11,6 +11,7 @@ usable_hands = 0 //Populated on init through list/bodyparts mobility_flags = MOBILITY_FLAGS_CARBON_DEFAULT blocks_emissive = EMISSIVE_BLOCK_NONE + mouse_drop_zone = TRUE // STOP_OVERLAY_UPDATE_BODY_PARTS is removed after we call update_body_parts() during init. living_flags = ALWAYS_DEATHGASP|STOP_OVERLAY_UPDATE_BODY_PARTS ///List of [/obj/item/organ]s in the mob. They don't go in the contents for some reason I don't want to know. diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 8cd4881999f..b66032462f2 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -24,7 +24,7 @@ . = ..() RegisterSignal(src, COMSIG_COMPONENT_CLEAN_FACE_ACT, PROC_REF(clean_face)) - AddComponent(/datum/component/personal_crafting) + AddComponent(/datum/component/personal_crafting, ui_human_crafting) AddElement(/datum/element/footstep, FOOTSTEP_MOB_HUMAN, 1, -6) AddComponent(/datum/component/bloodysoles/feet, FOOTPRINT_SPRITE_SHOES) AddElement(/datum/element/ridable, /datum/component/riding/creature/human) diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index e6c7f9edd9b..73f63b8bfe1 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -85,8 +85,8 @@ /mob/living/carbon/human/check_block(atom/hit_by, damage, attack_text = "the attack", attack_type = MELEE_ATTACK, armour_penetration = 0, damage_type = BRUTE) . = ..() - if(.) - return TRUE + if(. == SUCCESSFUL_BLOCK) + return SUCCESSFUL_BLOCK var/block_chance_modifier = round(damage / -3) for(var/obj/item/worn_thing in get_equipped_items(INCLUDE_HELD)) @@ -100,9 +100,9 @@ var/final_block_chance = worn_thing.block_chance - (clamp((armour_penetration - worn_thing.armour_penetration) / 2, 0, 100)) + block_chance_modifier if(worn_thing.hit_reaction(src, hit_by, attack_text, final_block_chance, damage, attack_type, damage_type)) - return TRUE + return SUCCESSFUL_BLOCK - return FALSE + return FAILED_BLOCK /mob/living/carbon/human/grippedby(mob/living/carbon/user, instant = FALSE) if(w_uniform) @@ -191,7 +191,7 @@ var/damage = HAS_TRAIT(user, TRAIT_PERFECT_ATTACKER) ? monkey_mouth.unarmed_damage_high : rand(monkey_mouth.unarmed_damage_low, monkey_mouth.unarmed_damage_high) if(!damage) return FALSE - if(check_block(user, damage, "the [user.name]")) + if(check_block(user, damage, "the [user.name]", attack_type = UNARMED_ATTACK)) return FALSE apply_damage(damage, BRUTE, affecting, run_armor_check(affecting, MELEE)) return TRUE @@ -248,9 +248,6 @@ return TRUE apply_damage(damage, BRUTE, affecting, armor_block) - - - /mob/living/carbon/human/attack_larva(mob/living/carbon/alien/larva/L, list/modifiers) . = ..() if(!.) @@ -258,7 +255,7 @@ var/damage = rand(L.melee_damage_lower, L.melee_damage_upper) if(!damage) return - if(check_block(L, damage, "the [L.name]")) + if(check_block(L, damage, "the [L.name]", attack_type = UNARMED_ATTACK)) return FALSE if(stat != DEAD) L.amount_grown = min(L.amount_grown + damage, L.max_grown) diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm index 81355918311..6b4af60788b 100644 --- a/code/modules/mob/living/emote.dm +++ b/code/modules/mob/living/emote.dm @@ -733,6 +733,9 @@ if(!emote_is_valid(user, our_message)) return FALSE + if(type_override) + emote_type = type_override + if(!params) var/user_emote_type = get_custom_emote_type_from_user() diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index c27980f68b1..bcdca5dbb59 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -128,6 +128,7 @@ bare_wound_bonus = proj.bare_wound_bonus, sharpness = proj.sharpness, attack_direction = get_dir(proj.starting, src), + attacking_item = proj, ) apply_effects( @@ -206,10 +207,11 @@ /mob/living/hitby(atom/movable/AM, skipcatch, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum) if(!isitem(AM)) // Filled with made up numbers for non-items. - if(check_block(AM, 30, "\the [AM.name]", THROWN_PROJECTILE_ATTACK, 0, BRUTE)) + if(check_block(AM, 30, "\the [AM.name]", THROWN_PROJECTILE_ATTACK, 0, BRUTE) & SUCCESSFUL_BLOCK) hitpush = FALSE skipcatch = TRUE blocked = TRUE + return SUCCESSFUL_BLOCK else playsound(loc, 'sound/items/weapons/genhit.ogg', 50, TRUE, -1) //Item sounds are handled in the item itself if(!isvendor(AM) && !iscarbon(AM)) //Vendors have special interactions, while carbon mobs already generate visible messages! @@ -234,7 +236,7 @@ hitpush = FALSE if(blocked) - return TRUE + return SUCCESSFUL_BLOCK var/mob/thrown_by = thrown_item.thrownby?.resolve() if(thrown_by) @@ -296,7 +298,7 @@ return FALSE if(SEND_SIGNAL(src, COMSIG_LIVING_GRAB, target) & (COMPONENT_CANCEL_ATTACK_CHAIN|COMPONENT_SKIP_ATTACK)) return FALSE - if(target.check_block(src, 0, "[src]'s grab")) + if(target.check_block(src, 0, "[src]'s grab", UNARMED_ATTACK)) return FALSE target.grabbedby(src) return TRUE @@ -403,7 +405,7 @@ return FALSE var/damage = rand(user.melee_damage_lower, user.melee_damage_upper) - if(check_block(user, damage, "[user]'s [user.attack_verb_simple]", MELEE_ATTACK/*or UNARMED_ATTACK?*/, user.armour_penetration, user.melee_damage_type)) + if(check_block(user, damage, "[user]'s [user.attack_verb_simple]", UNARMED_ATTACK, user.armour_penetration, user.melee_damage_type)) return FALSE if(user.attack_sound) @@ -518,7 +520,7 @@ /mob/living/attack_alien(mob/living/carbon/alien/adult/user, list/modifiers) SEND_SIGNAL(src, COMSIG_MOB_ATTACK_ALIEN, user, modifiers) if(LAZYACCESS(modifiers, RIGHT_CLICK)) - if(check_block(user, 0, "[user]'s tackle", MELEE_ATTACK, 0, BRUTE)) + if(check_block(user, 0, "[user]'s tackle", UNARMED_ATTACK, 0, BRUTE)) return FALSE user.do_attack_animation(src, ATTACK_EFFECT_DISARM) return TRUE @@ -527,7 +529,7 @@ if(HAS_TRAIT(user, TRAIT_PACIFISM)) to_chat(user, span_warning("You don't want to hurt anyone!")) return FALSE - if(check_block(user, user.melee_damage_upper, "[user]'s slash", MELEE_ATTACK, 0, BRUTE)) + if(check_block(user, user.melee_damage_upper, "[user]'s slash", UNARMED_ATTACK, 0, BRUTE)) return FALSE user.do_attack_animation(src) return TRUE @@ -811,6 +813,6 @@ /mob/living/proc/check_block(atom/hit_by, damage, attack_text = "the attack", attack_type = MELEE_ATTACK, armour_penetration = 0, damage_type = BRUTE) if(SEND_SIGNAL(src, COMSIG_LIVING_CHECK_BLOCK, hit_by, damage, attack_text, attack_type, armour_penetration, damage_type) & SUCCESSFUL_BLOCK) - return TRUE + return SUCCESSFUL_BLOCK - return FALSE + return FAILED_BLOCK diff --git a/code/modules/mob/living/silicon/robot/robot_defines.dm b/code/modules/mob/living/silicon/robot/robot_defines.dm index 83f14301519..daf66bd8257 100644 --- a/code/modules/mob/living/silicon/robot/robot_defines.dm +++ b/code/modules/mob/living/silicon/robot/robot_defines.dm @@ -16,6 +16,7 @@ has_limbs = TRUE hud_type = /datum/hud/robot unique_name = TRUE + mouse_drop_zone = TRUE ///Represents the cyborg's model (engineering, medical, etc.) var/obj/item/robot_model/model = null diff --git a/code/modules/mob/living/silicon/silicon_defense.dm b/code/modules/mob/living/silicon/silicon_defense.dm index 404b0324f71..7a78cb4be05 100644 --- a/code/modules/mob/living/silicon/silicon_defense.dm +++ b/code/modules/mob/living/silicon/silicon_defense.dm @@ -82,13 +82,13 @@ /mob/living/silicon/check_block(atom/hitby, damage, attack_text, attack_type, armour_penetration, damage_type, attack_flag) . = ..() - if(.) - return TRUE + if(. == SUCCESSFUL_BLOCK) + return SUCCESSFUL_BLOCK if(damage_type == BRUTE && attack_type == UNARMED_ATTACK && attack_flag == MELEE && damage <= 10) playsound(src, 'sound/effects/bang.ogg', 10, TRUE) visible_message(span_danger("[attack_text] doesn't leave a dent on [src]!"), vision_distance = COMBAT_MESSAGE_RANGE) - return TRUE - return FALSE + return SUCCESSFUL_BLOCK + return FAILED_BLOCK /mob/living/silicon/attack_drone(mob/living/basic/drone/user) if(user.combat_mode) diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index f19a3991ca3..743bdad8c45 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -281,6 +281,9 @@ if (SEND_SIGNAL(src, COMSIG_MOB_ATTEMPT_HALT_SPACEMOVE, movement_dir, continuous_move, backup) & COMPONENT_PREVENT_SPACEMOVE_HALT) return FALSE + if (drift_handler?.attempt_halt(movement_dir, continuous_move, backup)) + return FALSE + if(continuous_move || !istype(backup) || !movement_dir || backup.anchored) return TRUE @@ -300,8 +303,9 @@ /** * Finds a target near a mob that is viable for pushing off when moving. * Takes the intended movement direction as input, alongside if the context is checking if we're allowed to continue drifting + * If include_floors is TRUE, includes floors *with gravity* */ -/mob/get_spacemove_backup(moving_direction, continuous_move) +/mob/get_spacemove_backup(moving_direction, continuous_move, include_floors = FALSE) var/atom/secondary_backup var/list/priority_dirs = (moving_direction in GLOB.cardinals) ? GLOB.cardinals : GLOB.diagonals for(var/atom/pushover as anything in range(1, get_turf(src))) @@ -309,13 +313,15 @@ continue if(isarea(pushover)) continue + var/is_priority = pushover.loc == loc || (get_dir(src, pushover) in priority_dirs) if(isturf(pushover)) var/turf/turf = pushover if(isspaceturf(turf)) continue if(!turf.density && !mob_negates_gravity()) - continue - if (get_dir(src, pushover) in priority_dirs) + if (!include_floors || !turf.has_gravity()) + continue + if (is_priority) return pushover secondary_backup = pushover continue @@ -343,13 +349,13 @@ if(moving_direction == get_dir(src, pushover)) // Can't push "off" of something that you're walking into continue if(rebound.anchored) - if (get_dir(src, rebound) in priority_dirs) + if (is_priority) return rebound secondary_backup = rebound continue if(pulling == rebound) continue - if (get_dir(src, rebound) in priority_dirs) + if (is_priority) return rebound secondary_backup = rebound return secondary_backup diff --git a/code/modules/mod/mod_control.dm b/code/modules/mod/mod_control.dm index 8d5c5c20954..3b1f2a648bc 100644 --- a/code/modules/mod/mod_control.dm +++ b/code/modules/mod/mod_control.dm @@ -771,3 +771,10 @@ mod_link.end_call() mod_link.frequency = null + +/obj/item/mod/control/proc/get_visor_overlay(mutable_appearance/standing) + var/list/overrides = list() + SEND_SIGNAL(src, COMSIG_MOD_GET_VISOR_OVERLAY, standing, overrides) + if (length(overrides)) + return overrides[1] + return mutable_appearance(worn_icon, "[skin]-helmet-visor", layer = standing.layer + 0.1) diff --git a/code/modules/mod/modules/modules_antag.dm b/code/modules/mod/modules/modules_antag.dm index 3eef7d47f15..ba5e1711fcb 100644 --- a/code/modules/mod/modules/modules_antag.dm +++ b/code/modules/mod/modules/modules_antag.dm @@ -102,6 +102,17 @@ else REMOVE_TRAIT(mod.wearer, TRAIT_HEAD_INJURY_BLOCKED, REF(src)) +/obj/item/mod/module/armor_booster/on_install() + RegisterSignal(mod, COMSIG_MOD_GET_VISOR_OVERLAY, PROC_REF(on_visor_overlay)) + +/obj/item/mod/module/armor_booster/on_uninstall(deleting) + UnregisterSignal(mod, COMSIG_MOD_GET_VISOR_OVERLAY) + +/obj/item/mod/module/armor_booster/proc/on_visor_overlay(datum/source, mutable_appearance/standing, list/overrides) + SIGNAL_HANDLER + if (active) + overrides += mutable_appearance(overlay_icon_file, "module_armorbooster_visor-[mod.skin]", layer = standing.layer + 0.1) + ///Energy Shield - Gives you a rechargeable energy shield that nullifies attacks. /obj/item/mod/module/energy_shield name = "MOD energy shield module" diff --git a/code/modules/mod/modules/modules_general.dm b/code/modules/mod/modules/modules_general.dm index 3f4dfe405f7..a766e3f6e4d 100644 --- a/code/modules/mod/modules/modules_general.dm +++ b/code/modules/mod/modules/modules_general.dm @@ -664,13 +664,15 @@ complexity = 1 idle_power_cost = DEFAULT_CHARGE_DRAIN * 0.3 incompatible_modules = list(/obj/item/mod/module/plasma_stabilizer) - overlay_state_inactive = "module_plasma" required_slots = list(ITEM_SLOT_HEAD) -/obj/item/mod/module/plasma_stabilizer/generate_worn_overlay() - if(locate(/obj/item/mod/module/infiltrator) in mod.modules) +/obj/item/mod/module/plasma_stabilizer/generate_worn_overlay(mutable_appearance/standing) + if (!active) return list() - return ..() + var/mutable_appearance/visor_overlay = mod.get_visor_overlay(standing) + visor_overlay.appearance_flags |= RESET_COLOR + visor_overlay.color = COLOR_VOID_PURPLE + return list(visor_overlay) /obj/item/mod/module/plasma_stabilizer/on_equip() ADD_TRAIT(mod.wearer, TRAIT_HEAD_ATMOS_SEALED, REF(src)) diff --git a/code/modules/mod/modules/modules_maint.dm b/code/modules/mod/modules/modules_maint.dm index 48089b0125c..7344993802c 100644 --- a/code/modules/mod/modules/modules_maint.dm +++ b/code/modules/mod/modules/modules_maint.dm @@ -87,7 +87,6 @@ desc = "A Super Cool Awesome Visor (SCAV), intended for modular suits." icon_state = "rave_visor" complexity = 1 - overlay_state_inactive = "module_rave" required_slots = list(ITEM_SLOT_HEAD|ITEM_SLOT_MASK) /// The client colors applied to the wearer. var/datum/client_colour/rave_screen @@ -132,9 +131,13 @@ SEND_SOUND(mod.wearer, sound('sound/machines/terminal/terminal_off.ogg', volume = 50, channel = CHANNEL_JUKEBOX)) /obj/item/mod/module/visor/rave/generate_worn_overlay(mutable_appearance/standing) - . = ..() - for(var/mutable_appearance/appearance as anything in .) - appearance.color = isnull(music_player.active_song_sound) ? null : rainbow_order[rave_number] + if (!active) + return list() + var/mutable_appearance/visor_overlay = mod.get_visor_overlay(standing) + visor_overlay.appearance_flags |= RESET_COLOR + if (!isnull(music_player.active_song_sound)) + visor_overlay.color = rainbow_order[rave_number] + return list(visor_overlay) /obj/item/mod/module/visor/rave/on_active_process(seconds_per_tick) rave_number++ diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm index 60c6aeb4dfe..ff113e2b2cd 100644 --- a/code/modules/paperwork/pen.dm +++ b/code/modules/paperwork/pen.dm @@ -11,12 +11,13 @@ * Pens */ /obj/item/pen - desc = "It's a normal black ink pen." name = "pen" + desc = "It's a normal black ink pen." icon = 'icons/obj/service/bureaucracy.dmi' icon_state = "pen" inhand_icon_state = "pen" worn_icon_state = "pen" + icon_angle = -135 slot_flags = ITEM_SLOT_BELT | ITEM_SLOT_EARS throwforce = 0 w_class = WEIGHT_CLASS_TINY @@ -304,8 +305,8 @@ * (Alan) Edaggers */ /obj/item/pen/edagger - attack_verb_continuous = list("slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts") //these won't show up if the pen is off - attack_verb_simple = list("slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut") + attack_verb_continuous = list("slashes", "slices", "tears", "lacerates", "rips", "dices", "cuts") //these won't show up if the pen is off + attack_verb_simple = list("slash", "slice", "tear", "lacerate", "rip", "dice", "cut") sharpness = SHARP_POINTY armour_penetration = 20 bare_wound_bonus = 10 @@ -322,9 +323,14 @@ var/hidden_desc = "It's a normal black ink pe- Wait. That's a thing used to stab people!" /// The real icons used when extended. var/hidden_icon = "edagger" + var/list/alt_continuous = list("stabs", "pierces", "shanks") + var/list/alt_simple = list("stab", "pierce", "shank") /obj/item/pen/edagger/Initialize(mapload) . = ..() + alt_continuous = string_list(alt_continuous) + alt_simple = string_list(alt_simple) + AddComponent(/datum/component/alternative_sharpness, SHARP_POINTY, alt_continuous, alt_simple, -5, TRAIT_TRANSFORM_ACTIVE) AddComponent(/datum/component/butchering, \ speed = 6 SECONDS, \ butcher_sound = 'sound/items/weapons/blade1.ogg', \ diff --git a/code/modules/power/lighting/light_items.dm b/code/modules/power/lighting/light_items.dm index 357507d0aa4..a5b40e0534f 100644 --- a/code/modules/power/lighting/light_items.dm +++ b/code/modules/power/lighting/light_items.dm @@ -55,6 +55,7 @@ icon_state = "ltube" base_state = "ltube" inhand_icon_state = "ltube" + icon_angle = -45 brightness = 8 custom_price = PAYCHECK_CREW * 0.5 @@ -75,6 +76,7 @@ desc = "A replacement light bulb." icon_state = "lbulb" base_state = "lbulb" + icon_angle = -90 inhand_icon_state = "contvapour" lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' diff --git a/code/modules/power/turbine/turbine.dm b/code/modules/power/turbine/turbine.dm index e839800158f..2112002e507 100644 --- a/code/modules/power/turbine/turbine.dm +++ b/code/modules/power/turbine/turbine.dm @@ -1,11 +1,18 @@ +///Minimum pressure of gases pumped through the turbine #define MINIMUM_TURBINE_PRESSURE 0.01 +///Returns the minimum pressure if it falls below the value #define PRESSURE_MAX(value)(max((value), MINIMUM_TURBINE_PRESSURE)) +///Use emissive for overlays +#define EMISSIVE_OVERLAY (1 << 0) +///No turned off overlay +#define NO_INACTIVE_OVERLAY (1 << 1) /obj/machinery/power/turbine + icon = 'icons/obj/machines/engine/turbine.dmi' density = TRUE resistance_flags = FIRE_PROOF can_atmos_pass = ATMOS_PASS_DENSITY - processing_flags = NONE + processing_flags = START_PROCESSING_MANUALLY ///Checks if the machine is processing or not var/active = FALSE @@ -17,15 +24,8 @@ var/obj/item/turbine_parts/part_path ///The gas mixture this turbine part is storing var/datum/gas_mixture/machine_gasmix - - ///Our overlay when active - var/active_overlay = "" - ///Our overlay when off - var/off_overlay = "" - ///Our overlay when open - var/open_overlay = "" - ///Should we use emissive appearance? - var/emissive = FALSE + ///Flags for our overlays + var/overlay_flags = NONE /obj/machinery/power/turbine/Initialize(mapload, gas_theoretical_volume) . = ..() @@ -59,41 +59,6 @@ deactivate_parts() return ..() -/** - * Handles all the calculations needed for the gases, work done, temperature increase/decrease - * - * Arguments - * * datum/gas_mixture/input_mix - the gas from the environment or from another part of the turbine - * * datum/gas_mixture/output_mix - the gas that got pumped into this part from the input mix. - * ideally should be same as input mix but varying texmperatur & pressures can cause varying results - * * work_amount_to_remove - the amount of work to subtract from the actual work done to pump in the input mixture. - * For e.g. if gas was transfered from the inlet compressor to the rotor we want to subtract the work done - * by the inlet from the rotor to get the true work done - * * intake_size - the percentage of gas to be fed into an turbine part, controlled by turbine computer for inlet compressor only - */ -/obj/machinery/power/turbine/proc/transfer_gases(datum/gas_mixture/input_mix, datum/gas_mixture/output_mix, work_amount_to_remove, intake_size = 1) - //pump gases. if no gases were transferred then no work was done - var/output_pressure = PRESSURE_MAX(output_mix.return_pressure()) - var/datum/gas_mixture/transferred_gases = input_mix.pump_gas_to(output_mix, input_mix.return_pressure() * intake_size) - if(!transferred_gases) - return 0 - - //compute work done - var/work_done = QUANTIZE(transferred_gases.total_moles()) * R_IDEAL_GAS_EQUATION * transferred_gases.temperature * log((transferred_gases.volume * PRESSURE_MAX(transferred_gases.return_pressure())) / (output_mix.volume * output_pressure)) * TURBINE_WORK_CONVERSION_MULTIPLIER - if(work_amount_to_remove) - work_done = work_done - work_amount_to_remove - - //compute temperature & work from temperature if that is a lower value - var/output_mix_heat_capacity = output_mix.heat_capacity() - if(!output_mix_heat_capacity) - return 0 - work_done = min(work_done, (output_mix_heat_capacity * output_mix.temperature - output_mix_heat_capacity * TCMB) / TURBINE_HEAT_CONVERSION_MULTIPLIER) - output_mix.temperature = max((output_mix.temperature * output_mix_heat_capacity + work_done * TURBINE_HEAT_CONVERSION_MULTIPLIER) / output_mix_heat_capacity, TCMB) - return work_done - -/obj/machinery/power/turbine/block_superconductivity() - return TRUE - /obj/machinery/power/turbine/add_context(atom/source, list/context, obj/item/held_item, mob/user) if(isnull(held_item)) return NONE @@ -128,7 +93,7 @@ . = ..() if(installed_part) . += span_notice("Currently at tier [installed_part.current_tier].") - if(installed_part.current_tier + 1 < installed_part.max_tier) + if(installed_part.current_tier + 1 < TURBINE_PART_TIER_FOUR) . += span_notice("Can be upgraded by using a tier [installed_part.current_tier + 1] part.") . += span_notice("The [installed_part.name] can be [EXAMINE_HINT("pried")] out.") else @@ -140,15 +105,54 @@ /obj/machinery/power/turbine/update_overlays() . = ..() + if(panel_open) - . += open_overlay + . += "[base_icon_state]_open" if(active) - . += active_overlay - if(emissive) - . += emissive_appearance(icon, active_overlay, src) - else - . += off_overlay + . += "[base_icon_state]_on" + if(overlay_flags & EMISSIVE_OVERLAY) + . += emissive_appearance(icon, "[base_icon_state]_on", src) + else if(!(overlay_flags & NO_INACTIVE_OVERLAY)) + . += "[base_icon_state]_off" + + +/** + * Handles all the calculations needed for the gases, work done, temperature increase/decrease + * + * Arguments + * * datum/gas_mixture/input_mix - the gas from the environment or from another part of the turbine + * * datum/gas_mixture/output_mix - the gas that got pumped into this part from the input mix. + * ideally should be same as input mix but varying texmperatur & pressures can cause varying results + * * work_amount_to_remove - the amount of work to subtract from the actual work done to pump in the input mixture. + * For e.g. if gas was transfered from the inlet compressor to the rotor we want to subtract the work done + * by the inlet from the rotor to get the true work done + * * intake_size - the percentage of gas to be fed into an turbine part, controlled by turbine computer for inlet compressor only + */ +/obj/machinery/power/turbine/proc/transfer_gases(datum/gas_mixture/input_mix, datum/gas_mixture/output_mix, work_amount_to_remove, intake_size = 1) + PROTECTED_PROC(TRUE) + + //pump gases. if no gases were transferred then no work was done + var/output_pressure = PRESSURE_MAX(output_mix.return_pressure()) + var/datum/gas_mixture/transferred_gases = input_mix.pump_gas_to(output_mix, input_mix.return_pressure() * intake_size) + if(!transferred_gases) + return 0 + + //compute work done + var/work_done = QUANTIZE(transferred_gases.total_moles()) * R_IDEAL_GAS_EQUATION * transferred_gases.temperature * log((transferred_gases.volume * PRESSURE_MAX(transferred_gases.return_pressure())) / (output_mix.volume * output_pressure)) * TURBINE_WORK_CONVERSION_MULTIPLIER + if(work_amount_to_remove) + work_done = work_done - work_amount_to_remove + + //compute temperature & work from temperature if that is a lower value + var/output_mix_heat_capacity = output_mix.heat_capacity() + if(!output_mix_heat_capacity) + return 0 + work_done = min(work_done, (output_mix_heat_capacity * output_mix.temperature - output_mix_heat_capacity * TCMB) / TURBINE_HEAT_CONVERSION_MULTIPLIER) + output_mix.temperature = max((output_mix.temperature * output_mix_heat_capacity + work_done * TURBINE_HEAT_CONVERSION_MULTIPLIER) / output_mix_heat_capacity, TCMB) + return work_done + +/obj/machinery/power/turbine/block_superconductivity() + return TRUE /obj/machinery/power/turbine/screwdriver_act(mob/living/user, obj/item/tool) . = ITEM_INTERACT_BLOCKING @@ -165,7 +169,7 @@ deactivate_parts(user) else activate_parts(user) - update_appearance() + update_appearance(UPDATE_OVERLAYS) return ITEM_INTERACT_SUCCESS @@ -229,22 +233,22 @@ if(gone == installed_part) installed_part = null -/obj/machinery/power/turbine/attackby(obj/item/turbine_parts/object, mob/user, params) - //not the correct part +/obj/machinery/power/turbine/item_interaction(mob/living/user, obj/item/turbine_parts/object, list/modifiers) + . = NONE if(!istype(object, part_path)) return ..() //not in a state to accep the part. return TRUE so we don't bash the machine and damage it if(active) balloon_alert(user, "turn off the machine first!") - return TRUE + return ITEM_INTERACT_BLOCKING if(!panel_open) balloon_alert(user, "open the maintenance hatch first!") - return TRUE + return ITEM_INTERACT_BLOCKING //install the part if(!do_after(user, 2 SECONDS, src)) - return TRUE + return ITEM_INTERACT_BLOCKING if(installed_part) user.put_in_hands(installed_part) balloon_alert(user, "replaced part with the one in hand") @@ -252,22 +256,21 @@ balloon_alert(user, "installed new part") user.transferItemToLoc(object, src) installed_part = object - return TRUE + return ITEM_INTERACT_SUCCESS /// Gets the efficiency of the installed part, returns 0 if no part is installed /obj/machinery/power/turbine/proc/get_efficiency() + SHOULD_BE_PURE(TRUE) + return installed_part?.part_efficiency || 0 /obj/machinery/power/turbine/inlet_compressor name = "inlet compressor" desc = "The input side of a turbine generator, contains the compressor." - icon = 'icons/obj/machines/engine/turbine.dmi' icon_state = "inlet_compressor" + base_icon_state = "inlet" circuit = /obj/item/circuitboard/machine/turbine_compressor part_path = /obj/item/turbine_parts/compressor - active_overlay = "inlet_animation" - off_overlay = "inlet_off" - open_overlay = "inlet_open" /// The rotor this inlet is linked to var/obj/machinery/power/turbine/core_rotor/rotor @@ -296,6 +299,8 @@ * Returns temperature of the gas mix absorbed only if some work was done */ /obj/machinery/power/turbine/inlet_compressor/proc/compress_gases() + SHOULD_NOT_OVERRIDE(TRUE) + compressor_work = 0 compressor_pressure = MINIMUM_TURBINE_PRESSURE if(QDELETED(input_turf)) @@ -314,16 +319,14 @@ return input_turf_mixture.temperature +//===========================OUTLET============================================== /obj/machinery/power/turbine/turbine_outlet name = "turbine outlet" desc = "The output side of a turbine generator, contains the turbine and the stator." - icon = 'icons/obj/machines/engine/turbine.dmi' icon_state = "turbine_outlet" + base_icon_state = "outlet" circuit = /obj/item/circuitboard/machine/turbine_stator part_path = /obj/item/turbine_parts/stator - active_overlay = "outlet_animation" - off_overlay = "outlet_off" - open_overlay = "outlet_open" /// The rotor this outlet is linked to var/obj/machinery/power/turbine/core_rotor/rotor @@ -343,6 +346,8 @@ /// push gases from its gas mix to output turf /obj/machinery/power/turbine/turbine_outlet/proc/expel_gases() + SHOULD_NOT_OVERRIDE(TRUE) + if(QDELETED(output_turf)) output_turf = get_step(loc, dir) //turf is blocked don't eject gases @@ -358,18 +363,16 @@ //return ejected gases return ejected_gases +//===========================================CORE ROTOR========================================= /obj/machinery/power/turbine/core_rotor name = "core rotor" desc = "The middle part of a turbine generator, contains the rotor and the main computer." - icon = 'icons/obj/machines/engine/turbine.dmi' icon_state = "core_rotor" - active_overlay = "core_light" - open_overlay = "core_open" - active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION - emissive = TRUE + base_icon_state = "core" can_change_cable_layer = TRUE circuit = /obj/item/circuitboard/machine/turbine_rotor part_path = /obj/item/turbine_parts/rotor + overlay_flags = EMISSIVE_OVERLAY | NO_INACTIVE_OVERLAY ///ID to easily connect the main part of the turbine to the computer var/mapping_id @@ -378,9 +381,9 @@ ///Reference to the turbine var/obj/machinery/power/turbine/turbine_outlet/turbine ///Rotation per minute the machine is doing - var/rpm + var/rpm = 0 ///Amount of power the machine is producing - var/produced_energy + var/produced_energy = 0 ///Check to see if all parts are connected to the core var/all_parts_connected = FALSE ///Max rmp that the installed parts can handle, limits the rpms @@ -462,16 +465,21 @@ //works same as regular left click return multitool_act(user, tool) -/// convinience proc for balloon alert which returns if viewer is null +/** + * convinience proc for balloon alert which returns if viewer is null + * Arguments + * + * * mob/viewer - the player receiving the message + * * text - the message + */ /obj/machinery/power/turbine/core_rotor/proc/feedback(mob/viewer, text) + PRIVATE_PROC(TRUE) + if(isnull(viewer)) return balloon_alert(viewer, text) -/** - * Called to activate the complete machine, checks for part presence, correct orientation and installed parts - * Registers the input/output turfs - */ +///Called to activate the complete machine, checks for part presence, correct orientation and installed parts /obj/machinery/power/turbine/core_rotor/activate_parts(mob/user, check_only = FALSE) //if this is not a checkup and all parts are connected then we have nothing to do if(!check_only && all_parts_connected) @@ -479,13 +487,18 @@ //locate compressor & turbine, when checking we simply check to see if they are still there if(!check_only) - compressor = locate(/obj/machinery/power/turbine/inlet_compressor) in get_step(src, REVERSE_DIR(dir)) - turbine = locate(/obj/machinery/power/turbine/turbine_outlet) in get_step(src, dir) + compressor = locate() in get_step(src, REVERSE_DIR(dir)) + turbine = locate() in get_step(src, dir) - //maybe look for them the other way around. we want the rotor to allign with them either way for player convinience - if(!compressor && !turbine) - compressor = locate(/obj/machinery/power/turbine/inlet_compressor) in get_step(src, dir) - turbine = locate(/obj/machinery/power/turbine/turbine_outlet) in get_step(src, REVERSE_DIR(dir)) + //maybe look for them the other way around. this means the rotor is facing the wrong way + if(QDELETED(compressor) && QDELETED(turbine)) + compressor = locate() in get_step(src, dir) + turbine = locate() in get_step(src, REVERSE_DIR(dir)) + + //show corrective actions + if(!QDELETED(compressor) || !QDELETED(turbine)) + feedback(user, "rotor is facing the wrong way!") + return (all_parts_connected = FALSE) //sanity checks for compressor if(QDELETED(compressor)) @@ -505,17 +518,17 @@ if(QDELETED(turbine)) feedback(user, "missing turbine!") return (all_parts_connected = FALSE) - if(turbine.dir != dir && turbine.dir != REVERSE_DIR(dir)) + if(turbine.dir != dir && turbine.dir != REVERSE_DIR(dir)) //make sure it's not perpendicular to the rotor feedback(user, "turbine not aligned with rotor!") return (all_parts_connected = FALSE) if(!turbine.can_connect) - feedback(user, "turbine panel is either open or is misplaced!") //we say misplaced because can_connect becomes FALSE when this turbine is moved + feedback(user, "close turbine panel!") //we say misplaced because can_connect becomes FALSE when this turbine is moved return (all_parts_connected = FALSE) if(!turbine.installed_part) feedback(user, "turbine is missing stator part!") return (all_parts_connected = FALSE) - //final sanity check to make sure turbine & compressor are facing the same direction. From an visual perspective they will appear facing away from each other actually. I know blame spriter's + //sanity check to make sure turbine & compressor are facing the same direction. From an visual perspective they will appear facing away from each other actually. I know blame spriter's if(compressor.dir != turbine.dir) feedback(user, "turbine & compressor are not facing away from each other!") return (all_parts_connected = FALSE) @@ -537,85 +550,60 @@ * Allows to null the various machines and references from the main core */ /obj/machinery/power/turbine/core_rotor/deactivate_parts() - if(all_parts_connected) - power_off() + toggle_power(force_off = TRUE) compressor?.rotor = null compressor = null turbine?.rotor = null turbine = null all_parts_connected = FALSE disconnect_from_network() - SSair.stop_processing_machine(src) /obj/machinery/power/turbine/core_rotor/on_deconstruction(disassembled) deactivate_parts() return ..() /// Toggle power on and off, not safe -/obj/machinery/power/turbine/core_rotor/proc/toggle_power() - if(active) - power_off() - return - power_on() - -/** - * Activate all three parts, not safe, it assumes the machine already connected and properly working - * It does a minimun check to ensure the parts still exist - */ -/obj/machinery/power/turbine/core_rotor/proc/power_on() - if(active || QDELETED(compressor) || QDELETED(turbine)) - return - active = TRUE - compressor.active = TRUE - turbine.active = TRUE - call_parts_update_appearance() - SSair.start_processing_machine(src) - -/// Calls all parts update appearance proc. -/obj/machinery/power/turbine/core_rotor/proc/call_parts_update_appearance() - update_appearance() - if(!QDELETED(compressor)) - compressor.update_appearance() - if(!QDELETED(turbine)) - turbine.update_appearance() +/obj/machinery/power/turbine/core_rotor/proc/toggle_power(force_off) + SHOULD_NOT_OVERRIDE(TRUE) + + //toggle status + if(force_off) + if(!active) //was already off + return + active = FALSE + else + active = !active -/** - * Deactivate all three parts, not safe, it assumes the machine already connected and properly working - * will try to turn off whatever components are left of this machine - */ -/obj/machinery/power/turbine/core_rotor/proc/power_off() - if(!active) - return - active = FALSE + //update operation status of parts + update_appearance(UPDATE_OVERLAYS) if(!QDELETED(compressor)) - compressor.active = FALSE + compressor.active = active + compressor.update_appearance(UPDATE_OVERLAYS) if(!QDELETED(turbine)) - turbine.active = FALSE - call_parts_update_appearance() - SSair.stop_processing_machine(src) + turbine.active = active + turbine.update_appearance(UPDATE_OVERLAYS) -/// Returns true if all parts have their panel closed -/obj/machinery/power/turbine/core_rotor/proc/all_parts_ready() - if(QDELETED(compressor)) - return FALSE - if(QDELETED(turbine)) - return FALSE - return !panel_open && !compressor.panel_open && !turbine.panel_open + //start or stop processing + if(active) + update_mode_power_usage(ACTIVE_POWER_USE, active_power_usage) + begin_processing() + else + unset_static_power() + end_processing() /// Getter for turbine integrity, return the amount in % /obj/machinery/power/turbine/core_rotor/proc/get_turbine_integrity() + SHOULD_NOT_OVERRIDE(TRUE) + var/integrity = damage / 500 integrity = max(round(100 - integrity * 100, 0.01), 0) return integrity -/obj/machinery/power/turbine/core_rotor/process_atmos() +/obj/machinery/power/turbine/core_rotor/process(seconds_per_tick) if(!active || !activate_parts(check_only = TRUE) || (machine_stat & BROKEN) || !powered(ignore_use_power = TRUE)) - power_off() + deactivate_parts() return PROCESS_KILL - //use power to operate internal electronics & stuff - update_mode_power_usage(ACTIVE_POWER_USE, active_power_usage) - //===============COMPRESSOR WORKING========// //Transfer gases from turf to compressor var/temperature = compressor.compress_gases() @@ -668,9 +656,9 @@ work_done = max(work_done - compressor.compressor_work * TURBINE_COMPRESSOR_STATOR_INTERACTION_MULTIPLIER - turbine_work, 0) //calculate final acheived rpm rpm = ((work_done * compressor.get_efficiency()) ** turbine.get_efficiency()) * get_efficiency() / TURBINE_RPM_CONVERSION - rpm = FLOOR(min(rpm, max_allowed_rpm), 1) + rpm = min(ROUND_UP(rpm), max_allowed_rpm) //add energy into the grid, also use part of it for turbine operation - produced_energy = rpm * TURBINE_ENERGY_RECTIFICATION_MULTIPLIER * TURBINE_RPM_CONVERSION + produced_energy = rpm * TURBINE_ENERGY_RECTIFICATION_MULTIPLIER * TURBINE_RPM_CONVERSION * seconds_per_tick add_avail(produced_energy) /obj/item/paper/guides/jobs/atmos/turbine @@ -686,3 +674,5 @@ #undef PRESSURE_MAX #undef MINIMUM_TURBINE_PRESSURE +#undef EMISSIVE_OVERLAY +#undef NO_INACTIVE_OVERLAY diff --git a/code/modules/power/turbine/turbine_computer.dm b/code/modules/power/turbine/turbine_computer.dm index 36a556daefb..7771bda03f8 100644 --- a/code/modules/power/turbine/turbine_computer.dm +++ b/code/modules/power/turbine/turbine_computer.dm @@ -20,8 +20,8 @@ register_machine(main) break -/obj/machinery/computer/turbine_computer/multitool_act(mob/living/user, obj/item/tool) - var/obj/item/multitool/multitool = tool +/obj/machinery/computer/turbine_computer/multitool_act(mob/living/user, obj/item/multitool/multitool) + . = ITEM_INTERACT_FAILURE if(!istype(multitool.buffer, /obj/machinery/power/turbine/core_rotor)) to_chat(user, span_notice("Wrong machine type in [multitool] buffer...")) return @@ -29,12 +29,21 @@ to_chat(user, span_notice("Changing [src] bluespace network...")) if(!do_after(user, 0.2 SECONDS, src)) return + playsound(get_turf(user), 'sound/machines/click.ogg', 10, TRUE) register_machine(multitool.buffer) to_chat(user, span_notice("You link [src] to the console in [multitool]'s buffer.")) - return TRUE + return ITEM_INTERACT_SUCCESS + +/** + * Links the rotor with this computer + * Arguments + * + * * obj/machinery/power/turbine/core_rotor/machine - the machine to link + */ +/obj/machinery/computer/turbine_computer/proc/register_machine(obj/machinery/power/turbine/core_rotor/machine) + PRIVATE_PROC(TRUE) -/obj/machinery/computer/turbine_computer/proc/register_machine(machine) turbine_core = WEAKREF(machine) /obj/machinery/computer/turbine_computer/ui_interact(mob/user, datum/tgui/ui) @@ -45,26 +54,27 @@ ui.open() /obj/machinery/computer/turbine_computer/ui_data(mob/user) - var/list/data = list() + . = list() + //do we have the main rotor with all parts connected var/obj/machinery/power/turbine/core_rotor/main_control = turbine_core?.resolve() - data["connected"] = !!QDELETED(main_control) - if(!main_control) + if(QDELETED(main_control) || !main_control.all_parts_connected) + .["connected"] = FALSE return + else + .["connected"] = TRUE - data["active"] = main_control.active - data["rpm"] = main_control.rpm ? main_control.rpm : 0 - data["power"] = main_control.produced_energy ? main_control.produced_energy : 0 - data["integrity"] = main_control.get_turbine_integrity() - data["parts_linked"] = main_control.all_parts_connected - data["parts_ready"] = main_control.all_parts_ready() - - data["max_rpm"] = main_control.max_allowed_rpm - data["max_temperature"] = main_control.max_allowed_temperature - data["temp"] = main_control.compressor?.input_turf?.air.temperature || 0 - data["regulator"] = QDELETED(main_control.compressor) ? 0 : main_control.compressor.intake_regulator + //operation status + .["active"] = main_control.active + .["rpm"] = main_control.rpm + .["power"] = energy_to_power(main_control.produced_energy) + .["integrity"] = main_control.get_turbine_integrity() - return data + //running parameters + .["max_rpm"] = main_control.max_allowed_rpm + .["max_temperature"] = main_control.max_allowed_temperature + .["temp"] = main_control.compressor.input_turf?.air.temperature || 0 + .["regulator"] = main_control.compressor.intake_regulator /obj/machinery/computer/turbine_computer/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) . = ..() @@ -74,19 +84,35 @@ switch(action) if("toggle_power") var/obj/machinery/power/turbine/core_rotor/main_control = turbine_core?.resolve() - if(!main_control || !main_control.all_parts_connected || main_control.rpm > 1000) - return TRUE - if(!main_control.activate_parts(usr, check_only = TRUE)) - return TRUE + if(!main_control) + return FALSE + + if(!main_control.active) //turning on the machine requires all part to be linked + if(!main_control.activate_parts(ui.user, check_only = TRUE)) + return FALSE + else if(main_control.rpm > 1000) //turning off requires rpm to be less than 1000 + return FALSE + main_control.toggle_power() main_control.rpm = 0 main_control.produced_energy = 0 - . = TRUE + return TRUE + if("regulate") - var/intake_size = text2num(params["regulate"]) + var/intake_size = params["regulate"] + if(isnull(intake_size)) + return FALSE + + intake_size = text2num(intake_size) + if(isnull(intake_size)) + return FALSE + var/obj/machinery/power/turbine/core_rotor/main_control = turbine_core?.resolve() - if(intake_size == null || !main_control) - return - if(!QDELETED(main_control.compressor)) - main_control.compressor.intake_regulator = clamp(intake_size, 0.01, 1) - . = TRUE + if(!main_control) + return FALSE + + if(QDELETED(main_control.compressor)) + return FALSE + + main_control.compressor.intake_regulator = clamp(intake_size, 0.01, 1) + return TRUE diff --git a/code/modules/power/turbine/turbine_parts.dm b/code/modules/power/turbine/turbine_parts.dm index 4215fccf39f..e568f9e0964 100644 --- a/code/modules/power/turbine/turbine_parts.dm +++ b/code/modules/power/turbine/turbine_parts.dm @@ -1,3 +1,8 @@ +///String to access turbine part typepath to upgrade +#define TURBINE_UPGRADE_PART "part" +///String to access turbine part required amount to upgrade +#define TURBINE_UPGRADE_AMOUNT "amount" + /obj/item/turbine_parts name = "turbine parts" desc = "you really should call an admin" @@ -8,90 +13,62 @@ var/part_efficiency = 0 ///Efficiency increase amount for each tier var/part_efficiency_increase_amount = 0 - ///Current part tier var/current_tier = TURBINE_PART_TIER_ONE - ///Max part tier - var/max_tier = TURBINE_PART_TIER_FOUR - - ///Stores the path of the material for the second tier upgrade - var/obj/item/stack/sheet/second_tier_material = /obj/item/stack/sheet/plasteel - ///Amount of second tier material for the upgrade - var/second_tier_material_amount = 10 - - ///Stores the path of the material for the third tier upgrade - var/obj/item/stack/sheet/third_tier_material = /obj/item/stack/sheet/mineral/titanium - ///Amount of third tier material for the upgrade - var/third_tier_material_amount = 10 - - ///Stores the path of the material for the fourth tier upgrade - var/obj/item/stack/sheet/fourth_tier_material = /obj/item/stack/sheet/mineral/metal_hydrogen - ///Amount of fourth tier material for the upgrade - var/fourth_tier_material_amount = 5 - ///Max rpm reachable by the part var/max_rpm = 35000 - ///Multiplier to increase the max rpm per tier, max should be around 500000 rpm - var/max_rpm_tier_multiplier = 2.5 - ///Max temperature achievable by the part before the turbine starts to take damage var/max_temperature = 50000 - ///Max temperature exponential value per tier - var/max_temperature_tier_exponential = 1.2 /obj/item/turbine_parts/examine(mob/user) . = ..() - . += "This is a tier [current_tier] turbine part, rated for [max_rpm] rpm and [max_temperature] K." - var/upgrade_material_name_amount - switch(current_tier) - if(TURBINE_PART_TIER_ONE) - upgrade_material_name_amount = "[second_tier_material_amount] [initial(second_tier_material.name)] sheets" - if(TURBINE_PART_TIER_TWO) - upgrade_material_name_amount = "[third_tier_material_amount] [initial(third_tier_material.name)] sheets" - if(TURBINE_PART_TIER_THREE) - upgrade_material_name_amount = "[fourth_tier_material_amount] [initial(fourth_tier_material.name)] sheets" + . += span_notice("This is a tier [current_tier] turbine part, rated for [max_rpm] rpm and [max_temperature] K.") - if(upgrade_material_name_amount) - . += "Can be upgraded with [upgrade_material_name_amount]." + var/list/required_parts = get_tier_upgrades() + if(length(required_parts)) + var/obj/item/stack/material = required_parts[TURBINE_UPGRADE_PART] + . += span_notice("Can be upgraded with [required_parts[TURBINE_UPGRADE_AMOUNT]] [initial(material.name)] sheets.") else - . += "Is already at max tier." + . += span_notice("Is already at max tier.") + +///Returns a list containing the typepath & amount of it required to upgrade to the next tier +/obj/item/turbine_parts/proc/get_tier_upgrades() + PROTECTED_PROC(TRUE) + SHOULD_BE_PURE(TRUE) + RETURN_TYPE(/list) -/obj/item/turbine_parts/attackby(obj/item/attacking_item, mob/user, params) - if(current_tier >= max_tier) - return FALSE switch(current_tier) if(TURBINE_PART_TIER_ONE) - if(!istype(attacking_item, second_tier_material)) - return - var/obj/item/stack/sheet/second_tier = attacking_item - if(do_after(user, 1 SECONDS, src) && second_tier.use(second_tier_material_amount)) - current_tier = 2 - part_efficiency += part_efficiency_increase_amount - max_rpm *= max_rpm_tier_multiplier - max_temperature = max_temperature ** max_temperature_tier_exponential - return TRUE + return list(TURBINE_UPGRADE_PART = /obj/item/stack/sheet/plasteel, TURBINE_UPGRADE_AMOUNT = 10) if(TURBINE_PART_TIER_TWO) - if(!istype(attacking_item, third_tier_material)) - return - var/obj/item/stack/sheet/third_tier = attacking_item - if(do_after(user, 2 SECONDS, src) && third_tier.use(third_tier_material_amount)) - current_tier = 3 - part_efficiency += part_efficiency_increase_amount - max_rpm *= max_rpm_tier_multiplier - max_temperature = max_temperature ** max_temperature_tier_exponential - return TRUE + return list(TURBINE_UPGRADE_PART = /obj/item/stack/sheet/mineral/titanium, TURBINE_UPGRADE_AMOUNT = 10) if(TURBINE_PART_TIER_THREE) - if(!istype(attacking_item, fourth_tier_material)) - return - var/obj/item/stack/sheet/fourth_tier = attacking_item - if(do_after(user, 3 SECONDS, src) && fourth_tier.use(fourth_tier_material_amount)) - current_tier = 4 - part_efficiency += part_efficiency_increase_amount - max_rpm *= max_rpm_tier_multiplier - max_temperature = max_temperature ** max_temperature_tier_exponential - return TRUE - - return ..() + return list(TURBINE_UPGRADE_PART = /obj/item/stack/sheet/mineral/metal_hydrogen, TURBINE_UPGRADE_AMOUNT = 5) + +/obj/item/turbine_parts/item_interaction(mob/living/user, obj/item/attacking_item, list/modifiers) + . = NONE + + var/list/required_parts = get_tier_upgrades() + if(!length(required_parts)) + balloon_alert(user, "already at max tier!") + return ITEM_INTERACT_FAILURE + + var/obj/item/stack/sheet/material = attacking_item + if(!istype(material, required_parts[TURBINE_UPGRADE_PART])) + balloon_alert(user, "incorrect part!") + return ITEM_INTERACT_FAILURE + + var/amount = required_parts[TURBINE_UPGRADE_AMOUNT] + if(material.amount < amount) + balloon_alert(user, "requires [amount] sheets!") + return ITEM_INTERACT_FAILURE + + if(do_after(user, current_tier SECONDS, src) && material.use(amount)) + current_tier += 1 + part_efficiency += part_efficiency_increase_amount + max_rpm *= 2.5 + max_temperature = max_temperature ** 1.2 + return ITEM_INTERACT_SUCCESS /obj/item/turbine_parts/compressor name = "compressor part" @@ -113,9 +90,15 @@ icon_state = "stator_part" part_efficiency = 0.85 part_efficiency_increase_amount = 0.015 - second_tier_material = /obj/item/stack/sheet/mineral/titanium - third_tier_material = /obj/item/stack/sheet/mineral/metal_hydrogen - fourth_tier_material = /obj/item/stack/sheet/mineral/zaukerite - second_tier_material_amount = 15 - third_tier_material_amount = 15 - fourth_tier_material_amount = 10 + +/obj/item/turbine_parts/stator/get_tier_upgrades() + switch(current_tier) + if(TURBINE_PART_TIER_ONE) + return list(TURBINE_UPGRADE_PART = /obj/item/stack/sheet/mineral/titanium, TURBINE_UPGRADE_AMOUNT = 15) + if(TURBINE_PART_TIER_TWO) + return list(TURBINE_UPGRADE_PART = /obj/item/stack/sheet/mineral/metal_hydrogen, TURBINE_UPGRADE_AMOUNT = 15) + if(TURBINE_PART_TIER_THREE) + return list(TURBINE_UPGRADE_PART = /obj/item/stack/sheet/mineral/zaukerite, TURBINE_UPGRADE_AMOUNT = 10) + +#undef TURBINE_UPGRADE_PART +#undef TURBINE_UPGRADE_AMOUNT diff --git a/code/modules/projectiles/ammunition/_firing.dm b/code/modules/projectiles/ammunition/_firing.dm index 5a704354ed3..25973e92e7a 100644 --- a/code/modules/projectiles/ammunition/_firing.dm +++ b/code/modules/projectiles/ammunition/_firing.dm @@ -61,6 +61,8 @@ loaded_projectile.damage *= gun.projectile_damage_multiplier * integrity_mult loaded_projectile.stamina *= gun.projectile_damage_multiplier * integrity_mult + loaded_projectile.speed *= gun.projectile_speed_multiplier * integrity_mult + loaded_projectile.wound_bonus += gun.projectile_wound_bonus loaded_projectile.wound_bonus *= loaded_projectile.wound_bonus >= 0 ? 1 : 2 - integrity_mult loaded_projectile.bare_wound_bonus += gun.projectile_wound_bonus diff --git a/code/modules/projectiles/ammunition/ballistic/revolver.dm b/code/modules/projectiles/ammunition/ballistic/revolver.dm index 0126a461723..6e0c26af735 100644 --- a/code/modules/projectiles/ammunition/ballistic/revolver.dm +++ b/code/modules/projectiles/ammunition/ballistic/revolver.dm @@ -1,26 +1,26 @@ // .357 (Syndie Revolver) -/obj/item/ammo_casing/a357 +/obj/item/ammo_casing/c357 name = ".357 bullet casing" desc = "A .357 bullet casing." caliber = CALIBER_357 - projectile_type = /obj/projectile/bullet/a357 + projectile_type = /obj/projectile/bullet/c357 -/obj/item/ammo_casing/a357/spent +/obj/item/ammo_casing/c357/spent projectile_type = null -/obj/item/ammo_casing/a357/match +/obj/item/ammo_casing/c357/match name = ".357 match bullet casing" desc = "A .357 bullet casing, manufactured to exceedingly high standards." - projectile_type = /obj/projectile/bullet/a357/match + projectile_type = /obj/projectile/bullet/c357/match -/obj/item/ammo_casing/a357/phasic +/obj/item/ammo_casing/c357/phasic name = ".357 phasic bullet casing" - projectile_type = /obj/projectile/bullet/a357/phasic + projectile_type = /obj/projectile/bullet/c357/phasic -/obj/item/ammo_casing/a357/heartseeker +/obj/item/ammo_casing/c357/heartseeker name = ".357 heartseeker bullet casing" - projectile_type = /obj/projectile/bullet/a357/heartseeker + projectile_type = /obj/projectile/bullet/c357/heartseeker // 7.62x38mmR (Nagant Revolver) @@ -53,6 +53,11 @@ desc = "A .38 rubber bullet casing, manufactured to exceedingly bouncy standards." projectile_type = /obj/projectile/bullet/c38/match/bouncy +/obj/item/ammo_casing/c38/match/true + name = ".38 True Strike bullet casing" + desc = "A .38 True Strike bullet casing." + projectile_type = /obj/projectile/bullet/c38/match/true + /obj/item/ammo_casing/c38/dumdum name = ".38 DumDum bullet casing" desc = "A .38 DumDum bullet casing." diff --git a/code/modules/projectiles/ammunition/energy/stun.dm b/code/modules/projectiles/ammunition/energy/stun.dm index 7fb22e42ef5..6fa8ee80c6d 100644 --- a/code/modules/projectiles/ammunition/energy/stun.dm +++ b/code/modules/projectiles/ammunition/energy/stun.dm @@ -16,6 +16,9 @@ /obj/item/ammo_casing/energy/electrode/old e_cost = LASER_SHOTS(1, STANDARD_CELL_CHARGE) +/obj/item/ammo_casing/energy/electrode/ai_turrets + projectile_type = /obj/projectile/energy/electrode/ai_turrets + /obj/item/ammo_casing/energy/disabler projectile_type = /obj/projectile/beam/disabler select_name = "disable" diff --git a/code/modules/projectiles/boxes_magazines/ammo_boxes.dm b/code/modules/projectiles/boxes_magazines/ammo_boxes.dm index bbd89389eb8..b664be74e87 100644 --- a/code/modules/projectiles/boxes_magazines/ammo_boxes.dm +++ b/code/modules/projectiles/boxes_magazines/ammo_boxes.dm @@ -2,7 +2,7 @@ name = "speed loader (.357)" desc = "Designed to quickly reload revolvers." icon_state = "357" - ammo_type = /obj/item/ammo_casing/a357 + ammo_type = /obj/item/ammo_casing/c357 max_ammo = 7 caliber = CALIBER_357 multiple_sprites = AMMO_BOX_PER_BULLET @@ -13,13 +13,13 @@ /obj/item/ammo_box/a357/match name = "speed loader (.357 Match)" desc = "Designed to quickly reload revolvers. These rounds are manufactured within extremely tight tolerances, making them easy to show off trickshots with." - ammo_type = /obj/item/ammo_casing/a357/match + ammo_type = /obj/item/ammo_casing/c357/match ammo_band_color = "#77828a" /obj/item/ammo_box/a357/phasic name = "speed loader (.357 Phasic)" desc = "Designed to quickly reload revolvers. Holds phasic ammo, also known as 'Ghost Lead', allowing it to pass through non-organic material." - ammo_type = /obj/item/ammo_casing/a357/phasic + ammo_type = /obj/item/ammo_casing/c357/phasic ammo_band_color = "#693a6a" /obj/item/ammo_box/a357/heartseeker @@ -27,7 +27,7 @@ desc = "Designed to quickly reload revolvers. Holds heartseeker ammo, which veers into targets with exceptional precision using \ an unknown method. It apparently predicts movement using neural pulses in the brain, but that's less marketable. \ As seen in the hit NTFlik horror-space western film, Forget-Me-Not! Brought to you by Roseus Galactic!" - ammo_type = /obj/item/ammo_casing/a357/heartseeker + ammo_type = /obj/item/ammo_casing/c357/heartseeker ammo_band_color = "#a91e1e" /obj/item/ammo_box/c38 @@ -60,6 +60,12 @@ ammo_type = /obj/item/ammo_casing/c38/match/bouncy ammo_band_color = "#556696" +/obj/item/ammo_box/c38/true + name = "speed loader (.38 True Strike)" + desc = "Designed to quickly reload revolvers. Bullets bounce towards new targets with surprising accuracy." + ammo_type = /obj/item/ammo_casing/c38/match/true + ammo_band_color = "#d647b0" + /obj/item/ammo_box/c38/dumdum name = "speed loader (.38 DumDum)" desc = "Designed to quickly reload revolvers. These rounds expand on impact, allowing them to shred the target and cause massive bleeding. Very weak against armor and distant targets." diff --git a/code/modules/projectiles/boxes_magazines/external/rifle.dm b/code/modules/projectiles/boxes_magazines/external/rifle.dm index 882fefedec1..96916fe9bb5 100644 --- a/code/modules/projectiles/boxes_magazines/external/rifle.dm +++ b/code/modules/projectiles/boxes_magazines/external/rifle.dm @@ -21,3 +21,66 @@ /obj/item/ammo_box/magazine/m223/phasic name = "toploader magazine (.223 Phasic)" ammo_type = /obj/item/ammo_casing/a223/phasic + +// .38 (Battle Rifle) // + +/obj/item/ammo_box/magazine/m38 + name = "battle rifle magazine (.38)" + desc = "A magazine for a BR-38 battle rifle." + icon_state = "38mag" + base_icon_state = "38mag" + w_class = WEIGHT_CLASS_NORMAL + ammo_type = /obj/item/ammo_casing/c38 + caliber = CALIBER_38 + max_ammo = 15 + ammo_band_icon = "+38mag_ammo_band" + ammo_band_color = null + +/obj/item/ammo_box/magazine/m38/update_icon_state() + . = ..() + icon_state = "[base_icon_state][ammo_count() ? "-ammo" : ""]" + +/obj/item/ammo_box/magazine/m38/empty + start_empty = TRUE + +/obj/item/ammo_box/magazine/m38/trac + name = "battle rifle magazine (.38 TRAC)" + desc = "A magazine for a BR-38 battle rifle. TRAC bullets embed a tracking implant within the target's body and are entirely nonlethal." + ammo_type = /obj/item/ammo_casing/c38/trac + ammo_band_color = "#7b6383" + +/obj/item/ammo_box/magazine/m38/match + name = "battle rifle magazine (.38 Match)" + desc = "A magazine for a BR-38 battle rifle. These rounds are manufactured within extremely tight tolerances, making them easy to show off trickshots with." + ammo_type = /obj/item/ammo_casing/c38/match + ammo_band_color = "#7b6383" + +/obj/item/ammo_box/magazine/m38/match/bouncy + name = "battle rifle magazine (.38 Rubber)" + desc = "A magazine for a BR-38 battle rifle. These rounds are incredibly bouncy and MOSTLY nonlethal, making them great to show off trickshots with." + ammo_type = /obj/item/ammo_casing/c38/match/bouncy + ammo_band_color = "#556696" + +/obj/item/ammo_box/magazine/m38/true + name = "battle rifle magazine (.38 True Strike)" + desc = "A magazine for a BR-38 battle rifle. Bullets bounce towards new targets with surprising accuracy." + ammo_type = /obj/item/ammo_casing/c38/match/true + ammo_band_color = "#d647b0" + +/obj/item/ammo_box/magazine/m38/dumdum + name = "battle rifle magazine (.38 DumDum)" + desc = "A magazine for a BR-38 battle rifle. These rounds expand on impact, allowing them to shred the target and cause massive bleeding. Very weak against armor and distant targets." + ammo_type = /obj/item/ammo_casing/c38/dumdum + ammo_band_color = "#969578" + +/obj/item/ammo_box/magazine/m38/hotshot + name = "battle rifle magazine (.38 Hot Shot)" + desc = "A magazine for a BR-38 battle rifle. Hot Shot bullets contain an incendiary payload." + ammo_type = /obj/item/ammo_casing/c38/hotshot + ammo_band_color = "#805a57" + +/obj/item/ammo_box/magazine/m38/iceblox + name = "battle rifle magazine (.38 Iceblox)" + desc = "A magazine for a BR-38 battle rifle. Iceblox bullets contain a cryogenic payload." + ammo_type = /obj/item/ammo_casing/c38/iceblox + ammo_band_color = "#658e94" diff --git a/code/modules/projectiles/boxes_magazines/internal/_cylinder.dm b/code/modules/projectiles/boxes_magazines/internal/_cylinder.dm index 28df0262352..7f467881a9d 100644 --- a/code/modules/projectiles/boxes_magazines/internal/_cylinder.dm +++ b/code/modules/projectiles/boxes_magazines/internal/_cylinder.dm @@ -1,6 +1,6 @@ /obj/item/ammo_box/magazine/internal/cylinder name = "revolver cylinder" - ammo_type = /obj/item/ammo_casing/a357 + ammo_type = /obj/item/ammo_casing/c357 caliber = CALIBER_357 max_ammo = 7 diff --git a/code/modules/projectiles/boxes_magazines/internal/revolver.dm b/code/modules/projectiles/boxes_magazines/internal/revolver.dm index ced68ca5cb4..1e891abeef2 100644 --- a/code/modules/projectiles/boxes_magazines/internal/revolver.dm +++ b/code/modules/projectiles/boxes_magazines/internal/revolver.dm @@ -12,7 +12,7 @@ /obj/item/ammo_box/magazine/internal/cylinder/rus357 name = "\improper Russian revolver cylinder" - ammo_type = /obj/item/ammo_casing/a357 + ammo_type = /obj/item/ammo_casing/c357 caliber = CALIBER_357 max_ammo = 6 multiload = FALSE @@ -21,8 +21,8 @@ /obj/item/ammo_box/magazine/internal/cylinder/rus357/Initialize(mapload) . = ..() for (var/i in 1 to max_ammo - 1) - stored_ammo += new /obj/item/ammo_casing/a357/spent(src) - stored_ammo += new /obj/item/ammo_casing/a357(src) + stored_ammo += new /obj/item/ammo_casing/c357/spent(src) + stored_ammo += new /obj/item/ammo_casing/c357(src) /obj/item/ammo_box/magazine/internal/cylinder/peashooter name = "peashooter cylinder" diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index f52bd88cd54..76cf2d18113 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -54,6 +54,10 @@ /// Even snowflakier way to modify projectile wounding bonus/potential for projectiles fired from this gun. var/projectile_wound_bonus = 0 + /// The most reasonable way to modify projectile speed values for projectile fired from this gun. Honest. + /// Lower values are better, higher values are worse. + var/projectile_speed_multiplier = 1 + var/spread = 0 //Spread induced by the gun itself. var/randomspread = 1 //Set to 0 for shotguns. This is used for weapons that don't fire all their bullets at once. diff --git a/code/modules/projectiles/guns/ballistic.dm b/code/modules/projectiles/guns/ballistic.dm index 45c1e9c65ea..93ef571258b 100644 --- a/code/modules/projectiles/guns/ballistic.dm +++ b/code/modules/projectiles/guns/ballistic.dm @@ -477,7 +477,7 @@ /obj/item/gun/ballistic/shoot_live_shot(mob/living/user, pointblank = 0, atom/pbtarget = null, message = 1) if(isnull(chambered)) return ..() - if(can_misfire && chambered.can_misfire != FALSE) + if(can_misfire) misfire_probability += misfire_percentage_increment misfire_probability = clamp(misfire_probability, 0, misfire_probability_cap) if(chambered.can_misfire) diff --git a/code/modules/projectiles/guns/ballistic/automatic.dm b/code/modules/projectiles/guns/ballistic/automatic.dm index 1c158cf4a87..89c6deaa4d2 100644 --- a/code/modules/projectiles/guns/ballistic/automatic.dm +++ b/code/modules/projectiles/guns/ballistic/automatic.dm @@ -352,3 +352,196 @@ actions_types = list() fire_sound = 'sound/items/weapons/laser.ogg' casing_ejector = FALSE + +// NT Battle Rifle // + +/obj/item/gun/ballistic/automatic/battle_rifle + name = "\improper NT BR-38 battle rifle" + desc = "Nanotrasen's prototype security weapon, found exclusively in the hands of their private security teams. Chambered in .38 pistol rounds. \ + Ignore that this makes it technically a carbine. And that it functions as a designated marksman rifle. Marketing weren't being very co-operative \ + when it came time to name the gun. That, and the endless arguments in board rooms about exactly what designation the gun is meant to be." + icon = 'icons/obj/weapons/guns/wide_guns.dmi' + icon_state = "battle_rifle" + inhand_icon_state = "battle_rifle" + base_icon_state = "battle_rifle" + worn_icon = 'icons/mob/clothing/back.dmi' + worn_icon_state = "battle_rifle" + slot_flags = ITEM_SLOT_BACK + + weapon_weight = WEAPON_HEAVY + accepted_magazine_type = /obj/item/ammo_box/magazine/m38 + w_class = WEIGHT_CLASS_BULKY + force = 15 //this thing is kind of oversized, okay? + mag_display = TRUE + projectile_damage_multiplier = 1.2 + projectile_speed_multiplier = 1.2 + fire_delay = 2 + burst_size = 1 + actions_types = list() + spread = 10 //slightly inaccurate in burst fire mode, mostly important for long range shooting + fire_sound = 'sound/items/weapons/thermalpistol.ogg' + suppressor_x_offset = 8 + + /// Determines how many shots we can make before the weapon needs to be maintained. + var/shots_before_degradation = 10 + /// The max number of allowed shots this gun can have before degradation. + var/max_shots_before_degradation = 10 + /// Determines the degradation stage. The higher the value, the more poorly the weapon performs. + var/degradation_stage = 0 + /// Maximum degradation stage. + var/degradation_stage_max = 5 + /// The probability of degradation increasing per shot. + var/degradation_probability = 10 + /// The maximum speed malus for projectile flight speed. Projectiles probably shouldn't move too slowly or else they will start to cause problems. + var/maximum_speed_malus = 0.7 + /// What is our damage multiplier if the gun is emagged? + var/emagged_projectile_damage_multiplier = 1.6 + + /// Whether or not our gun is suffering an EMP related malfunction. + var/emp_malfunction = FALSE + + /// Our timer for when our gun is suffering an extreme malfunction. AKA it is going to explode + var/explosion_timer + + SET_BASE_PIXEL(-8, 0) + +/obj/item/gun/ballistic/automatic/battle_rifle/Initialize(mapload) + . = ..() + AddComponent(/datum/component/scope, range_modifier = 2) + register_context() + +/obj/item/gun/ballistic/automatic/battle_rifle/add_context(atom/source, list/context, obj/item/held_item, mob/user) + . = ..() + + if(held_item?.tool_behaviour == TOOL_MULTITOOL && shots_before_degradation < max_shots_before_degradation) + context[SCREENTIP_CONTEXT_LMB] = "Reset System" + return CONTEXTUAL_SCREENTIP_SET + +/obj/item/gun/ballistic/automatic/battle_rifle/examine_more(mob/user) + . = ..() + . += span_notice("Looking down at the [name], you recall something you read in a promotional pamphlet... ") + + . += span_info("The BR-38 possesses an acceleration rail that launches bullets at higher than typical velocity.\ + This allows even less powerful cartridges to put out significant amounts of stopping power.") + + . += span_notice("However, you also remember some of the rumors... ") + + . += span_notice("In a sour twist of irony for Nanotrasen's historical issues with ballistics-based security weapons, the BR-38 has one significant flaw. \ + It is possible for the weapon to suffer from unintended discombulations due to closed heat distribution systems should the weapon be tampered with. \ + R&D are working on this issue before the weapon sees commercial sales. That, and trying to work out why the weapon's onboard computation systems suffer \ + from so many calculation errors.") + +/obj/item/gun/ballistic/automatic/battle_rifle/examine(mob/user) + . = ..() + if(shots_before_degradation) + . += span_notice("[src] can fire [shots_before_degradation] more times before risking system degradation.") + else + . += span_notice("[src] is in the process of system degradation. It is currently at stage [degradation_stage] of [degradation_stage_max]. Use a multitool on [src] to recalibrate. Alternatively, insert it into a weapon recharger.") + +/obj/item/gun/ballistic/automatic/battle_rifle/update_icon_state() + . = ..() + if(!shots_before_degradation) + inhand_icon_state = "[base_icon_state]-empty" + else + inhand_icon_state = "[base_icon_state]" + +/obj/item/gun/ballistic/automatic/battle_rifle/update_overlays() + . = ..() + if(degradation_stage) + . += "[base_icon_state]_empty" + else if(shots_before_degradation) + var/ratio_for_overlay = CEILING(clamp(shots_before_degradation / max_shots_before_degradation, 0, 1) * 3, 1) + . += "[icon_state]_stage_[ratio_for_overlay]" + +/obj/item/gun/ballistic/automatic/battle_rifle/emp_act(severity) + . = ..() + if (!(. & EMP_PROTECT_SELF) && prob(50 / severity)) + shots_before_degradation = 0 + emp_malfunction = TRUE + attempt_degradation(TRUE) + +/obj/item/gun/ballistic/automatic/battle_rifle/emag_act(mob/user, obj/item/card/emag/emag_card) + . = ..() + if(obj_flags & EMAGGED) + return FALSE + obj_flags |= EMAGGED + projectile_damage_multiplier = emagged_projectile_damage_multiplier + balloon_alert(user, "heat distribution systems deactivated") + return TRUE + +/obj/item/gun/ballistic/automatic/battle_rifle/multitool_act(mob/living/user, obj/item/tool) + if(!tool.use_tool(src, user, 20 SECONDS, volume = 50)) + balloon_alert(user, "interrupted!") + return ITEM_INTERACT_BLOCKING + + emp_malfunction = FALSE + shots_before_degradation = initial(shots_before_degradation) + degradation_stage = initial(degradation_stage) + projectile_speed_multiplier = initial(projectile_speed_multiplier) + fire_delay = initial(fire_delay) + update_appearance() + balloon_alert(user, "system reset") + return ITEM_INTERACT_SUCCESS + +/obj/item/gun/ballistic/automatic/battle_rifle/try_fire_gun(atom/target, mob/living/user, params) + . = ..() + if(!chambered || (chambered && !chambered.loaded_projectile)) + return + + if(shots_before_degradation) + shots_before_degradation -- + return + + else if ((obj_flags & EMAGGED) && degradation_stage == degradation_stage_max && !explosion_timer) + perform_extreme_malfunction(user) + + else + attempt_degradation(FALSE) + + +/obj/item/gun/ballistic/automatic/battle_rifle/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0) + if(chambered.loaded_projectile && prob(75) && (emp_malfunction || degradation_stage == degradation_stage_max)) + balloon_alert_to_viewers("*click*") + playsound(src, dry_fire_sound, dry_fire_sound_volume, TRUE) + return + + return ..() + +/// Proc to handle weapon degradation. Called when attempting to fire or immediately after an EMP takes place. +/obj/item/gun/ballistic/automatic/battle_rifle/proc/attempt_degradation(force_increment = FALSE) + if(!prob(degradation_probability) && !force_increment || degradation_stage == degradation_stage_max) + return //Only update if we actually increment our degradation stage + + degradation_stage = clamp(degradation_stage + (obj_flags & EMAGGED ? 2 : 1), 0, degradation_stage_max) + projectile_speed_multiplier = clamp(initial(projectile_speed_multiplier) + degradation_stage * 0.1, initial(projectile_speed_multiplier), maximum_speed_malus) + fire_delay = initial(fire_delay) + (degradation_stage * 0.5) + do_sparks(1, TRUE, src) + update_appearance() + +/// Called by /obj/machinery/recharger while inserted: attempts to recalibrate our gun but reducing degradation. +/obj/item/gun/ballistic/automatic/battle_rifle/proc/attempt_recalibration(restoring_shots_before_degradation = FALSE, recharge_rate = 1) + emp_malfunction = FALSE + + if(restoring_shots_before_degradation) + shots_before_degradation = clamp(round(shots_before_degradation + recharge_rate, 1), 0, max_shots_before_degradation) + + else + degradation_stage = clamp(degradation_stage - 1, 0, degradation_stage_max) + if(degradation_stage) + projectile_speed_multiplier = clamp(initial(projectile_speed_multiplier) - degradation_stage * 0.1, maximum_speed_malus, initial(projectile_speed_multiplier)) + fire_delay = initial(fire_delay) + (degradation_stage * 0.5) + else + projectile_speed_multiplier = initial(projectile_speed_multiplier) + fire_delay = initial(fire_delay) + + update_appearance() + +/// Proc to handle the countdown for our detonation +/obj/item/gun/ballistic/automatic/battle_rifle/proc/perform_extreme_malfunction(mob/living/user) + balloon_alert(user, "gun is exploding, throw it!") + explosion_timer = addtimer(CALLBACK(src, PROC_REF(fucking_explodes_you)), 5 SECONDS, (TIMER_UNIQUE|TIMER_OVERRIDE)) + playsound(src, 'sound/items/weapons/gun/general/empty_alarm.ogg', 50, FALSE) + +/// proc to handle our detonation +/obj/item/gun/ballistic/automatic/battle_rifle/proc/fucking_explodes_you() + explosion(src, devastation_range = 1, heavy_impact_range = 3, light_impact_range = 6, explosion_cause = src) diff --git a/code/modules/projectiles/guns/energy/energy_gun.dm b/code/modules/projectiles/guns/energy/energy_gun.dm index e826e1392bf..f6421ab7e1b 100644 --- a/code/modules/projectiles/guns/energy/energy_gun.dm +++ b/code/modules/projectiles/guns/energy/energy_gun.dm @@ -136,7 +136,7 @@ inhand_icon_state = "turretlaser" slot_flags = null w_class = WEIGHT_CLASS_HUGE - ammo_type = list(/obj/item/ammo_casing/energy/electrode, /obj/item/ammo_casing/energy/laser) + ammo_type = list(/obj/item/ammo_casing/energy/electrode/ai_turrets, /obj/item/ammo_casing/energy/laser) weapon_weight = WEAPON_HEAVY trigger_guard = TRIGGER_GUARD_NONE ammo_x_offset = 2 diff --git a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm index d542f229914..ba63e41af4c 100644 --- a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm +++ b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm @@ -225,6 +225,11 @@ update_appearance() /obj/projectile/kinetic/on_range() + if(!pressure_decrease_active && !lavaland_equipment_pressure_check(get_turf(src))) + name = "weakened [name]" + damage = damage * pressure_decrease + pressure_decrease_active = TRUE + strike_thing(loc) ..() diff --git a/code/modules/projectiles/guns/magic/arcane_barrage.dm b/code/modules/projectiles/guns/magic/arcane_barrage.dm index 74be54a6323..3534b99675d 100644 --- a/code/modules/projectiles/guns/magic/arcane_barrage.dm +++ b/code/modules/projectiles/guns/magic/arcane_barrage.dm @@ -6,6 +6,7 @@ icon_state = "arcane_barrage" inhand_icon_state = "arcane_barrage" base_icon_state = "arcane_barrage" + icon_angle = 90 lefthand_file = 'icons/mob/inhands/weapons/guns_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/guns_righthand.dmi' slot_flags = null diff --git a/code/modules/projectiles/guns/magic/staff.dm b/code/modules/projectiles/guns/magic/staff.dm index 6a383befa54..e84bb9cd1f3 100644 --- a/code/modules/projectiles/guns/magic/staff.dm +++ b/code/modules/projectiles/guns/magic/staff.dm @@ -3,6 +3,7 @@ ammo_type = /obj/item/ammo_casing/magic/nothing worn_icon_state = null icon_state = "staff" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/staves_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi' item_flags = NEEDS_PERMIT | NO_MAT_REDEMPTION @@ -242,6 +243,7 @@ ammo_type = /obj/item/ammo_casing/magic/spellblade icon_state = "spellblade" inhand_icon_state = "spellblade" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' hitsound = 'sound/items/weapons/rapierhit.ogg' diff --git a/code/modules/projectiles/guns/magic/wand.dm b/code/modules/projectiles/guns/magic/wand.dm index 0a82f44318e..6f59998ba61 100644 --- a/code/modules/projectiles/guns/magic/wand.dm +++ b/code/modules/projectiles/guns/magic/wand.dm @@ -4,6 +4,7 @@ ammo_type = /obj/item/ammo_casing/magic icon_state = "nothingwand" inhand_icon_state = "wand" + icon_angle = -45 lefthand_file = 'icons/mob/inhands/items_lefthand.dmi' righthand_file = 'icons/mob/inhands/items_righthand.dmi' base_icon_state = "nothingwand" diff --git a/code/modules/projectiles/guns/special/meat_hook.dm b/code/modules/projectiles/guns/special/meat_hook.dm index c3462abdd91..2034b400e17 100644 --- a/code/modules/projectiles/guns/special/meat_hook.dm +++ b/code/modules/projectiles/guns/special/meat_hook.dm @@ -8,6 +8,7 @@ ammo_type = /obj/item/ammo_casing/magic/hook icon_state = "hook" inhand_icon_state = "hook" + icon_angle = 45 lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' fire_sound = 'sound/items/weapons/batonextend.ogg' diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 1a21ac4f82d..065a4899fc7 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -420,12 +420,18 @@ // Shooting yourself point-blank if (firer == original) original = null + if (firer == fired_from) + fired_from = null firer = null /obj/projectile/proc/original_deleted(datum/source) SIGNAL_HANDLER original = null +/obj/projectile/proc/fired_from_deleted(datum/source) + SIGNAL_HANDLER + fired_from = null + /obj/projectile/proc/on_ricochet(atom/target) ricochets++ if(!ricochet_auto_aim_angle || !ricochet_auto_aim_range) @@ -752,11 +758,13 @@ /obj/projectile/proc/fire(fire_angle, atom/direct_target) LAZYINITLIST(impacted) - if (fired_from) - SEND_SIGNAL(fired_from, COMSIG_PROJECTILE_BEFORE_FIRE, src, original) if (firer) RegisterSignal(firer, COMSIG_QDELETING, PROC_REF(firer_deleted)) SEND_SIGNAL(firer, COMSIG_PROJECTILE_FIRER_BEFORE_FIRE, src, fired_from, original) + if (fired_from) + if (firer != fired_from) + RegisterSignal(fired_from, COMSIG_QDELETING, PROC_REF(fired_from_deleted)) + SEND_SIGNAL(fired_from, COMSIG_PROJECTILE_BEFORE_FIRE, src, original) if (original) if (firer != original) RegisterSignal(original, COMSIG_QDELETING, PROC_REF(original_deleted)) diff --git a/code/modules/projectiles/projectile/bullets/revolver.dm b/code/modules/projectiles/projectile/bullets/revolver.dm index 096acf5acae..6513be9cfb7 100644 --- a/code/modules/projectiles/projectile/bullets/revolver.dm +++ b/code/modules/projectiles/projectile/bullets/revolver.dm @@ -48,7 +48,6 @@ name = ".38 Rubber bullet" damage = 10 stamina = 30 - weak_against_armour = TRUE ricochets_max = 6 ricochet_incidence_leeway = 0 ricochet_chance = 130 @@ -57,6 +56,16 @@ sharpness = NONE embed_type = null +/obj/projectile/bullet/c38/match/true + name = ".38 True Strike bullet" + damage = 15 + ricochet_auto_aim_range = 3 + ricochet_auto_aim_angle = 100 + ricochet_incidence_leeway = 0 + ricochet_shoots_firer = FALSE + shrapnel_type = null + embed_type = null + // premium .38 ammo from cargo, weak against armor, lower base damage, but excellent at embedding and causing slice wounds at close range /obj/projectile/bullet/c38/dumdum name = ".38 DumDum bullet" @@ -106,9 +115,9 @@ /obj/projectile/bullet/c38/hotshot/on_hit(atom/target, blocked = 0, pierce_hit) . = ..() if(iscarbon(target)) - var/mob/living/carbon/M = target - M.adjust_fire_stacks(6) - M.ignite_mob() + var/mob/living/carbon/criminal_scum = target + criminal_scum.adjust_fire_stacks(6) + criminal_scum.ignite_mob() /obj/projectile/bullet/c38/iceblox //see /obj/projectile/temp for the original code name = ".38 Iceblox bullet" @@ -119,24 +128,24 @@ /obj/projectile/bullet/c38/iceblox/on_hit(atom/target, blocked = 0, pierce_hit) . = ..() if(isliving(target)) - var/mob/living/M = target - M.adjust_bodytemperature(((100-blocked)/100)*(temperature - M.bodytemperature)) + var/mob/living/criminal_scum = target + criminal_scum.adjust_bodytemperature(((100-blocked)/100)*(temperature - criminal_scum.bodytemperature)) // .357 (Syndie Revolver) -/obj/projectile/bullet/a357 +/obj/projectile/bullet/c357 name = ".357 bullet" damage = 60 wound_bonus = -30 -/obj/projectile/bullet/a357/phasic +/obj/projectile/bullet/c357/phasic name = ".357 phasic bullet" icon_state = "gaussphase" damage = 35 armour_penetration = 100 projectile_phasing = PASSTABLE | PASSGLASS | PASSGRILLE | PASSCLOSEDTURF | PASSMACHINE | PASSSTRUCTURE | PASSDOORS -/obj/projectile/bullet/a357/heartseeker +/obj/projectile/bullet/c357/heartseeker name = ".357 heartseeker bullet" icon_state = "gauss" damage = 50 @@ -144,7 +153,7 @@ homing_turn_speed = 120 // admin only really, for ocelot memes -/obj/projectile/bullet/a357/match +/obj/projectile/bullet/c357/match name = ".357 match bullet" ricochets_max = 5 ricochet_chance = 140 diff --git a/code/modules/projectiles/projectile/energy/stun.dm b/code/modules/projectiles/projectile/energy/stun.dm index fb5c041b338..168e7b0a989 100644 --- a/code/modules/projectiles/projectile/energy/stun.dm +++ b/code/modules/projectiles/projectile/energy/stun.dm @@ -2,28 +2,397 @@ name = "electrode" icon_state = "spark" color = COLOR_YELLOW - paralyze = 10 SECONDS - stutter = 10 SECONDS - jitter = 40 SECONDS hitsound = 'sound/items/weapons/taserhit.ogg' - range = 7 + range = 5 + reflectable = FALSE tracer_type = /obj/effect/projectile/tracer/stun muzzle_type = /obj/effect/projectile/muzzle/stun impact_type = /obj/effect/projectile/impact/stun + /// How much stamina damage will the tase deal in 1 second + VAR_PROTECTED/tase_stamina = 60 + /// Electrodes that follow the projectile + VAR_PRIVATE/datum/weakref/beam_weakref + /// We need to track who was the ORIGINAL firer of the projectile specifically to ensure deflects work correctly + VAR_PRIVATE/datum/weakref/initial_firer_weakref -/obj/projectile/energy/electrode/on_hit(atom/target, blocked = 0, pierce_hit) +/obj/projectile/energy/electrode/is_hostile_projectile() + return TRUE + +/obj/projectile/energy/electrode/Destroy() + QDEL_NULL(beam_weakref) + return ..() + +/obj/projectile/energy/electrode/fire(fire_angle, atom/direct_target) + if(firer) + beam_weakref = WEAKREF(firer.Beam( + BeamTarget = src, + icon = 'icons/effects/beam.dmi', + icon_state = "electrodes_nozap", + maxdistance = maximum_range + 1, + beam_type = /obj/effect/ebeam/electrodes_nozap, + )) + initial_firer_weakref = WEAKREF(firer) + return ..() + +/obj/projectile/energy/electrode/on_hit(mob/living/target, blocked = 0, pierce_hit) . = ..() - if(!ismob(target) || blocked >= 100) //Fully blocked by mob or collided with dense object - burst into sparks! - do_sparks(1, TRUE, src) - else if(iscarbon(target)) - var/mob/living/carbon/C = target - C.add_mood_event("tased", /datum/mood_event/tased) - SEND_SIGNAL(C, COMSIG_LIVING_MINOR_SHOCK) - if(HAS_TRAIT(C, TRAIT_HULK)) - C.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" ), forced = "hulk") - else if(!C.check_stun_immunity(CANKNOCKDOWN)) - addtimer(CALLBACK(C, TYPE_PROC_REF(/mob/living/carbon, do_jitter_animation), 20), 0.5 SECONDS) + if(pierce_hit) + return + if(. == BULLET_ACT_BLOCK || blocked >= 100 || !isliving(target)) + return + // we need a "from", otherwise, where does the electricity come from? + if(isnull(fired_from)) + target.visible_message( + span_warning("[src]\s collide with [target] harmlessly[isfloorturf(target.loc) ? ", before falling to [target.loc]" : ""]."), + span_notice("[src] collide with you harmlessly[isfloorturf(target.loc) ? ", before falling to [target.loc]" : ""]."), + ) + return + + do_sparks(1, TRUE, src) + do_sparks(1, TRUE, fired_from) + target.apply_status_effect( + /*type = *//datum/status_effect/tased, + /*taser = */fired_from, + /*firer = */initial_firer_weakref?.resolve() || firer, + /*tase_stamina = */tase_stamina, + /*energy_drain = */STANDARD_CELL_CHARGE * 0.05, + /*electrode_name = */"\the [src]\s", + /*tase_range = */maximum_range + 1, + ) /obj/projectile/energy/electrode/on_range() //to ensure the bolt sparks when it reaches the end of its range if it didn't hit a target yet do_sparks(1, TRUE, src) - ..() + return ..() + +/obj/projectile/energy/electrode/ai_turrets + tase_stamina = 120 + +/// Status effect tracking being tased by someone! +/datum/status_effect/tased + id = "being_tased" + status_type = STATUS_EFFECT_MULTIPLE + alert_type = null + tick_interval = 0.25 SECONDS + on_remove_on_mob_delete = TRUE + /// What atom is tasing us? + VAR_PRIVATE/datum/taser + /// What atom is using the atom tasing us? Sometimes the same as the taser, such as with turrets. + VAR_PRIVATE/atom/movable/firer + /// The beam datum representing the taser electrodes + VAR_PRIVATE/datum/beam/tase_line + /// How much stamina damage does it aim to cause in a second? + VAR_FINAL/stamina_per_second = 80 + /// How much energy does the taser use per tick? + VAR_FINAL/energy_drain = STANDARD_CELL_CHARGE * 0.05 + /// What do we name the electrodes? + VAR_FINAL/electrode_name + /// How far can the taser reach? + VAR_FINAL/tase_range = 6 + +/datum/status_effect/tased/on_creation( + mob/living/new_owner, + datum/fired_from, + atom/movable/firer, + tase_stamina = 80, + energy_drain = STANDARD_CELL_CHARGE * 0.05, + electrode_name = "the electrodes", + tase_range = 6, +) + if(isnull(fired_from) || isnull(firer) || !can_tase_with(fired_from)) + qdel(src) + return + + src.stamina_per_second = tase_stamina + src.energy_drain = energy_drain + src.electrode_name = electrode_name + src.tase_range = tase_range + + . = ..() + if(!.) + return + + set_taser(fired_from) + set_firer(firer) + +/// Checks if the passed atom is captable of being used to tase someone +/datum/status_effect/tased/proc/can_tase_with(datum/with_what) + if(istype(with_what, /obj/item/gun/energy)) + var/obj/item/gun/energy/taser_gun = with_what + if(isnull(taser_gun.cell)) + return FALSE + + else if(istype(with_what, /obj/machinery)) + var/obj/machinery/taser_machine = with_what + if(!taser_machine.is_operational) + return FALSE + + return TRUE + +/// Actually does the tasing with the passed atom +/// Returns TRUE if the tasing was successful, FALSE if it failed +/datum/status_effect/tased/proc/do_tase_with(atom/with_what, seconds_between_ticks) + if(!can_see(taser, owner, 5)) + return FALSE + if(istype(with_what, /obj/item/gun/energy)) + var/obj/item/gun/energy/taser_gun = with_what + if(!taser_gun.cell?.use(energy_drain * seconds_between_ticks)) + return FALSE + taser_gun.update_appearance() + return TRUE + + if(istype(taser, /obj/machinery)) + var/obj/machinery/taser_machine = taser + if(!taser_machine.is_operational) + return FALSE + if(!taser_machine.use_energy(energy_drain * seconds_between_ticks, force = FALSE)) + return FALSE + return TRUE + + if(istype(taser, /obj/item/mecha_parts/mecha_equipment)) + var/obj/item/mecha_parts/mecha_equipment/taser_equipment = taser + if(!taser_equipment.chassis \ + || !taser_equipment.active \ + || taser_equipment.get_integrity() <= 1 \ + || taser_equipment.chassis.is_currently_ejecting \ + || taser_equipment.chassis.equipment_disabled \ + || !taser_equipment.chassis.use_energy(energy_drain * seconds_between_ticks)) + return FALSE + return TRUE + + return TRUE + +/datum/status_effect/tased/on_apply() + if(issilicon(owner) || isbot(owner) || isdrone(owner) || HAS_TRAIT(owner, TRAIT_PIERCEIMMUNE)) + owner.visible_message(span_warning("[capitalize(electrode_name)] fail to catch [owner][isfloorturf(owner.loc) ? ", falling to [owner.loc]" : ""]!")) + return FALSE + + RegisterSignal(owner, COMSIG_LIVING_RESIST, PROC_REF(try_remove_taser)) + RegisterSignal(owner, COMSIG_CARBON_PRE_MISC_HELP, PROC_REF(someome_removing_taser)) + SEND_SIGNAL(owner, COMSIG_LIVING_MINOR_SHOCK) + if(!owner.has_status_effect(type)) + // does not use the status effect api because we snowflake it a bit + owner.throw_alert(type, /atom/movable/screen/alert/tazed) + owner.add_mood_event("tased", /datum/mood_event/tased) + owner.add_movespeed_modifier(/datum/movespeed_modifier/being_tased) + if(!HAS_TRAIT(owner, TRAIT_ANALGESIA)) + owner.emote("scream") + if(HAS_TRAIT(owner, TRAIT_HULK)) + owner.say(pick( + ";RAAAAAAAARGH!", + ";HNNNNNNNNNGGGGGGH!", + ";GWAAAAAAAARRRHHH!", + "NNNNNNNNGGGGGGGGHH!", + ";AAAAAAARRRGH!", + ), forced = "hulk") + if(ishuman(owner)) + var/mob/living/carbon/human/human_owner = owner + human_owner.force_say() + return TRUE + +/datum/status_effect/tased/on_remove() + if(istype(taser, /obj/machinery/porta_turret)) + var/obj/machinery/porta_turret/taser_turret = taser + taser_turret.manual_control = initial(taser_turret.manual_control) + taser_turret.always_up = initial(taser_turret.always_up) + taser_turret.check_should_process() + else if(istype(taser, /obj/machinery/power/emitter)) + var/obj/machinery/power/emitter/taser_emitter = taser + taser_emitter.manual = initial(taser_emitter.manual) + + var/mob/living/mob_firer = firer + if(istype(mob_firer)) + mob_firer.remove_movespeed_modifier(/datum/movespeed_modifier/tasing_someone) + + if(!QDELING(owner) && !owner.has_status_effect(type)) + owner.adjust_jitter_up_to(10 SECONDS, 1 MINUTES) + owner.remove_movespeed_modifier(/datum/movespeed_modifier/being_tased) + owner.clear_alert(type) + + taser = null + firer = null + QDEL_NULL(tase_line) + +/datum/status_effect/tased/tick(seconds_between_ticks) + if(!do_tase_with(taser, seconds_between_ticks)) + end_tase() + return + + owner.adjust_stutter_up_to(10 SECONDS, 20 SECONDS) + owner.adjust_jitter_up_to(20 SECONDS, 30 SECONDS) + if(owner.stat <= SOFT_CRIT) + owner.do_jitter_animation(INFINITY) // maximum POWER + + // You are damp, that's bad when you're being tased + if(owner.fire_stacks < 0) + owner.apply_damage(max(1, owner.fire_stacks * -0.5 * seconds_between_ticks), FIRE, spread_damage = TRUE) + if(SPT_PROB(25, seconds_between_ticks)) + do_sparks(1, FALSE, owner) + + // clumsy people might hit their head while being tased + if(HAS_TRAIT(owner, TRAIT_CLUMSY) && owner.body_position == LYING_DOWN && SPT_PROB(20, seconds_between_ticks)) + owner.apply_damage(10, BRUTE, BODY_ZONE_HEAD) + playsound(owner, 'sound/effects/tableheadsmash.ogg', 75, TRUE) + + // the actual stunning is here + if(!owner.check_stun_immunity(CANSTUN|CANKNOCKDOWN)) + owner.apply_damage(stamina_per_second * seconds_between_ticks, STAMINA) + +/// Sets the passed atom as the "taser" +/datum/status_effect/tased/proc/set_taser(datum/new_taser) + taser = new_taser + RegisterSignals(taser, list(COMSIG_QDELETING, COMSIG_ITEM_DROPPED, COMSIG_ITEM_EQUIPPED), PROC_REF(end_tase)) + RegisterSignal(taser, COMSIG_GUN_TRY_FIRE, PROC_REF(block_firing)) + // snowflake cases! yay! + if(istype(taser, /obj/machinery/porta_turret)) + var/obj/machinery/porta_turret/taser_turret = taser + taser_turret.manual_control = TRUE + taser_turret.always_up = TRUE + else if(istype(taser, /obj/machinery/power/emitter)) + var/obj/machinery/power/emitter/taser_emitter = taser + taser_emitter.manual = TRUE + +/// Sets the passed atom as the person operating the taser, the "firer" +/datum/status_effect/tased/proc/set_firer(atom/new_firer) + firer = new_firer + if(taser != firer) // Turrets, notably, are both + RegisterSignal(firer, COMSIG_QDELETING, PROC_REF(end_tase)) + + RegisterSignal(firer, COMSIG_MOB_CLICKON, PROC_REF(user_cancel_tase)) + + // Ensures AI mobs or turrets don't tase players until they run out of power + var/mob/living/mob_firer = new_firer + if(!istype(mob_firer) || isnull(mob_firer.client)) + // If multiple things are tasing the same mob, give up sooner, so they can select a new target potentially + addtimer(CALLBACK(src, PROC_REF(end_tase)), (owner.has_status_effect(type) != src) ? 2 SECONDS : 8 SECONDS) + if(istype(mob_firer)) + mob_firer.add_movespeed_modifier(/datum/movespeed_modifier/tasing_someone) + + if(firer == owner) + return + + tase_line = firer.Beam( + BeamTarget = owner, + icon = 'icons/effects/beam.dmi', + icon_state = "electrodes", + maxdistance = tase_range, + beam_type = /obj/effect/ebeam/reacting/electrodes, + ) + RegisterSignal(tase_line, COMSIG_BEAM_ENTERED, PROC_REF(disrupt_tase)) + RegisterSignal(tase_line, COMSIG_QDELETING, PROC_REF(end_tase)) + // moves the tase beam up or down if the target moves up or down + tase_line.RegisterSignal(owner, COMSIG_LIVING_SET_BODY_POSITION, TYPE_PROC_REF(/datum/beam, redrawing)) + +/datum/status_effect/tased/proc/block_firing(...) + SIGNAL_HANDLER + return COMPONENT_CANCEL_GUN_FIRE + +/datum/status_effect/tased/proc/user_cancel_tase(mob/living/source, atom/clicked_on, modifiers) + SIGNAL_HANDLER + if(clicked_on != owner) + return NONE + if(LAZYACCESS(modifiers, SHIFT_CLICK)) + return NONE + end_tase() + source.changeNext_move(CLICK_CD_GRABBING) + return COMSIG_MOB_CANCEL_CLICKON + +/datum/status_effect/tased/proc/end_tase(...) + SIGNAL_HANDLER + if(QDELING(src)) + return + owner.visible_message( + span_warning("[capitalize(electrode_name)] stop shocking [owner][isfloorturf(owner.loc) ? ", falling to [owner.loc]" : ""]."), + span_notice("[capitalize(electrode_name)] stop shocking you[isfloorturf(owner.loc) ? ", falling to [owner.loc]" : ""]."), + ) + qdel(src) + +/datum/status_effect/tased/proc/try_remove_taser(datum/source) + SIGNAL_HANDLER + INVOKE_ASYNC(src, PROC_REF(try_remove_taser_async), owner) + +/datum/status_effect/tased/proc/someome_removing_taser(datum/source, mob/living/helper) + SIGNAL_HANDLER + INVOKE_ASYNC(src, PROC_REF(try_remove_taser_async), helper) + return COMPONENT_BLOCK_MISC_HELP + +/datum/status_effect/tased/proc/try_remove_taser_async(mob/living/remover) + if(DOING_INTERACTION(remover, id)) + return + owner.shake_up_animation() + playsound(owner, 'sound/items/weapons/thudswoosh.ogg', 50, TRUE, -1) + remover.visible_message( + span_warning("[owner] tries to remove [electrode_name][remover == owner ? "" : " from [owner]"]!"), + span_notice("You try to remove [electrode_name][remover == owner ? "" : " from [owner]"]!"), + ) + // If embedding was less... difficult to work with, I would make tasers rely on an embedded object to handle this + if(!do_after(remover, 5 SECONDS, owner, extra_checks = CALLBACK(src, PROC_REF(try_remove_taser_checks)), interaction_key = id)) + return + remover.visible_message( + span_warning("[owner] removes [electrode_name] from [remover == owner ? "[owner.p_their()]" : "[owner]'s"] body!"), + span_notice("You remove [electrode_name][remover == owner ? "" : " from [owner]'s body"]!"), + ) + end_tase() + +/datum/status_effect/tased/proc/try_remove_taser_checks() + return !QDELETED(src) + +/datum/status_effect/tased/proc/disrupt_tase(datum/beam/source, obj/effect/ebeam/beam_effect, atom/movable/entering) + SIGNAL_HANDLER + + if(!isliving(entering) || entering == taser || entering == firer || entering == owner) + return + if(entering.pass_flags & (PASSMOB|PASSGRILLE|PASSTABLE)) + return + var/mob/living/disruptor = entering + if(!HAS_TRAIT(entering, TRAIT_CLUMSY) || prob(50)) + if(isliving(firer)) + // taser firer can lie down so people can cross over it! + var/mob/living/firer_living = firer + if(firer_living.body_position != disruptor.body_position) + return + else + // otherwise you can limbo under it + if(disruptor.body_position == LYING_DOWN) + return + disruptor.visible_message( + span_warning("[disruptor] gets tangled in [electrode_name]!"), + span_warning("You get tangled in [electrode_name]!"), + ) + if(!disruptor.check_stun_immunity(CANSTUN|CANKNOCKDOWN)) + disruptor.apply_damage(90, STAMINA) + disruptor.Knockdown(5 SECONDS) + disruptor.adjust_jitter_up_to(10 SECONDS, 30 SECONDS) + qdel(src) + +/// Screen alert for being tased, clicking does a resist +/atom/movable/screen/alert/tazed + name = "Tased!" + desc = "You're being tased! You can click this or resist to attempt to stop it, assuming you've not already collapsed." + icon_state = "stun" + clickable_glow = TRUE + +/atom/movable/screen/alert/tazed/Click(location, control, params) + . = ..() + if(!.) + return + var/mob/living/clicker = usr + clicker.resist() + +/obj/effect/ebeam/electrodes_nozap + name = "electrodes" + alpha = 192 + +/obj/effect/ebeam/reacting/electrodes + name = "electrodes" + light_system = OVERLAY_LIGHT + light_on = TRUE + light_color = COLOR_YELLOW + light_power = 1 + light_range = 1.5 + +// movespeed mods +/datum/movespeed_modifier/tasing_someone + multiplicative_slowdown = 2 + +/datum/movespeed_modifier/being_tased + multiplicative_slowdown = 4 diff --git a/code/modules/reagents/chemistry/reagents/drug_reagents.dm b/code/modules/reagents/chemistry/reagents/drug_reagents.dm index 28c299c87f0..4a4bf137b3c 100644 --- a/code/modules/reagents/chemistry/reagents/drug_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drug_reagents.dm @@ -865,3 +865,54 @@ ) new /obj/structure/bouncy_castle(gored.loc, gored) gored.gib() + +/datum/reagent/drug/syndol + name = "Syndol" + description = "A potent and addictive hallucinogen used by syndicate agents disorient certain targets. \ + It is said that the hallucinations it causes are tailored to the user's fears, but tests have been inconclusive, \ + with subjects in security and assistants reporting wildly different experiences." + color = "#c90000" + taste_description = "metallic" + ph = 7 + overdose_threshold = 10 + chemical_flags = REAGENT_CAN_BE_SYNTHESIZED + addiction_types = list(/datum/addiction/hallucinogens = 20) + /// Track the active hallucination we're giving out so we don't replace it by accident + VAR_PRIVATE/datum/weakref/active_hallucination_weakref + +/datum/reagent/drug/syndol/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) + . = ..() + var/obj/item/organ/liver = affected_mob.get_organ_slot(ORGAN_SLOT_LIVER) + if(isnull(liver) || !(liver.organ_flags & affected_organ_flags)) + return + // non-trivial but not immediately dangerous liver damage + liver.apply_organ_damage(0.5 * REM * seconds_per_tick) + // anti-hallucinogens can counteract the effects + if(HAS_TRAIT(affected_mob, TRAIT_HALLUCINATION_IMMUNE) || affected_mob.reagents.has_reagent(/datum/reagent/medicine/haloperidol, amount = 3, needs_metabolizing = TRUE)) + QDEL_NULL(active_hallucination_weakref) + return + + // and the main event, funny hallucinations + if(active_hallucination_weakref?.resolve()) + return + var/greatest_fear + if(HAS_TRAIT(liver, TRAIT_LAW_ENFORCEMENT_METABOLISM)) + greatest_fear = /datum/hallucination/delusion/preset/syndies + else if(HAS_TRAIT(liver, TRAIT_MAINTENANCE_METABOLISM) || HAS_TRAIT(liver, TRAIT_COMEDY_METABOLISM)) + greatest_fear = /datum/hallucination/delusion/preset/seccies + + if(greatest_fear) + // 5 minutes = 15 units, roughly. we cancel the hallucination early when we exit the mob, anyway + active_hallucination_weakref = WEAKREF(affected_mob.cause_hallucination(greatest_fear, name, duration = 5 MINUTES, skip_nearby = !overdosed)) + else + // if they're just some random schmuck, give them random hallucinations + affected_mob.adjust_hallucinations_up_to(4 SECONDS * REM * seconds_per_tick, 20 SECONDS) + +/datum/reagent/drug/syndol/on_mob_end_metabolize(mob/living/affected_mob) + . = ..() + affected_mob.adjust_hallucinations(-16 SECONDS) + QDEL_NULL(active_hallucination_weakref) + +/datum/reagent/drug/syndol/overdose_start(mob/living/affected_mob) + // no message, just refresh the hallucination + QDEL_NULL(active_hallucination_weakref) diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index d82f8d8d59a..51ca08f6b8d 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -1400,12 +1400,7 @@ if(reac_volume < 1) return - exposed_turf.wash(clean_types) - for(var/am in exposed_turf) - var/atom/movable/movable_content = am - if(ismopable(movable_content)) // Mopables will be cleaned anyways by the turf wash - continue - movable_content.wash(clean_types) + exposed_turf.wash(clean_types, TRUE) for(var/mob/living/basic/slime/exposed_slime in exposed_turf) exposed_slime.adjustToxLoss(rand(5,10)) diff --git a/code/modules/reagents/reagent_containers/cups/bottle.dm b/code/modules/reagents/reagent_containers/cups/bottle.dm index 4c757e0e146..2a81c39886b 100644 --- a/code/modules/reagents/reagent_containers/cups/bottle.dm +++ b/code/modules/reagents/reagent_containers/cups/bottle.dm @@ -37,6 +37,11 @@ desc = "A small bottle of spewium." list_reagents = list(/datum/reagent/toxin/spewium = 30) +/obj/item/reagent_containers/cup/bottle/syndol + name = "syndol bottle" + desc = "A small bottle of syndol." + list_reagents = list(/datum/reagent/drug/syndol = 30) + /obj/item/reagent_containers/cup/bottle/morphine name = "morphine bottle" desc = "A small bottle of morphine." diff --git a/code/modules/reagents/reagent_containers/cups/glassbottle.dm b/code/modules/reagents/reagent_containers/cups/glassbottle.dm index bd1a1cd5a35..93f16140d54 100644 --- a/code/modules/reagents/reagent_containers/cups/glassbottle.dm +++ b/code/modules/reagents/reagent_containers/cups/glassbottle.dm @@ -10,6 +10,7 @@ icon = 'icons/obj/drinks/bottles.dmi' icon_state = "glassbottle" worn_icon_state = "bottle" + icon_angle = 90 fill_icon_thresholds = list(0, 10, 20, 30, 40, 50, 60, 70, 80, 90) custom_price = PAYCHECK_CREW * 1.1 amount_per_transfer_from_this = 10 @@ -699,7 +700,7 @@ if(spillable) return - if(attacking_item.sharpness != SHARP_EDGED) + if(attacking_item.get_sharpness() != SHARP_EDGED) return if(attacking_item != user.get_active_held_item()) //no TK allowed diff --git a/code/modules/religion/sparring/ceremonial_gear.dm b/code/modules/religion/sparring/ceremonial_gear.dm index 2c7e73b5a75..d755704a6d3 100644 --- a/code/modules/religion/sparring/ceremonial_gear.dm +++ b/code/modules/religion/sparring/ceremonial_gear.dm @@ -5,6 +5,7 @@ icon_state = "default" inhand_icon_state = "default" icon = 'icons/obj/weapons/ritual_weapon.dmi' + icon_angle = -45 //does the exact thing we want so heck why not greyscale_config = /datum/greyscale_config/ceremonial_blade @@ -18,8 +19,8 @@ throwforce = 1 //10 wound_bonus = CANT_WOUND // bad for sparring w_class = WEIGHT_CLASS_NORMAL - attack_verb_continuous = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts") - attack_verb_simple = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut") + attack_verb_continuous = list("attacks", "slashes", "slices", "tears", "lacerates", "rips", "dices", "cuts") + attack_verb_simple = list("attack", "slash", "slice", "tear", "lacerate", "rip", "dice", "cut") block_chance = 3 //30 block_sound = 'sound/items/weapons/parry.ogg' sharpness = SHARP_EDGED @@ -27,6 +28,8 @@ material_flags = MATERIAL_EFFECTS | MATERIAL_ADD_PREFIX | MATERIAL_GREYSCALE //doesn't affect stats of the weapon as to avoid gamering your opponent with a dope weapon armor_type = /datum/armor/item_ceremonial_blade resistance_flags = FIRE_PROOF + var/list/alt_continuous = list("stabs", "pierces", "impales") + var/list/alt_simple = list("stab", "pierce", "impale") /datum/armor/item_ceremonial_blade fire = 100 @@ -34,6 +37,9 @@ /obj/item/ceremonial_blade/Initialize(mapload) . = ..() + alt_continuous = string_list(alt_continuous) + alt_simple = string_list(alt_simple) + AddComponent(/datum/component/alternative_sharpness, SHARP_POINTY, alt_continuous, alt_simple) AddComponent(/datum/component/butchering, \ speed = 4 SECONDS, \ effectiveness = 105, \ diff --git a/code/modules/research/designs/autolathe/security_designs.dm b/code/modules/research/designs/autolathe/security_designs.dm index b3bc0d8101d..7fbf06e122f 100644 --- a/code/modules/research/designs/autolathe/security_designs.dm +++ b/code/modules/research/designs/autolathe/security_designs.dm @@ -179,7 +179,7 @@ id = "a357" build_type = AUTOLATHE materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT*2) - build_path = /obj/item/ammo_casing/a357 + build_path = /obj/item/ammo_casing/c357 category = list( RND_CATEGORY_HACKED, RND_CATEGORY_WEAPONS + RND_SUBCATEGORY_WEAPONS_AMMO, diff --git a/code/modules/research/designs/weapon_designs.dm b/code/modules/research/designs/weapon_designs.dm index ebda0f1e3b4..872821e9827 100644 --- a/code/modules/research/designs/weapon_designs.dm +++ b/code/modules/research/designs/weapon_designs.dm @@ -3,7 +3,7 @@ ///////////////////////////////////////// /datum/design/c38/sec - id = "sec_38" + id = "c38_sec" build_type = PROTOLATHE | AWAY_LATHE category = list( RND_CATEGORY_WEAPONS + RND_SUBCATEGORY_WEAPONS_AMMO @@ -16,7 +16,11 @@ desc = "Designed to quickly reload revolvers. TRAC bullets embed a tracking implant within the target's body. The implant's signal is incompatible with teleporters." id = "c38_trac" build_type = PROTOLATHE | AWAY_LATHE - materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 10, /datum/material/silver =SHEET_MATERIAL_AMOUNT * 2.5, /datum/material/gold =HALF_SHEET_MATERIAL_AMOUNT) + materials = list( + /datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT * 10, + /datum/material/silver = HALF_SHEET_MATERIAL_AMOUNT * 2.5, + /datum/material/gold = HALF_SHEET_MATERIAL_AMOUNT, + ) build_path = /obj/item/ammo_box/c38/trac category = list( RND_CATEGORY_WEAPONS + RND_SUBCATEGORY_WEAPONS_AMMO @@ -28,7 +32,10 @@ desc = "Designed to quickly reload revolvers. Hot Shot bullets contain an incendiary payload." id = "c38_hotshot" build_type = PROTOLATHE | AWAY_LATHE - materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 10, /datum/material/plasma = SHEET_MATERIAL_AMOUNT * 2.5) + materials = list( + /datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT * 10, + /datum/material/plasma = HALF_SHEET_MATERIAL_AMOUNT * 2.5, + ) build_path = /obj/item/ammo_box/c38/hotshot category = list( RND_CATEGORY_WEAPONS + RND_SUBCATEGORY_WEAPONS_AMMO @@ -40,7 +47,10 @@ desc = "Designed to quickly reload revolvers. Iceblox bullets contain a cryogenic payload." id = "c38_iceblox" build_type = PROTOLATHE | AWAY_LATHE - materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 10, /datum/material/plasma = SHEET_MATERIAL_AMOUNT * 2.5) + materials = list( + /datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT * 10, + /datum/material/plasma = HALF_SHEET_MATERIAL_AMOUNT * 2.5, + ) build_path = /obj/item/ammo_box/c38/iceblox category = list( RND_CATEGORY_WEAPONS + RND_SUBCATEGORY_WEAPONS_AMMO @@ -52,13 +62,125 @@ desc = "Designed to quickly reload revolvers. Rubber bullets are bouncy and less-than-lethal." id = "c38_rubber" build_type = PROTOLATHE | AWAY_LATHE - materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 10) + materials = list(/datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT * 10) build_path = /obj/item/ammo_box/c38/match/bouncy category = list( RND_CATEGORY_WEAPONS + RND_SUBCATEGORY_WEAPONS_AMMO ) departmental_flags = DEPARTMENT_BITFLAG_SECURITY +/datum/design/c38_true + name = "Speedloader (.38 True Strike) (Lethal)" + desc = "Designed to quickly reload revolvers. Bullets bounce towards new targets with surprising accuracy." + id = "c38_true_strike" + build_type = PROTOLATHE | AWAY_LATHE + materials = list( + /datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT * 10, + /datum/material/bluespace = HALF_SHEET_MATERIAL_AMOUNT, + ) + build_path = /obj/item/ammo_box/magazine/m38/true + category = list( + RND_CATEGORY_WEAPONS + RND_SUBCATEGORY_WEAPONS_AMMO + ) + departmental_flags = DEPARTMENT_BITFLAG_SECURITY + +/datum/design/c38_mag + name = "Magazine (.38) (Lethal)" + desc = "Designed to tactically reload a NT BR-38 Battle Rifle. Less powerful by design, guns chambered in .38 caliber rounds are still quite popular for use by police forces, \ + private security firms and organizations unable to access energy-based nonlethal weaponry. The lower (relative) penetrative power is useful for preventing potential hull damage \ + aboard space stations and shuttles." + id = "c38_mag" + build_type = PROTOLATHE | AWAY_LATHE + materials = list( + /datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT * 30, + /datum/material/plastic = HALF_SHEET_MATERIAL_AMOUNT * 3, + ) + build_path = /obj/item/ammo_box/magazine/m38 + category = list( + RND_CATEGORY_WEAPONS + RND_SUBCATEGORY_WEAPONS_AMMO + ) + departmental_flags = DEPARTMENT_BITFLAG_SECURITY + +/datum/design/c38_trac_mag + name = "Magazine (.38 TRAC) (Less Lethal)" + desc = "Designed to tactically reload a NT BR-38 Battle Rifle. TRAC bullets embed a tracking implant within the target's body. The implant's signal is incompatible with teleporters." + id = "c38_trac_mag" + build_type = PROTOLATHE | AWAY_LATHE + materials = list( + /datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT * 30, + /datum/material/silver = HALF_SHEET_MATERIAL_AMOUNT * 2.5, + /datum/material/gold = HALF_SHEET_MATERIAL_AMOUNT, + /datum/material/plastic = HALF_SHEET_MATERIAL_AMOUNT * 3, + ) + build_path = /obj/item/ammo_box/magazine/m38/trac + category = list( + RND_CATEGORY_WEAPONS + RND_SUBCATEGORY_WEAPONS_AMMO + ) + departmental_flags = DEPARTMENT_BITFLAG_SECURITY + +/datum/design/c38_hotshot_mag + name = "Magazine (.38 Hot Shot) (Very Lethal)" + desc = "Designed to tactically reload a NT BR-38 Battle Rifle. Hot Shot bullets contain an incendiary payload." + id = "c38_hotshot_mag" + build_type = PROTOLATHE | AWAY_LATHE + materials = list( + /datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT * 30, + /datum/material/plasma = HALF_SHEET_MATERIAL_AMOUNT * 2.5, + /datum/material/plastic = HALF_SHEET_MATERIAL_AMOUNT * 3, + ) + build_path = /obj/item/ammo_box/magazine/m38/hotshot + category = list( + RND_CATEGORY_WEAPONS + RND_SUBCATEGORY_WEAPONS_AMMO + ) + departmental_flags = DEPARTMENT_BITFLAG_SECURITY + +/datum/design/c38_iceblox_mag + name = "Magazine (.38 Iceblox) (Lethal/Very Lethal (Lizardpeople))" + desc = "Designed to tactically reload a NT BR-38 Battle Rifle. Iceblox bullets contain a cryogenic payload." + id = "c38_iceblox_mag" + build_type = PROTOLATHE | AWAY_LATHE + materials = list( + /datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT * 30, + /datum/material/plasma = HALF_SHEET_MATERIAL_AMOUNT * 2.5, + /datum/material/plastic = HALF_SHEET_MATERIAL_AMOUNT * 3, + ) + build_path = /obj/item/ammo_box/magazine/m38/iceblox + category = list( + RND_CATEGORY_WEAPONS + RND_SUBCATEGORY_WEAPONS_AMMO + ) + departmental_flags = DEPARTMENT_BITFLAG_SECURITY + +/datum/design/c38_rubber_mag + name = "Magazine (.38 Rubber) (Less Lethal)" + desc = "Designed to tactically reload a NT BR-38 Battle Rifle. Rubber bullets are bouncy and less-than-lethal." + id = "c38_rubber_mag" + build_type = PROTOLATHE | AWAY_LATHE + materials = list( + /datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT * 30, + /datum/material/plastic = HALF_SHEET_MATERIAL_AMOUNT * 3, + ) + build_path = /obj/item/ammo_box/magazine/m38/match/bouncy + category = list( + RND_CATEGORY_WEAPONS + RND_SUBCATEGORY_WEAPONS_AMMO + ) + departmental_flags = DEPARTMENT_BITFLAG_SECURITY + +/datum/design/c38_true_mag + name = "Magazine (.38 Truee Strike) (Lethal)" + desc = "Designed to tactically reload a NT BR-38 Battle Rifle. Bullets bounce towards new targets with surprising accuracy." + id = "c38_true_strike_mag" + build_type = PROTOLATHE | AWAY_LATHE + materials = list( + /datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT * 30, + /datum/material/plastic = HALF_SHEET_MATERIAL_AMOUNT * 3, + /datum/material/bluespace = HALF_SHEET_MATERIAL_AMOUNT, + ) + build_path = /obj/item/ammo_box/magazine/m38/true + category = list( + RND_CATEGORY_WEAPONS + RND_SUBCATEGORY_WEAPONS_AMMO + ) + departmental_flags = DEPARTMENT_BITFLAG_SECURITY + /datum/design/rubbershot/sec id = "sec_rshot" desc = "Rubbershot shotgun shells. Fires a cloud of pellets. Rubber bullets are bouncy and less-than-lethal." diff --git a/code/modules/research/part_replacer.dm b/code/modules/research/part_replacer.dm new file mode 100644 index 00000000000..6c5bb5f6464 --- /dev/null +++ b/code/modules/research/part_replacer.dm @@ -0,0 +1,186 @@ +///RPED. Allows installing & exchaging parts on machines +/obj/item/storage/part_replacer + name = "rapid part exchange device" + desc = "Special mechanical module made to store, sort, and apply standard machine parts." + icon_state = "RPED" + inhand_icon_state = "RPED" + worn_icon_state = "RPED" + lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi' + righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi' + w_class = WEIGHT_CLASS_HUGE + storage_type = /datum/storage/rped + +/obj/item/storage/part_replacer/interact_with_atom(obj/attacked_object, mob/living/user, list/modifiers) + if(user.combat_mode || !istype(attacked_object) || HAS_TRAIT(attacked_object, TRAIT_COMBAT_MODE_SKIP_INTERACTION)) + return ITEM_INTERACT_SKIP_TO_ATTACK + + //its very important to NOT block so frames can still interact with it + if(!ismachinery(attacked_object) || istype(attacked_object, /obj/machinery/computer)) + return NONE + + var/obj/machinery/attacked_machinery = attacked_object + if(!LAZYLEN(attacked_machinery.component_parts)) + return ITEM_INTERACT_FAILURE + + return attacked_machinery.exchange_parts(user, src) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_FAILURE + +///Plays the sound for RPED exhanging or installing parts. +/obj/item/storage/part_replacer/proc/play_rped_sound() + playsound(src, 'sound/items/tools/rped.ogg', 40, TRUE) + +/** + * Gets parts sorted in order of their tier + * Arguments + * + * * ignore_stacks - should the final list contain stacks + */ +/obj/item/storage/part_replacer/proc/get_sorted_parts(ignore_stacks = FALSE) + RETURN_TYPE(/list/obj/item) + + var/list/obj/item/part_list = list() + //Assemble a list of current parts, then sort them by their rating! + for(var/obj/item/component_part in contents) + //No need to put circuit boards in this list or stacks when exchanging parts + if(istype(component_part, /obj/item/circuitboard) || (ignore_stacks && istype(component_part, /obj/item/stack))) + continue + part_list += component_part + //Sort the parts. This ensures that higher tier items are applied first. + sortTim(part_list, GLOBAL_PROC_REF(cmp_rped_sort)) + + return part_list + +///Bluespace RPED. Allows exchanging parts from a distance & through cameras +/obj/item/storage/part_replacer/bluespace + name = "bluespace rapid part exchange device" + desc = "A version of the RPED that allows for replacement of parts and scanning from a distance, along with higher capacity for parts." + icon_state = "BS_RPED" + inhand_icon_state = "BS_RPED" + w_class = WEIGHT_CLASS_NORMAL + storage_type = /datum/storage/rped/bluespace + +/obj/item/storage/part_replacer/bluespace/Initialize(mapload) + . = ..() + + RegisterSignal(src, COMSIG_ATOM_ENTERED, PROC_REF(on_part_entered)) + RegisterSignal(src, COMSIG_ATOM_EXITED, PROC_REF(on_part_exited)) + +/obj/item/storage/part_replacer/bluespace/interact_with_atom(obj/attacked_object, mob/living/user, list/modifiers) + . = ..() + if(. & ITEM_INTERACT_ANY_BLOCKER) + user.Beam(attacked_object, icon_state = "rped_upgrade", time = 0.5 SECONDS) + +/obj/item/storage/part_replacer/bluespace/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + return interact_with_atom(interacting_with, user, modifiers) + +/obj/item/storage/part_replacer/bluespace/play_rped_sound() + if(prob(1)) + playsound(src, 'sound/items/pshoom/pshoom_2.ogg', 40, TRUE) + return + playsound(src, 'sound/items/pshoom/pshoom.ogg', 40, TRUE) + +/** + * Signal handler for when a part has been inserted into the BRPED. + * + * If the inserted item is a rigged or corrupted cell, does some logging. + * + * If it has a reagent holder, clears the reagents and registers signals to prevent new + * reagents being added and registers clean up signals on inserted item's removal from + * the BRPED. + */ +/obj/item/storage/part_replacer/bluespace/proc/on_part_entered(datum/source, obj/item/inserted_component) + SIGNAL_HANDLER + + if(istype(inserted_component, /obj/item/stock_parts/power_store)) + var/obj/item/stock_parts/power_store/inserted_cell = inserted_component + if(inserted_cell.rigged || inserted_cell.corrupted) + message_admins("[ADMIN_LOOKUPFLW(usr)] has inserted rigged/corrupted [inserted_cell] into [src].") + usr.log_message("has inserted rigged/corrupted [inserted_cell] into [src].", LOG_GAME) + usr.log_message("inserted rigged/corrupted [inserted_cell] into [src]", LOG_ATTACK) + return + + if(inserted_component.reagents) + if(length(inserted_component.reagents.reagent_list)) + inserted_component.reagents.clear_reagents() + to_chat(usr, span_notice("[src] churns as [inserted_component] has its reagents emptied into bluespace.")) + RegisterSignal(inserted_component.reagents, COMSIG_REAGENTS_PRE_ADD_REAGENT, PROC_REF(on_insered_component_reagent_pre_add)) + +/** + * Signal handler for when the reagents datum of an inserted part has reagents added to it. + * + * Registers the PRE_ADD variant which allows the signal handler to stop reagents being + * added. + * + * Simply returns COMPONENT_CANCEL_REAGENT_ADD. We never want to allow people to add + * reagents to beakers in BRPEDs as they can then be used for spammable remote bombing. + */ +/obj/item/storage/part_replacer/bluespace/proc/on_insered_component_reagent_pre_add(datum/source, reagent, amount, reagtemp, data, no_react) + SIGNAL_HANDLER + + return COMPONENT_CANCEL_REAGENT_ADD + +/** + * Signal handler for a part is removed from the BRPED. + * + * Does signal registration cleanup on its reagents, if it has any. + */ +/obj/item/storage/part_replacer/bluespace/proc/on_part_exited(datum/source, obj/item/removed_component) + SIGNAL_HANDLER + + if(removed_component.reagents) + UnregisterSignal(removed_component.reagents, COMSIG_REAGENTS_PRE_ADD_REAGENT) + +//RPED with tiered contents +/obj/item/storage/part_replacer/bluespace/tier1/PopulateContents() + for(var/i in 1 to 10) + new /obj/item/stock_parts/capacitor(src) + new /obj/item/stock_parts/scanning_module(src) + new /obj/item/stock_parts/servo(src) + new /obj/item/stock_parts/micro_laser(src) + new /obj/item/stock_parts/matter_bin(src) + new /obj/item/stock_parts/power_store/cell/high(src) + +/obj/item/storage/part_replacer/bluespace/tier2/PopulateContents() + for(var/i in 1 to 10) + new /obj/item/stock_parts/capacitor/adv(src) + new /obj/item/stock_parts/scanning_module/adv(src) + new /obj/item/stock_parts/servo/nano(src) + new /obj/item/stock_parts/micro_laser/high(src) + new /obj/item/stock_parts/matter_bin/adv(src) + new /obj/item/stock_parts/power_store/cell/super(src) + +/obj/item/storage/part_replacer/bluespace/tier3/PopulateContents() + for(var/i in 1 to 10) + new /obj/item/stock_parts/capacitor/super(src) + new /obj/item/stock_parts/scanning_module/phasic(src) + new /obj/item/stock_parts/servo/pico(src) + new /obj/item/stock_parts/micro_laser/ultra(src) + new /obj/item/stock_parts/matter_bin/super(src) + new /obj/item/stock_parts/power_store/cell/hyper(src) + +/obj/item/storage/part_replacer/bluespace/tier4/PopulateContents() + for(var/i in 1 to 10) + new /obj/item/stock_parts/capacitor/quadratic(src) + new /obj/item/stock_parts/scanning_module/triphasic(src) + new /obj/item/stock_parts/servo/femto(src) + new /obj/item/stock_parts/micro_laser/quadultra(src) + new /obj/item/stock_parts/matter_bin/bluespace(src) + new /obj/item/stock_parts/power_store/cell/bluespace(src) + +//used in a cargo crate +/obj/item/storage/part_replacer/cargo/PopulateContents() + for(var/i in 1 to 10) + new /obj/item/stock_parts/capacitor(src) + new /obj/item/stock_parts/scanning_module(src) + new /obj/item/stock_parts/servo(src) + new /obj/item/stock_parts/micro_laser(src) + new /obj/item/stock_parts/matter_bin(src) + +///Cyborg variant +/obj/item/storage/part_replacer/cyborg + name = "rapid part exchange device" + desc = "Special mechanical module made to store, sort, and apply standard machine parts. This one has an extra large compartment for more parts." + icon_state = "borgrped" + inhand_icon_state = "RPED" + lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi' + righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi' + storage_type = /datum/storage/rped/bluespace diff --git a/code/modules/research/stock_parts.dm b/code/modules/research/stock_parts.dm index 95839344469..beafc7ba260 100644 --- a/code/modules/research/stock_parts.dm +++ b/code/modules/research/stock_parts.dm @@ -1,218 +1,6 @@ /*Power cells are in code\modules\power\cell.dm If you create T5+ please take a pass at mech_fabricator.dm. The parts being good enough allows it to go into minus values and create materials out of thin air when printing stuff.*/ -/obj/item/storage/part_replacer - name = "rapid part exchange device" - desc = "Special mechanical module made to store, sort, and apply standard machine parts." - icon_state = "RPED" - inhand_icon_state = "RPED" - worn_icon_state = "RPED" - lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi' - righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi' - w_class = WEIGHT_CLASS_HUGE - var/works_from_distance = FALSE - var/pshoom_or_beepboopblorpzingshadashwoosh = 'sound/items/tools/rped.ogg' - var/alt_sound = null - -/obj/item/storage/part_replacer/Initialize(mapload) - . = ..() - create_storage(storage_type = /datum/storage/rped) - -/obj/item/storage/part_replacer/proc/part_replace_action(obj/attacked_object, mob/living/user) - if(!ismachinery(attacked_object) || istype(attacked_object, /obj/machinery/computer)) - return FALSE - - var/obj/machinery/attacked_machinery = attacked_object - if(!LAZYLEN(attacked_machinery.component_parts)) - return FALSE - - if(attacked_machinery.exchange_parts(user, src) && works_from_distance) - user.Beam(attacked_machinery, icon_state = "rped_upgrade", time = 0.5 SECONDS) - return TRUE - -/obj/item/storage/part_replacer/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) - if(part_replace_action(interacting_with, user)) - return ITEM_INTERACT_SUCCESS - return NONE - -/obj/item/storage/part_replacer/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) - if(!works_from_distance) - return NONE - if(part_replace_action(interacting_with, user)) - user.Beam(interacting_with, icon_state = "rped_upgrade", time = 0.5 SECONDS) - return ITEM_INTERACT_SUCCESS - if(istype(interacting_with, /obj/structure/frame)) - // Cursed snowflake but we need to handle frame ranged interaction here - // Likely no longer necessary with the new framework, revisit later - interacting_with.item_interaction(user, src) - user.Beam(interacting_with, icon_state = "rped_upgrade", time = 0.5 SECONDS) - return ITEM_INTERACT_SUCCESS - return NONE - -/obj/item/storage/part_replacer/proc/play_rped_sound() - //Plays the sound for RPED exhanging or installing parts. - if(alt_sound && prob(1)) - playsound(src, alt_sound, 40, TRUE) - else - playsound(src, pshoom_or_beepboopblorpzingshadashwoosh, 40, TRUE) - -/obj/item/storage/part_replacer/bluespace - name = "bluespace rapid part exchange device" - desc = "A version of the RPED that allows for replacement of parts and scanning from a distance, along with higher capacity for parts." - icon_state = "BS_RPED" - inhand_icon_state = "BS_RPED" - w_class = WEIGHT_CLASS_NORMAL - works_from_distance = TRUE - pshoom_or_beepboopblorpzingshadashwoosh = 'sound/items/pshoom/pshoom.ogg' - alt_sound = 'sound/items/pshoom/pshoom_2.ogg' - -/obj/item/storage/part_replacer/bluespace/Initialize(mapload) - . = ..() - - atom_storage.max_slots = 400 - atom_storage.max_total_storage = 800 - atom_storage.max_specific_storage = WEIGHT_CLASS_GIGANTIC - - RegisterSignal(src, COMSIG_ATOM_ENTERED, PROC_REF(on_part_entered)) - RegisterSignal(src, COMSIG_ATOM_EXITED, PROC_REF(on_part_exited)) - -/** - * Signal handler for when a part has been inserted into the BRPED. - * - * If the inserted item is a rigged or corrupted cell, does some logging. - * - * If it has a reagent holder, clears the reagents and registers signals to prevent new - * reagents being added and registers clean up signals on inserted item's removal from - * the BRPED. - */ -/obj/item/storage/part_replacer/bluespace/proc/on_part_entered(datum/source, obj/item/inserted_component) - SIGNAL_HANDLER - - if(istype(inserted_component, /obj/item/stock_parts/power_store)) - var/obj/item/stock_parts/power_store/inserted_cell = inserted_component - if(inserted_cell.rigged || inserted_cell.corrupted) - message_admins("[ADMIN_LOOKUPFLW(usr)] has inserted rigged/corrupted [inserted_cell] into [src].") - usr.log_message("has inserted rigged/corrupted [inserted_cell] into [src].", LOG_GAME) - usr.log_message("inserted rigged/corrupted [inserted_cell] into [src]", LOG_ATTACK) - return - - if(inserted_component.reagents) - if(length(inserted_component.reagents.reagent_list)) - inserted_component.reagents.clear_reagents() - to_chat(usr, span_notice("[src] churns as [inserted_component] has its reagents emptied into bluespace.")) - RegisterSignal(inserted_component.reagents, COMSIG_REAGENTS_PRE_ADD_REAGENT, PROC_REF(on_insered_component_reagent_pre_add)) - -/** - * Signal handler for when the reagents datum of an inserted part has reagents added to it. - * - * Registers the PRE_ADD variant which allows the signal handler to stop reagents being - * added. - * - * Simply returns COMPONENT_CANCEL_REAGENT_ADD. We never want to allow people to add - * reagents to beakers in BRPEDs as they can then be used for spammable remote bombing. - */ -/obj/item/storage/part_replacer/bluespace/proc/on_insered_component_reagent_pre_add(datum/source, reagent, amount, reagtemp, data, no_react) - SIGNAL_HANDLER - - return COMPONENT_CANCEL_REAGENT_ADD - -/** - * Signal handler for a part is removed from the BRPED. - * - * Does signal registration cleanup on its reagents, if it has any. - */ -/obj/item/storage/part_replacer/bluespace/proc/on_part_exited(datum/source, obj/item/removed_component) - SIGNAL_HANDLER - - if(removed_component.reagents) - UnregisterSignal(removed_component.reagents, COMSIG_REAGENTS_PRE_ADD_REAGENT) - - -/obj/item/storage/part_replacer/bluespace/tier1 - -/obj/item/storage/part_replacer/bluespace/tier1/PopulateContents() - for(var/i in 1 to 10) - new /obj/item/stock_parts/capacitor(src) - new /obj/item/stock_parts/scanning_module(src) - new /obj/item/stock_parts/servo(src) - new /obj/item/stock_parts/micro_laser(src) - new /obj/item/stock_parts/matter_bin(src) - new /obj/item/stock_parts/power_store/cell/high(src) - -/obj/item/storage/part_replacer/bluespace/tier2 - -/obj/item/storage/part_replacer/bluespace/tier2/PopulateContents() - for(var/i in 1 to 10) - new /obj/item/stock_parts/capacitor/adv(src) - new /obj/item/stock_parts/scanning_module/adv(src) - new /obj/item/stock_parts/servo/nano(src) - new /obj/item/stock_parts/micro_laser/high(src) - new /obj/item/stock_parts/matter_bin/adv(src) - new /obj/item/stock_parts/power_store/cell/super(src) - -/obj/item/storage/part_replacer/bluespace/tier3 - -/obj/item/storage/part_replacer/bluespace/tier3/PopulateContents() - for(var/i in 1 to 10) - new /obj/item/stock_parts/capacitor/super(src) - new /obj/item/stock_parts/scanning_module/phasic(src) - new /obj/item/stock_parts/servo/pico(src) - new /obj/item/stock_parts/micro_laser/ultra(src) - new /obj/item/stock_parts/matter_bin/super(src) - new /obj/item/stock_parts/power_store/cell/hyper(src) - -/obj/item/storage/part_replacer/bluespace/tier4 - -/obj/item/storage/part_replacer/bluespace/tier4/PopulateContents() - for(var/i in 1 to 10) - new /obj/item/stock_parts/capacitor/quadratic(src) - new /obj/item/stock_parts/scanning_module/triphasic(src) - new /obj/item/stock_parts/servo/femto(src) - new /obj/item/stock_parts/micro_laser/quadultra(src) - new /obj/item/stock_parts/matter_bin/bluespace(src) - new /obj/item/stock_parts/power_store/cell/bluespace(src) - -/obj/item/storage/part_replacer/cargo //used in a cargo crate - -/obj/item/storage/part_replacer/cargo/PopulateContents() - for(var/i in 1 to 10) - new /obj/item/stock_parts/capacitor(src) - new /obj/item/stock_parts/scanning_module(src) - new /obj/item/stock_parts/servo(src) - new /obj/item/stock_parts/micro_laser(src) - new /obj/item/stock_parts/matter_bin(src) - -/obj/item/storage/part_replacer/cyborg - name = "rapid part exchange device" - desc = "Special mechanical module made to store, sort, and apply standard machine parts. This one has an extra large compartment for more parts." - icon_state = "borgrped" - inhand_icon_state = "RPED" - lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi' - righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi' - -/obj/item/storage/part_replacer/cyborg/Initialize(mapload) - . = ..() - atom_storage.max_slots = 400 - atom_storage.max_total_storage = 800 - atom_storage.max_specific_storage = WEIGHT_CLASS_GIGANTIC - -/obj/item/storage/part_replacer/proc/get_sorted_parts(ignore_stacks = FALSE) - var/list/part_list = list() - //Assemble a list of current parts, then sort them by their rating! - for(var/obj/item/component_part in contents) - //No need to put circuit boards in this list or stacks when exchanging parts - if(istype(component_part, /obj/item/circuitboard) || (ignore_stacks && istype(component_part, /obj/item/stack))) - continue - part_list += component_part - //Sort the parts. This ensures that higher tier items are applied first. - sortTim(part_list, GLOBAL_PROC_REF(cmp_rped_sort)) - return part_list - -/proc/cmp_rped_sort(obj/item/first_item, obj/item/second_item) - /** - * even though stacks aren't stock parts, get_part_rating() is defined on the item level (see /obj/item/proc/get_part_rating()) and defaults to returning 0. - */ - return second_item.get_part_rating() - first_item.get_part_rating() /obj/item/stock_parts name = "stock part" diff --git a/code/modules/research/techweb/nodes/cyborg_nodes.dm b/code/modules/research/techweb/nodes/cyborg_nodes.dm index eda52defa5e..781ed343672 100644 --- a/code/modules/research/techweb/nodes/cyborg_nodes.dm +++ b/code/modules/research/techweb/nodes/cyborg_nodes.dm @@ -161,7 +161,6 @@ "implantcase", "implanter", "locator", - "c38_trac", ) research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS) announce_channels = list(RADIO_CHANNEL_SECURITY, RADIO_CHANNEL_MEDICAL) diff --git a/code/modules/research/techweb/nodes/security_nodes.dm b/code/modules/research/techweb/nodes/security_nodes.dm index 97d2036207c..02679b4280e 100644 --- a/code/modules/research/techweb/nodes/security_nodes.dm +++ b/code/modules/research/techweb/nodes/security_nodes.dm @@ -7,7 +7,9 @@ "toy_armblade", "toygun", "c38_rubber", - "sec_38", + "c38_rubber_mag", + "c38_sec", + "c38_mag", "capbox", "foam_dart", "sec_beanbag_slug", @@ -80,7 +82,13 @@ prereq_ids = list(TECHWEB_NODE_EXPLOSIVES) design_ids = list( "c38_hotshot", + "c38_hotshot_mag", "c38_iceblox", + "c38_iceblox_mag", + "c38_trac", + "c38_trac_mag", + "c38_true_strike", + "c38_true_strike_mag", "techshotshell", ) research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_4_POINTS) diff --git a/code/modules/research/xenobiology/crossbreeding/_weapons.dm b/code/modules/research/xenobiology/crossbreeding/_weapons.dm index 3cc46b9be32..c73ef832c54 100644 --- a/code/modules/research/xenobiology/crossbreeding/_weapons.dm +++ b/code/modules/research/xenobiology/crossbreeding/_weapons.dm @@ -87,6 +87,7 @@ Slimecrossing Weapons icon = 'icons/obj/science/slimecrossing.dmi' icon_state = "bloodgun" inhand_icon_state = "bloodgun" + icon_angle = 180 lefthand_file = 'icons/mob/inhands/weapons/guns_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/guns_righthand.dmi' item_flags = ABSTRACT | DROPDEL diff --git a/code/modules/surgery/tools.dm b/code/modules/surgery/tools.dm index 2f14388fd49..04fa06dcfaa 100644 --- a/code/modules/surgery/tools.dm +++ b/code/modules/surgery/tools.dm @@ -4,6 +4,7 @@ icon = 'icons/obj/medical/surgery_tools.dmi' icon_state = "retractor" inhand_icon_state = "retractor" + icon_angle = 45 lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT*3, /datum/material/glass =SHEET_MATERIAL_AMOUNT * 1.5) @@ -25,6 +26,7 @@ /obj/item/retractor/cyborg icon = 'icons/mob/silicon/robot_items.dmi' icon_state = "toolkit_medborg_retractor" + icon_angle = 45 /obj/item/hemostat name = "hemostat" @@ -32,6 +34,7 @@ icon = 'icons/obj/medical/surgery_tools.dmi' icon_state = "hemostat" inhand_icon_state = "hemostat" + icon_angle = 135 lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' custom_materials = list(/datum/material/iron =SHEET_MATERIAL_AMOUNT * 2.5, /datum/material/glass = SHEET_MATERIAL_AMOUNT*1.25) @@ -55,6 +58,7 @@ /obj/item/hemostat/cyborg icon = 'icons/mob/silicon/robot_items.dmi' icon_state = "toolkit_medborg_hemostat" + icon_angle = 45 /obj/item/cautery name = "cautery" @@ -62,6 +66,7 @@ icon = 'icons/obj/medical/surgery_tools.dmi' icon_state = "cautery" inhand_icon_state = "cautery" + icon_angle = 135 lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT*1.25, /datum/material/glass = SMALL_MATERIAL_AMOUNT*7.5) @@ -89,6 +94,7 @@ /obj/item/cautery/cyborg icon = 'icons/mob/silicon/robot_items.dmi' icon_state = "toolkit_medborg_cautery" + icon_angle = 45 /obj/item/cautery/advanced name = "searing tool" @@ -201,6 +207,7 @@ icon = 'icons/obj/medical/surgery_tools.dmi' icon_state = "scalpel" inhand_icon_state = "scalpel" + icon_angle = 180 lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' obj_flags = CONDUCTS_ELECTRICITY @@ -212,8 +219,8 @@ throw_speed = 3 throw_range = 5 custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT*2, /datum/material/glass =HALF_SHEET_MATERIAL_AMOUNT) - attack_verb_continuous = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts") - attack_verb_simple = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut") + attack_verb_continuous = list("attacks", "slashes", "slices", "tears", "lacerates", "rips", "dices", "cuts") + attack_verb_simple = list("attack", "slash", "slice", "tear", "lacerate", "rip", "dice", "cut") hitsound = 'sound/items/weapons/bladeslice.ogg' sharpness = SHARP_EDGED tool_behaviour = TOOL_SCALPEL @@ -222,6 +229,8 @@ bare_wound_bonus = 15 /// How this looks when placed in a surgical tray var/surgical_tray_overlay = "scalpel_normal" + var/list/alt_continuous = list("stabs", "pierces", "impales") + var/list/alt_simple = list("stab", "pierce", "impale") /obj/item/scalpel/Initialize(mapload) . = ..() @@ -231,6 +240,9 @@ bonus_modifier = 0, \ ) AddElement(/datum/element/eyestab) + alt_continuous = string_list(alt_continuous) + alt_simple = string_list(alt_simple) + AddComponent(/datum/component/alternative_sharpness, SHARP_POINTY, alt_continuous, alt_simple) /obj/item/scalpel/get_surgery_tool_overlay(tray_extended) return surgical_tray_overlay @@ -242,6 +254,7 @@ /obj/item/scalpel/cyborg icon = 'icons/mob/silicon/robot_items.dmi' icon_state = "toolkit_medborg_scalpel" + icon_angle = 0 /obj/item/scalpel/augment desc = "Ultra-sharp blade attached directly to your bone for extra-accuracy." @@ -253,6 +266,7 @@ icon = 'icons/obj/medical/surgery_tools.dmi' icon_state = "saw" inhand_icon_state = "saw" + icon_angle = 180 lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' hitsound = 'sound/items/weapons/circsawhit.ogg' @@ -297,6 +311,7 @@ /obj/item/circular_saw/cyborg icon = 'icons/mob/silicon/robot_items.dmi' icon_state = "toolkit_medborg_saw" + icon_angle = 0 /obj/item/circular_saw/augment desc = "A small but very fast spinning saw. It rips and tears until it is done." @@ -461,12 +476,13 @@ name = "mechanical pinches" desc = "An agglomerate of rods and gears." icon = 'icons/obj/medical/surgery_tools.dmi' - custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT*6, /datum/material/glass = SHEET_MATERIAL_AMOUNT*2, /datum/material/silver = SHEET_MATERIAL_AMOUNT*2, /datum/material/titanium =SHEET_MATERIAL_AMOUNT * 2.5) icon_state = "adv_retractor" inhand_icon_state = "adv_retractor" surgical_tray_overlay = "retractor_advanced" + icon_angle = 0 lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' + custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT*6, /datum/material/glass = SHEET_MATERIAL_AMOUNT*2, /datum/material/silver = SHEET_MATERIAL_AMOUNT*2, /datum/material/titanium =SHEET_MATERIAL_AMOUNT * 2.5) w_class = WEIGHT_CLASS_NORMAL toolspeed = 0.7 @@ -507,6 +523,7 @@ desc = "A type of heavy duty surgical shears used for achieving a clean separation between limb and patient. Keeping the patient still is imperative to be able to secure and align the shears." icon = 'icons/obj/medical/surgery_tools.dmi' icon_state = "shears" + icon_angle = 90 obj_flags = CONDUCTS_ELECTRICITY item_flags = SURGICAL_TOOL toolspeed = 1 @@ -592,6 +609,7 @@ desc = "For setting things right." icon = 'icons/obj/medical/surgery_tools.dmi' icon_state = "bonesetter" + icon_angle = 135 lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' custom_materials = list(/datum/material/iron =SHEET_MATERIAL_AMOUNT * 2.5, /datum/material/glass = SHEET_MATERIAL_AMOUNT*1.25, /datum/material/silver = SHEET_MATERIAL_AMOUNT*1.25) @@ -609,6 +627,7 @@ /obj/item/bonesetter/cyborg icon = 'icons/mob/silicon/robot_items.dmi' icon_state = "toolkit_medborg_bonesetter" + icon_angle = 45 /obj/item/blood_filter name = "blood filter" diff --git a/code/modules/transport/tram/tram_doors.dm b/code/modules/transport/tram/tram_doors.dm index 6e1680bcb4c..5eb3be234e3 100644 --- a/code/modules/transport/tram/tram_doors.dm +++ b/code/modules/transport/tram/tram_doors.dm @@ -211,7 +211,7 @@ if(!hasPower() && density) balloon_alert(user, "pulling emergency exit...") if(do_after(user, 4 SECONDS, target = src)) - try_to_crowbar(src, user, TRUE) + try_to_crowbar(null, user, TRUE) return TRUE /** diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm index 4d16d24e9e9..6e6045d675c 100644 --- a/code/modules/unit_tests/_unit_tests.dm +++ b/code/modules/unit_tests/_unit_tests.dm @@ -311,6 +311,7 @@ #include "unit_test.dm" #include "verify_config_tags.dm" #include "verify_emoji_names.dm" +#include "washing.dm" #include "weird_food.dm" #include "wizard_loadout.dm" #include "worn_icons.dm" diff --git a/code/modules/unit_tests/unit_test.dm b/code/modules/unit_tests/unit_test.dm index 6a2bda4ee25..241d7b54c39 100644 --- a/code/modules/unit_tests/unit_test.dm +++ b/code/modules/unit_tests/unit_test.dm @@ -254,6 +254,8 @@ GLOBAL_VAR_INIT(focused_tests, focused_tests()) //Yet more templates /obj/machinery/restaurant_portal, //Template type + /obj/machinery/power/turbine, + //Template type /obj/effect/mob_spawn, //Template type /obj/structure/holosign/robot_seat, diff --git a/code/modules/unit_tests/washing.dm b/code/modules/unit_tests/washing.dm new file mode 100644 index 00000000000..c0239e9244f --- /dev/null +++ b/code/modules/unit_tests/washing.dm @@ -0,0 +1,43 @@ +/datum/unit_test/washing + /// Stuff we want to test that isn't cleanables, just to make sure they are getting cleaned when they should + var/list/cleanable_bonus_list = list( + /obj/effect/rune, + /obj/item/clothing/gloves/color/black, + /mob/living/carbon/human/dummy/consistent, + ) + + /// Tracks if we caught the clean signal, to know we washed successfully + VAR_PRIVATE/clean_sig_caught = 0 + +/datum/unit_test/washing/Run() + for(var/i in subtypesof(/obj/effect/decal/cleanable) + cleanable_bonus_list) + var/atom/movable/to_clean = allocate(i) + var/mopable = HAS_TRAIT(to_clean, TRAIT_MOPABLE) + + clean_sig_caught = 0 + RegisterSignal(to_clean, COMSIG_COMPONENT_CLEAN_ACT, PROC_REF(clean_caught)) + run_loc_floor_bottom_left.wash(CLEAN_ALL) + // mopables are cleaned when their turf is cleaned + if(mopable) + if(clean_sig_caught == 0) + TEST_FAIL("[i] was not cleaned when its turf was cleaned (cleaning only mopables)!") + if(clean_sig_caught > 1) + TEST_FAIL("[i] was cleaned more than once when its turf was cleaned (cleaning only mopables)!") + // non-mopables require the all_contents = TRUE flag to be cleaned + else + if(clean_sig_caught != 0) + TEST_FAIL("[i] was cleaned when its turf was cleaned (cleaning only mopables)!") + run_loc_floor_bottom_left.wash(CLEAN_ALL, TRUE) + if(clean_sig_caught == 0) + TEST_FAIL("[i] was not cleaned when its turf was cleaned (cleaning all contents)!") + if(clean_sig_caught > 1) + TEST_FAIL("[i] was cleaned more than once when its turf was cleaned (cleaning all contents)!") + + if(!QDELETED(to_clean)) + if(istype(to_clean, /obj/effect/decal/cleanable)) + TEST_FAIL("[i] was not deleted when its turf was cleaned!") + qdel(to_clean) + +/datum/unit_test/washing/proc/clean_caught(...) + SIGNAL_HANDLER + clean_sig_caught += 1 diff --git a/code/modules/uplink/uplink_items/job.dm b/code/modules/uplink/uplink_items/job.dm index d9723f202f1..4923fd855e9 100644 --- a/code/modules/uplink/uplink_items/job.dm +++ b/code/modules/uplink/uplink_items/job.dm @@ -267,7 +267,7 @@ progression_minimum = 15 MINUTES item = /obj/item/gun/chem cost = 12 - restricted_roles = list(JOB_CHEMIST, JOB_CHIEF_MEDICAL_OFFICER, JOB_BOTANIST) + restricted_roles = list(JOB_CHEMIST, JOB_MEDICAL_DOCTOR, JOB_CHIEF_MEDICAL_OFFICER, JOB_BOTANIST) /datum/uplink_item/role_restricted/pie_cannon name = "Banana Cream Pie Cannon" diff --git a/code/modules/vehicles/lavaboat.dm b/code/modules/vehicles/lavaboat.dm index fbe130d9697..307c47ab9e2 100644 --- a/code/modules/vehicles/lavaboat.dm +++ b/code/modules/vehicles/lavaboat.dm @@ -23,6 +23,7 @@ icon = 'icons/mob/rideables/vehicles.dmi' icon_state = "oar" inhand_icon_state = "oar" + icon_angle = 45 lefthand_file = 'icons/mob/inhands/items/lavaland_lefthand.dmi' righthand_file = 'icons/mob/inhands/items/lavaland_righthand.dmi' force = 12 diff --git a/code/modules/vehicles/mecha/equipment/weapons/weapons.dm b/code/modules/vehicles/mecha/equipment/weapons/weapons.dm index c62b2a0d9ce..c811e94c309 100644 --- a/code/modules/vehicles/mecha/equipment/weapons/weapons.dm +++ b/code/modules/vehicles/mecha/equipment/weapons/weapons.dm @@ -68,6 +68,7 @@ var/obj/projectile/projectile_obj = new projectile(get_turf(src)) projectile_obj.log_override = TRUE //we log being fired ourselves a little further down. projectile_obj.firer = chassis + projectile_obj.fired_from = src // mech = firer, equipment = fired from projectile_obj.aim_projectile(target, source, modifiers, spread) if(isliving(source) && source.client) //dont want it to happen from syndie mecha npc mobs, they do direct fire anyways var/mob/living/shooter = source @@ -193,6 +194,7 @@ icon_state = "mecha_honker" energy_drain = 200 equip_cooldown = 150 + projectiles_per_shot = 0 range = MECHA_MELEE|MECHA_RANGED kickback = FALSE mech_flags = EXOSUIT_MODULE_HONK diff --git a/code/modules/vehicles/vehicle_key.dm b/code/modules/vehicles/vehicle_key.dm index 2bcc17115b0..60b578d0962 100644 --- a/code/modules/vehicles/vehicle_key.dm +++ b/code/modules/vehicles/vehicle_key.dm @@ -26,6 +26,7 @@ /obj/item/key/janitor desc = "A keyring with a small steel key, and a pink fob reading \"Pussy Wagon\"." icon_state = "keyjanitor" + icon_angle = 90 force = 2 w_class = WEIGHT_CLASS_SMALL throwforce = 9 diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm index 779d253f29c..79e6b86f545 100644 --- a/code/modules/vending/_vending.dm +++ b/code/modules/vending/_vending.dm @@ -1161,15 +1161,15 @@ GLOBAL_LIST_EMPTY(vending_machines_to_restock) return FALSE /obj/machinery/vending/exchange_parts(mob/user, obj/item/storage/part_replacer/replacer) - if(!istype(replacer)) - return FALSE - if(!component_parts || !refill_canister) + if(!istype(replacer) || !component_parts || !refill_canister) return FALSE - if(!panel_open || replacer.works_from_distance) + var/works_from_distance = istype(replacer, /obj/item/storage/part_replacer/bluespace) + + if(!panel_open || works_from_distance) to_chat(user, display_parts(user)) - if(!panel_open && !replacer.works_from_distance) + if(!panel_open && !works_from_distance) return FALSE var/restocked = 0 diff --git a/html/changelogs/AutoChangeLog-pr-88574.yml b/html/changelogs/AutoChangeLog-pr-88574.yml new file mode 100644 index 00000000000..7f7b8f9c8e7 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-88574.yml @@ -0,0 +1,4 @@ +author: "Melbert" +delete-after: True +changes: + - bugfix: "Lobby button sprites" \ No newline at end of file diff --git a/html/changelogs/archive/2024-12.yml b/html/changelogs/archive/2024-12.yml index d1dbade2017..7fdad317573 100644 --- a/html/changelogs/archive/2024-12.yml +++ b/html/changelogs/archive/2024-12.yml @@ -333,8 +333,141 @@ grungussuss: - bugfix: '*me emote works again' 2024-12-14: + EnterTheJake: + - bugfix: temporary blocks such as blade heretic orbiting knives properly stop body + throws. + Ghommie: + - bugfix: Actually fixed alt-clicking aquariums. + Majkl-J: + - bugfix: Aloe cream no longer catches fire seconds after finishing baking + - bugfix: Overcharged SMESes no longer spam runtime when timers chug up + NecromancerAnne (code), orcacora (sprites): + - rscadd: Adds NT BR-38 Battle Rifles. A hybrid weapon. Find it in your local armory + and cargo catalogue today. (Keep away from EMPs) + Runi-c: + - balance: medical doctors can buy Reagent Dartgun from traitor uplink + SmArtKar: + - bugfix: Fixes primed stingbangs being invisible SmArtKar, LemonInTheDark: - rscadd: Changed how spraycans color items - "old" mode is still availible via right click. - refactor: Refactored how some items and effects color things so that they look prettier. + SyncIt21: + - code_imp: improved code for leaning + distributivgesetz: + - code_imp: Fixed rare cases where moving an object somewhere could silently fail, + but still run unintended code. Report any weird issues on Github + grungussuss: + - bugfix: fixed regal rat attack logic + - bugfix: fixed access on birdshot engi mulebot delivery window + mcbalaam: + - qol: Now all antagonists are visible to an admin in the orbit menu! + norsvenska: + - spellcheck: The Lance and Raven shuttle airlocks are now properly labelled emergency + airlocks, rather than emegency airlocks. + - spellcheck: The radio jammer now releases disruptor waves, rather than distruptor + waves. + timothymtorres: + - sound: Add water sound to sinks +2024-12-15: + Ghommie: + - bugfix: Fixed the displayed stats when examining fishing rods twice. + LT3: + - bugfix: Fixed unconstructed solar panels on Nebulastation port aft solars + Melbert: + - rscadd: Adds Syndol to the chemical kit, an addictive hallucinogen that applies + bonus effects when security officers, assistants, or clowns are exposed. + - bugfix: Metalgen works as a lockpick; igniting a crate metalgen'd into plasma + will properly drop its contents. + - code_imp: Hiding stuff in food should generally work more consistently now. + - bugfix: Fixes players not doing the "searching for item" do-after for items hidden + in food. + - qol: When dragging an item (like, with your mouse cursor. not physically), your + cursor updates when hovering humans or cyborgs to indicate you're hovering over + a human or cyborg. + Paxilmaniac: + - bugfix: Fixes resin sprayers not working if the target is more than one tile away + from you + necromanceranne: + - code_imp: Various mob attack procs are treated as unarmed attacks as a baseline + assumption, rather than melee attacks. + timothymtorres: + - code_imp: Improve looping sounds to allow nested and non-associative lists +2024-12-16: + JoshAdamPowell: + - map: In the new year's budget the syndicate have decided that chemists need beakers + to do their job properly. + Melbert: + - qol: Treatment message now better reflects what you're doing ("suturing", "applying", + etc) + - bugfix: Gauze is now stickier (and will actually apply to bodyparts) + OrionTheFox: + - bugfix: fixed the outdated N-Spect description falsely claiming it can scan people. + It can't. Nanotrasen denies all claims it ever broke sapient right to privacy + by giving crew full-body scanners in a handheld format. + SmArtKar: + - rscadd: Rave and plasma stabilizer MODules now utilize theme-specific visors + - qol: Jetpacks should ACTUALLY feel better now + SyncIt21: + - bugfix: Turbine converts energy to power correctly & shows correct reading with + multitool + - refactor: turbine code has been overall improved. report bugs on github + tontyGH: + - bugfix: Underlining your messages in loud mode shouldn't break anymore +2024-12-17: + Melbert: + - balance: Tasers are now more realistic + - rscdel: Electrodes are no longer in the hallucination projectile pool + OrionTheFox: + - image: resprited the Blood Cult Archives/Altar (the two summoning tables) + SyncIt21: + - code_imp: improved code for RPED + - refactor: RPED attack chain has been refactored. Reports bugs on github +2024-12-18: + SmArtKar: + - rscadd: Added new (purely visual) animations to sharp and pointy items. + - rscadd: Certain items, like knives and swords, now have a secondary stabbing attack. + - balance: Spears are now pointy and no longer act as oversized knives. + - balance: Structure damage is now affected by attacking item's AP. + - bugfix: You will now see the same attack verb in chat as everyone else. +2024-12-19: + 00-Steven: + - bugfix: Custom emotes done via the custom emote keybind default to both audible + and visible again. + Darkened-Earth: + - bugfix: NanoTrasen has shown a xenobiology containment engineer for Delta class + stations a very important lesson between inlets and outlets + Hatterhat: + - qol: You can now pull singular trophies off kinetic crushers with RMB. + - qol: Kinetic crushers now have screentips informing people that they can remove + trophies via empty hand (RMB) or crowbar (LMB). + Melbert: + - bugfix: Gibs get bulk cleaned if you clean the turf again + - refactor: Changed how things determine "I can be bulk cleaned if I clean the turf + underneath me", let me know if you notice anything not getting bulk cleaned + or weird things getting bulk cleaned + SmArtKar: + - bugfix: Fixed a Honkerblast 5000 runtime + - bugfix: Fixed mech KA AOE dealing full damage in pressurized environments + - bugfix: Fixed c38 not misfiring when chambered in c357 + - qol: Resist button now has visible feedback. + - qol: Readjusted UI layout. + - image: Completely redrawn Midnight and Midnight-derived UIs! + mikederkan: + - bugfix: fixes a minor spelling/grammatical error in the Funeral Supply and Religious + Supplies crates. + timothymtorres: + - sound: Add fishtank looping sounds to cryo cells when in use. Sound is from https://freesound.org/people/DudeAwesome/sounds/386023/ + - sound: Add dice rolling sound + tontyGH: + - bugfix: /datum/gas_machine_connector will abstract_move() if their parent also + abstract_move()s, preventing a runtime +2024-12-20: + Melbert: + - bugfix: Meshes should work better + - bugfix: Medical item usage is correctly blackbox logged + - bugfix: Double balloon alerts from medical item usage + - bugfix: Poultice works on dead people + SmArtKar: + - bugfix: Fixed an airlock unlocking runtime diff --git a/icons/effects/beam.dmi b/icons/effects/beam.dmi index 41bdf992bbf..12bbd4788f0 100644 Binary files a/icons/effects/beam.dmi and b/icons/effects/beam.dmi differ diff --git a/icons/hud/64x16_actions.dmi b/icons/hud/64x16_actions.dmi index 23865a80f03..6a54c8e4bb3 100644 Binary files a/icons/hud/64x16_actions.dmi and b/icons/hud/64x16_actions.dmi differ diff --git a/icons/hud/screen_alien.dmi b/icons/hud/screen_alien.dmi index 5f3806dc7bb..e1f513f5b8f 100644 Binary files a/icons/hud/screen_alien.dmi and b/icons/hud/screen_alien.dmi differ diff --git a/icons/hud/screen_clockwork.dmi b/icons/hud/screen_clockwork.dmi index 809dfe8f1a8..d620da7e790 100644 Binary files a/icons/hud/screen_clockwork.dmi and b/icons/hud/screen_clockwork.dmi differ diff --git a/icons/hud/screen_detective.dmi b/icons/hud/screen_detective.dmi index 818bbcfc78b..0516ce6f079 100644 Binary files a/icons/hud/screen_detective.dmi and b/icons/hud/screen_detective.dmi differ diff --git a/icons/hud/screen_glass.dmi b/icons/hud/screen_glass.dmi index 3cf16106cd8..08db68e4d24 100644 Binary files a/icons/hud/screen_glass.dmi and b/icons/hud/screen_glass.dmi differ diff --git a/icons/hud/screen_midnight.dmi b/icons/hud/screen_midnight.dmi index 5de157be030..d748823d4ce 100644 Binary files a/icons/hud/screen_midnight.dmi and b/icons/hud/screen_midnight.dmi differ diff --git a/icons/hud/screen_operative.dmi b/icons/hud/screen_operative.dmi index 5fbaa7c5d5d..8719ef18d39 100644 Binary files a/icons/hud/screen_operative.dmi and b/icons/hud/screen_operative.dmi differ diff --git a/icons/hud/screen_plasmafire.dmi b/icons/hud/screen_plasmafire.dmi index d8b669c96c8..652beabadd8 100644 Binary files a/icons/hud/screen_plasmafire.dmi and b/icons/hud/screen_plasmafire.dmi differ diff --git a/icons/hud/screen_retro.dmi b/icons/hud/screen_retro.dmi index f3621569d76..21275e5320c 100644 Binary files a/icons/hud/screen_retro.dmi and b/icons/hud/screen_retro.dmi differ diff --git a/icons/hud/screen_slimecore.dmi b/icons/hud/screen_slimecore.dmi index a6160087ab8..790575deae7 100644 Binary files a/icons/hud/screen_slimecore.dmi and b/icons/hud/screen_slimecore.dmi differ diff --git a/icons/hud/screen_trasenknox.dmi b/icons/hud/screen_trasenknox.dmi index 4e17feb5211..bb6f82caafb 100644 Binary files a/icons/hud/screen_trasenknox.dmi and b/icons/hud/screen_trasenknox.dmi differ diff --git a/icons/mob/clothing/back.dmi b/icons/mob/clothing/back.dmi index a67830ac5e9..9fd317494ad 100644 Binary files a/icons/mob/clothing/back.dmi and b/icons/mob/clothing/back.dmi differ diff --git a/icons/mob/clothing/belt_mirror.dmi b/icons/mob/clothing/belt_mirror.dmi index 95f7bc00ae9..0ffdb70219c 100644 Binary files a/icons/mob/clothing/belt_mirror.dmi and b/icons/mob/clothing/belt_mirror.dmi differ diff --git a/icons/mob/clothing/modsuit/mod_clothing.dmi b/icons/mob/clothing/modsuit/mod_clothing.dmi index 815983f7094..8a39f37bf0b 100644 Binary files a/icons/mob/clothing/modsuit/mod_clothing.dmi and b/icons/mob/clothing/modsuit/mod_clothing.dmi differ diff --git a/icons/mob/clothing/modsuit/mod_modules.dmi b/icons/mob/clothing/modsuit/mod_modules.dmi index 3c68a87d549..d6dfa4c50a2 100644 Binary files a/icons/mob/clothing/modsuit/mod_modules.dmi and b/icons/mob/clothing/modsuit/mod_modules.dmi differ diff --git a/icons/mob/inhands/weapons/guns_lefthand.dmi b/icons/mob/inhands/weapons/guns_lefthand.dmi index 90df2a892f9..369365131c6 100644 Binary files a/icons/mob/inhands/weapons/guns_lefthand.dmi and b/icons/mob/inhands/weapons/guns_lefthand.dmi differ diff --git a/icons/mob/inhands/weapons/guns_righthand.dmi b/icons/mob/inhands/weapons/guns_righthand.dmi index eebed61656a..fb77baa515b 100644 Binary files a/icons/mob/inhands/weapons/guns_righthand.dmi and b/icons/mob/inhands/weapons/guns_righthand.dmi differ diff --git a/icons/obj/antags/cult/structures.dmi b/icons/obj/antags/cult/structures.dmi index 982742e8764..e42ce6c2202 100644 Binary files a/icons/obj/antags/cult/structures.dmi and b/icons/obj/antags/cult/structures.dmi differ diff --git a/icons/obj/machines/engine/turbine.dmi b/icons/obj/machines/engine/turbine.dmi index 1ae45eb2a1b..afd9839af13 100644 Binary files a/icons/obj/machines/engine/turbine.dmi and b/icons/obj/machines/engine/turbine.dmi differ diff --git a/icons/obj/weapons/grenade.dmi b/icons/obj/weapons/grenade.dmi index c65f6d0e9fb..628b271d423 100644 Binary files a/icons/obj/weapons/grenade.dmi and b/icons/obj/weapons/grenade.dmi differ diff --git a/icons/obj/weapons/guns/ammo.dmi b/icons/obj/weapons/guns/ammo.dmi index df6edd709f6..0f3b0620198 100644 Binary files a/icons/obj/weapons/guns/ammo.dmi and b/icons/obj/weapons/guns/ammo.dmi differ diff --git a/icons/obj/weapons/guns/wide_guns.dmi b/icons/obj/weapons/guns/wide_guns.dmi index 7e18f60eeb8..a193dcc5301 100644 Binary files a/icons/obj/weapons/guns/wide_guns.dmi and b/icons/obj/weapons/guns/wide_guns.dmi differ diff --git a/icons/ui/inventory/back.png b/icons/ui/inventory/back.png index 210045c1c66..e8226bc55e3 100644 Binary files a/icons/ui/inventory/back.png and b/icons/ui/inventory/back.png differ diff --git a/icons/ui/inventory/belt.png b/icons/ui/inventory/belt.png index 9bec60c7bb2..ef3e5586e47 100644 Binary files a/icons/ui/inventory/belt.png and b/icons/ui/inventory/belt.png differ diff --git a/icons/ui/inventory/collar.png b/icons/ui/inventory/collar.png index a7d1b527849..2e8c875851e 100644 Binary files a/icons/ui/inventory/collar.png and b/icons/ui/inventory/collar.png differ diff --git a/icons/ui/inventory/ears.png b/icons/ui/inventory/ears.png index 3c3ba349294..19752ed10d7 100644 Binary files a/icons/ui/inventory/ears.png and b/icons/ui/inventory/ears.png differ diff --git a/icons/ui/inventory/glasses.png b/icons/ui/inventory/glasses.png index 3dff0cd5992..9c8b0950abc 100644 Binary files a/icons/ui/inventory/glasses.png and b/icons/ui/inventory/glasses.png differ diff --git a/icons/ui/inventory/gloves.png b/icons/ui/inventory/gloves.png index 87c829eb626..f5c9de27b8e 100644 Binary files a/icons/ui/inventory/gloves.png and b/icons/ui/inventory/gloves.png differ diff --git a/icons/ui/inventory/hand_l.png b/icons/ui/inventory/hand_l.png index ab9535180d6..8923d81b5b7 100644 Binary files a/icons/ui/inventory/hand_l.png and b/icons/ui/inventory/hand_l.png differ diff --git a/icons/ui/inventory/hand_r.png b/icons/ui/inventory/hand_r.png index e6b0d3cb9da..b3b16b4e0cd 100644 Binary files a/icons/ui/inventory/hand_r.png and b/icons/ui/inventory/hand_r.png differ diff --git a/icons/ui/inventory/head.png b/icons/ui/inventory/head.png index 2d1b65159bb..650be20fe63 100644 Binary files a/icons/ui/inventory/head.png and b/icons/ui/inventory/head.png differ diff --git a/icons/ui/inventory/id.png b/icons/ui/inventory/id.png index 397b30ca42f..0505f38bc19 100644 Binary files a/icons/ui/inventory/id.png and b/icons/ui/inventory/id.png differ diff --git a/icons/ui/inventory/mask.png b/icons/ui/inventory/mask.png index dbaa80ec1ac..3690e6eca76 100644 Binary files a/icons/ui/inventory/mask.png and b/icons/ui/inventory/mask.png differ diff --git a/icons/ui/inventory/neck.png b/icons/ui/inventory/neck.png index 74cf1e33eaf..a6018e149c7 100644 Binary files a/icons/ui/inventory/neck.png and b/icons/ui/inventory/neck.png differ diff --git a/icons/ui/inventory/pocket.png b/icons/ui/inventory/pocket.png index 2e08ed41b05..0d31594a5a5 100644 Binary files a/icons/ui/inventory/pocket.png and b/icons/ui/inventory/pocket.png differ diff --git a/icons/ui/inventory/shoes.png b/icons/ui/inventory/shoes.png index b1b19c63397..170f81b5daa 100644 Binary files a/icons/ui/inventory/shoes.png and b/icons/ui/inventory/shoes.png differ diff --git a/icons/ui/inventory/suit.png b/icons/ui/inventory/suit.png index 71b877677fe..e3122ed47dc 100644 Binary files a/icons/ui/inventory/suit.png and b/icons/ui/inventory/suit.png differ diff --git a/icons/ui/inventory/suit_storage.png b/icons/ui/inventory/suit_storage.png index 0dd12ed4f8f..f35bd3783f7 100644 Binary files a/icons/ui/inventory/suit_storage.png and b/icons/ui/inventory/suit_storage.png differ diff --git a/icons/ui/inventory/uniform.png b/icons/ui/inventory/uniform.png index 56576429e8d..7f5951e3a0f 100644 Binary files a/icons/ui/inventory/uniform.png and b/icons/ui/inventory/uniform.png differ diff --git a/sound/attributions.txt b/sound/attributions.txt index a6cbf21f836..bd2e408c6c5 100644 --- a/sound/attributions.txt +++ b/sound/attributions.txt @@ -23,7 +23,6 @@ champagne_pop.ogg is credited to ultradust on freesound https://freesound.org/pe can_open.ogg adapted from https://freesound.org/people/MaxDemianAGL/sounds/130031/ can_shake.ogg adapted from https://freesound.org/people/mcmast/sounds/456703/ - splatter.ogg adapted from https://freesound.org/people/Rocktopus/sounds/233418/ hohoho.ogg and hehe.ogg are cut from a recording by Nanakisan on freesound: https://freesound.org/people/Nanakisan/sounds/253534/ mbox_full.ogg and mbox_end.ogg make use of The Ragtime Drummer by James Lent, in the public domain @@ -181,8 +180,6 @@ https://freesound.org/people/shw489/sounds/234389/ soup_boil1.ogg through soup_boil5.ogg and soup_boil_end.ogg are taken from Boiling Soup from Freesoung.org (CC4) and converted to OGG / split apart (but is otherwise unchanged): https://freesound.org/people/jorickhoofd/sounds/632783/ - - valve_opening.ogg was made by mixing water flowing samples from: https://freesound.org/people/scriotxstudios/sounds/349111/?attribution=1 and squeaky scrape sound from: https://freesound.org/people/Department64/sounds/669028/ which was modified with lower pitch @@ -191,7 +188,6 @@ liquid_pour2.ogg and liquid_pour3.ogg were cut from https://freesound.org/people/MattRuthSound/sounds/561896/ https://freesound.org/people/MattRuthSound/sounds/561895/ - roaring_fire.ogg made from: 10835 big fire loop.wav by Robinhood76 -- https://freesound.org/s/612277/ -- License: Attribution NonCommercial 4.0 fire_puff made from: Bonfire Being Lit by samararaine -- https://freesound.org/s/186374/ -- License: Creative Commons 0 @@ -208,8 +204,6 @@ Bottle Tap.wav by alex_alexalex -- https://freesound.org/s/395492/ -- License: A beaker_place.ogg was made by cutting and lowering pitch: place glass object.wav by milpower -- https://freesound.org/s/353105/ -- License: Creative Commons 0 - - glass_reverse.ogg is adapted from a combination of: https://freesound.org/people/C_Rogers/sounds/203368/ -- glass-shattering-hit_01.ogg by C_Rogers on freesound.org (CC0) https://freesound.org/people/Czarcazas/sounds/330800/ -- Audio reversal/fading of Shattering Glass (Small) by Czarcazas -- https://freesound.org/s/330800/ -- License: Attribution 3.0 @@ -217,3 +211,10 @@ https://freesound.org/people/Czarcazas/sounds/330800/ -- Audio reversal/fading o sound/effects/bonk.ogg - recorded by oranges on a coke zero bottle, edited by ninjanomnom, released to public domain sound\items\weapons\hammer_death_scream.ogg - Undefeatablesos' scream recorded by Niron3206, edited by Niron3206, License: Creative Commons 0 + +sound/machines/sink-faucet.ogg -- https://freesound.org/people/FOSSarts/sounds/740086/ -- by FOSSarts (CC0) + +cryo_1.ogg, cryo_2.ogg, cryo_3.ogg, cryo_4.ogg, cryo_5.ogg, cryo_6.ogg, cryo_7.ogg, cryo_8.ogg, cryo_9.ogg, cryo_10.ogg: +converted to OGG / split apart (but is otherwise unchanged) -- original from https://freesound.org/people/DudeAwesome/sounds/386023/ by DudeAwesome -- License: CC BY 4.0 + +sound/items/dice_roll.ogg -- https://freesound.org/people/Crovic/sounds/661935/ -- by Crovic (CC0) diff --git a/sound/items/dice_roll.ogg b/sound/items/dice_roll.ogg new file mode 100644 index 00000000000..71048df839b Binary files /dev/null and b/sound/items/dice_roll.ogg differ diff --git a/sound/machines/cryo/cryo_1.ogg b/sound/machines/cryo/cryo_1.ogg new file mode 100644 index 00000000000..daad20b1f49 Binary files /dev/null and b/sound/machines/cryo/cryo_1.ogg differ diff --git a/sound/machines/cryo/cryo_10.ogg b/sound/machines/cryo/cryo_10.ogg new file mode 100644 index 00000000000..eedc518222f Binary files /dev/null and b/sound/machines/cryo/cryo_10.ogg differ diff --git a/sound/machines/cryo/cryo_2.ogg b/sound/machines/cryo/cryo_2.ogg new file mode 100644 index 00000000000..7375eff09eb Binary files /dev/null and b/sound/machines/cryo/cryo_2.ogg differ diff --git a/sound/machines/cryo/cryo_3.ogg b/sound/machines/cryo/cryo_3.ogg new file mode 100644 index 00000000000..4cbb033daff Binary files /dev/null and b/sound/machines/cryo/cryo_3.ogg differ diff --git a/sound/machines/cryo/cryo_4.ogg b/sound/machines/cryo/cryo_4.ogg new file mode 100644 index 00000000000..6dff7c7a1c1 Binary files /dev/null and b/sound/machines/cryo/cryo_4.ogg differ diff --git a/sound/machines/cryo/cryo_5.ogg b/sound/machines/cryo/cryo_5.ogg new file mode 100644 index 00000000000..ff11f6d173d Binary files /dev/null and b/sound/machines/cryo/cryo_5.ogg differ diff --git a/sound/machines/cryo/cryo_6.ogg b/sound/machines/cryo/cryo_6.ogg new file mode 100644 index 00000000000..575b727958b Binary files /dev/null and b/sound/machines/cryo/cryo_6.ogg differ diff --git a/sound/machines/cryo/cryo_7.ogg b/sound/machines/cryo/cryo_7.ogg new file mode 100644 index 00000000000..f6fcb2bd0e3 Binary files /dev/null and b/sound/machines/cryo/cryo_7.ogg differ diff --git a/sound/machines/cryo/cryo_8.ogg b/sound/machines/cryo/cryo_8.ogg new file mode 100644 index 00000000000..2884ffa5bd2 Binary files /dev/null and b/sound/machines/cryo/cryo_8.ogg differ diff --git a/sound/machines/cryo/cryo_9.ogg b/sound/machines/cryo/cryo_9.ogg new file mode 100644 index 00000000000..c650837ed8b Binary files /dev/null and b/sound/machines/cryo/cryo_9.ogg differ diff --git a/sound/machines/sink-faucet.ogg b/sound/machines/sink-faucet.ogg new file mode 100644 index 00000000000..7102a394030 Binary files /dev/null and b/sound/machines/sink-faucet.ogg differ diff --git a/tgstation.dme b/tgstation.dme index 15b0963fa00..92521070815 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1052,6 +1052,7 @@ #include "code\datums\components\ai_has_target_timer.dm" #include "code\datums\components\ai_listen_to_weather.dm" #include "code\datums\components\ai_retaliate_advanced.dm" +#include "code\datums\components\alternative_sharpness.dm" #include "code\datums\components\amputating_limbs.dm" #include "code\datums\components\anti_magic.dm" #include "code\datums\components\appearance_on_aggro.dm" @@ -5871,6 +5872,7 @@ #include "code\modules\research\designs.dm" #include "code\modules\research\destructive_analyzer.dm" #include "code\modules\research\experimentor.dm" +#include "code\modules\research\part_replacer.dm" #include "code\modules\research\rdconsole.dm" #include "code\modules\research\rdmachines.dm" #include "code\modules\research\research_disk.dm" diff --git a/tgui/packages/tgui/interfaces/TurbineComputer.tsx b/tgui/packages/tgui/interfaces/TurbineComputer.tsx index 4d1305b88b5..f67a09f2687 100644 --- a/tgui/packages/tgui/interfaces/TurbineComputer.tsx +++ b/tgui/packages/tgui/interfaces/TurbineComputer.tsx @@ -9,7 +9,9 @@ import { NumberInput, ProgressBar, Section, + Stack, } from '../components'; +import { formatPower } from '../format'; import { Window } from '../layouts'; type TurbineInfo = { @@ -19,105 +21,99 @@ type TurbineInfo = { power: number; temp: number; integrity: number; - parts_linked: BooleanLike; - parts_ready: BooleanLike; max_rpm: number; max_temperature: number; regulator: number; }; -export const TurbineComputer = (props) => { +const TurbineDisplay = (props) => { const { act, data } = useBackend(); - const parts_not_connected = !data.parts_linked && ( - - - { - 'Parts not connected, use a multitool on the core rotor before trying again' - } - - + + return ( +
= 1000)} + onClick={() => act('toggle_power')} + > + {data.active ? 'Online' : 'Offline'} + + } + > + + + + act('regulate', { + regulate: value * 0.01, + }) + } + /> + + + + + + {data.rpm} RPM + + + {data.max_rpm} RPM + + + {data.temp} K + + + {data.max_temperature} K + + + {formatPower(data.power)} + + +
); - const parts_not_ready = data.parts_linked && !data.parts_ready && ( +}; + +const OutOfService = (props) => { + return ( - - { - 'Some parts have open maintenance hatchet, please close them before starting' - } - + + + + { + 'Parts not connected, close all mantainence panels/use a multitool on the rotor before trying again' + } + + + ); +}; + +export const TurbineComputer = (props) => { + const { data } = useBackend(); + return ( -
= 1000) || !data.parts_linked} - onClick={() => act('toggle_power')} - /> - } - > - {parts_not_connected} - {parts_not_ready} - - - - act('regulate', { - regulate: value * 0.01, - }) - } - /> - - - - - - {data.rpm} RPM - - - {data.max_rpm} RPM - - - {data.temp} K - - - {data.max_temperature} K - - - {data.power * 4 * 0.001} kW - - -
+ {data.connected ? : }
); diff --git a/tools/UpdatePaths/Scripts/repaths_a357_to_c357.txt b/tools/UpdatePaths/Scripts/repaths_a357_to_c357.txt new file mode 100644 index 00000000000..28ad97efff1 --- /dev/null +++ b/tools/UpdatePaths/Scripts/repaths_a357_to_c357.txt @@ -0,0 +1,3 @@ +#comment Repaths instances of a357 with c357, so as to acknowledge that it is consistent with other casings. + +/obj/item/ammo_casing/c357 : /obj/item/ammo_casing/a357{@OLD}