diff --git a/.editorconfig b/.editorconfig index 13dcd5e029..c44572fbf9 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,11 +1,14 @@ [*] -insert_final_newline = true indent_style = tab indent_size = 4 +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true +#end_of_line = lf [*.yml] indent_style = space indent_size = 2 -[*.txt] -insert_final_newline = false +[*.py] +indent_style = space diff --git a/.gitattributes b/.gitattributes index a0a624af04..c447869d3e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,9 +1,42 @@ -# merger hooks, run tools/hooks/install.bat or install.sh to set up -*.dmm merge=dmm -*.dmi merge=dmi - -# force changelog merging to use union -html/changelog.html merge=union - -# force all files to be LF * text=auto + +## Enforce text mode and LF line breaks +## porter note: not yet LFing dm. +# *.bat text eol=lf +*.css text eol=lf +# *.dm text eol=lf +# *.dme text eol=lf +# *.dmf text eol=lf +*.htm text eol=lf +*.html text eol=lf +*.js text eol=lf +*.json text eol=lf +*.jsx text eol=lf +# *.md text eol=lf +*.py text eol=lf +*.scss text eol=lf +# *.sh text eol=lf +# *.sql text eol=lf +*.svg text eol=lf +*.ts text eol=lf +*.tsx text eol=lf +# *.txt text eol=lf +*.yaml text eol=lf +*.yml text eol=lf + +## Enforce binary mode +*.bmp binary +*.dll binary +*.dmb binary +*.exe binary +*.gif binary +*.jpg binary +*.png binary +*.so binary + +## Merger hooks, run tools/hooks/install.bat or install.sh to set up +*.dmm text eol=lf merge=dmm +*.dmi binary merge=dmi + +## Force changelog merging to use union +html/changelog.html text eol=lf merge=union diff --git a/.github/workflows/autobuild_tgui.yml b/.github/workflows/autobuild_tgui.yml deleted file mode 100644 index 226ea2b7ce..0000000000 --- a/.github/workflows/autobuild_tgui.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: Autobuild TGUI - -on: - push: - branches: - - 'master' - paths: - - 'tgui/**.js' - - 'tgui/**.scss' - -jobs: - build: - name: Rebuild TGUI - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v1 - with: - fetch-depth: 25 - - name: Setup Node - uses: actions/setup-node@v1 - with: - node-version: '>=12.13' - - name: Build TGUI - run: bin/tgui --ci - working-directory: ./tgui - - name: Commit Artifacts - run: | - git config --local user.email "action@github.com" - git config --local user.name "TGUI" - git pull origin master - git commit -m "Automatic TGUI Rebuild [ci skip]" -a || true - - name: Push Artifacts - uses: ad-m/github-push-action@master - with: - github_token: ${{ secrets.GITHUB_MASTER_KEY }} diff --git a/.github/workflows/round_id_linker.yml b/.github/workflows/round_id_linker.yml new file mode 100644 index 0000000000..37998a93eb --- /dev/null +++ b/.github/workflows/round_id_linker.yml @@ -0,0 +1,12 @@ +name: "Round ID Linker" +on: + issues: + types: [opened] + +jobs: + link_rounds: + runs-on: ubuntu-latest + steps: + - uses: Cidatel-Station-13/round_linker@master #notice: fork the round linkies from tg!! + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index f65245c021..e885761104 100644 --- a/.gitignore +++ b/.gitignore @@ -198,13 +198,36 @@ Temporary Items !/.vscode/extensions.json tools/MapAtmosFixer/MapAtmosFixer/obj/* tools/MapAtmosFixer/MapAtmosFixer/bin/* +tools/CreditsTool/bin/* +tools/CreditsTool/obj/* #GitHub Atom .atom-build.json -#Jukebox audio files -/config/jukebox_music/**/* +#KDevelop and Kate +*.kdev4* +*.kate-swp #extra map stuff /_maps/**/backup/ /_maps/templates.dm + +#dmdoc default folder +/dmdoc + +# Ignore custom music and title screens (amend as appropriate) +/config/jukebox_music/sounds/* +!/config/jukebox_music/sounds/exclude +/config/title_music/sounds/* +!/config/title_music/sounds/exclude +/config/title_screens/images/* +!/config/title_screens/images/exclude + +#Linux docker +tools/LinuxOneShot/SetupProgram/obj/* +tools/LinuxOneShot/SetupProgram/bin/* +tools/LinuxOneShot/SetupProgram/.vs +tools/LinuxOneShot/Database +tools/LinuxOneShot/TGS_Config +tools/LinuxOneShot/TGS_Instances +tools/LinuxOneShot/TGS_Logs diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000000..11d27b55d3 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,11 @@ +build: + stage: build + rules: + - if: $CI_MERGE_REQUEST_IID || $CI_COMMIT_REF_NAME == "master" + changes: + - tgui/**/*.js + - tgui/**/*.scss + when: always + image: node:lts + script: + - tgui/bin/tgui --ci diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/.travis.yml b/.travis.yml index 2214df3aee..83ef6fa8ff 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,13 @@ language: generic +os: linux dist: xenial -sudo: false branches: except: - ___TGS3TempBranch - ___TGSTempBranch -matrix: +jobs: include: - name: "Run Linters" addons: @@ -16,9 +16,15 @@ matrix: - python3 - python3-pip - python3-setuptools + - pcregrep + - rustc + - cargo + cache: + directories: + - $HOME/SpacemanDMM install: - tools/travis/install_build_tools.sh - - tools/travis/install_dreamchecker.sh + - tools/travis/install_spaceman_dmm.sh dreamchecker script: - tools/travis/check_filedirs.sh tgstation.dme - tools/travis/check_changelogs.sh @@ -76,3 +82,21 @@ matrix: script: - tools/travis/dm.sh -DTRAVISBUILDING tgstation.dme || travis_terminate 1 - tools/travis/run_server.sh + + # - name: "Generate Documentation" + # # Only run for non-PR commits to the real master branch. + # if: branch = master AND head_branch IS blank + # install: + # - tools/travis/install_spaceman_dmm.sh dmdoc + # before_script: + # # Travis checks out a hash, try to get back on a branch. + # - git checkout $TRAVIS_BRANCH || true + # script: + # - ~/dmdoc + # - touch dmdoc/.nojekyll + # deploy: + # provider: pages + # skip_cleanup: true + # local_dir: dmdoc + # token: $DMDOC_GITHUB_TOKEN + # fqdn: codedocs.tgstation13.org diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index 17253e2665..943aa85efd 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -12556,15 +12556,11 @@ /area/engine/atmospherics_engine) "aAb" = ( /turf/closed/wall, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "aAc" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/closed/wall, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "aAd" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/tile/neutral{ @@ -13138,9 +13134,7 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/delivery, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "aBh" = ( /obj/item/kirbyplants/random, /obj/machinery/light/small{ @@ -13149,25 +13143,19 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/delivery, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "aBi" = ( /obj/structure/table, /obj/item/clothing/suit/apron/overalls, /obj/item/cultivator, /obj/effect/turf_decal/bot, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "aBj" = ( /obj/machinery/biogenerator, /obj/effect/turf_decal/delivery, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "aBk" = ( /obj/structure/table, /obj/item/reagent_containers/food/snacks/grown/wheat, @@ -13182,18 +13170,14 @@ pixel_y = 4 }, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "aBl" = ( /obj/machinery/hydroponics/soil, /obj/item/seeds/tea, /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/delivery, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "aBm" = ( /obj/item/kirbyplants/random, /obj/machinery/status_display/evac{ @@ -13201,9 +13185,7 @@ }, /obj/effect/turf_decal/delivery, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "aBn" = ( /obj/structure/table, /obj/item/stack/packageWrap, @@ -13213,9 +13195,7 @@ /obj/item/reagent_containers/food/snacks/grown/cherries, /obj/effect/turf_decal/bot, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "aBo" = ( /obj/item/kirbyplants/random, /obj/machinery/light/small{ @@ -13225,18 +13205,14 @@ /obj/effect/turf_decal/delivery, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "aBp" = ( /obj/machinery/hydroponics/soil, /obj/item/seeds/poppy, /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/delivery, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "aBq" = ( /obj/structure/cable/white{ icon_state = "2-4" @@ -13817,33 +13793,25 @@ /area/engine/atmospherics_engine) "aCv" = ( /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "aCw" = ( /obj/effect/turf_decal/delivery, /obj/machinery/hydroponics/soil, /obj/item/seeds/watermelon, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "aCx" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on{ dir = 4 }, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "aCy" = ( /obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{ dir = 4 }, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "aCz" = ( /obj/structure/cable/white{ icon_state = "1-2" @@ -14459,21 +14427,15 @@ }, /obj/effect/turf_decal/bot, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "aDy" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "aDz" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "aDA" = ( /obj/structure/sink{ dir = 4; @@ -14484,9 +14446,7 @@ }, /obj/effect/turf_decal/bot, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "aDB" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, @@ -14968,34 +14928,26 @@ icon_state = "2-4" }, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "aEC" = ( /obj/structure/cable/white{ icon_state = "4-8" }, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "aED" = ( /obj/structure/cable/white{ icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/supply/hidden, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "aEE" = ( /obj/structure/cable/white{ icon_state = "2-8" }, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "aEG" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/cable/white{ @@ -15628,18 +15580,14 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/delivery, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "aFK" = ( /obj/machinery/hydroponics/soil, /obj/item/seeds/harebell, /obj/machinery/light/small, /obj/effect/turf_decal/delivery, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "aFL" = ( /obj/structure/table, /obj/item/shovel/spade, @@ -15658,9 +15606,7 @@ }, /obj/effect/turf_decal/bot, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "aFM" = ( /obj/machinery/status_display/evac{ pixel_y = -32 @@ -15669,34 +15615,26 @@ /obj/machinery/hydroponics/soil, /obj/item/seeds/poppy/geranium, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "aFN" = ( /obj/structure/table, /obj/item/plant_analyzer, /obj/item/hatchet, /obj/effect/turf_decal/bot, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "aFO" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden, /obj/effect/turf_decal/delivery, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "aFP" = ( /obj/structure/cable/white{ icon_state = "1-2" }, /obj/effect/turf_decal/delivery, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "aFQ" = ( /obj/structure/table, /obj/item/crowbar, @@ -15704,9 +15642,7 @@ /obj/item/reagent_containers/glass/bucket, /obj/effect/turf_decal/bot, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "aFR" = ( /obj/machinery/hydroponics/soil, /obj/item/seeds/tower, @@ -15715,9 +15651,7 @@ /obj/effect/turf_decal/delivery, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "aFS" = ( /obj/structure/cable/white{ icon_state = "1-2" @@ -16707,9 +16641,7 @@ "aHl" = ( /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "aHm" = ( /obj/machinery/door/airlock/maintenance_hatch{ name = "Maintenance Hatch"; @@ -16721,9 +16653,7 @@ dir = 1 }, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "aHn" = ( /obj/machinery/door/airlock/maintenance_hatch{ name = "Maintenance Hatch"; @@ -16737,16 +16667,12 @@ dir = 1 }, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "aHo" = ( /obj/effect/spawner/structure/window/reinforced, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/open/floor/plating, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "aHp" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/cable/white{ @@ -125347,9 +125273,7 @@ /obj/item/reagent_containers/glass/bucket, /obj/effect/turf_decal/delivery, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "etO" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 4 @@ -125474,9 +125398,7 @@ /obj/machinery/hydroponics/soil, /obj/item/seeds/grape, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "faI" = ( /obj/structure/cable/white{ icon_state = "1-2" @@ -126395,9 +126317,7 @@ pixel_x = 6 }, /turf/open/floor/plasteel, -/area/hydroponics/garden/abandoned{ - name = "Maintenance Garden" - }) +/area/hydroponics/garden/abandoned) "loH" = ( /obj/effect/turf_decal/tile/neutral{ dir = 1 diff --git a/_maps/map_files/KiloStation/KiloStation.dmm b/_maps/map_files/KiloStation/KiloStation.dmm index f426ad8e97..51bfe5038e 100644 --- a/_maps/map_files/KiloStation/KiloStation.dmm +++ b/_maps/map_files/KiloStation/KiloStation.dmm @@ -75352,9 +75352,7 @@ /obj/machinery/atmospherics/pipe/simple/orange/visible{ dir = 4 }, -/obj/machinery/airalarm{ - pixel_z = 24 - }, +/obj/machinery/airalarm, /obj/machinery/light/small, /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating{ diff --git a/_maps/map_files/PubbyStation/job_changes.dm b/_maps/map_files/PubbyStation/job_changes.dm deleted file mode 100644 index 726601725b..0000000000 --- a/_maps/map_files/PubbyStation/job_changes.dm +++ /dev/null @@ -1,20 +0,0 @@ -#define JOB_MODIFICATION_MAP_NAME "PubbyStation" - -/datum/job/hos/New() - ..() - MAP_JOB_CHECK - access += ACCESS_CREMATORIUM - minimal_access += ACCESS_CREMATORIUM - -/datum/job/warden/New() - ..() - MAP_JOB_CHECK - access += ACCESS_CREMATORIUM - minimal_access += ACCESS_CREMATORIUM - -/datum/job/officer/New() - ..() - MAP_JOB_CHECK - access += ACCESS_CREMATORIUM - minimal_access += ACCESS_CREMATORIUM - diff --git a/_maps/pubbystation.json b/_maps/pubbystation.json index f99cca57c5..acf49b773b 100644 --- a/_maps/pubbystation.json +++ b/_maps/pubbystation.json @@ -7,5 +7,10 @@ "whiteship": "whiteship_pubby", "ferry": "ferry_fancy", "cargo": "cargo_box" - } + }, + "job_access_add": { + "/datum/job/hos": [27], + "/datum/job/officer": [27], + "/datum/job/detective": [27] + } } diff --git a/_maps/templates/hilbertshotel.dmm b/_maps/templates/hilbertshotel.dmm index 4e4d8f8267..da5d13d93e 100644 --- a/_maps/templates/hilbertshotel.dmm +++ b/_maps/templates/hilbertshotel.dmm @@ -7,7 +7,7 @@ /area/hilbertshotel) "c" = ( /obj/machinery/jukebox{ - req_access = null + req_one_access = null }, /turf/open/indestructible/hotelwood, /area/hilbertshotel) diff --git a/code/__DEFINES/_flags/item_flags.dm b/code/__DEFINES/_flags/item_flags.dm index 26e764c45b..7da71e22cb 100644 --- a/code/__DEFINES/_flags/item_flags.dm +++ b/code/__DEFINES/_flags/item_flags.dm @@ -22,12 +22,10 @@ #define SURGICAL_TOOL (1<<10) ///Can be worn on certain slots (currently belt and id) that would otherwise require an uniform. #define NO_UNIFORM_REQUIRED (1<<11) -///Damage when attacking people is not affected by combat mode. -#define NO_COMBAT_MODE_FORCE_MODIFIER (1<<12) /// This item can be used to parry. Only a basic check used to determine if we should proceed with parry chain at all. -#define ITEM_CAN_PARRY (1<<13) +#define ITEM_CAN_PARRY (1<<12) /// This item can be used in the directional blocking system. Only a basic check used to determine if we should proceed with directional block handling at all. -#define ITEM_CAN_BLOCK (1<<14) +#define ITEM_CAN_BLOCK (1<<13) // Flags for the clothing_flags var on /obj/item/clothing diff --git a/code/__DEFINES/colors.dm b/code/__DEFINES/colors.dm index 2273d34c82..fb461acfa4 100644 --- a/code/__DEFINES/colors.dm +++ b/code/__DEFINES/colors.dm @@ -1,54 +1,54 @@ // This is eventually for wjohn to add more color standardization stuff like I keep asking him >:( -#define COLOR_INPUT_DISABLED "#F0F0F0" -#define COLOR_INPUT_ENABLED "#D3B5B5" -#define COLOR_FLOORTILE_GRAY "#8D8B8B" -#define COLOR_ALMOST_BLACK "#333333" -#define COLOR_BLACK "#000000" -#define COLOR_RED "#FF0000" -#define COLOR_RED_LIGHT "#FF3333" -#define COLOR_MAROON "#800000" -#define COLOR_YELLOW "#FFFF00" -#define COLOR_OLIVE "#808000" -#define COLOR_LIME "#32CD32" -#define COLOR_GREEN "#008000" -#define COLOR_CYAN "#00FFFF" -#define COLOR_TEAL "#008080" -#define COLOR_BLUE "#0000FF" -#define COLOR_BLUE_LIGHT "#33CCFF" -#define COLOR_NAVY "#000080" -#define COLOR_PINK "#FFC0CB" -#define COLOR_MAGENTA "#FF00FF" -#define COLOR_PURPLE "#800080" -#define COLOR_ORANGE "#FF9900" -#define COLOR_BEIGE "#CEB689" -#define COLOR_BLUE_GRAY "#75A2BB" -#define COLOR_BROWN "#BA9F6D" -#define COLOR_DARK_BROWN "#997C4F" -#define COLOR_DARK_ORANGE "#C3630C" -#define COLOR_GREEN_GRAY "#99BB76" -#define COLOR_RED_GRAY "#B4696A" -#define COLOR_PALE_BLUE_GRAY "#98C5DF" -#define COLOR_PALE_GREEN_GRAY "#B7D993" -#define COLOR_PALE_ORANGE "#FFC066" -#define COLOR_PALE_RED_GRAY "#D59998" -#define COLOR_PALE_PURPLE_GRAY "#CBB1CA" -#define COLOR_PURPLE_GRAY "#AE8CA8" +#define COLOR_INPUT_DISABLED "#F0F0F0" +#define COLOR_INPUT_ENABLED "#D3B5B5" +#define COLOR_FLOORTILE_GRAY "#8D8B8B" +#define COLOR_ALMOST_BLACK "#333333" +#define COLOR_BLACK "#000000" +#define COLOR_RED "#FF0000" +#define COLOR_RED_LIGHT "#FF3333" +#define COLOR_MAROON "#800000" +#define COLOR_YELLOW "#FFFF00" +#define COLOR_OLIVE "#808000" +#define COLOR_LIME "#32CD32" +#define COLOR_GREEN "#008000" +#define COLOR_CYAN "#00FFFF" +#define COLOR_TEAL "#008080" +#define COLOR_BLUE "#0000FF" +#define COLOR_BLUE_LIGHT "#33CCFF" +#define COLOR_NAVY "#000080" +#define COLOR_PINK "#FFC0CB" +#define COLOR_MAGENTA "#FF00FF" +#define COLOR_PURPLE "#800080" +#define COLOR_ORANGE "#FF9900" +#define COLOR_BEIGE "#CEB689" +#define COLOR_BLUE_GRAY "#75A2BB" +#define COLOR_BROWN "#BA9F6D" +#define COLOR_DARK_BROWN "#997C4F" +#define COLOR_DARK_ORANGE "#C3630C" +#define COLOR_GREEN_GRAY "#99BB76" +#define COLOR_RED_GRAY "#B4696A" +#define COLOR_PALE_BLUE_GRAY "#98C5DF" +#define COLOR_PALE_GREEN_GRAY "#B7D993" +#define COLOR_PALE_ORANGE "#FFC066" +#define COLOR_PALE_RED_GRAY "#D59998" +#define COLOR_PALE_PURPLE_GRAY "#CBB1CA" +#define COLOR_PURPLE_GRAY "#AE8CA8" -//Color defines used by the assembly detailer. -#define COLOR_ASSEMBLY_BLACK "#545454" -#define COLOR_ASSEMBLY_BGRAY "#9497AB" -#define COLOR_ASSEMBLY_WHITE "#E2E2E2" -#define COLOR_ASSEMBLY_RED "#CC4242" -#define COLOR_ASSEMBLY_ORANGE "#E39751" -#define COLOR_ASSEMBLY_BEIGE "#AF9366" -#define COLOR_ASSEMBLY_BROWN "#97670E" -#define COLOR_ASSEMBLY_GOLD "#AA9100" -#define COLOR_ASSEMBLY_YELLOW "#CECA2B" -#define COLOR_ASSEMBLY_GURKHA "#999875" -#define COLOR_ASSEMBLY_LGREEN "#789876" -#define COLOR_ASSEMBLY_GREEN "#44843C" -#define COLOR_ASSEMBLY_LBLUE "#5D99BE" -#define COLOR_ASSEMBLY_BLUE "#38559E" -#define COLOR_ASSEMBLY_PURPLE "#6F6192" -#define COLOR_ASSEMBLY_PINK "#ff4adc" +// Color defines used by the assembly detailer. +#define COLOR_ASSEMBLY_BLACK "#545454" +#define COLOR_ASSEMBLY_BGRAY "#9497AB" +#define COLOR_ASSEMBLY_WHITE "#E2E2E2" +#define COLOR_ASSEMBLY_RED "#CC4242" +#define COLOR_ASSEMBLY_ORANGE "#E39751" +#define COLOR_ASSEMBLY_BEIGE "#AF9366" +#define COLOR_ASSEMBLY_BROWN "#97670E" +#define COLOR_ASSEMBLY_GOLD "#AA9100" +#define COLOR_ASSEMBLY_YELLOW "#CECA2B" +#define COLOR_ASSEMBLY_GURKHA "#999875" +#define COLOR_ASSEMBLY_LGREEN "#789876" +#define COLOR_ASSEMBLY_GREEN "#44843C" +#define COLOR_ASSEMBLY_LBLUE "#5D99BE" +#define COLOR_ASSEMBLY_BLUE "#38559E" +#define COLOR_ASSEMBLY_PURPLE "#6F6192" +#define COLOR_ASSEMBLY_PINK "#ff4adc" diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm index eff5d9eca9..5f5a76b58d 100644 --- a/code/__DEFINES/combat.dm +++ b/code/__DEFINES/combat.dm @@ -34,6 +34,8 @@ #define COMBAT_FLAGS_DEFAULT (COMBAT_FLAG_PARRY_CAPABLE | COMBAT_FLAG_BLOCK_CAPABLE) /// Default combat flags for everyone else (so literally everyone but humans). #define COMBAT_FLAGS_SPRINT_EXEMPT (COMBAT_FLAG_SPRINT_ACTIVE | COMBAT_FLAG_SPRINT_TOGGLED | COMBAT_FLAG_SPRINT_FORCED | COMBAT_FLAG_PARRY_CAPABLE | COMBAT_FLAG_BLOCK_CAPABLE) +/// Default combat flags for those in stamina combat system +#define COMBAT_FLAGS_STAMINA_COMBAT (COMBAT_FLAG_PARRY_CAPABLE | COMBAT_FLAG_BLOCK_CAPABLE | COMBAT_FLAG_STAMINA_BUFFER) /// The user wants sprint mode on #define COMBAT_FLAG_SPRINT_TOGGLED (1<<0) @@ -47,8 +49,8 @@ #define COMBAT_FLAG_RESISTING_REST (1<<4) /// Intentionally resting #define COMBAT_FLAG_INTENTIONALLY_RESTING (1<<5) -/// Currently stamcritted but not as violently -#define COMBAT_FLAG_SOFT_STAMCRIT (1<<6) +/// This mob requires stamina buffer to do things that require stamina buffer. Not having this exempts the mob from stamina combat. +#define COMBAT_FLAG_STAMINA_BUFFER (1<<6) /// Force sprint mode on at all times, overrides everything including sprint disable traits. #define COMBAT_FLAG_SPRINT_FORCED (1<<7) /// This mob is capable of using the active parrying system. @@ -64,26 +66,17 @@ // Helpers for getting someone's stamcrit state. Cast to living. #define NOT_STAMCRIT 0 -#define SOFT_STAMCRIT 1 -#define HARD_STAMCRIT 2 +#define HARD_STAMCRIT 1 // Stamcrit check helpers #define IS_STAMCRIT(mob) (CHECK_STAMCRIT(mob) != NOT_STAMCRIT) -#define CHECK_STAMCRIT(mob) ((mob.combat_flags & COMBAT_FLAG_HARD_STAMCRIT)? HARD_STAMCRIT : ((mob.combat_flags & COMBAT_FLAG_SOFT_STAMCRIT)? SOFT_STAMCRIT : NOT_STAMCRIT)) +#define CHECK_STAMCRIT(mob) (mob.combat_flags & COMBAT_FLAG_HARD_STAMCRIT) //stamina stuff -///Threshold over which attacks start being hindered. -#define STAMINA_NEAR_SOFTCRIT 90 -///softcrit for stamina damage. prevents standing up, some actions that cost stamina, etc, but doesn't force a rest or stop movement -#define STAMINA_SOFTCRIT 100 -///sanity cap to prevent stamina actions (that are still performable) from sending you into crit. -#define STAMINA_NEAR_CRIT 130 -///crit for stamina damage. forces a rest, and stops movement until stamina goes back to stamina softcrit +/// crit for stamina damage. forces a rest, and stops movement until stamina goes back to stamina softcrit #define STAMINA_CRIT 140 -///same as STAMINA_SOFTCRIT except for the more traditional health calculations -#define STAMINA_SOFTCRIT_TRADITIONAL 0 -///ditto, but for STAMINA_CRIT -#define STAMINA_CRIT_TRADITIONAL -40 +/// Threshold under for which you are unable to draw from stamina health to replace stamina buffer +#define STAMINA_NO_OVERDRAW_THRESHOLD 100 #define CRAWLUNDER_DELAY 30 //Delay for crawling under a standing mob @@ -252,36 +245,6 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list( //We will round to this value in damage calculations. #define DAMAGE_PRECISION 0.01 -//items total mass, used to calculate their attacks' stamina costs. If not defined, the cost will be (w_class * 1.25) -#define TOTAL_MASS_TINY_ITEM 1.25 -#define TOTAL_MASS_SMALL_ITEM 2.5 -#define TOTAL_MASS_NORMAL_ITEM 3.75 -#define TOTAL_MASS_BULKY_ITEM 5 -#define TOTAL_MASS_HUGE_ITEM 6.25 -#define TOTAL_MASS_GIGANTIC_ITEM 7.5 - -#define TOTAL_MASS_HAND_REPLACEMENT 5 //standard punching stamina cost. most hand replacements are huge items anyway. -#define TOTAL_MASS_MEDIEVAL_WEAPON 3.6 //very, very generic average sword/warpick/etc. weight in pounds. -#define TOTAL_MASS_TOY_SWORD 1.5 - -//stamina cost defines. -#define STAM_COST_ATTACK_OBJ_MULT 1.2 -#define STAM_COST_ATTACK_MOB_MULT 1 -#define STAM_COST_BATON_MOB_MULT 1 -#define STAM_COST_NO_COMBAT_MULT 1.25 -#define STAM_COST_W_CLASS_MULT 1.25 -#define STAM_COST_THROW_MULT 2 -#define STAM_COST_THROW_MOB 2.5 //multiplied by (mob size + 1)^2. - -///Multiplier of the (STAMINA_NEAR_CRIT - user current stamina loss) : (STAMINA_NEAR_CRIT - STAMINA_SOFTCRIT) ratio used in damage penalties when stam soft-critted. -#define STAM_CRIT_ITEM_ATTACK_PENALTY 0.66 -/// changeNext_move penalty multiplier of the above. -#define STAM_CRIT_ITEM_ATTACK_DELAY 1.75 -/// Damage penalty when fighting prone. -#define LYING_DAMAGE_PENALTY 0.7 -/// Added delay when firing guns stam-softcritted. Summed with a hardset CLICK_CD_RANGE delay, similar to STAM_CRIT_DAMAGE_DELAY otherwise. -#define STAM_CRIT_GUN_DELAY 2.75 - //stamina recovery defines. Blocked if combat mode is on. #define STAM_RECOVERY_STAM_CRIT -7.5 #define STAM_RECOVERY_RESTING -6 diff --git a/code/__DEFINES/combat/stamina_combat.dm b/code/__DEFINES/combat/stamina_combat.dm new file mode 100644 index 0000000000..1f781ca3e0 --- /dev/null +++ b/code/__DEFINES/combat/stamina_combat.dm @@ -0,0 +1,35 @@ +// Stamina Buffer + +// Standard amounts for stamina usage + +// Multipliers +/// Base stamina cost for an item of a certain w_class without total_mass set. +#define STAM_COST_W_CLASS_MULT 1.25 + +// Flat amounts +/// Usage for eyestabbing with a screwdriver +#define STAMINA_COST_ITEM_EYESTAB 7.5 +/// Usage for shoving yourself off the ground instantly +#define STAMINA_COST_SHOVE_UP 10 + +//items total mass, used to calculate their attacks' stamina costs. If not defined, the cost will be (w_class * 1.25) +#define TOTAL_MASS_TINY_ITEM 1.25 +#define TOTAL_MASS_SMALL_ITEM 2.5 +#define TOTAL_MASS_NORMAL_ITEM 3.75 +#define TOTAL_MASS_BULKY_ITEM 5 +#define TOTAL_MASS_HUGE_ITEM 6.25 +#define TOTAL_MASS_GIGANTIC_ITEM 7.5 + +#define TOTAL_MASS_HAND_REPLACEMENT 5 //standard punching stamina cost. most hand replacements are huge items anyway. +#define TOTAL_MASS_MEDIEVAL_WEAPON 3.6 //very, very generic average sword/warpick/etc. weight in pounds. +#define TOTAL_MASS_TOY_SWORD 1.5 + +//stamina cost defines. +#define STAM_COST_ATTACK_OBJ_MULT 0.75 +#define STAM_COST_ATTACK_MOB_MULT 1 +#define STAM_COST_BATON_MOB_MULT 0.85 +#define STAM_COST_THROW_MULT 0.75 +#define STAM_COST_THROW_MOB 1.25 //multiplied by (mob size + 1)^2. + +/// Damage penalty when fighting prone. +#define LYING_DAMAGE_PENALTY 0.7 diff --git a/code/__DEFINES/configuration.dm b/code/__DEFINES/configuration.dm index 20c1df2ec7..0428a16828 100644 --- a/code/__DEFINES/configuration.dm +++ b/code/__DEFINES/configuration.dm @@ -3,6 +3,8 @@ #define CONFIG_SET(X, Y) global.config.Set(/datum/config_entry/##X, ##Y) /// Gets the datum of the object, for when editing a const define. #define CONFIG_GET_ENTRY(X) global.config.GetEntryDatum(/datum/config_entry/##X) +/// Caches an entry in the proc +#define CONFIG_CACHE_ENTRY_AND_FETCH_VALUE(X, varname) var/static/datum/config_entry/##X/entrycache_##varname;if(!entrycache_##varname){entrycache_##varname=CONFIG_GET_ENTRY(##X);};var/##varname=entrycache_##varname.config_entry_value #define CONFIG_MAPS_FILE "maps.txt" diff --git a/code/__DEFINES/maps.dm b/code/__DEFINES/maps.dm index c5c2dd58c2..854b6c9dcf 100644 --- a/code/__DEFINES/maps.dm +++ b/code/__DEFINES/maps.dm @@ -20,11 +20,6 @@ Multi-Z stations are supported and multi-Z mining and away missions would require only minor tweaks. */ -// helpers for modifying jobs, used in various job_changes.dm files -#define MAP_JOB_CHECK if(SSmapping.config.map_name != JOB_MODIFICATION_MAP_NAME) { return; } -#define MAP_JOB_CHECK_BASE if(SSmapping.config.map_name != JOB_MODIFICATION_MAP_NAME) { return ..(); } -#define MAP_REMOVE_JOB(jobpath) /datum/job/##jobpath/map_check() { return (SSmapping.config.map_name != JOB_MODIFICATION_MAP_NAME) && ..() } - #define SPACERUIN_MAP_EDGE_PAD 15 // traits diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index dae1b9bf95..e8849d04c8 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -1,17 +1,17 @@ /*ALL MOB-RELATED DEFINES THAT DON'T BELONG IN ANOTHER FILE GO HERE*/ -//Misc mob defines +// Misc mob defines -//Ready states at roundstart for mob/dead/new_player +// Ready states at roundstart for mob/dead/new_player #define PLAYER_NOT_READY 0 #define PLAYER_READY_TO_PLAY 1 #define PLAYER_READY_TO_OBSERVE 2 -//movement intent defines for the m_intent var +// movement intent defines for the m_intent var #define MOVE_INTENT_WALK "walk" #define MOVE_INTENT_RUN "run" -//Blood levels +// Blood levels #define BLOOD_VOLUME_MAX_LETHAL 2150 #define BLOOD_VOLUME_EXCESS 2100 #define BLOOD_VOLUME_MAXIMUM 2000 @@ -22,34 +22,34 @@ #define BLOOD_VOLUME_BAD 224 #define BLOOD_VOLUME_SURVIVE 122 -//Sizes of mobs, used by mob/living/var/mob_size +// Sizes of mobs, used by mob/living/var/mob_size #define MOB_SIZE_TINY 0 #define MOB_SIZE_SMALL 1 #define MOB_SIZE_HUMAN 2 #define MOB_SIZE_LARGE 3 -//Ventcrawling defines +// Ventcrawling defines #define VENTCRAWLER_NONE 0 #define VENTCRAWLER_NUDE 1 #define VENTCRAWLER_ALWAYS 2 -//Bloodcrawling defines +// Bloodcrawling defines #define BLOODCRAWL 1 #define BLOODCRAWL_EAT 2 -//Mob bio-types flags -#define MOB_ORGANIC (1 << 0) +// Mob bio-types flags +#define MOB_ORGANIC (1 << 0) #define MOB_MINERAL (1 << 1) -#define MOB_ROBOTIC (1 << 2) +#define MOB_ROBOTIC (1 << 2) #define MOB_UNDEAD (1 << 3) -#define MOB_HUMANOID (1 << 4) -#define MOB_BUG (1 << 5) +#define MOB_HUMANOID (1 << 4) +#define MOB_BUG (1 << 5) #define MOB_BEAST (1 << 6) -#define MOB_EPIC (1 << 7) //megafauna +#define MOB_EPIC (1 << 7) // Megafauna #define MOB_REPTILE (1 << 8) #define MOB_SPIRIT (1 << 9) -//Organ defines for carbon mobs +// Organ defines for carbon mobs #define ORGAN_ORGANIC 1 #define ORGAN_ROBOTIC 2 @@ -70,194 +70,194 @@ #define DEFAULT_BODYPART_ICON_ROBOTIC 'icons/mob/augmentation/augments.dmi' #define MONKEY_BODYPART "monkey" -#define ALIEN_BODYPART "alien" -#define LARVA_BODYPART "larva" -#define DEVIL_BODYPART "devil" +#define ALIEN_BODYPART "alien" +#define LARVA_BODYPART "larva" +#define DEVIL_BODYPART "devil" /*see __DEFINES/inventory.dm for bodypart bitflag defines*/ // Health/damage defines for carbon mobs #define HUMAN_MAX_OXYLOSS 3 #define HUMAN_CRIT_MAX_OXYLOSS (SSmobs.wait/30) -#define HEAT_DAMAGE_LEVEL_1 2 //Amount of damage applied when your body temperature just passes the 360.15k safety point -#define HEAT_DAMAGE_LEVEL_2 3 //Amount of damage applied when your body temperature passes the 400K point -#define HEAT_DAMAGE_LEVEL_3 8 //Amount of damage applied when your body temperature passes the 460K point and you are on fire +#define HEAT_DAMAGE_LEVEL_1 2 // Amount of damage applied when your body temperature just passes the 360.15k safety point +#define HEAT_DAMAGE_LEVEL_2 3 // Amount of damage applied when your body temperature passes the 400K point +#define HEAT_DAMAGE_LEVEL_3 8 // Amount of damage applied when your body temperature passes the 460K point and you are on fire -#define COLD_DAMAGE_LEVEL_1 0.5 //Amount of damage applied when your body temperature just passes the 260.15k safety point -#define COLD_DAMAGE_LEVEL_2 1.5 //Amount of damage applied when your body temperature passes the 200K point -#define COLD_DAMAGE_LEVEL_3 3 //Amount of damage applied when your body temperature passes the 120K point +#define COLD_DAMAGE_LEVEL_1 0.5 // Amount of damage applied when your body temperature just passes the 260.15k safety point +#define COLD_DAMAGE_LEVEL_2 1.5 // Amount of damage applied when your body temperature passes the 200K point +#define COLD_DAMAGE_LEVEL_3 3 // Amount of damage applied when your body temperature passes the 120K point -//Note that gas heat damage is only applied once every FOUR ticks. -#define HEAT_GAS_DAMAGE_LEVEL_1 2 //Amount of damage applied when the current breath's temperature just passes the 360.15k safety point -#define HEAT_GAS_DAMAGE_LEVEL_2 4 //Amount of damage applied when the current breath's temperature passes the 400K point -#define HEAT_GAS_DAMAGE_LEVEL_3 8 //Amount of damage applied when the current breath's temperature passes the 1000K point +// Note that gas heat damage is only applied once every FOUR ticks. +#define HEAT_GAS_DAMAGE_LEVEL_1 2 // Amount of damage applied when the current breath's temperature just passes the 360.15k safety point +#define HEAT_GAS_DAMAGE_LEVEL_2 4 // Amount of damage applied when the current breath's temperature passes the 400K point +#define HEAT_GAS_DAMAGE_LEVEL_3 8 // Amount of damage applied when the current breath's temperature passes the 1000K point -#define COLD_GAS_DAMAGE_LEVEL_1 0.5 //Amount of damage applied when the current breath's temperature just passes the 260.15k safety point -#define COLD_GAS_DAMAGE_LEVEL_2 1.5 //Amount of damage applied when the current breath's temperature passes the 200K point -#define COLD_GAS_DAMAGE_LEVEL_3 3 //Amount of damage applied when the current breath's temperature passes the 120K point +#define COLD_GAS_DAMAGE_LEVEL_1 0.5 // Amount of damage applied when the current breath's temperature just passes the 260.15k safety point +#define COLD_GAS_DAMAGE_LEVEL_2 1.5 // Amount of damage applied when the current breath's temperature passes the 200K point +#define COLD_GAS_DAMAGE_LEVEL_3 3 // Amount of damage applied when the current breath's temperature passes the 120K point -//Brain Damage defines -#define BRAIN_DAMAGE_MILD 20 +// Brain Damage defines +#define BRAIN_DAMAGE_MILD 20 #define BRAIN_DAMAGE_SEVERE 100 -#define BRAIN_DAMAGE_DEATH 200 +#define BRAIN_DAMAGE_DEATH 200 #define BRAIN_TRAUMA_MILD /datum/brain_trauma/mild #define BRAIN_TRAUMA_SEVERE /datum/brain_trauma/severe #define BRAIN_TRAUMA_SPECIAL /datum/brain_trauma/special #define BRAIN_TRAUMA_MAGIC /datum/brain_trauma/magic -#define TRAUMA_RESILIENCE_BASIC 1 //Curable with chems -#define TRAUMA_RESILIENCE_SURGERY 2 //Curable with brain surgery -#define TRAUMA_RESILIENCE_LOBOTOMY 3 //Curable with lobotomy -#define TRAUMA_RESILIENCE_WOUND 4 //Curable by healing the head wound -#define TRAUMA_RESILIENCE_MAGIC 5 //Curable only with magic -#define TRAUMA_RESILIENCE_ABSOLUTE 6 //This is here to stay +#define TRAUMA_RESILIENCE_BASIC 1 // Curable with chems +#define TRAUMA_RESILIENCE_SURGERY 2 // Curable with brain surgery +#define TRAUMA_RESILIENCE_LOBOTOMY 3 // Curable with lobotomy +#define TRAUMA_RESILIENCE_WOUND 4 // Curable by healing the head wound +#define TRAUMA_RESILIENCE_MAGIC 5 // Curable only with magic +#define TRAUMA_RESILIENCE_ABSOLUTE 6 // This is here to stay -//Limit of traumas for each resilience tier -#define TRAUMA_LIMIT_BASIC 3 -#define TRAUMA_LIMIT_SURGERY 2 -#define TRAUMA_LIMIT_WOUND 2 +// Limit of traumas for each resilience tier +#define TRAUMA_LIMIT_BASIC 3 +#define TRAUMA_LIMIT_SURGERY 2 +#define TRAUMA_LIMIT_WOUND 2 #define TRAUMA_LIMIT_LOBOTOMY 3 -#define TRAUMA_LIMIT_MAGIC 3 +#define TRAUMA_LIMIT_MAGIC 3 #define TRAUMA_LIMIT_ABSOLUTE INFINITY #define BRAIN_DAMAGE_INTEGRITY_MULTIPLIER 0.5 -//Surgery Defines +// Surgery Defines #define BIOWARE_GENERIC "generic" #define BIOWARE_NERVES "nerves" #define BIOWARE_CIRCULATION "circulation" #define BIOWARE_LIGAMENTS "ligaments" -//Health hud screws for carbon mobs -#define SCREWYHUD_NONE 0 -#define SCREWYHUD_CRIT 1 -#define SCREWYHUD_DEAD 2 +// Health hud screws for carbon mobs +#define SCREWYHUD_NONE 0 +#define SCREWYHUD_CRIT 1 +#define SCREWYHUD_DEAD 2 #define SCREWYHUD_HEALTHY 3 -//Threshold levels for beauty for humans +// Threshold levels for beauty for humans #define BEAUTY_LEVEL_HORRID -66 -#define BEAUTY_LEVEL_BAD -33 -#define BEAUTY_LEVEL_DECENT 33 -#define BEAUTY_LEVEL_GOOD 66 -#define BEAUTY_LEVEL_GREAT 100 +#define BEAUTY_LEVEL_BAD -33 +#define BEAUTY_LEVEL_DECENT 33 +#define BEAUTY_LEVEL_GOOD 66 +#define BEAUTY_LEVEL_GREAT 100 -//Moods levels for humans -#define MOOD_LEVEL_HAPPY4 15 -#define MOOD_LEVEL_HAPPY3 10 -#define MOOD_LEVEL_HAPPY2 6 -#define MOOD_LEVEL_HAPPY1 2 -#define MOOD_LEVEL_NEUTRAL 0 -#define MOOD_LEVEL_SAD1 -3 -#define MOOD_LEVEL_SAD2 -12 -#define MOOD_LEVEL_SAD3 -18 -#define MOOD_LEVEL_SAD4 -25 +// Moods levels for humans +#define MOOD_LEVEL_HAPPY4 15 +#define MOOD_LEVEL_HAPPY3 10 +#define MOOD_LEVEL_HAPPY2 6 +#define MOOD_LEVEL_HAPPY1 2 +#define MOOD_LEVEL_NEUTRAL 0 +#define MOOD_LEVEL_SAD1 -3 +#define MOOD_LEVEL_SAD2 -12 +#define MOOD_LEVEL_SAD3 -18 +#define MOOD_LEVEL_SAD4 -25 -//Sanity levels for humans -#define SANITY_AMAZING 150 -#define SANITY_GREAT 125 -#define SANITY_NEUTRAL 100 +// Sanity levels for humans +#define SANITY_AMAZING 150 +#define SANITY_GREAT 125 +#define SANITY_NEUTRAL 100 #define SANITY_DISTURBED 75 -#define SANITY_UNSTABLE 50 -#define SANITY_CRAZY 25 -#define SANITY_INSANE 0 +#define SANITY_UNSTABLE 50 +#define SANITY_CRAZY 25 +#define SANITY_INSANE 0 -//Nutrition levels for humans -#define NUTRITION_LEVEL_FAT 600 -#define NUTRITION_LEVEL_FULL 550 +// Nutrition levels for humans +#define NUTRITION_LEVEL_FAT 600 +#define NUTRITION_LEVEL_FULL 550 #define NUTRITION_LEVEL_WELL_FED 450 -#define NUTRITION_LEVEL_FED 350 -#define NUTRITION_LEVEL_HUNGRY 250 +#define NUTRITION_LEVEL_FED 350 +#define NUTRITION_LEVEL_HUNGRY 250 #define NUTRITION_LEVEL_STARVING 150 #define NUTRITION_LEVEL_START_MIN 250 #define NUTRITION_LEVEL_START_MAX 400 -//Disgust levels for humans -#define DISGUST_LEVEL_MAXEDOUT 150 -#define DISGUST_LEVEL_DISGUSTED 75 -#define DISGUST_LEVEL_VERYGROSS 50 -#define DISGUST_LEVEL_GROSS 25 +// Disgust levels for humans +#define DISGUST_LEVEL_MAXEDOUT 150 +#define DISGUST_LEVEL_DISGUSTED 75 +#define DISGUST_LEVEL_VERYGROSS 50 +#define DISGUST_LEVEL_GROSS 25 -//Charge levels for Ethereals -#define ETHEREAL_CHARGE_NONE 0 -#define ETHEREAL_CHARGE_LOWPOWER 20 -#define ETHEREAL_CHARGE_NORMAL 50 +// Charge levels for Ethereals +#define ETHEREAL_CHARGE_NONE 0 +#define ETHEREAL_CHARGE_LOWPOWER 20 +#define ETHEREAL_CHARGE_NORMAL 50 #define ETHEREAL_CHARGE_ALMOSTFULL 75 -#define ETHEREAL_CHARGE_FULL 100 -#define ETHEREAL_CHARGE_OVERLOAD 125 +#define ETHEREAL_CHARGE_FULL 100 +#define ETHEREAL_CHARGE_OVERLOAD 125 #define ETHEREAL_CHARGE_DANGEROUS 150 -//Slime evolution threshold. Controls how fast slimes can split/grow +// Slime evolution threshold. Controls how fast slimes can split/grow #define SLIME_EVOLUTION_THRESHOLD 10 -//Slime extract crossing. Controls how many extracts is required to feed to a slime to core-cross. +// Slime extract crossing. Controls how many extracts is required to feed to a slime to core-cross. #define SLIME_EXTRACT_CROSSING_REQUIRED 10 -//Slime commands defines -#define SLIME_FRIENDSHIP_FOLLOW 3 //Min friendship to order it to follow -#define SLIME_FRIENDSHIP_STOPEAT 5 //Min friendship to order it to stop eating someone -#define SLIME_FRIENDSHIP_STOPEAT_NOANGRY 7 //Min friendship to order it to stop eating someone without it losing friendship -#define SLIME_FRIENDSHIP_STOPCHASE 4 //Min friendship to order it to stop chasing someone (their target) -#define SLIME_FRIENDSHIP_STOPCHASE_NOANGRY 6 //Min friendship to order it to stop chasing someone (their target) without it losing friendship -#define SLIME_FRIENDSHIP_STAY 3 //Min friendship to order it to stay -#define SLIME_FRIENDSHIP_ATTACK 8 //Min friendship to order it to attack +// Slime commands defines +#define SLIME_FRIENDSHIP_FOLLOW 3 // Min friendship to order it to follow +#define SLIME_FRIENDSHIP_STOPEAT 5 // Min friendship to order it to stop eating someone +#define SLIME_FRIENDSHIP_STOPEAT_NOANGRY 7 // Min friendship to order it to stop eating someone without it losing friendship +#define SLIME_FRIENDSHIP_STOPCHASE 4 // Min friendship to order it to stop chasing someone (their target) +#define SLIME_FRIENDSHIP_STOPCHASE_NOANGRY 6 // Min friendship to order it to stop chasing someone (their target) without it losing friendship +#define SLIME_FRIENDSHIP_STAY 3 // Min friendship to order it to stay +#define SLIME_FRIENDSHIP_ATTACK 8 // Min friendship to order it to attack -//Sentience types, to prevent things like sentience potions from giving bosses sentience -#define SENTIENCE_ORGANIC 1 +// Sentience types, to prevent things like sentience potions from giving bosses sentience +#define SENTIENCE_ORGANIC 1 #define SENTIENCE_ARTIFICIAL 2 -// #define SENTIENCE_OTHER 3 unused -#define SENTIENCE_MINEBOT 4 -#define SENTIENCE_BOSS 5 +//#define SENTIENCE_OTHER 3 // Unused +#define SENTIENCE_MINEBOT 4 +#define SENTIENCE_BOSS 5 -//Mob AI Status +// Mob AI Status -//Hostile simple animals -//If you add a new status, be sure to add a list for it to the simple_animals global in _globalvars/lists/mobs.dm +// Hostile simple animals +// If you add a new status, be sure to add a list for it to the simple_animals global in _globalvars/lists/mobs.dm #define AI_ON 1 #define AI_IDLE 2 #define AI_OFF 3 #define AI_Z_OFF 4 -//determines if a mob can smash through it -#define ENVIRONMENT_SMASH_NONE 0 -#define ENVIRONMENT_SMASH_STRUCTURES (1<<0) //crates, lockers, ect -#define ENVIRONMENT_SMASH_WALLS (1<<1) //walls -#define ENVIRONMENT_SMASH_RWALLS (1<<2) //rwalls +// determines if a mob can smash through it +#define ENVIRONMENT_SMASH_NONE 0 +#define ENVIRONMENT_SMASH_STRUCTURES (1<<0) // crates, lockers, ect +#define ENVIRONMENT_SMASH_WALLS (1<<1) // walls +#define ENVIRONMENT_SMASH_RWALLS (1<<2) // rwalls -#define NO_SLIP_WHEN_WALKING (1<<0) -#define SLIDE (1<<1) -#define GALOSHES_DONT_HELP (1<<2) -#define FLYING_DOESNT_HELP (1<<3) -#define SLIDE_ICE (1<<4) -#define SLIP_WHEN_CRAWLING (1<<5) //clown planet ruin amongst others -#define SLIP_WHEN_JOGGING (1<<6) //slips prevented by walking are also dodged if the mob is nor sprinting or fatigued... unless this flag is on. +#define NO_SLIP_WHEN_WALKING (1<<0) +#define SLIDE (1<<1) +#define GALOSHES_DONT_HELP (1<<2) +#define FLYING_DOESNT_HELP (1<<3) +#define SLIDE_ICE (1<<4) +#define SLIP_WHEN_CRAWLING (1<<5) // clown planet ruin amongst others +#define SLIP_WHEN_JOGGING (1<<6) // slips prevented by walking are also dodged if the mob is nor sprinting or fatigued... unless this flag is on. #define MAX_CHICKENS 50 -///Flags used by the flags parameter of electrocute act. +// /Flags used by the flags parameter of electrocute act. -///Makes it so that the shock doesn't take gloves into account. -#define SHOCK_NOGLOVES (1 << 0) -///Used when the shock is from a tesla bolt. -#define SHOCK_TESLA (1 << 1) -///Used when an illusion shocks something. Makes the shock deal stamina damage and not trigger certain secondary effects. -#define SHOCK_ILLUSION (1 << 2) -///The shock doesn't stun. -#define SHOCK_NOSTUN (1 << 3) +// /Makes it so that the shock doesn't take gloves into account. +#define SHOCK_NOGLOVES (1 << 0) +// /Used when the shock is from a tesla bolt. +#define SHOCK_TESLA (1 << 1) +// /Used when an illusion shocks something. Makes the shock deal stamina damage and not trigger certain secondary effects. +#define SHOCK_ILLUSION (1 << 2) +// /The shock doesn't stun. +#define SHOCK_NOSTUN (1 << 3) -#define INCORPOREAL_MOVE_BASIC 1 -#define INCORPOREAL_MOVE_SHADOW 2 // leaves a trail of shadows -#define INCORPOREAL_MOVE_JAUNT 3 // is blocked by holy water/salt +#define INCORPOREAL_MOVE_BASIC 1 +#define INCORPOREAL_MOVE_SHADOW 2 // leaves a trail of shadows +#define INCORPOREAL_MOVE_JAUNT 3 // is blocked by holy water/salt -//Secbot and ED209 judgement criteria bitflag values +// Secbot and ED209 judgement criteria bitflag values #define JUDGE_EMAGGED (1<<0) #define JUDGE_IDCHECK (1<<1) #define JUDGE_WEAPONCHECK (1<<2) #define JUDGE_RECORDCHECK (1<<3) -//ED209's ignore monkeys +// ED209's ignore monkeys #define JUDGE_IGNOREMONKEYS (1<<4) #define MEGAFAUNA_DEFAULT_RECOVERY_TIME 5 @@ -266,45 +266,45 @@ // Offsets defines -#define OFFSET_UNIFORM "uniform" -#define OFFSET_ID "id" -#define OFFSET_GLOVES "gloves" -#define OFFSET_GLASSES "glasses" -#define OFFSET_EARS "ears" -#define OFFSET_SHOES "shoes" -#define OFFSET_S_STORE "s_store" -#define OFFSET_FACEMASK "mask" -#define OFFSET_HEAD "head" -#define OFFSET_EYES "eyes" -#define OFFSET_LIPS "lips" -#define OFFSET_BELT "belt" -#define OFFSET_BACK "back" -#define OFFSET_SUIT "suit" -#define OFFSET_NECK "neck" -#define OFFSET_HAIR "hair" -#define OFFSET_FHAIR "fhair" -#define OFFSET_MUTPARTS "mutantparts" +#define OFFSET_UNIFORM "uniform" +#define OFFSET_ID "id" +#define OFFSET_GLOVES "gloves" +#define OFFSET_GLASSES "glasses" +#define OFFSET_EARS "ears" +#define OFFSET_SHOES "shoes" +#define OFFSET_S_STORE "s_store" +#define OFFSET_FACEMASK "mask" +#define OFFSET_HEAD "head" +#define OFFSET_EYES "eyes" +#define OFFSET_LIPS "lips" +#define OFFSET_BELT "belt" +#define OFFSET_BACK "back" +#define OFFSET_SUIT "suit" +#define OFFSET_NECK "neck" +#define OFFSET_HAIR "hair" +#define OFFSET_FHAIR "fhair" +#define OFFSET_MUTPARTS "mutantparts" -//MINOR TWEAKS/MISC -#define AGE_MIN 18 //youngest a character can be //CITADEL EDIT - 17 --> 18 -#define AGE_MAX 85 //oldest a character can be -#define WIZARD_AGE_MIN 30 //youngest a wizard can be -#define APPRENTICE_AGE_MIN 29 //youngest an apprentice can be -#define SHOES_SLOWDOWN 0 //How much shoes slow you down by default. Negative values speed you up -#define SHOES_SPEED_SLIGHT SHOES_SLOWDOWN - 1 // slightest speed boost to movement -#define POCKET_STRIP_DELAY 40 //time taken (in deciseconds) to search somebody's pockets -#define DOOR_CRUSH_DAMAGE 15 //the amount of damage that airlocks deal when they crush you +// MINOR TWEAKS/MISC +#define AGE_MIN 18 // youngest a character can be // CITADEL EDIT - 17 --> 18 +#define AGE_MAX 85 // oldest a character can be +#define WIZARD_AGE_MIN 30 // youngest a wizard can be +#define APPRENTICE_AGE_MIN 29 // youngest an apprentice can be +#define SHOES_SLOWDOWN 0 // How much shoes slow you down by default. Negative values speed you up +#define SHOES_SPEED_SLIGHT SHOES_SLOWDOWN - 1 // slightest speed boost to movement +#define POCKET_STRIP_DELAY 40 // time taken (in deciseconds) to search somebody's pockets +#define DOOR_CRUSH_DAMAGE 15 // the amount of damage that airlocks deal when they crush you -#define HUNGER_FACTOR 0.1 //factor at which mob nutrition decreases -#define ETHEREAL_CHARGE_FACTOR 0.08 //factor at which ethereal's charge decreases -#define REAGENTS_METABOLISM 0.4 //How many units of reagent are consumed per tick, by default. +#define HUNGER_FACTOR 0.1 // factor at which mob nutrition decreases +#define ETHEREAL_CHARGE_FACTOR 0.08 // factor at which ethereal's charge decreases +#define REAGENTS_METABOLISM 0.4 // How many units of reagent are consumed per tick, by default. #define REAGENTS_EFFECT_MULTIPLIER (REAGENTS_METABOLISM / 0.4) // By defining the effect multiplier this way, it'll exactly adjust all effects according to how they originally were with the 0.4 metabolism // Roundstart trait system -#define MAX_QUIRKS 6 //The maximum amount of quirks one character can have at roundstart +#define MAX_QUIRKS 6 // The maximum amount of quirks one character can have at roundstart -#define MAX_REVIVE_FIRE_DAMAGE 180 +#define MAX_REVIVE_FIRE_DAMAGE 180 #define MAX_REVIVE_BRUTE_DAMAGE 180 // AI Toggles @@ -312,28 +312,28 @@ #define AI_VOX // Comment out if you don't want VOX to be enabled and have players download the voice sounds. // /obj/item/bodypart on_mob_life() retval flag -#define BODYPART_LIFE_UPDATE_HEALTH (1<<0) +#define BODYPART_LIFE_UPDATE_HEALTH (1<<0) #define HUMAN_FIRE_STACK_ICON_NUM 3 #define TYPING_INDICATOR_TIMEOUT 20 MINUTES -#define GRAB_PIXEL_SHIFT_PASSIVE 6 -#define GRAB_PIXEL_SHIFT_AGGRESSIVE 12 -#define GRAB_PIXEL_SHIFT_NECK 16 +#define GRAB_PIXEL_SHIFT_PASSIVE 6 +#define GRAB_PIXEL_SHIFT_AGGRESSIVE 12 +#define GRAB_PIXEL_SHIFT_NECK 16 #define SLEEP_CHECK_DEATH(X) sleep(X); if(QDELETED(src) || stat == DEAD) return; #define INTERACTING_WITH(X, Y) (Y in X.do_afters) -/// Field of vision defines. +// / Field of vision defines. #define FOV_90_DEGREES 90 #define FOV_180_DEGREES 180 #define FOV_270_DEGREES 270 -/// How far away you can be to make eye contact with someone while examining +// / How far away you can be to make eye contact with someone while examining #define EYE_CONTACT_RANGE 5 -/// If you examine the same atom twice in this timeframe, we call examine_more() instead of examine() +// / If you examine the same atom twice in this timeframe, we call examine_more() instead of examine() #define EXAMINE_MORE_TIME 1 SECONDS -#define SILENCE_RANGED_MESSAGE (1<<0) +#define SILENCE_RANGED_MESSAGE (1<<0) diff --git a/code/__DEFINES/skills/defines.dm b/code/__DEFINES/skills/defines.dm index 47aaeeb1dc..a0b34895df 100644 --- a/code/__DEFINES/skills/defines.dm +++ b/code/__DEFINES/skills/defines.dm @@ -40,7 +40,6 @@ #define SKILL_TRAIN_ATTACK_OBJ "train_attack_obj" #define SKILL_STAMINA_COST "stamina_cost" //Influences the stamina cost from weapon usage. #define SKILL_THROW_STAM_COST "throw_stam_cost" -#define SKILL_COMBAT_MODE "combat_mode" //The user must have combat mode on. #define SKILL_SANITY "sanity" //Is the skill affected by (in)sanity. #define SKILL_INTELLIGENCE "intelligence" //Is the skill affected by brain damage? diff --git a/code/__DEFINES/species.dm b/code/__DEFINES/species.dm new file mode 100644 index 0000000000..c6cc6a5037 --- /dev/null +++ b/code/__DEFINES/species.dm @@ -0,0 +1,50 @@ + +// Species ID Defines --------------------------- + +#define SPECIES_ABDUCTOR "abductor" +#define SPECIES_ANDROID "android" +#define SPECIES_ANGEL "angel" +#define SPECIES_MAMMAL "mammal" +#define SPECIES_INSECT "insect" +#define SPECIES_DULLAHAN "dullahan" +#define SPECIES_DWARF "dwarf" +#define SPECIES_ETHEREAL "ethereal" +#define SPECIES_FELINID "felinid" +#define SPECIES_FLY "fly" +#define SPECIES_GOLEM "golem" +#define SPECIES_HUMAN "human" +#define SPECIES_IPC "ipc" +#define SPECIES_JELLY "jelly" + #define SPECIES_SLIME "slime" + #define SPECIES_SLIME_HYBRID "slimeperson" + #define SPECIES_SLIME_LUMI "slimelumi" + #define SPECIES_STARGAZER "stargazer" +#define SPECIES_LIZARD "lizard" + #define SPECIES_ASHWALKER "ashlizard" +#define SPECIES_MUSHROOM "mush" +#define SPECIES_PLASMAMAN "plasmaman" +#define SPECIES_POD "pod" + #define SPECIES_POD_WEAK "podweak" +#define SPECIES_SHADOW "shadow" + #define SPECIES_NIGHTMARE "nightmare" +#define SPECIES_SKELETON "skeleton" + #define SPECIES_SKELETON_SPACE "spaceskeleton" +#define SPECIES_SYNTH_LIZARD "synthliz" +#define SPECIES_SYNTH "synth" + #define SPECIES_SYNTH_MIL "military_synth" +#define SPECIES_VAMPIRE "vampire" +#define SPECIES_XENOHYBRID "xeno" + +// Species Category Defines --------------------- + +#define SPECIES_CATEGORY_ALIEN "alien" +#define SPECIES_CATEGORY_BASIC "human" +#define SPECIES_CATEGORY_FURRY "furry" // Weird Category, but okay. +#define SPECIES_CATEGORY_GOLEM "golem" +#define SPECIES_CATEGORY_INSECT "insect" +#define SPECIES_CATEGORY_PLANT "plant" +#define SPECIES_CATEGORY_ROBOT "robotic" +#define SPECIES_CATEGORY_JELLY "jelly" +#define SPECIES_CATEGORY_SHADOW "shadow" +#define SPECIES_CATEGORY_SKELETON "skeleton" +#define SPECIES_CATEGORY_UNDEAD "undead" diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index 80633148e9..520f205381 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -164,6 +164,7 @@ #define TRAIT_NO_MIDROUND_ANTAG "no-midround-antag" //can't be turned into an antag by random events #define TRAIT_PUGILIST "pugilist" //This guy punches people for a living #define TRAIT_KI_VAMPIRE "ki-vampire" //when someone with this trait rolls maximum damage on a punch and stuns the target, they regain some stamina and do clone damage +#define TRAIT_MAULER "mauler" // this guy punches the shit out of people to hurt them, not to drain their stamina #define TRAIT_PASSTABLE "passtable" #define TRAIT_GIANT "giant" #define TRAIT_DWARF "dwarf" @@ -207,6 +208,10 @@ #define TRAIT_FAST_PUMP "fast_pump" #define TRAIT_NO_PROCESS_FOOD "no-process-food" // You don't get benefits from nutriment, nor nutrition from reagent consumables #define TRAIT_NICE_SHOT "nice_shot" //hnnnnnnnggggg..... you're pretty good... +/// Prevents stamina buffer regeneration +#define TRAIT_NO_STAMINA_BUFFER_REGENERATION "block_stamina_buffer_regen" +/// Prevents stamina regeneration +#define TRAIT_NO_STAMINA_REGENERATION "block_stamina_regen" // mobility flag traits // IN THE FUTURE, IT WOULD BE NICE TO DO SOMETHING SIMILAR TO https://github.com/tgstation/tgstation/pull/48923/files (ofcourse not nearly the same because I have my.. thoughts on it) diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index 85f5e4fd9b..b558b28cf2 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -252,7 +252,6 @@ GLOBAL_LIST_INIT(bitfields, list( "COMBAT_FLAG_SPRINT_ACTIVE" = COMBAT_FLAG_SPRINT_ACTIVE, "COMBAT_FLAG_ATTEMPTING_CRAWL" = COMBAT_FLAG_ATTEMPTING_CRAWL, "COMBAT_FLAG_HARD_STAMCRIT" = COMBAT_FLAG_HARD_STAMCRIT, - "COMBAT_FLAG_SOFT_STAMCRIT" = COMBAT_FLAG_SOFT_STAMCRIT, "COMBAT_FLAG_INTENTIONALLY_RESTING" = COMBAT_FLAG_INTENTIONALLY_RESTING, "COMBAT_FLAG_RESISTING_REST" = COMBAT_FLAG_RESISTING_REST, "COMBAT_FLAG_SPRINT_FORCED" = COMBAT_FLAG_SPRINT_FORCED diff --git a/code/_globalvars/lists/flavor_misc.dm b/code/_globalvars/lists/flavor_misc.dm index 9d8da6c145..a327b7fcde 100644 --- a/code/_globalvars/lists/flavor_misc.dm +++ b/code/_globalvars/lists/flavor_misc.dm @@ -282,7 +282,7 @@ GLOBAL_LIST_INIT(unlocked_mutant_parts, list("horns", "insect_fluff")) GLOBAL_LIST_INIT(colored_mutant_parts, list("insect_wings" = "wings_color", "deco_wings" = "wings_color", "horns" = "horns_color")) //body ids that have greyscale sprites -GLOBAL_LIST_INIT(greyscale_limb_types, list("human","moth","lizard","pod","plant","jelly","slime","golem","lum","stargazer","mush","ethereal","snail","c_golem","b_golem","mammal","xeno","ipc","insect","synthliz","avian","aquatic")) +GLOBAL_LIST_INIT(greyscale_limb_types, list("human","moth","lizard","pod","plant","jelly","slime","golem","slimelumi","stargazer","mush","ethereal","snail","c_golem","b_golem","mammal","xeno","ipc","insect","synthliz","avian","aquatic")) //body ids that have prosthetic sprites GLOBAL_LIST_INIT(prosthetic_limb_types, list("xion","bishop","cybersolutions","grayson","hephaestus","nanotrasen","talon")) diff --git a/code/_globalvars/lists/mobs.dm b/code/_globalvars/lists/mobs.dm index 134f9d9cbe..64bac1f9af 100644 --- a/code/_globalvars/lists/mobs.dm +++ b/code/_globalvars/lists/mobs.dm @@ -40,6 +40,7 @@ GLOBAL_LIST_EMPTY(sentient_disease_instances) GLOBAL_LIST_EMPTY(latejoin_ai_cores) GLOBAL_LIST_EMPTY(mob_config_movespeed_type_lookup) +GLOBAL_LIST_EMPTY(mob_config_movespeed_type_lookup_floating) GLOBAL_LIST_EMPTY(latejoiners) //CIT CHANGE - All latejoining people, for traitor-target purposes. @@ -47,14 +48,22 @@ GLOBAL_LIST_EMPTY(latejoiners) //CIT CHANGE - All latejoining people, for traito // NOTE: This is entirely based on the fact that byond typesof/subtypesof gets longer/deeper paths before shallower ones. // If that ever breaks this entire proc breaks. var/list/mob_types = typesof(/mob) - var/list/entry_value = CONFIG_GET(keyed_list/multiplicative_movespeed) + var/list/mob_types_floating = typesof(/mob) + var/list/entry_value = CONFIG_GET(keyed_list/multiplicative_movespeed/normal) + var/list/entry_value_floating = CONFIG_GET(keyed_list/multiplicative_movespeed/floating) var/list/configured_types = list() + var/list/configured_types_floating = list() for(var/path in entry_value) var/value = entry_value[path] if(isnull(value)) continue // associative list sets for elements that already exist preserve order mob_types[path] = value + for(var/path in entry_value_floating) + var/value = entry_value_floating[path] + if(isnull(value)) + continue + mob_types_floating[path] = value // now go back up through it to set everything, making absolute sure that base paths are overridden by child paths all the way down the path tree. for(var/i in length(mob_types) to 1 step -1) var/path = mob_types[i] @@ -63,7 +72,14 @@ GLOBAL_LIST_EMPTY(latejoiners) //CIT CHANGE - All latejoining people, for traito // we're going from bottom to top so it should be safe to do this without further checks.. for(var/subpath in typesof(path)) configured_types[subpath] = mob_types[path] + for(var/i in length(mob_types_floating) to 1 step -1) + var/path = mob_types_floating[i] + if(isnull(mob_types_floating[path])) + continue + for(var/subpath in typesof(path)) + configured_types_floating[subpath] = mob_types_floating[path] GLOB.mob_config_movespeed_type_lookup = configured_types + GLOB.mob_config_movespeed_type_lookup_floating = configured_types_floating if(update_mobs) update_mob_config_movespeeds() diff --git a/code/_onclick/hud/radial.dm b/code/_onclick/hud/radial.dm index 1ead41d513..929e01c6d9 100644 --- a/code/_onclick/hud/radial.dm +++ b/code/_onclick/hud/radial.dm @@ -318,4 +318,4 @@ GLOBAL_LIST_EMPTY(radial_menus) if(istype(custom_check)) if(!custom_check.Invoke()) return - return answer \ No newline at end of file + return answer diff --git a/code/_onclick/hud/screen_objects/stamina.dm b/code/_onclick/hud/screen_objects/stamina.dm index 5484014f8f..98a387d32d 100644 --- a/code/_onclick/hud/screen_objects/stamina.dm +++ b/code/_onclick/hud/screen_objects/stamina.dm @@ -11,7 +11,9 @@ /obj/screen/staminas/Click(location,control,params) if(isliving(usr)) var/mob/living/L = usr - to_chat(L, "You have [L.getStaminaLoss()] stamina loss.
Your stamina buffer can take [L.stambuffer] stamina loss, and recharges at no cost.
Your stamina buffer is [(L.stambuffer*(100/L.stambuffer))-(L.bufferedstam*(100/L.stambuffer))]% full.
") + CONFIG_CACHE_ENTRY_AND_FETCH_VALUE(number/stamina_combat/buffer_max, buffer_max) + to_chat(L, "You have [L.getStaminaLoss()] stamina loss.
\ +
Your stamina buffer is [round((L.stamina_buffer / buffer_max) * 100, 0.1)]% full.
") /obj/screen/staminas/update_icon_state() var/mob/living/carbon/user = hud?.mymob @@ -24,6 +26,19 @@ else icon_state = "stamina[clamp(FLOOR(user.getStaminaLoss() /20, 1), 0, 6)]" +/obj/screen/staminas/update_overlays() + . = ..() + var/mob/living/carbon/user = hud?.mymob + if(!user) + return + var/percent = user.getStaminaLoss() / STAMINA_CRIT + if((user.stat == DEAD) || (user.combat_flags & COMBAT_FLAG_HARD_STAMCRIT) || (user.hal_screwyhud in 1 to 2)) + . += list("stamina_alert3") + else if(percent >= 0.85) + . += list("stamina_alert2") + else if(percent >= 0.7) + . += list("stamina_alert1") + //stam buffer /obj/screen/staminabuffer icon = 'modular_citadel/icons/ui/screen_gen.dmi' @@ -33,29 +48,33 @@ layer = ABOVE_HUD_LAYER + 0.1 mouse_opacity = 0 -/obj/screen/staminabuffer/update_icon_state() +/obj/screen/staminabuffer/proc/mark_dirty() + if(update_to_mob()) + START_PROCESSING(SShuds, src) + +/obj/screen/staminabuffer/process() + if(!update_to_mob()) + return PROCESS_KILL + +/obj/screen/staminabuffer/Destroy() + STOP_PROCESSING(SShuds, src) + return ..() + +/obj/screen/staminabuffer/proc/update_to_mob() var/mob/living/carbon/user = hud?.mymob - if(!user) - return + user.UpdateStaminaBuffer(FALSE) + CONFIG_CACHE_ENTRY_AND_FETCH_VALUE(number/stamina_combat/buffer_max, buffer_max) + if(!user?.client) + return FALSE if(user.stat == DEAD || (user.combat_flags & COMBAT_FLAG_HARD_STAMCRIT) || (user.hal_screwyhud in 1 to 2)) - icon_state = "stambuffer7" - else if(user.hal_screwyhud == 5) icon_state = "stambuffer0" + return FALSE + else if(user.hal_screwyhud == 5) + icon_state = "stambuffer29" + return FALSE + else if(user.stamina_buffer >= buffer_max) + icon_state = "stambuffer29" + return FALSE else - switch(user.bufferedstam / user.stambuffer) - if(0.95 to INFINITY) - icon_state = "stambuffer7" - if(0.9 to 0.95) - icon_state = "stambuffer6" - if(0.8 to 0.9) - icon_state = "stambuffer5" - if(0.6 to 0.8) - icon_state = "stambuffer4" - if(0.4 to 0.6) - icon_state = "stambuffer3" - if(0.2 to 0.4) - icon_state = "stambuffer2" - if(0.05 to 0.2) - icon_state = "stambuffer1" - else - icon_state = "stambuffer0" + icon_state = "stambuffer[FLOOR((user.stamina_buffer / buffer_max) * 29, 1)]" + return TRUE diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 9e88476513..cd1ee56848 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -85,6 +85,9 @@ if(force && damtype != STAMINA && HAS_TRAIT(user, TRAIT_PACIFISM)) to_chat(user, "You don't want to harm other living beings!") return + + if(!UseStaminaBufferStandard(user, STAM_COST_ATTACK_MOB_MULT, null, TRUE)) + return DISCARD_LAST_ACTION if(!force) playsound(loc, 'sound/weapons/tap.ogg', get_clamped_volume(), 1, -1) @@ -100,10 +103,6 @@ log_combat(user, M, "attacked", src.name, "(INTENT: [uppertext(user.a_intent)]) (DAMTYPE: [uppertext(damtype)])") add_fingerprint(user) - var/weight = getweight(user, STAM_COST_ATTACK_MOB_MULT) //CIT CHANGE - makes attacking things cause stamina loss - if(weight) - user.adjustStaminaLossBuffered(weight) - // CIT SCREENSHAKE if(force >= 15) shake_camera(user, ((force - 10) * 0.01 + 1), ((force - 10) * 0.01)) @@ -120,31 +119,21 @@ if(SEND_SIGNAL(src, COMSIG_ITEM_ATTACK_OBJ, O, user) & COMPONENT_NO_ATTACK_OBJ) return if(item_flags & NOBLUDGEON) - return + return DISCARD_LAST_ACTION + if(!UseStaminaBufferStandard(user, STAM_COST_ATTACK_OBJ_MULT, warn = TRUE)) + return DISCARD_LAST_ACTION user.do_attack_animation(O) O.attacked_by(src, user) - var/weight = getweight(user, STAM_COST_ATTACK_OBJ_MULT) - if(weight) - user.adjustStaminaLossBuffered(weight)//CIT CHANGE - makes attacking things cause stamina loss /atom/movable/proc/attacked_by() return /obj/attacked_by(obj/item/I, mob/living/user, attackchain_flags = NONE, damage_multiplier = 1) var/totitemdamage = I.force * damage_multiplier - var/bad_trait - - var/stamloss = user.getStaminaLoss() - if(stamloss > STAMINA_NEAR_SOFTCRIT) //The more tired you are, the less damage you do. - var/penalty = (stamloss - STAMINA_NEAR_SOFTCRIT)/(STAMINA_NEAR_CRIT - STAMINA_NEAR_SOFTCRIT)*STAM_CRIT_ITEM_ATTACK_PENALTY - totitemdamage *= 1 - penalty - - if(SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE)) - bad_trait = SKILL_COMBAT_MODE //blacklist combat skills. if(I.used_skills && user.mind) if(totitemdamage) - totitemdamage = user.mind.item_action_skills_mod(I, totitemdamage, I.skill_difficulty, SKILL_ATTACK_OBJ, bad_trait) + totitemdamage = user.mind.item_action_skills_mod(I, totitemdamage, I.skill_difficulty, SKILL_ATTACK_OBJ) for(var/skill in I.used_skills) if(!(SKILL_TRAIN_ATTACK_OBJ in I.used_skills[skill])) continue @@ -187,28 +176,15 @@ if(!.) return - var/stamloss = user.getStaminaLoss() var/stam_mobility_mult = 1 - if(stamloss > STAMINA_NEAR_SOFTCRIT) //The more tired you are, the less damage you do. - var/penalty = (stamloss - STAMINA_NEAR_SOFTCRIT)/(STAMINA_NEAR_CRIT - STAMINA_NEAR_SOFTCRIT)*STAM_CRIT_ITEM_ATTACK_PENALTY - stam_mobility_mult -= penalty if(stam_mobility_mult > LYING_DAMAGE_PENALTY && !CHECK_MOBILITY(user, MOBILITY_STAND)) //damage penalty for fighting prone, doesn't stack with the above. stam_mobility_mult = LYING_DAMAGE_PENALTY . *= stam_mobility_mult - var/bad_trait - if(!(I.item_flags & NO_COMBAT_MODE_FORCE_MODIFIER)) - if(SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE)) - bad_trait = SKILL_COMBAT_MODE //blacklist combat skills. - if(SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_ACTIVE)) - . *= 0.8 - else if(SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE)) - . *= 1.2 - if(!user.mind || !I.used_skills) return if(.) - . = user.mind.item_action_skills_mod(I, ., I.skill_difficulty, SKILL_ATTACK_MOB, bad_trait) + . = user.mind.item_action_skills_mod(I, ., I.skill_difficulty, SKILL_ATTACK_MOB) for(var/skill in I.used_skills) if(!(SKILL_TRAIN_ATTACK_MOB in I.used_skills[skill])) continue @@ -263,21 +239,23 @@ . = (total_mass || w_class * STAM_COST_W_CLASS_MULT) * multiplier if(!user) return - var/bad_trait - if(SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE)) - . *= STAM_COST_NO_COMBAT_MULT - bad_trait = SKILL_COMBAT_MODE if(used_skills && user.mind) - . = user.mind.item_action_skills_mod(src, ., skill_difficulty, trait, bad_trait, FALSE) - var/total_health = user.getStaminaLoss() - . = clamp(., 0, STAMINA_NEAR_CRIT - total_health) + . = user.mind.item_action_skills_mod(src, ., skill_difficulty, trait, null, FALSE) + +/** + * Uses the amount of stamina required for a standard hit + */ +/obj/item/proc/UseStaminaBufferStandard(mob/living/user, multiplier = 1, trait = SKILL_STAMINA_COST, warn = TRUE) + ASSERT(user) + var/cost = getweight(user, multiplier, trait) + return user.UseStaminaBuffer(cost, warn) /// How long this staggers for. 0 and negatives supported. /obj/item/proc/melee_stagger_duration(force_override) if(!isnull(stagger_force)) return stagger_force /// totally not an untested, arbitrary equation. - return clamp((1.5 + (w_class/7.5)) * ((force_override || force) / 2), 0, 10 SECONDS) + return clamp((1.5 + (w_class/5)) * ((force_override || force) / 1.5), 0, 10 SECONDS) /obj/item/proc/do_stagger_action(mob/living/target, mob/living/user, force_override) if(!CHECK_BITFIELD(target.status_flags, CANSTAGGER)) diff --git a/code/controllers/configuration/entries/game_options.dm b/code/controllers/configuration/entries/game_options.dm index 8f55293820..c91ac2e0d4 100644 --- a/code/controllers/configuration/entries/game_options.dm +++ b/code/controllers/configuration/entries/game_options.dm @@ -230,14 +230,6 @@ /datum/config_entry/keyed_list/multiplicative_movespeed key_mode = KEY_MODE_TYPE value_mode = VALUE_MODE_NUM - config_entry_value = list( //DEFAULTS - /mob/living/simple_animal = 1, - /mob/living/silicon/pai = 1, - /mob/living/carbon/alien/humanoid/sentinel = 0.25, - /mob/living/carbon/alien/humanoid/drone = 0.5, - /mob/living/carbon/alien/humanoid/royal/praetorian = 1, - /mob/living/carbon/alien/humanoid/royal/queen = 3 - ) /datum/config_entry/keyed_list/multiplicative_movespeed/ValidateAndSet() . = ..() @@ -249,6 +241,24 @@ if(. && (var_name == NAMEOF(src, config_entry_value))) update_config_movespeed_type_lookup(TRUE) +/datum/config_entry/keyed_list/multiplicative_movespeed/normal + config_entry_value = list( //DEFAULTS + /mob/living/simple_animal = 1, + /mob/living/silicon/pai = 1, + /mob/living/carbon/alien/humanoid/sentinel = 0.25, + /mob/living/carbon/alien/humanoid/drone = 0.5, + /mob/living/carbon/alien/humanoid/royal/praetorian = 1, + /mob/living/carbon/alien/humanoid/royal/queen = 3 + ) + +/datum/config_entry/keyed_list/multiplicative_movespeed/floating + config_entry_value = list( + /mob/living = 0, + /mob/living/carbon/alien/humanoid = 0, + /mob/living/carbon/alien/humanoid/royal/praetorian = 0, + /mob/living/carbon/alien/humanoid/royal/queen = 2 + ) + /datum/config_entry/number/movedelay //Used for modifying movement speed for mobs. abstract_type = /datum/config_entry/number/movedelay integer = FALSE @@ -280,6 +290,12 @@ /datum/config_entry/number/movedelay/sprint_speed_increase config_entry_value = 1 +/datum/config_entry/number/movedelay/sprint_max_tiles_increase + config_entry_value = 5 + +/datum/config_entry/number/movedelay/sprint_absolute_max_tiles + config_entry_value = 13 + /datum/config_entry/number/movedelay/sprint_buffer_max config_entry_value = 24 @@ -291,7 +307,7 @@ /////////////////////////////////////////////////Outdated move delay /datum/config_entry/number/outdated_movedelay - deprecated_by = /datum/config_entry/keyed_list/multiplicative_movespeed + deprecated_by = /datum/config_entry/keyed_list/multiplicative_movespeed/normal abstract_type = /datum/config_entry/number/outdated_movedelay var/movedelay_type diff --git a/code/controllers/configuration/entries/stamina_combat.dm b/code/controllers/configuration/entries/stamina_combat.dm new file mode 100644 index 0000000000..65580899f1 --- /dev/null +++ b/code/controllers/configuration/entries/stamina_combat.dm @@ -0,0 +1,35 @@ +/datum/config_entry/number/stamina_combat + integer = FALSE + abstract_type = /datum/config_entry/number/stamina_combat + +/// Maximum stamina buffer +/datum/config_entry/number/stamina_combat/buffer_max + config_entry_value = 25 + +/// Seconds until percent_regeneration_out_of_combat kicks in +/datum/config_entry/number/stamina_combat/out_of_combat_timer + config_entry_value = 15 + +/// Base regeneration per second +/datum/config_entry/number/stamina_combat/base_regeneration + config_entry_value = 0.5 + +/// Combat mode regeneration per second +/datum/config_entry/number/stamina_combat/combat_regeneration + config_entry_value = 5 + +/// After out_of_combat_timer elapses, additionally regenerate this percent of total stamina per second. Unaffected by combat mode. +/datum/config_entry/number/stamina_combat/percent_regeneration_out_of_combat + config_entry_value = 30 + +/// Seconds after an action for which your regeneration is penalized +/datum/config_entry/number/stamina_combat/post_action_penalty_delay + config_entry_value = 5 + +/// Factor to multiply by for penalizing post-action-stamina-regen +/datum/config_entry/number/stamina_combat/post_action_penalty_factor + config_entry_value = 0.25 + +/// Factor to multiply by for stamina usage past buffer into health +/datum/config_entry/number/stamina_combat/overdraw_penalty_factor + config_entry_value = 1.5 diff --git a/code/controllers/subsystem/input.dm b/code/controllers/subsystem/input.dm index 32936af9e9..bc3f6cf51b 100644 --- a/code/controllers/subsystem/input.dm +++ b/code/controllers/subsystem/input.dm @@ -64,10 +64,10 @@ SUBSYSTEM_DEF(input) // Misc macroset_classic_input["Tab"] = "\".winset \\\"mainwindow.macro=[SKIN_MACROSET_CLASSIC_HOTKEYS] map.focus=true input.background-color=[COLOR_INPUT_DISABLED]\\\"\"" macroset_classic_input["Escape"] = "\".winset \\\"input.text=\\\"\\\"\\\"\"" - + // FINALLY, WE CAN DO SOMETHING MORE NORMAL FOR THE SNOWFLAKE-BUT-LESS KEYSET. - - // HAHA - SIKE. Because of BYOND weirdness (tl;dr not specifically binding this way results in potentially duplicate chatboxes when + + // HAHA - SIKE. Because of BYOND weirdness (tl;dr not specifically binding this way results in potentially duplicate chatboxes when // conflicts occur with something like say indicator vs say), we're going to snowflake this anyways var/list/hard_binds = list( "O" = "ooc", @@ -80,7 +80,7 @@ SUBSYSTEM_DEF(input) for(var/key in hard_binds) for(var/modifier in anti_collision_modifiers) hard_bind_anti_collision["[modifier]+[key]"] = ".NONSENSICAL_VERB_THAT_DOES_NOTHING" - + macroset_classic_hotkey = list( "Any" = "\"KeyDown \[\[*\]\]\"", "Any+UP" = "\"KeyUp \[\[*\]\]\"", @@ -88,7 +88,7 @@ SUBSYSTEM_DEF(input) "Escape" = "\".winset \\\"input.text=\\\"\\\"\\\"\"", "Back" = "\".winset \\\"input.text=\\\"\\\"\\\"\"", ) - + macroset_classic_hotkey |= hard_binds macroset_classic_hotkey |= hard_bind_anti_collision @@ -100,7 +100,7 @@ SUBSYSTEM_DEF(input) "Escape" = "\".winset \\\"input.text=\\\"\\\"\\\"\"", "Back" = "\".winset \\\"input.text=\\\"\\\"\\\"\"", ) - + macroset_hotkey |= hard_binds macroset_hotkey |= hard_bind_anti_collision diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm index e61a3b3854..0f936bdeff 100644 --- a/code/controllers/subsystem/job.dm +++ b/code/controllers/subsystem/job.dm @@ -55,9 +55,10 @@ SUBSYSTEM_DEF(job) continue if(!job.config_check()) continue - if(!job.map_check()) //Even though we initialize before mapping, this is fine because the config is loaded at new + if(!job.map_check(SSmapping.config)) //Even though we initialize before mapping, this is fine because the config is loaded at new testing("Removed [job.type] due to map config"); continue + job.process_map_overrides(SSmapping.config) occupations += job name_occupations[job.title] = job type_occupations[J] = job diff --git a/code/controllers/subsystem/minimum_spawns.dm b/code/controllers/subsystem/minimum_spawns.dm new file mode 100644 index 0000000000..caab2b1949 --- /dev/null +++ b/code/controllers/subsystem/minimum_spawns.dm @@ -0,0 +1,144 @@ +SUBSYSTEM_DEF(min_spawns) + name = "Minimum Spawns" /// this hot steaming pile of garbage makes sure theres a minimum of tendrils scattered around + init_order = INIT_ORDER_DEFAULT + flags = SS_BACKGROUND | SS_NO_FIRE | SS_ALWAYS_SHOW_STAT + wait = 2 + var/where_we_droppin_boys_iterations = 0 + var/snaxi_snowflake_check = FALSE + var/list/active_spawns = list() // lavaland, snaxi, etc. primary spawn list + var/list/active_spawns_2 = list() // snaxi underground, etc. secondary spawn list + var/list/valid_mining_turfs = list() // lavaland/snaxi turfs + var/list/valid_mining_turfs_2 = list() // snaxi underground turfs + +GLOBAL_LIST_INIT(minimum_lavaland_spawns, list( + /obj/structure/spawner/lavaland, + /obj/structure/spawner/lavaland/goliath, + /obj/structure/spawner/lavaland/legion, + /mob/living/simple_animal/hostile/megafauna/dragon, + /mob/living/simple_animal/hostile/megafauna/colossus, + /mob/living/simple_animal/hostile/megafauna/bubblegum +)) + +GLOBAL_LIST_INIT(minimum_snow_surface_spawns, list( + /obj/structure/spawner/ice_moon, + /obj/structure/spawner/ice_moon/polarbear +)) +GLOBAL_LIST_INIT(minimum_snow_under_spawns, list( + /obj/structure/spawner/ice_moon/demonic_portal, + /obj/structure/spawner/ice_moon/demonic_portal/ice_whelp, + /obj/structure/spawner/ice_moon/demonic_portal/snowlegion +)) + +// step 1: check for which list(s) to use - done +// step 2: check for caves - done +// step 3: check for mobs - done +// step 4: start throwing shit down - done +// step 5: snaxi support - done? + +/datum/controller/subsystem/min_spawns/Initialize(start_timeofday) + var/list/snaxi_zs_list = SSmapping.levels_by_trait(ZTRAIT_ICE_RUINS) // boy if these things arent mutually exclusive + var/list/lavaland_zs_list = SSmapping.levels_by_trait(ZTRAIT_LAVA_RUINS) // i'm gonna fuckin scream + if(snaxi_zs_list.len) + active_spawns = GLOB.minimum_snow_surface_spawns + active_spawns_2 = GLOB.minimum_snow_under_spawns + snaxi_snowflake_check = TRUE + else if(lavaland_zs_list.len) //todo: recognizing maps that aren't lavaland mining but are also not snaxi + active_spawns = GLOB.minimum_lavaland_spawns + else + return ..() // call it a day i guess + // borrowing this from auxbase code - see code\modules\mining\aux_base.dm + if(snaxi_snowflake_check) + for(var/z_level in SSmapping.levels_by_trait(ZTRAIT_ICE_RUINS)) + for(var/turf/TT in Z_TURFS(z_level)) + if(!isarea(TT.loc)) + continue + var/area/A = TT.loc + if(!A.mob_spawn_allowed) + continue + if(!istype(TT, /turf/open/floor/plating/asteroid)) + continue + if(typesof(/turf/open/lava) in orange(9, TT)) + continue + valid_mining_turfs.Add(TT) + for(var/z_level in SSmapping.levels_by_trait(ZTRAIT_ICE_RUINS_UNDERGROUND)) + for(var/turf/TT in Z_TURFS(z_level)) + if(!isarea(TT.loc)) + continue + var/area/A = TT.loc + if(!A.mob_spawn_allowed) + continue + if(!istype(TT, /turf/open/floor/plating/asteroid)) + continue + if(typesof(/turf/open/lava) in orange(9, TT)) + continue + valid_mining_turfs_2.Add(TT) + else + for(var/z_level in SSmapping.levels_by_trait(ZTRAIT_LAVA_RUINS)) + for(var/turf/TT in Z_TURFS(z_level)) + if(!isarea(TT.loc)) + continue + var/area/A = TT.loc + if(!A.mob_spawn_allowed) + continue + if(!istype(TT, /turf/open/floor/plating/asteroid)) + continue + if(typesof(/turf/open/lava) in orange(9, TT)) + continue + valid_mining_turfs.Add(TT) + if(!valid_mining_turfs.len) + return ..() // call it a day i guess + // if we're at this point we might as well fucking hit it + where_we_droppin_boys() + return ..() + +/datum/controller/subsystem/min_spawns/proc/where_we_droppin_boys() + while(active_spawns.len) + where_we_droppin_boys_iterations++ + CHECK_TICK + if(where_we_droppin_boys_iterations >= 1250) + INIT_ANNOUNCE("Minimum Spawns subsystem stopped early on spawns list 1 - too many iterations!") + break + var/turf/RT = pick_n_take(valid_mining_turfs) //Pick a random mining Z-level turf + var/MS_tospawn = pick_n_take(active_spawns) + for(var/mob/living/simple_animal/hostile/megafauna/H in urange(70,RT)) //prevents mob clumps + if((istype(MS_tospawn, /mob/living/simple_animal/hostile/megafauna)) && get_dist(RT, H) <= 70) + active_spawns.Add(MS_tospawn) + continue //let's try not to dump megas too close to each other? + if((istype(MS_tospawn, /obj/structure/spawner)) && get_dist(RT, H) <= 40) + active_spawns.Add(MS_tospawn) + continue //let's at least /try/ to space these out? + for(var/obj/structure/spawner/LT in urange(70,RT)) //prevents tendril/mega clumps + if((istype(MS_tospawn, /mob/living/simple_animal/hostile/megafauna)) && get_dist(RT, LT) <= 70) + active_spawns.Add(MS_tospawn) + continue //let's try not to dump megas too close to each other? + if((istype(MS_tospawn, /obj/structure/spawner)) && get_dist(RT, LT) <= 40) + active_spawns.Add(MS_tospawn) + continue //let's at least /try/ to space these out? + // man the overhead on this is gonna SUCK + new MS_tospawn(RT) + while(active_spawns_2.len) + where_we_droppin_boys_iterations++ + CHECK_TICK + if(where_we_droppin_boys_iterations >= 1250) + INIT_ANNOUNCE("Minimum Spawns subsystem stopped early on active list 2 - too many iterations!") + break + var/turf/RT2 = pick_n_take(valid_mining_turfs_2) //Pick a random mining Z-level turf + var/MS2_tospawn = pick_n_take(active_spawns_2) + for(var/mob/living/simple_animal/hostile/H in urange(70,RT2)) //prevents mob clumps + if((istype(MS2_tospawn, /mob/living/simple_animal/hostile/megafauna) || ismegafauna(H)) && get_dist(RT2, H) <= 70) + active_spawns_2.Add(MS2_tospawn) + continue //let's try not to dump megas too close to each other? + if((istype(MS2_tospawn, /obj/structure/spawner)) && get_dist(RT2, H) <= 40) + active_spawns_2.Add(MS2_tospawn) + continue //let's at least /try/ to space these out? + for(var/obj/structure/spawner/LT in urange(70,RT2)) //prevents tendril/mega clumps + if((istype(MS2_tospawn, /mob/living/simple_animal/hostile/megafauna)) && get_dist(RT2, LT) <= 70) + active_spawns_2.Add(MS2_tospawn) + continue //let's try not to dump megas too close to each other? + if((istype(MS2_tospawn, /obj/structure/spawner)) && get_dist(RT2, LT) <= 40) + active_spawns_2.Add(MS2_tospawn) + continue //let's at least /try/ to space these out? + // man the overhead on this is gonna SUCK + new MS2_tospawn(RT2) + if(!active_spawns.len && !active_spawns_2.len) + return // we're done here diff --git a/code/controllers/subsystem/npcpool.dm b/code/controllers/subsystem/npcpool.dm index c67deaede1..c20820c092 100644 --- a/code/controllers/subsystem/npcpool.dm +++ b/code/controllers/subsystem/npcpool.dm @@ -5,6 +5,10 @@ SUBSYSTEM_DEF(npcpool) runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME var/list/currentrun = list() + /// catches sleeping + var/invoking = FALSE + /// Invoke start time + var/invoke_start = 0 /datum/controller/subsystem/npcpool/stat_entry(msg) var/list/activelist = GLOB.simple_animals[AI_ON] @@ -12,7 +16,6 @@ SUBSYSTEM_DEF(npcpool) return ..() /datum/controller/subsystem/npcpool/fire(resumed = FALSE) - if (!resumed) var/list/activelist = GLOB.simple_animals[AI_ON] src.currentrun = activelist.Copy() @@ -24,12 +27,22 @@ SUBSYSTEM_DEF(npcpool) var/mob/living/simple_animal/SA = currentrun[currentrun.len] --currentrun.len - if(!SA.ckey && !SA.mob_transforming) - if(SA.stat != DEAD) - SA.handle_automated_movement() - if(SA.stat != DEAD) - SA.handle_automated_action() - if(SA.stat != DEAD) - SA.handle_automated_speech() + invoking = TRUE + invoke_start = world.time + INVOKE_ASYNC(src, .proc/invoke_process, SA) + if(invoking) + stack_trace("WARNING: [SA] ([SA.type]) slept during NPCPool processing.") + invoking = FALSE + if (MC_TICK_CHECK) return + +/datum/controller/subsystem/npcpool/proc/invoke_process(mob/living/simple_animal/SA) + if(!SA.ckey && !SA.mob_transforming) + if(SA.stat != DEAD) + SA.handle_automated_movement() + if(SA.stat != DEAD) + SA.handle_automated_action() + if(SA.stat != DEAD) + SA.handle_automated_speech() + invoking = FALSE diff --git a/code/datums/diseases/transformation.dm b/code/datums/diseases/transformation.dm index e90eededd9..f952307685 100644 --- a/code/datums/diseases/transformation.dm +++ b/code/datums/diseases/transformation.dm @@ -236,12 +236,12 @@ switch(stage) if(1) if(ishuman(affected_mob) && affected_mob.dna) - if(affected_mob.dna.species.id == "slime" || affected_mob.dna.species.id == "stargazer" || affected_mob.dna.species.id == "lum") + if(affected_mob.dna.species.id == "slime" || affected_mob.dna.species.id == "stargazer" || affected_mob.dna.species.id == "slimelumi") stage = 5 if(3) if(ishuman(affected_mob)) var/mob/living/carbon/human/human = affected_mob - if(human.dna.species.id != "slime" && affected_mob.dna.species.id != "stargazer" && affected_mob.dna.species.id != "lum") + if(human.dna.species.id != "slime" && affected_mob.dna.species.id != "stargazer" && affected_mob.dna.species.id != "slimelumi") human.set_species(/datum/species/jelly/slime) /datum/disease/transformation/corgi diff --git a/code/datums/martial/sleeping_carp.dm b/code/datums/martial/sleeping_carp.dm index 7d884344f1..81b7ea0628 100644 --- a/code/datums/martial/sleeping_carp.dm +++ b/code/datums/martial/sleeping_carp.dm @@ -130,7 +130,7 @@ playsound(get_turf(A), pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 75, TRUE) P.firer = A P.setAngle(rand(0, 360))//SHING - A.adjustStaminaLossBuffered (3) //Citadel change to stop infinite bullet sponging as you run away, but it is buffered! + A.adjustStaminaLoss(3) return BULLET_ACT_FORCE_PIERCE return BULLET_ACT_HIT diff --git a/code/datums/ruins/lavaland.dm b/code/datums/ruins/lavaland.dm index 933eaf082e..a08b535aff 100644 --- a/code/datums/ruins/lavaland.dm +++ b/code/datums/ruins/lavaland.dm @@ -114,14 +114,12 @@ description = "..." suffix = "lavaland_surface_sloth.dmm" // Generates nothing but atmos runtimes and salt - cost = 0 /datum/map_template/ruin/lavaland/ratvar name = "Dead God" id = "ratvar" - description = "Ratvars final resting place." + description = "Ratvar's final resting place." suffix = "lavaland_surface_dead_ratvar.dmm" - cost = 0 allow_duplicates = FALSE /datum/map_template/ruin/lavaland/hierophant @@ -137,7 +135,7 @@ id = "blooddrunk" description = "A strange arrangement of stone tiles and an insane, beastly miner contemplating them." suffix = "lavaland_surface_blooddrunk1.dmm" - cost = 0 + always_place = TRUE allow_duplicates = FALSE //will only spawn one variant of the ruin /datum/map_template/ruin/lavaland/blood_drunk_miner/guidance diff --git a/code/datums/weather/weather_types/ash_storm.dm b/code/datums/weather/weather_types/ash_storm.dm index 43190ef50c..6248be0de5 100644 --- a/code/datums/weather/weather_types/ash_storm.dm +++ b/code/datums/weather/weather_types/ash_storm.dm @@ -95,8 +95,8 @@ if(is_ash_immune(L)) return if(is_species(L, /datum/species/lizard/ashwalker)) - if(!IS_STAMCRIT(L)) - L.adjustStaminaLossBuffered(4) + if(L.getStaminaLoss() < (STAMINA_CRIT - 40)) + L.adjustStaminaLoss(4) return L.adjustFireLoss(4) diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 0a6c2b9eca..4715c3bed3 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -36,6 +36,7 @@ var/grab_state = 0 var/throwforce = 0 var/datum/component/orbiter/orbiting + /// Used for space ztransit stuff var/can_be_z_moved = TRUE ///If we were without gravity and another animation happened, the bouncing will stop, and we need to restart it in next life(). var/floating_need_update = FALSE diff --git a/code/game/machinery/wishgranter.dm b/code/game/machinery/wishgranter.dm index 12fdc2193b..6aeef4b6ac 100644 --- a/code/game/machinery/wishgranter.dm +++ b/code/game/machinery/wishgranter.dm @@ -84,7 +84,7 @@ if(is_station_level(T.z)) destinations += B var/chosen_beacon = pick(destinations) - var/obj/effect/portal/jaunt_tunnel/J = new (get_turf(src), src, 100, null, FALSE, get_turf(chosen_beacon)) + var/obj/effect/portal/jaunt_tunnel/J = new (get_turf(src), 100, null, FALSE, get_turf(chosen_beacon)) try_move_adjacent(J) playsound(src,'sound/effects/sparks4.ogg',50,1) charges-- diff --git a/code/game/mecha/equipment/tools/other_tools.dm b/code/game/mecha/equipment/tools/other_tools.dm index 8039aabd1f..4dbb57479f 100644 --- a/code/game/mecha/equipment/tools/other_tools.dm +++ b/code/game/mecha/equipment/tools/other_tools.dm @@ -56,7 +56,7 @@ var/turf/target_turf = pick(L) if(!target_turf) return - var/list/obj/effect/portal/created = create_portal_pair(get_turf(src), target_turf, src, 300, 1, /obj/effect/portal/anom) + var/list/obj/effect/portal/created = create_portal_pair(get_turf(src), target_turf, 300, 1, /obj/effect/portal/anom) var/turf/T = get_turf(target) message_admins("[ADMIN_LOOKUPFLW(chassis.occupant)] used a Wormhole Generator in [ADMIN_VERBOSEJMP(T)]") log_game("[key_name(chassis.occupant)] used a Wormhole Generator in [AREACOORD(T)]") diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index b4c114eb6a..1c75f1e533 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -315,7 +315,7 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb return if(loc == user && current_equipped_slot && current_equipped_slot != SLOT_HANDS) if(current_equipped_slot in user.check_obscured_slots()) - to_chat(src, "You are unable to unequip that while wearing other garments over it!") + to_chat(user, "You are unable to unequip that while wearing other garments over it!") return FALSE if(resistance_flags & ON_FIRE) @@ -383,7 +383,7 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb return if(loc == user && current_equipped_slot && current_equipped_slot != SLOT_HANDS) if(current_equipped_slot in user.check_obscured_slots()) - to_chat(src, "You are unable to unequip that while wearing other garments over it!") + to_chat(user, "You are unable to unequip that while wearing other garments over it!") return FALSE @@ -565,7 +565,7 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb to_chat(user, "You cannot locate any organic eyes on this brain!") return - if(IS_STAMCRIT(user))//CIT CHANGE - makes eyestabbing impossible if you're in stamina softcrit + if(IS_STAMCRIT(user) || !user.UseStaminaBuffer(STAMINA_COST_ITEM_EYESTAB, warn = TRUE))//CIT CHANGE - makes eyestabbing impossible if you're in stamina softcrit to_chat(user, "You're too exhausted for that.")//CIT CHANGE - ditto return //CIT CHANGE - ditto @@ -575,8 +575,6 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb user.do_attack_animation(M) - user.adjustStaminaLossBuffered(10)//CIT CHANGE - makes eyestabbing cost stamina - if(M != user) M.visible_message("[user] has stabbed [M] in the eye with [src]!", \ "[user] stabs you in the eye with [src]!") diff --git a/code/game/objects/items/defib.dm b/code/game/objects/items/defib.dm index 484901990a..4777796331 100644 --- a/code/game/objects/items/defib.dm +++ b/code/game/objects/items/defib.dm @@ -4,7 +4,7 @@ /obj/item/defibrillator name = "defibrillator" desc = "A device that delivers powerful shocks to detachable paddles that resuscitate incapacitated patients." - icon = 'icons/obj/items_and_weapons.dmi' + icon = 'icons/obj/defibrillators.dmi' icon_state = "defibunit" item_state = "defibunit" lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' @@ -23,8 +23,8 @@ var/obj/item/stock_parts/cell/cell var/combat = FALSE //can we revive through space suits? var/grab_ghost = FALSE // Do we pull the ghost back into their body? - var/healdisk = FALSE // Will we shock people dragging the body? - var/pullshocksafely = FALSE //Dose the unit have the healdisk upgrade? + var/healdisk = FALSE // Does the unit have the healdisk upgrade? + var/pullshocksafely = FALSE // Will we shock people dragging the body? var/primetime = 0 // is the defib faster var/timedeath = 10 var/disarm_shock_time = 10 @@ -261,7 +261,7 @@ /obj/item/shockpaddles name = "defibrillator paddles" desc = "A pair of plastic-gripped paddles with flat metal surfaces that are used to deliver powerful electric shocks." - icon = 'icons/obj/items_and_weapons.dmi' + icon = 'icons/obj/defibrillators.dmi' icon_state = "defibpaddles0" item_state = "defibpaddles0" lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' @@ -682,7 +682,7 @@ /obj/item/shockpaddles/cyborg name = "cyborg defibrillator paddles" - icon = 'icons/obj/items_and_weapons.dmi' + icon = 'icons/obj/defibrillators.dmi' icon_state = "defibpaddles0" item_state = "defibpaddles0" req_defib = FALSE @@ -703,7 +703,7 @@ name = "syndicate defibrillator paddles" desc = "A pair of paddles used to revive deceased operatives. It possesses both the ability to penetrate armor and to deliver powerful shocks offensively." combat = TRUE - icon = 'icons/obj/items_and_weapons.dmi' + icon = 'icons/obj/defibrillators.dmi' icon_state = "defibpaddles0" item_state = "defibpaddles0" req_defib = FALSE diff --git a/code/game/objects/items/electrostaff.dm b/code/game/objects/items/electrostaff.dm index 65d2fdd699..31aaff12b5 100644 --- a/code/game/objects/items/electrostaff.dm +++ b/code/game/objects/items/electrostaff.dm @@ -21,12 +21,11 @@ var/can_block_projectiles = FALSE //can't block guns var/lethal_cost = 400 //10000/400*20 = 500. decent enough? var/lethal_damage = 20 - var/lethal_stam_cost = 4 var/stun_cost = 333 //10000/333*25 = 750. stunbatons are at time of writing 10000/1000*49 = 490. var/stun_status_effect = STATUS_EFFECT_ELECTROSTAFF //a small slowdown effect var/stun_stamdmg = 40 var/stun_status_duration = 25 - var/stun_stam_cost = 3.5 + var/stam_cost = 3.5 var/wielded = FALSE // track wielded status on item // haha security desword time /s @@ -171,7 +170,7 @@ turn_off() /obj/item/electrostaff/attack(mob/living/target, mob/living/user) - if(IS_STAMCRIT(user))//CIT CHANGE - makes it impossible to baton in stamina softcrit + if(IS_STAMCRIT(user) || !user.UseStaminaBuffer(stam_cost))//CIT CHANGE - makes it impossible to baton in stamina softcrit to_chat(user, "You're too exhausted to use [src] properly.")//CIT CHANGE - ditto return //CIT CHANGE - ditto if(on && HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50)) @@ -186,13 +185,11 @@ if(user.a_intent != INTENT_HARM) if(stun_act(target, user, null, return_list)) user.do_attack_animation(target) - user.adjustStaminaLossBuffered(stun_stam_cost) return else if(!harm_act(target, user, null, return_list)) return ..() //if you can't fry them just beat them with it else //we did harm act them user.do_attack_animation(target) - user.adjustStaminaLossBuffered(lethal_stam_cost) /obj/item/electrostaff/proc/stun_act(mob/living/target, mob/living/user, no_charge_and_force = FALSE, list/block_return = list()) var/stunforce = block_calculate_resultant_damage(stun_stamdmg, block_return) diff --git a/code/game/objects/items/melee/energy.dm b/code/game/objects/items/melee/energy.dm index 679491aeb6..7d95b8e736 100644 --- a/code/game/objects/items/melee/energy.dm +++ b/code/game/objects/items/melee/energy.dm @@ -190,12 +190,53 @@ /obj/item/melee/transforming/energy/sword/saber possible_colors = list("red" = LIGHT_COLOR_RED, "blue" = LIGHT_COLOR_LIGHT_CYAN, "green" = LIGHT_COLOR_GREEN, "purple" = LIGHT_COLOR_LAVENDER) + unique_reskin = list("Sword" = "sword0", "saber" = "esaber0") var/hacked = FALSE + var/saber = FALSE -/obj/item/melee/transforming/energy/sword/saber/set_sword_color() - if(LAZYLEN(possible_colors)) +/obj/item/melee/transforming/energy/sword/saber/transform_weapon(mob/living/user, supress_message_text) + . = ..() + if(.) + if(active) + if(sword_color) + if(saber) + icon_state = "esaber[sword_color]" + else + icon_state = "sword[sword_color]" + else + if(saber) + icon_state = "esaber0" + else + icon_state = "sword0" + +/obj/item/melee/transforming/energy/sword/saber/reskin_obj(mob/M) + . = ..() + if(icon_state == "esaber0") + saber = TRUE + if(active) + if(saber) + icon_state = "esaber[sword_color]" + else + icon_state = "sword[sword_color]" + +/obj/item/melee/transforming/energy/sword/saber/set_sword_color(var/color_forced) + if(color_forced) // wow i really do not like this at fucking all holy SHIT + if(color_forced == "red") + sword_color = "red" + light_color = LIGHT_COLOR_RED + else if(color_forced == "blue") + sword_color = "blue" + light_color = LIGHT_COLOR_LIGHT_CYAN + else if(color_forced == "green") + sword_color = "green" + light_color = LIGHT_COLOR_GREEN + else if(color_forced == "purple") + sword_color = "purple" + light_color = LIGHT_COLOR_LAVENDER + else if(LAZYLEN(possible_colors)) sword_color = pick(possible_colors) light_color = possible_colors[sword_color] + return /obj/item/melee/transforming/energy/sword/saber/process() . = ..() @@ -204,30 +245,59 @@ light_color = possible_colors[set_color] update_light() -/obj/item/melee/transforming/energy/sword/saber/red - possible_colors = list("red" = LIGHT_COLOR_RED) +/obj/item/melee/transforming/energy/sword/saber/red/Initialize(mapload) + . = ..() + set_sword_color("red") -/obj/item/melee/transforming/energy/sword/saber/blue - possible_colors = list("blue" = LIGHT_COLOR_LIGHT_CYAN) +/obj/item/melee/transforming/energy/sword/saber/blue/Initialize(mapload) + . = ..() + set_sword_color("blue") -/obj/item/melee/transforming/energy/sword/saber/green - possible_colors = list("green" = LIGHT_COLOR_GREEN) +/obj/item/melee/transforming/energy/sword/saber/green/Initialize(mapload) + . = ..() + set_sword_color("green") -/obj/item/melee/transforming/energy/sword/saber/purple - possible_colors = list("purple" = LIGHT_COLOR_LAVENDER) +/obj/item/melee/transforming/energy/sword/saber/purple/Initialize(mapload) + . = ..() + set_sword_color("purple") + +/obj/item/melee/transforming/energy/sword/saber/proc/select_sword_color(mob/user) /// this is for the radial + if(!istype(user) || user.incapacitated()) + return + + var/static/list/options = list( + "red" = image(icon = 'icons/obj/items_and_weapons.dmi', icon_state = "swordred-blade"), + "blue" = image(icon = 'icons/obj/items_and_weapons.dmi', icon_state = "swordblue-blade"), + "green" = image(icon = 'icons/obj/items_and_weapons.dmi', icon_state = "swordgreen-blade"), + "purple" = image(icon = 'icons/obj/items_and_weapons.dmi', icon_state = "swordpurple-blade") + ) + + var/choice = show_radial_menu(user, src, options, custom_check = FALSE, radius = 36, require_near = TRUE) + + if(src && choice && !user.incapacitated() && in_range(user,src)) + set_sword_color(choice) + to_chat(user, "[src] is now [choice].") /obj/item/melee/transforming/energy/sword/saber/attackby(obj/item/W, mob/living/user, params) if(istype(W, /obj/item/multitool)) + if(user.a_intent == INTENT_DISARM) + if(!active) + to_chat(user, "COLOR_SET") + hacked = FALSE + select_sword_color(user) + return + else + to_chat(user, "Turn it off first - getting that close to an active sword is not a great idea.") + return if(!hacked) hacked = TRUE sword_color = "rainbow" to_chat(user, "RNBW_ENGAGE") - if(active) icon_state = "swordrainbow" user.update_inv_hands() else - to_chat(user, "It's already fabulous!") + to_chat(user, "It's already fabulous! If you wanted to reset the color, though, try a disarming intent while it's off.") else return ..() diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm index 52ff0f740e..15d10c4d11 100644 --- a/code/game/objects/items/melee/misc.dm +++ b/code/game/objects/items/melee/misc.dm @@ -352,6 +352,8 @@ return else if(cooldown_check < world.time) + if(!UseStaminaBufferStandard(user, STAM_COST_BATON_MOB_MULT, warn = TRUE)) + return DISCARD_LAST_ACTION if(target.mob_run_block(src, 0, "[user]'s [name]", ATTACK_TYPE_MELEE, 0, user, null, null) & BLOCK_SUCCESS) playsound(target, 'sound/weapons/genhit.ogg', 50, 1) return @@ -373,7 +375,6 @@ else target.LAssailant = WEAKREF(user) cooldown_check = world.time + cooldown - user.adjustStaminaLossBuffered(getweight(user, STAM_COST_BATON_MOB_MULT)) else var/wait_desc = get_wait_description() if(wait_desc) diff --git a/code/game/objects/items/mop.dm b/code/game/objects/items/mop.dm index b420bfc002..01ef96b7e8 100644 --- a/code/game/objects/items/mop.dm +++ b/code/game/objects/items/mop.dm @@ -56,22 +56,20 @@ return if(T) + if(!L.UseStaminaBuffer(stamusage, warn = TRUE)) + return user.visible_message("[user] cleans \the [T] with [src].", "You clean \the [T] with [src].") clean(T) user.DelayNextAction(CLICK_CD_MELEE) user.do_attack_animation(T, used_item = src) - if(istype(L)) - L.adjustStaminaLossBuffered(stamusage) playsound(T, "slosh", 50, 1) - /obj/effect/attackby(obj/item/I, mob/user, params) if(istype(I, /obj/item/mop) || istype(I, /obj/item/soap)) return else return ..() - /obj/item/mop/proc/janicart_insert(mob/user, obj/structure/janitorialcart/J) if(insertable) J.put_in_cart(src, user) diff --git a/code/game/objects/items/powerfist.dm b/code/game/objects/items/powerfist.dm index 2834b3b758..bd83404356 100644 --- a/code/game/objects/items/powerfist.dm +++ b/code/game/objects/items/powerfist.dm @@ -6,7 +6,7 @@ lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' flags_1 = CONDUCT_1 - item_flags = NEEDS_PERMIT | NO_COMBAT_MODE_FORCE_MODIFIER //To avoid ambushing and oneshotting healthy crewmembers on force setting 3. + item_flags = NEEDS_PERMIT attack_verb = list("whacked", "fisted", "power-punched") force = 20 throwforce = 10 @@ -76,6 +76,9 @@ if(!tank) to_chat(user, "\The [src] can't operate without a source of gas!") return FALSE + var/weight = getweight(user, STAM_COST_ATTACK_MOB_MULT) + if(!user.UseStaminaBuffer(weight, warn = TRUE)) + return FALSE var/datum/gas_mixture/gasused = tank.air_contents.remove(gasperfist * fisto_setting) var/turf/T = get_turf(src) if(!T) @@ -108,8 +111,4 @@ target.throw_at(throw_target, 5 * fisto_setting, 0.5 + (fisto_setting / 2)) log_combat(user, target, "power fisted", src) - - var/weight = getweight(user, STAM_COST_ATTACK_MOB_MULT) - if(weight) - user.adjustStaminaLossBuffered(weight) return TRUE diff --git a/code/game/objects/items/shields.dm b/code/game/objects/items/shields.dm index 4952c93928..d1d57fe375 100644 --- a/code/game/objects/items/shields.dm +++ b/code/game/objects/items/shields.dm @@ -136,15 +136,17 @@ if(!(shield_flags & SHIELD_BASH_GROUND_SLAM)) to_chat(user, "You can't ground slam with [src]!") return FALSE + if(!user.UseStaminaBuffer(shieldbash_stamcost, warn = TRUE)) + return FALSE bash_target(user, target, NONE, harmful) user.do_attack_animation(target, used_item = src) playsound(src, harmful? "swing_hit" : 'sound/weapons/thudswoosh.ogg', 75, 1) last_shieldbash = world.time - user.adjustStaminaLossBuffered(shieldbash_stamcost) return TRUE // Directional sweep! last_shieldbash = world.time - user.adjustStaminaLossBuffered(shieldbash_stamcost) + if(!user.UseStaminaBuffer(shieldbash_stamcost, warn = TRUE)) + return FALSE // Since we are in combat mode, we can probably safely use the user's dir instead of getting their mouse pointing cardinal dir. var/bashdir = user.dir do_shieldbash_effect(user, bashdir, harmful) diff --git a/code/game/objects/items/storage/bags.dm b/code/game/objects/items/storage/bags.dm index b64aa60cac..ab1aab32a0 100644 --- a/code/game/objects/items/storage/bags.dm +++ b/code/game/objects/items/storage/bags.dm @@ -234,7 +234,7 @@ STR.max_w_class = WEIGHT_CLASS_NORMAL STR.max_combined_w_class = 100 STR.max_items = 100 - STR.can_hold = typecacheof(list(/obj/item/reagent_containers/food/snacks/grown, /obj/item/seeds, /obj/item/grown, /obj/item/reagent_containers/honeycomb)) + STR.can_hold = typecacheof(list(/obj/item/reagent_containers/food/snacks/grown, /obj/item/seeds, /obj/item/grown, /obj/item/reagent_containers/honeycomb, /obj/item/disk/plantgene)) //////// diff --git a/code/game/objects/items/storage/belt.dm b/code/game/objects/items/storage/belt.dm index 590df34cde..28af52a646 100755 --- a/code/game/objects/items/storage/belt.dm +++ b/code/game/objects/items/storage/belt.dm @@ -830,3 +830,28 @@ var/datum/component/storage/STR = GetComponent(/datum/component/storage) STR.max_items = 2 STR.max_w_class = WEIGHT_CLASS_BULKY + WEIGHT_CLASS_NORMAL //katana and waki. + +/obj/item/storage/belt/plant + name = "botanical belt" + desc = "A belt used to hold most hydroponics supplies. Suprisingly, not green." + icon_state = "plantbelt" + item_state = "plantbelt" + content_overlays = TRUE + +/obj/item/storage/belt/plant/ComponentInitialize() + . = ..() + var/datum/component/storage/STR = GetComponent(/datum/component/storage) + STR.max_items = 6 + STR.max_w_class = WEIGHT_CLASS_NORMAL + STR.can_hold = typecacheof(list( + /obj/item/reagent_containers/spray/plantbgone, + /obj/item/plant_analyzer, + /obj/item/seeds, + /obj/item/reagent_containers/glass/bottle, + /obj/item/reagent_containers/glass/beaker, + /obj/item/cultivator, + /obj/item/reagent_containers/spray/pestspray, + /obj/item/hatchet, + /obj/item/shovel/spade, + /obj/item/gun/energy/floragun + )) diff --git a/code/game/objects/items/stunbaton.dm b/code/game/objects/items/stunbaton.dm index 5e76d506ba..a7d96fe6eb 100644 --- a/code/game/objects/items/stunbaton.dm +++ b/code/game/objects/items/stunbaton.dm @@ -166,13 +166,12 @@ if(turned_on) if(baton_stun(M, user, disarming)) user.do_attack_animation(M) - user.adjustStaminaLossBuffered(getweight(user, STAM_COST_BATON_MOB_MULT)) else if(user.a_intent != INTENT_HARM) //they'll try to bash in the last proc. M.visible_message("[user] has prodded [M] with [src]. Luckily it was off.", \ "[user] has prodded you with [src]. Luckily it was off") return disarming || (user.a_intent != INTENT_HARM) -/obj/item/melee/baton/proc/baton_stun(mob/living/L, mob/user, disarming = FALSE) +/obj/item/melee/baton/proc/baton_stun(mob/living/L, mob/living/user, disarming = FALSE) var/list/return_list = list() if(L.mob_run_block(src, 0, "[user]'s [name]", ATTACK_TYPE_MELEE, 0, user, null, return_list) & BLOCK_SUCCESS) //No message; check_shields() handles that playsound(L, 'sound/weapons/genhit.ogg', 50, 1) @@ -194,6 +193,9 @@ return FALSE stunpwr *= round(stuncharge/hitcost, 0.1) + if(!user.UseStaminaBuffer(getweight(user, STAM_COST_BATON_MOB_MULT), warn = TRUE)) + return FALSE + if(!disarming) if(knockdown) L.DefaultCombatKnockdown(50, override_stamdmg = 0) //knockdown diff --git a/code/game/objects/items/tanks/jetpack.dm b/code/game/objects/items/tanks/jetpack.dm index 7cf25098e1..29961d12b4 100644 --- a/code/game/objects/items/tanks/jetpack.dm +++ b/code/game/objects/items/tanks/jetpack.dm @@ -55,6 +55,8 @@ RegisterSignal(user, COMSIG_MOVABLE_MOVED, .proc/move_react) if(full_speed) user.add_movespeed_modifier(/datum/movespeed_modifier/jetpack/fullspeed) + else + user.add_movespeed_modifier(/datum/movespeed_modifier/jetpack) /obj/item/tank/jetpack/proc/turn_off(mob/user) on = FALSE @@ -63,6 +65,7 @@ ion_trail.stop() UnregisterSignal(user, COMSIG_MOVABLE_MOVED) user.remove_movespeed_modifier(/datum/movespeed_modifier/jetpack/fullspeed) + user.remove_movespeed_modifier(/datum/movespeed_modifier/jetpack) /obj/item/tank/jetpack/proc/move_react(mob/user) allow_thrust(0.01, user) diff --git a/code/game/objects/items/tools/screwdriver.dm b/code/game/objects/items/tools/screwdriver.dm index bb507e5725..bf767af2ed 100644 --- a/code/game/objects/items/tools/screwdriver.dm +++ b/code/game/objects/items/tools/screwdriver.dm @@ -161,4 +161,4 @@ item_state = "screwdriver_nuke" usesound = 'sound/items/pshoom.ogg' toolspeed = 0.2 - random_color = FALSE \ No newline at end of file + random_color = FALSE diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index 3abee4db33..8a14d99776 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -304,18 +304,36 @@ /obj/proc/reskin_obj(mob/M) if(!LAZYLEN(unique_reskin)) return - var/list/skins = list() - for(var/S in unique_reskin) - skins[S] = image(icon = icon, icon_state = unique_reskin[S]) - var/choice = show_radial_menu(M, src, skins, custom_check = CALLBACK(src, .proc/check_skinnable, M), radius = 40, require_near = TRUE) - if(!choice) - return FALSE - icon_state = unique_reskin[choice] - current_skin = choice - return -/obj/proc/check_skinnable(/mob/M) - if(current_skin || !always_reskinnable) + var/list/items = list() + for(var/reskin_option in unique_reskin) + var/image/item_image = image(icon = src.icon, icon_state = unique_reskin[reskin_option]) + items += list("[reskin_option]" = item_image) + sortList(items) + + var/pick = show_radial_menu(M, src, items, custom_check = CALLBACK(src, .proc/check_reskin_menu, M), radius = 38, require_near = TRUE) + if(!pick) + return + if(!unique_reskin[pick]) + return + current_skin = pick + icon_state = unique_reskin[pick] + to_chat(M, "[src] is now skinned as '[pick].'") + +/** + * Checks if we are allowed to interact with a radial menu for reskins + * + * Arguments: + * * user The mob interacting with the menu + */ +/obj/proc/check_reskin_menu(mob/user) + if(QDELETED(src)) + return FALSE + if(current_skin) + return FALSE + if(!istype(user)) + return FALSE + if(user.incapacitated()) return FALSE return TRUE diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 9f91d2c5e0..31f11a199c 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -73,7 +73,7 @@ if(user.grab_state < GRAB_AGGRESSIVE) to_chat(user, "You need a better grip to do that!") return - if(user.grab_state >= GRAB_NECK) + if(user.grab_state >= GRAB_NECK || HAS_TRAIT(user, TRAIT_MAULER)) tablelimbsmash(user, pushed_mob) else tablepush(user, pushed_mob) @@ -147,7 +147,7 @@ pushed_mob.Knockdown(30) var/obj/item/bodypart/banged_limb = pushed_mob.get_bodypart(user.zone_selected) || pushed_mob.get_bodypart(BODY_ZONE_HEAD) var/extra_wound = 0 - if(HAS_TRAIT(user, TRAIT_HULK)) + if(HAS_TRAIT(user, TRAIT_HULK) || HAS_TRAIT(user, TRAIT_MAULER)) extra_wound = 20 banged_limb.receive_damage(30, wound_bonus = extra_wound) pushed_mob.apply_damage(60, STAMINA) diff --git a/code/game/turfs/space/space.dm b/code/game/turfs/space/space.dm index 3df64550b1..b150d4930e 100644 --- a/code/game/turfs/space/space.dm +++ b/code/game/turfs/space/space.dm @@ -133,13 +133,10 @@ else to_chat(user, "The plating is going to need some support! Place metal rods first.") -/turf/open/space/Entered(atom/movable/A, atom/OldLoc) - . = ..() - - var/turf/old = get_turf(OldLoc) - if(!isspaceturf(old) && ismob(A)) - var/mob/M = A - M.update_gravity(M.mob_has_gravity()) +/turf/open/space/Entered(atom/movable/A) + ..() + if ((!(A) || src != A.loc)) + return if(destination_z && destination_x && destination_y && !(A.pulledby || !A.can_be_z_moved)) var/tx = destination_x @@ -160,18 +157,27 @@ ty-- DT = locate(tx, ty, destination_z) - var/atom/movable/AM = A.pulling + var/atom/movable/pulling = A.pulling + var/atom/movable/puller = A A.forceMove(DT) - if(AM) - var/turf/T = get_step(A.loc,turn(A.dir, 180)) - AM.can_be_z_moved = FALSE - AM.forceMove(T) - A.start_pulling(AM) - AM.can_be_z_moved = TRUE + + while (pulling != null) + var/next_pulling = pulling.pulling + + var/turf/T = get_step(puller.loc, turn(puller.dir, 180)) + pulling.can_be_z_moved = FALSE + pulling.forceMove(T) + puller.start_pulling(pulling) + pulling.can_be_z_moved = TRUE + + puller = pulling + pulling = next_pulling //now we're on the new z_level, proceed the space drifting stoplag()//Let a diagonal move finish, if necessary A.newtonian_move(A.inertia_dir) + A.inertia_moving = TRUE + /turf/open/space/Exited(atom/movable/AM, atom/OldLoc) . = ..() diff --git a/code/modules/antagonists/changeling/powers/mutations.dm b/code/modules/antagonists/changeling/powers/mutations.dm index 24288be078..05c265bc15 100644 --- a/code/modules/antagonists/changeling/powers/mutations.dm +++ b/code/modules/antagonists/changeling/powers/mutations.dm @@ -6,6 +6,10 @@ Shield Armor Tentacles + Hatterhat Additions: + claws! (glove slot) + jagged (thieves') claws + bone gauntlets for punching dudes */ @@ -89,7 +93,7 @@ return 1 var/mob/living/carbon/human/H = user if(istype(H.wear_suit, suit_type) || istype(H.head, helmet_type)) - H.visible_message("[H] casts off [H.p_their()] [suit_name_simple]!", "We cast off our [suit_name_simple].", "You hear the organic matter ripping and tearing!") + H.visible_message("[H] casts off [H.p_their()] [suit_name_simple]!", "We cast off our [suit_name_simple].", "You hear organic matter ripping and tearing!") H.temporarilyRemoveItemFromInventory(H.head, TRUE) //The qdel on dropped() takes care of it H.temporarilyRemoveItemFromInventory(H.wear_suit, TRUE) H.update_inv_wear_suit() @@ -461,7 +465,7 @@ if(--remaining_uses < 1) if(ishuman(loc)) var/mob/living/carbon/human/H = loc - H.visible_message("With a sickening crunch, [H] reforms [H.p_their()] shield into an arm!", "We assimilate our shield into our body", "With a sickening crunch, [H] reforms [H.p_their()] shield into an arm!", "We assimilate our shield into our body.", "With a sickening crunch, [H] reforms [H.p_their()] [glove_name_simple] into hands!", "We assimilate our [glove_name_simple].", "You hear organic matter ripping and tearing!") + H.temporarilyRemoveItemFromInventory(H.gloves, TRUE) //The qdel on dropped() takes care of it + H.update_inv_gloves() + playsound(H.loc, 'sound/effects/blobattack.ogg', 30, 1) + if(blood_on_castoff) + H.add_splatter_floor() + playsound(H.loc, 'sound/effects/splat.ogg', 50, 1) //So real sounds + + changeling.chem_recharge_slowdown -= recharge_slowdown + return 1 + +/obj/effect/proc_holder/changeling/gloves/on_refund(mob/user) + if(!ishuman(user)) + return + action.Remove(user) + var/mob/living/carbon/human/H = user + check_gloves(H) + +/obj/effect/proc_holder/changeling/gloves/sting_action(mob/living/carbon/human/user) + if(!user.canUnEquip(user.gloves)) + to_chat(user, "\the [user.gloves] is stuck to your body, you cannot grow [glove_name_simple] over it!") + return + + user.dropItemToGround(user.gloves) + + user.equip_to_slot_if_possible(new glove_type(user), SLOT_GLOVES, 1, 1, 1) + playsound(user, 'sound/effects/blobattack.ogg', 30, 1) + var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling) + changeling.chem_recharge_slowdown += recharge_slowdown + return TRUE + +/obj/item/clothing/gloves/claws + name = "claws of doing nothing" + desc = "These shouldn't be here." + icon_state = "bracers" + item_state = "bracers" + transfer_prints = TRUE + body_parts_covered = HANDS + cold_protection = HANDS + min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT + max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT + armor = list("melee" = 20, "bullet" = 20, "laser" = 20, "energy" = 20, "bomb" = 35, "bio" = 35, "rad" = 35, "fire" = 0, "acid" = 0) + +/obj/item/clothing/gloves/claws/Initialize() + . = ..() + ADD_TRAIT(src, TRAIT_NODROP, CHANGELING_TRAIT) + +/obj/item/clothing/gloves/claws/vulture // prying shit off dead/soon to be dead dudes! + name = "jagged claws" + desc = "Good for prying things off of people and looking incredibly creepy." + strip_mod = 2 + +/obj/effect/proc_holder/changeling/gloves/gauntlets + name = "Bone Gauntlets" + desc = "We turn our hands into solid bone and chitin, sacrificing dexterity for raw strength." + helptext = "These grotesque, bone-and-chitin gauntlets are remarkably good at beating victims senseless, and cannot be used in lesser form. This ability is loud, and might cause our blood to react violently to heat." + chemical_cost = 10 // same cost as armblade because its a sidegrade (sacrifice utility for punching people violently) + dna_cost = 2 + loudness = 2 + req_human = 1 + action_icon = 'icons/mob/actions/actions_changeling.dmi' + action_icon_state = "ling_gauntlets" + action_background_icon_state = "bg_ling" + + glove_type = /obj/item/clothing/gloves/fingerless/pugilist/cling // just punch his head off dude + glove_name_simple = "bone gauntlets" + +/obj/item/clothing/gloves/fingerless/pugilist/cling // switches between lesser GotNS and Big Punchy Rib Breaky Hands + name = "hewn bone gauntlets" + icon_state = "ling_gauntlets" + item_state = "ling_gauntlets" + desc = "Rough bone and chitin, pulsing with an abomination barely called \"life\". Good for punching people, not so much for firearms." + transfer_prints = TRUE + body_parts_covered = ARMS|HANDS + cold_protection = ARMS|HANDS + min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT + max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT + armor = list("melee" = 20, "bullet" = 20, "laser" = 20, "energy" = 20, "bomb" = 35, "bio" = 35, "rad" = 35, "fire" = 0, "acid" = 0) + enhancement = 9 // first, do harm. all of it. all of the harm. just fuck em up. + wound_enhancement = 9 + var/fast_enhancement = 9 + var/fast_wound_enhancement = 9 + var/slow_enhancement = 20 + var/slow_wound_enhancement = 20 + silent = TRUE + inherited_trait = TRAIT_CHUNKYFINGERS // dummy thicc bone hands + secondary_trait = TRAIT_MAULER // its only violence from here, bucko + var/fasthands = TRUE + +/obj/item/clothing/gloves/fingerless/pugilist/cling/examine(mob/user) + . = ..() + . += "[src] are formed to allow for [fasthands ? "fast, precise strikes" : "crippling, damaging blows"]." + . += "Alt-click them to change between rapid strikes and strong blows." + +/obj/item/clothing/gloves/fingerless/pugilist/cling/AltClick(mob/user) + . = ..() + use_buffs(user, FALSE) // reset + fasthands = !fasthands + if(fasthands) + enhancement = fast_enhancement + wound_enhancement = fast_wound_enhancement + else + enhancement = slow_enhancement // fuck em up kiddo + wound_enhancement = slow_wound_enhancement // really. fuck em up. + to_chat(user, "[src] are now formed to allow for [fasthands ? "fast, precise strikes" : "crippling, damaging blows"].") + addtimer(CALLBACK(src, .proc/use_buffs, user, TRUE), 0.1) // go fuckin get em + +/obj/item/clothing/gloves/fingerless/pugilist/cling/Initialize() + . = ..() + ADD_TRAIT(src, TRAIT_NODROP, CHANGELING_TRAIT) + +/obj/item/clothing/gloves/fingerless/pugilist/cling/equipped(mob/user, slot) + . = ..() + if(current_equipped_slot == SLOT_GLOVES) + to_chat(user, "With [src] formed around our arms, we are ready to fight.") + +/obj/item/clothing/gloves/fingerless/pugilist/cling/dropped(mob/user) + . = ..() + if(wornonce) + to_chat(user, "With [src] assimilated, we feel less ready to punch things.") + +/obj/item/clothing/gloves/fingerless/pugilist/cling/Touch(atom/target, proximity = TRUE) + if(!isliving(target)) + return + var/mob/living/M = loc + if(fasthands) + M.SetNextAction(CLICK_CD_RANGE) // fast punches + else + M.SetNextAction(CLICK_CD_GRABBING) // strong punches + return NO_AUTO_CLICKDELAY_HANDLING | ATTACK_IGNORE_ACTION diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index 2fbe738acb..ea01b0c0ed 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -45,13 +45,12 @@ var/dynamic_fhair_suffix = ""//mask > head for facial hair //basically a restriction list. - var/list/species_restricted = null + var/list/species_restricted //Basically syntax is species_restricted = list("Species Name","Species Name") //Add a "exclude" string to do the opposite, making it only only species listed that can't wear it. //You append this to clothing objects - // How much clothing damage has been dealt to each of the limbs of the clothing, assuming it covers more than one limb var/list/damage_by_parts // How much integrity is in a specific limb before that limb is disabled (for use in [/obj/item/clothing/proc/take_damage_zone], and only if we cover multiple zones.) Set to 0 to disable shredding. @@ -477,7 +476,6 @@ BLIND // can't see anything return TRUE - /// If we're a clothing with at least 1 shredded/disabled zone, give the wearer a periodic heads up letting them know their clothes are damaged /obj/item/clothing/proc/bristle(mob/living/L) if(!istype(L)) diff --git a/code/modules/clothing/gloves/miscellaneous.dm b/code/modules/clothing/gloves/miscellaneous.dm index b5d92fb780..f9f587ae5b 100644 --- a/code/modules/clothing/gloves/miscellaneous.dm +++ b/code/modules/clothing/gloves/miscellaneous.dm @@ -20,8 +20,14 @@ body_parts_covered = ARMS cold_protection = ARMS strip_delay = 300 //you can't just yank them off + /// did you ever get around to wearing these or no + var/wornonce = FALSE ///Extra damage through the punch. var/enhancement = 0 //it's a +0 to your punches because it isn't magical + ///extra wound bonus through the punch (MAYBE DON'T BE GENEROUS WITH THIS) + var/wound_enhancement = 0 + /// do we give the flavortext for wearing them + var/silent = FALSE ///Main trait added by the gloves to the user on wear. var/inherited_trait = TRAIT_NOGUNS //what are you, dishonoroable? ///Secondary trait added by the gloves to the user on wear. @@ -29,7 +35,18 @@ /obj/item/clothing/gloves/fingerless/pugilist/equipped(mob/user, slot) . = ..() - if(slot == SLOT_GLOVES) + if(current_equipped_slot == SLOT_GLOVES) + use_buffs(user, TRUE) + wornonce = TRUE + +/obj/item/clothing/gloves/fingerless/pugilist/dropped(mob/user) + . = ..() + if(wornonce) + use_buffs(user, FALSE) + wornonce = FALSE + +/obj/item/clothing/gloves/fingerless/pugilist/proc/use_buffs(mob/user, buff) + if(buff) // tarukaja if(ishuman(user)) var/mob/living/carbon/human/H = user ADD_TRAIT(H, TRAIT_PUGILIST, GLOVE_TRAIT) @@ -37,17 +54,20 @@ ADD_TRAIT(H, secondary_trait, GLOVE_TRAIT) H.dna.species.punchdamagehigh += enhancement H.dna.species.punchdamagelow += enhancement - -/obj/item/clothing/gloves/fingerless/pugilist/dropped(mob/user) - - REMOVE_TRAIT(user, TRAIT_PUGILIST, GLOVE_TRAIT) - REMOVE_TRAIT(user, inherited_trait, GLOVE_TRAIT) - REMOVE_TRAIT(user, secondary_trait, GLOVE_TRAIT) - if(ishuman(user)) - var/mob/living/carbon/human/H = user - H.dna.species.punchdamagehigh -= enhancement - H.dna.species.punchdamagelow -= enhancement - return ..() + H.dna.species.punchwoundbonus += wound_enhancement + if(!silent) + to_chat(H, "With [src] on your arms, you feel ready to punch things.") + else // dekaja + REMOVE_TRAIT(user, TRAIT_PUGILIST, GLOVE_TRAIT) + REMOVE_TRAIT(user, inherited_trait, GLOVE_TRAIT) + REMOVE_TRAIT(user, secondary_trait, GLOVE_TRAIT) + if(ishuman(user)) + var/mob/living/carbon/human/H = user + H.dna.species.punchdamagehigh -= enhancement + H.dna.species.punchdamagelow -= enhancement + H.dna.species.punchwoundbonus -= wound_enhancement + if(!silent) + to_chat(user, "With [src] off of your arms, you feel less ready to punch things.") /obj/item/clothing/gloves/fingerless/pugilist/chaplain name = "armwraps of unyielding resolve" @@ -93,6 +113,7 @@ icon_state = "rapid" item_state = "rapid" enhancement = 10 //omae wa mou shindeiru + wound_enhancement = 10 var/warcry = "AT" secondary_trait = TRAIT_NOSOFTCRIT //basically extra health diff --git a/code/modules/clothing/gloves/tacklers.dm b/code/modules/clothing/gloves/tacklers.dm index f4b4140a1a..eda36ea12f 100644 --- a/code/modules/clothing/gloves/tacklers.dm +++ b/code/modules/clothing/gloves/tacklers.dm @@ -65,12 +65,14 @@ heat_protection = HANDS max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT resistance_flags = NONE + strip_mod = 1.2 // because apparently black gloves had this /obj/item/clothing/gloves/tackler/combat/insulated name = "guerrilla gloves" desc = "Superior quality combative gloves, good for performing tackle takedowns as well as absorbing electrical shocks." siemens_coefficient = 0 permeability_coefficient = 0.05 + strip_mod = 1.5 // and combat gloves had this?? /obj/item/clothing/gloves/tackler/combat/insulated/infiltrator name = "insidious guerrilla gloves" diff --git a/code/modules/clothing/masks/miscellaneous.dm b/code/modules/clothing/masks/miscellaneous.dm index 11df38cfdd..5dd35788f1 100644 --- a/code/modules/clothing/masks/miscellaneous.dm +++ b/code/modules/clothing/masks/miscellaneous.dm @@ -355,7 +355,7 @@ /obj/item/clothing/mask/paper/Initialize(mapload) - .=..() + . = ..() papermask_designs = list( "Blank" = image(icon = src.icon, icon_state = "plainmask"), "Neutral" = image(icon = src.icon, icon_state = "neutralmask"), @@ -384,7 +384,7 @@ "Vertical" = "verticalmask", "Horizontal" = "horizontalmask", "X" ="xmask", "Bugeyes" = "bugmask", "Double" = "doublemask", "Mark" = "markmask") - var/choice = show_radial_menu(user,src, papermask_designs, custom_check = FALSE, radius = 36, require_near = TRUE) + var/choice = show_radial_menu(user, src, papermask_designs, custom_check = FALSE, radius = 36, require_near = TRUE) if(src && choice && !user.incapacitated() && in_range(user,src)) icon_state = options[choice] diff --git a/code/modules/events/wormholes.dm b/code/modules/events/wormholes.dm index 0920c9ccb6..e723ddd79b 100644 --- a/code/modules/events/wormholes.dm +++ b/code/modules/events/wormholes.dm @@ -29,7 +29,7 @@ for(var/i = 1, i <= number_of_wormholes, i++) var/turf/T = pick(pick_turfs) - wormholes += new /obj/effect/portal/wormhole(T, null, 0, null, FALSE) + wormholes += new /obj/effect/portal/wormhole(T, 0, null, FALSE) /datum/round_event/wormholes/announce(fake) priority_announce("Space-time anomalies detected on the station. There is no additional data.", "Anomaly Alert", "spanomalies") diff --git a/code/modules/food_and_drinks/food/snacks_soup.dm b/code/modules/food_and_drinks/food/snacks_soup.dm index eea7cdb87d..38a68ad364 100644 --- a/code/modules/food_and_drinks/food/snacks_soup.dm +++ b/code/modules/food_and_drinks/food/snacks_soup.dm @@ -291,3 +291,12 @@ tastes = list("creamy peas"= 2, "parsnip" = 1) filling_color = "#9dc530" foodtype = VEGETABLES + +/obj/item/reagent_containers/food/snacks/soup/facehuggerpot + name = "pot of face hugger jambalaya" + desc = "An entire pot of an extremely spicy dish made using extremely exotic ingredients. Highly recommend by an interdimensional businessman." + icon_state = "facehuggerpot" + bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 2) + list_reagents = list(/datum/reagent/consumable/nutriment = 10, /datum/reagent/consumable/nutriment/vitamin = 4) + tastes = list("face huggers" = 1) + foodtype = MEAT diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_soup.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_soup.dm index 6372137edc..c52218c913 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_soup.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_soup.dm @@ -291,3 +291,18 @@ ) result = /obj/item/reagent_containers/food/snacks/soup/peasoup subcategory = CAT_SOUP + +/datum/crafting_recipe/food/facehuggerjambalayapot + name = "Facehugger jambalaya" + reqs = list( + /datum/reagent/bluespace = 10, + /datum/reagent/consumable/ethanol/booger =10, + /obj/item/organ/heart= 3, + /obj/item/clothing/mask/facehugger = 1, + /obj/item/reagent_containers/food/snacks/egg = 1, + /datum/reagent/consumable/blackpepper = 5, + /datum/reagent/toxin/acid = 5 + + ) + result = /obj/item/reagent_containers/food/snacks/soup/facehuggerpot + subcategory = CAT_SOUP diff --git a/code/modules/holiday/holidays.dm b/code/modules/holiday/holidays.dm index 83bb67b879..f6e4684e21 100644 --- a/code/modules/holiday/holidays.dm +++ b/code/modules/holiday/holidays.dm @@ -351,7 +351,7 @@ /datum/holiday/halloween name = HALLOWEEN - begin_day = 28 + begin_day = 1 begin_month = OCTOBER end_day = 2 end_month = NOVEMBER diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm index aa8a7b60c2..a1a177c028 100644 --- a/code/modules/hydroponics/hydroponics.dm +++ b/code/modules/hydroponics/hydroponics.dm @@ -42,6 +42,14 @@ icon = 'icons/obj/hydroponics/equipment.dmi' icon_state = "hydrotray3" +/obj/machinery/hydroponics/constructable/ComponentInitialize() + . = ..() + AddComponent(/datum/component/simple_rotation, ROTATION_ALTCLICK | ROTATION_CLOCKWISE | ROTATION_COUNTERCLOCKWISE | ROTATION_VERBS, null, CALLBACK(src, .proc/can_be_rotated)) + AddComponent(/datum/component/plumbing/simple_demand) + +/obj/machinery/hydroponics/constructable/proc/can_be_rotated(mob/user, rotation_type) + return !anchored + /obj/machinery/hydroponics/constructable/RefreshParts() var/tmp_capacity = 0 for (var/obj/item/stock_parts/matter_bin/M in component_parts) diff --git a/code/modules/integrated_electronics/subtypes/output.dm b/code/modules/integrated_electronics/subtypes/output.dm index efd98c4d50..833b2963ad 100644 --- a/code/modules/integrated_electronics/subtypes/output.dm +++ b/code/modules/integrated_electronics/subtypes/output.dm @@ -44,18 +44,18 @@ /obj/item/integrated_circuit/output/screen/large/do_work() ..() - if(isliving(assembly.loc))//this whole block just returns if the assembly is neither in a mobs hands or on the ground - var/mob/living/H = assembly.loc - if(H.get_active_held_item() != assembly && H.get_inactive_held_item() != assembly) - return - else - if(!isturf(assembly.loc)) - return - - var/atom/host = assembly || src var/list/mobs = list() - for(var/mob/M in range(0, get_turf(src))) - mobs += M + if(isliving(assembly.loc)) + mobs += assembly.loc + var/mob/living/L = assembly.loc + if(L.is_holding(src)) + for(var/mob/M in range(1, get_turf(src))) + mobs += M + else + for(var/mob/M in range(2, get_turf(src))) + mobs += M + + var/atom/host = assembly || src to_chat(mobs, "[icon2html(host.icon, world, host.icon_state)] flashes a message: [stuff_to_display]") host.investigate_log("displayed \"[html_encode(stuff_to_display)]\" as [type].", INVESTIGATE_CIRCUIT) diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm index 0feceaf1a8..b0ac5248c1 100644 --- a/code/modules/jobs/job_types/_job.dm +++ b/code/modules/jobs/job_types/_job.dm @@ -73,6 +73,31 @@ /// Starting skill modifiers. var/list/starting_modifiers +/** + * Checks if we should be created on a certain map + */ +/datum/job/proc/map_check(datum/map_config/C) + return (length(C.job_whitelist)? (type in C.job_whitelist) : !(type in C.job_blacklist)) + +/** + * Processes map specific overrides + */ +/datum/job/proc/process_map_overrides(datum/map_config/C) + if(type in C.job_override_spawn_positions) + spawn_positions = C.job_override_spawn_positions[type] + if(type in C.job_override_total_positions) + total_positions = C.job_override_total_positions[type] + if(type in C.job_access_override) + access = C.job_access_override[type] + minimal_access = access + else + if(type in C.job_access_add) + access += C.job_access_add[type] + minimal_access += C.job_access_add[type] + if(type in C.job_access_remove) + access -= C.job_access_add[type] + minimal_access -= C.job_access_remove[type] + //Only override this proc //H is usually a human unless an /equip override transformed it /datum/job/proc/after_spawn(mob/living/H, mob/M, latejoin = FALSE) @@ -175,9 +200,6 @@ /datum/job/proc/config_check() return TRUE -/datum/job/proc/map_check() - return TRUE - /datum/job/proc/radio_help_message(mob/M) to_chat(M, "Prefix your message with :h to speak on your department's radio. To see other prefixes, look closely at your headset.") diff --git a/code/modules/jobs/map_changes/map_changes.dm b/code/modules/jobs/map_changes/map_changes.dm deleted file mode 100644 index 575075037b..0000000000 --- a/code/modules/jobs/map_changes/map_changes.dm +++ /dev/null @@ -1,4 +0,0 @@ -//this needs to come after the job_types subfolder to keep the correct ordering - -#include "..\..\..\..\_maps\map_files\PubbyStation\job_changes.dm" -#undef JOB_MODIFICATION_MAP_NAME \ No newline at end of file diff --git a/code/modules/keybindings/bindings_client.dm b/code/modules/keybindings/bindings_client.dm index 3a47cd2315..3d12f89cfe 100644 --- a/code/modules/keybindings/bindings_client.dm +++ b/code/modules/keybindings/bindings_client.dm @@ -1,6 +1,7 @@ // Clients aren't datums so we have to define these procs indpendently. // These verbs are called for all key press and release events /client/verb/keyDown(_key as text) + SHOULD_NOT_SLEEP(TRUE) set instant = TRUE set hidden = TRUE @@ -83,6 +84,7 @@ keyUp("[key]") /client/verb/keyUp(_key as text) + SHOULD_NOT_SLEEP(TRUE) set instant = TRUE set hidden = TRUE diff --git a/code/modules/keybindings/setup.dm b/code/modules/keybindings/setup.dm index a53820b5d2..47dbfd855f 100644 --- a/code/modules/keybindings/setup.dm +++ b/code/modules/keybindings/setup.dm @@ -1,12 +1,11 @@ /datum/proc/key_down(key, client/user) // Called when a key is pressed down initially - return + SHOULD_NOT_SLEEP(TRUE) /datum/proc/key_up(key, client/user) // Called when a key is released - return + SHOULD_NOT_SLEEP(TRUE) /datum/proc/keyLoop(client/user) // Called once every frame - set waitfor = FALSE - return + SHOULD_NOT_SLEEP(TRUE) // removes all the existing macros /client/proc/erase_all_macros() diff --git a/code/modules/mapping/map_config.dm b/code/modules/mapping/map_config.dm index c03ef65f43..d18ca1e1e3 100644 --- a/code/modules/mapping/map_config.dm +++ b/code/modules/mapping/map_config.dm @@ -43,6 +43,21 @@ /// Orientation to load in by default. var/orientation = SOUTH //byond defaults to placing everyting SOUTH. + /// Jobs whitelist - if this is not empty, ONLY these jobs are allowed. Overrides blacklist. + var/list/job_whitelist + /// Jobs blacklist - if this is not empty, jobs in this aren't allowed. + var/list/job_blacklist + /// Job spawn position mod - type = number + var/list/job_override_spawn_positions + /// Job total position mod - type = number + var/list/job_override_total_positions + /// Add these accesses to jobs - type = list() + var/list/job_access_add + /// Remove these accesses from jobs - type = list() + var/list/job_access_remove + /// Override job accesses - type = list() - overrides everything else + var/list/job_access_override + /proc/load_map_config(filename = "data/next_map.json", default_to_box, delete_after, error_if_missing = TRUE) var/datum/map_config/config = new if (default_to_box) @@ -161,6 +176,69 @@ allow_custom_shuttles = json["allow_custom_shuttles"] != FALSE + if("job_whitelist" in json) + job_whitelist = list() + for(var/path in json["job_whitelist"]) + var/type = text2path(path) + if(!path) + log_config("map datum [config_filename] failed to validate path [path] in job overrides.") + continue + job_whitelist += type + + if("job_blacklist" in json) + job_blacklist = list() + for(var/path in json["job_blacklist"]) + var/type = text2path(path) + if(!path) + log_config("map datum [config_filename] failed to validate path [path] in job overrides.") + continue + job_blacklist += type + + if("job_override_spawn_positions" in json) + job_override_spawn_positions = list() + for(var/path in json["job_override_spawn_positions"]) + var/type = text2path(path) + if(!path) + log_config("map datum [config_filename] failed to validate path [path] in job overrides.") + continue + job_override_spawn_positions += type + + if("job_override_total_positions" in json) + job_override_total_positions = list() + for(var/path in json["job_override_total_positions"]) + var/type = text2path(path) + if(!path) + log_config("map datum [config_filename] failed to validate path [path] in job overrides.") + continue + job_override_total_positions += type + + if("job_access_add" in json) + job_access_add = list() + for(var/path in json["job_acces_add"]) + var/type = text2path(path) + if(!path) + log_config("map datum [config_filename] failed to validate path [path] in job overrides.") + continue + job_access_add[type] = json["job_access_add"] + + if("job_access_remove" in json) + job_access_remove = list() + for(var/path in json["job_acces_add"]) + var/type = text2path(path) + if(!path) + log_config("map datum [config_filename] failed to validate path [path] in job overrides.") + continue + job_access_remove[type] = json["job_access_remove"] + + if("job_access_override" in json) + job_access_override = list() + for(var/path in json["job_acces_add"]) + var/type = text2path(path) + if(!path) + log_config("map datum [config_filename] failed to validate path [path] in job overrides.") + continue + job_access_override[type] = json["job_access_override"] + defaulted = FALSE return TRUE #undef CHECK_EXISTS @@ -190,6 +268,13 @@ jsonlist["announcertype"] = announcertype jsonlist["orientation"] = orientation jsonlist["allow_custom_shuttles"] = allow_custom_shuttles + jsonlist["job_whitelist"] = job_whitelist + jsonlist["job_blacklist"] = job_blacklist + jsonlist["job_override_spawn_positions"] = job_override_spawn_positions + jsonlist["job_override_total_positions"] = job_override_total_positions + jsonlist["job_access_add"] = job_access_add + jsonlist["job_access_remove"] = job_access_remove + jsonlist["job_access_override"] = job_access_override if(fexists("data/next_map.json")) fdel("data/next_map.json") var/F = file("data/next_map.json") diff --git a/code/modules/mapping/ruins.dm b/code/modules/mapping/ruins.dm index 193106c294..b681c348e0 100644 --- a/code/modules/mapping/ruins.dm +++ b/code/modules/mapping/ruins.dm @@ -135,7 +135,12 @@ //That's done remove from priority even if it failed if(forced) //TODO : handle forced ruins with multiple variants + // this might work? forced_ruins -= current_pick + if(!current_pick.allow_duplicates) + for(var/datum/map_template/ruin/R in forced_ruins) + if(R.id == current_pick.id) + forced_ruins -= R forced = FALSE if(failed_to_place) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 11b133f5e7..26486f255a 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -191,8 +191,8 @@ if(HAS_TRAIT(src, TRAIT_PACIFISM)) to_chat(src, "You gently let go of [throwable_mob].") return - - adjustStaminaLossBuffered(STAM_COST_THROW_MOB * ((throwable_mob.mob_size+1)**2))// throwing an entire person shall be very tiring + if(!UseStaminaBuffer(STAM_COST_THROW_MOB * ((throwable_mob.mob_size+1)**2), TRUE)) + return var/turf/start_T = get_turf(loc) //Get the start and target tile for the descriptors var/turf/end_T = get_turf(target) if(start_T && end_T) @@ -206,7 +206,8 @@ to_chat(src, "You set [I] down gently on the ground.") return - adjustStaminaLossBuffered(I.getweight(src, STAM_COST_THROW_MULT, SKILL_THROW_STAM_COST)) + if(!UseStaminaBuffer(I.getweight(src, STAM_COST_THROW_MULT, SKILL_THROW_STAM_COST), warn = TRUE)) + return if(thrown_thing) var/power_throw = 0 @@ -594,15 +595,23 @@ remove_movespeed_modifier(/datum/movespeed_modifier/carbon_softcrit) /mob/living/carbon/update_stamina() - var/stam = getStaminaLoss() - if(stam > DAMAGE_PRECISION) - var/total_health = (maxHealth - stam) - if(total_health <= crit_threshold && !stat) - if(CHECK_MOBILITY(src, MOBILITY_STAND)) - to_chat(src, "You're too exhausted to keep going...") - KnockToFloor(TRUE) - update_health_hud() - + var/total_health = getStaminaLoss() + if(total_health) + if(!(combat_flags & COMBAT_FLAG_HARD_STAMCRIT) && total_health >= STAMINA_CRIT && !stat) + to_chat(src, "You're too exhausted to keep going...") + set_resting(TRUE, FALSE, FALSE) + SEND_SIGNAL(src, COMSIG_DISABLE_COMBAT_MODE) + ENABLE_BITFIELD(combat_flags, COMBAT_FLAG_HARD_STAMCRIT) + filters += CIT_FILTER_STAMINACRIT + update_mobility() + if((combat_flags & COMBAT_FLAG_HARD_STAMCRIT) && total_health <= STAMINA_CRIT) + to_chat(src, "You don't feel nearly as exhausted anymore.") + DISABLE_BITFIELD(combat_flags, COMBAT_FLAG_HARD_STAMCRIT) + filters -= CIT_FILTER_STAMINACRIT + update_mobility() + UpdateStaminaBuffer() + update_health_hud() + /mob/living/carbon/update_sight() if(!client) return diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 904753f9b1..1b7ab81d59 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -254,10 +254,10 @@ if(href_list["pockets"]) var/strip_mod = 1 var/strip_silence = FALSE - var/obj/item/clothing/gloves/g = gloves - if (istype(g)) - strip_mod = g.strip_mod - strip_silence = g.strip_silence + var/obj/item/clothing/gloves/G = gloves + if(istype(G)) + strip_mod = G.strip_mod + strip_silence = G.strip_silence var/pocket_side = href_list["pockets"] var/pocket_id = (pocket_side == "right" ? SLOT_R_STORE : SLOT_L_STORE) var/obj/item/pocket_item = (pocket_id == SLOT_R_STORE ? r_store : l_store) @@ -805,7 +805,7 @@ hud_used.healthdoll.icon_state = "healthdoll_DEAD" hud_used.staminas?.update_icon_state() - hud_used.staminabuffer?.update_icon_state() + hud_used.staminabuffer?.mark_dirty() /mob/living/carbon/human/fully_heal(admin_revive = FALSE) if(admin_revive) @@ -1044,10 +1044,9 @@ remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown) remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown_flying) return - var/stambufferinfluence = (bufferedstam*(100/stambuffer))*0.2 //CIT CHANGE - makes stamina buffer influence movedelay if(!HAS_TRAIT(src, TRAIT_IGNOREDAMAGESLOWDOWN)) //if we want to ignore slowdown from damage, but not from equipment var/scaling = maxHealth / 100 - var/health_deficiency = (((maxHealth / scaling) + stambufferinfluence) - (health / scaling) + (getStaminaLoss()*0.75))//CIT CHANGE - reduces the impact of staminaloss and makes stamina buffer influence it + var/health_deficiency = ((maxHealth / scaling) - (health / scaling) + (getStaminaLoss()*0.75))//CIT CHANGE - reduces the impact of staminaloss and makes stamina buffer influence it if(health_deficiency >= 40) add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown, TRUE, (health_deficiency-39) / 75) add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown_flying, TRUE, (health_deficiency-39) / 25) diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index a6a3f408dc..89a4570e8d 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -7,7 +7,7 @@ buckle_lying = FALSE mob_biotypes = MOB_ORGANIC|MOB_HUMANOID /// Enable stamina combat - combat_flags = COMBAT_FLAGS_DEFAULT | COMBAT_FLAG_UNARMED_PARRY + combat_flags = COMBAT_FLAGS_STAMINA_COMBAT | COMBAT_FLAG_UNARMED_PARRY status_flags = CANSTUN|CANKNOCKDOWN|CANUNCONSCIOUS|CANPUSH|CANSTAGGER has_field_of_vision = FALSE //Handled by species. diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm index 5ced11e35a..97c40c96d7 100644 --- a/code/modules/mob/living/carbon/human/human_movement.dm +++ b/code/modules/mob/living/carbon/human/human_movement.dm @@ -11,11 +11,6 @@ /mob/living/carbon/human/movement_delay() . = ..() - if(CHECK_MOBILITY(src, MOBILITY_STAND) && m_intent == MOVE_INTENT_RUN && (combat_flags & COMBAT_FLAG_SPRINT_ACTIVE)) - var/static/datum/config_entry/number/movedelay/sprint_speed_increase/SSI - if(!SSI) - SSI = CONFIG_GET_ENTRY(number/movedelay/sprint_speed_increase) - . -= SSI.config_entry_value if (m_intent == MOVE_INTENT_WALK && HAS_TRAIT(src, TRAIT_SPEEDY_STEP)) . -= 1.5 @@ -61,7 +56,11 @@ HM.on_move(NewLoc) if(. && (combat_flags & COMBAT_FLAG_SPRINT_ACTIVE) && !(movement_type & FLYING) && CHECK_ALL_MOBILITY(src, MOBILITY_MOVE|MOBILITY_STAND) && m_intent == MOVE_INTENT_RUN && has_gravity(loc) && (!pulledby || (pulledby.pulledby == src))) if(!HAS_TRAIT(src, TRAIT_FREESPRINT)) - doSprintLossTiles(1) + var/datum/movespeed_modifier/equipment_speedmod/MM = get_movespeed_modifier_datum(/datum/movespeed_modifier/equipment_speedmod) + var/amount = 1 + if(MM?.multiplicative_slowdown >= 1) + amount *= (1 + (6 - (3 / MM.multiplicative_slowdown))) + doSprintLossTiles(amount) if((oldpseudoheight - pseudo_z_axis) >= 8) to_chat(src, "You trip off of the elevated surface!") for(var/obj/item/I in held_items) diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index e68984738a..3a3171e24c 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -64,7 +64,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) var/stunmod = 1 // multiplier for stun duration var/punchdamagelow = 1 //lowest possible punch damage. if this is set to 0, punches will always miss var/punchdamagehigh = 10 //highest possible punch damage - var/punchstunthreshold = 10//damage at which punches from this race will stun //yes it should be to the attacked race but it's not useful that way even if it's logical + var/punchstunthreshold = 10 //damage at which punches from this race will stun //yes it should be to the attacked race but it's not useful that way even if it's logical + var/punchwoundbonus = 0 // additional wound bonus. generally zero. var/siemens_coeff = 1 //base electrocution coefficient var/damage_overlay_type = "human" //what kind of damage overlays (if any) appear on our species when wounded? var/fixed_mut_color = "" //to use MUTCOLOR with a fixed color that's independent of dna.feature["mcolor"] @@ -106,7 +107,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) var/whitelisted = 0 //Is this species restricted to certain players? var/whitelist = list() //List the ckeys that can use this species, if it's whitelisted.: list("John Doe", "poopface666", "SeeALiggerPullTheTrigger") Spaces & capitalization can be included or ignored entirely for each key as it checks for both. var/icon_limbs //Overrides the icon used for the limbs of this species. Mainly for downstream, and also because hardcoded icons disgust me. Implemented and maintained as a favor in return for a downstream's implementation of synths. - var/species_type + var/species_category var/tail_type //type of tail i.e. mam_tail var/wagging_type //type of wagging i.e. waggingtail_lizard @@ -1361,9 +1362,10 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) if(!(attackchain_flags & ATTACK_IS_PARRY_COUNTERATTACK)) if(HAS_TRAIT(user, TRAIT_PUGILIST))//CITADEL CHANGE - makes punching cause staminaloss but funny martial artist types get a discount - user.adjustStaminaLossBuffered(1.5) - else - user.adjustStaminaLossBuffered(3.5) + if(!user.UseStaminaBuffer(1.5, warn = TRUE)) + return + else if(!user.UseStaminaBuffer(3.5, warn = TRUE)) + return if(attacker_style && attacker_style.harm_act(user,target)) return TRUE @@ -1384,6 +1386,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) user.do_attack_animation(target, ATTACK_EFFECT_PUNCH) var/damage = rand(user.dna.species.punchdamagelow, user.dna.species.punchdamagehigh) + var/punchwoundbonus = user.dna.species.punchwoundbonus var/puncherstam = user.getStaminaLoss() var/puncherbrute = user.getBruteLoss() var/punchedstam = target.getStaminaLoss() @@ -1399,6 +1402,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) //END OF CITADEL CHANGES var/obj/item/bodypart/affecting = target.get_bodypart(ran_zone(user.zone_selected)) + if(HAS_TRAIT(user, TRAIT_PUGILIST)) + affecting = target.get_bodypart(check_zone(user.zone_selected)) // if you're going the based unarmed route you won't miss if(!affecting) //Maybe the bodypart is missing? Or things just went wrong.. affecting = target.get_bodypart(BODY_ZONE_CHEST) //target chest instead, as failsafe. Or hugbox? You decide. @@ -1410,8 +1415,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) if(user.dna.species.punchdamagelow) if(atk_verb == ATTACK_EFFECT_KICK) //kicks never miss (provided your species deals more than 0 damage) miss_chance = 0 - else if(HAS_TRAIT(user, TRAIT_PUGILIST)) //pugilists have a flat 10% miss chance - miss_chance = 10 + else if(HAS_TRAIT(user, TRAIT_PUGILIST)) //pugilists, being good at Punching People, also never miss + miss_chance = 0 else miss_chance = min(10 + max(puncherstam * 0.5, puncherbrute * 0.5), 100) //probability of miss has a base of 10, and modified based on half brute total. Capped at max 100 to prevent weirdness in prob() @@ -1425,12 +1430,13 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) var/armor_block = target.run_armor_check(affecting, "melee") + if(HAS_TRAIT(user, TRAIT_MAULER)) // maulers get 15 armorpierce because if you're going to punch someone you might as well do a good job of it + armor_block = target.run_armor_check(affecting, "melee", armour_penetration = 15) // lot of good that sec jumpsuit did you playsound(target.loc, user.dna.species.attack_sound, 25, 1, -1) - - target.visible_message("[user] [atk_verb]s [target]!", \ - "[user] [atk_verb]s you!", null, COMBAT_MESSAGE_RANGE, null, \ - user, "You [atk_verb] [target]!") + target.visible_message("[user] [atk_verb]ed [target]!", \ + "[user] [atk_verb]ed you!", null, COMBAT_MESSAGE_RANGE, null, \ + user, "You [atk_verb]ed [target]!") target.lastattacker = user.real_name target.lastattackerckey = user.ckey @@ -1440,11 +1446,15 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) target.dismembering_strike(user, affecting.body_zone) if(atk_verb == ATTACK_EFFECT_KICK)//kicks deal 1.5x raw damage + 0.5x stamina damage - target.apply_damage(damage*1.5, attack_type, affecting, armor_block) + target.apply_damage(damage*1.5, attack_type, affecting, armor_block, wound_bonus = punchwoundbonus) target.apply_damage(damage*0.5, STAMINA, affecting, armor_block) log_combat(user, target, "kicked") - else//other attacks deal full raw damage + 2x in stamina damage - target.apply_damage(damage, attack_type, affecting, armor_block) + else if(HAS_TRAIT(user, TRAIT_MAULER)) // mauler punches deal 1.3x raw damage + 1x stam damage, and have some armor pierce + target.apply_damage(damage*1.3, attack_type, affecting, armor_block, wound_bonus = punchwoundbonus) + target.apply_damage(damage, STAMINA, affecting, armor_block) + log_combat(user, target, "punched (mauler)") + else //other attacks deal full raw damage + 2x in stamina damage + target.apply_damage(damage, attack_type, affecting, armor_block, wound_bonus = punchwoundbonus) target.apply_damage(damage*2, STAMINA, affecting, armor_block) log_combat(user, target, "punched") @@ -1494,6 +1504,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) return FALSE else if(aim_for_mouth && ( target_on_help || target_restrained || target_aiming_for_mouth)) + if(!user.UseStaminaBuffer(3, warn = TRUE)) + return playsound(target.loc, 'sound/weapons/slap.ogg', 50, 1, -1) target.visible_message(\ @@ -1501,7 +1513,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) "[user] slaps you in the face! ",\ "You hear a slap.", target = user, target_message = "You slap [user == target ? "yourself" : "\the [target]"] in the face! ") user.do_attack_animation(target, ATTACK_EFFECT_FACE_SLAP) - user.adjustStaminaLossBuffered(3) if (!HAS_TRAIT(target, TRAIT_PERMABONER)) stop_wagging_tail(target) return FALSE @@ -1509,8 +1520,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) if(target.client?.prefs.cit_toggles & NO_ASS_SLAP) to_chat(user,"A force stays your hand, preventing you from slapping \the [target]'s ass!") return FALSE + if(!user.UseStaminaBuffer(3, warn = TRUE)) + return FALSE user.do_attack_animation(target, ATTACK_EFFECT_ASS_SLAP) - user.adjustStaminaLossBuffered(3) target.adjust_arousal(20,maso = TRUE) if (ishuman(target) && HAS_TRAIT(target, TRAIT_MASO) && target.has_dna() && prob(10)) target.mob_climax(forced_climax=TRUE) @@ -1528,9 +1540,11 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) user.do_attack_animation(target, ATTACK_EFFECT_DISARM) if(HAS_TRAIT(user, TRAIT_PUGILIST))//CITADEL CHANGE - makes disarmspam cause staminaloss, pugilists can do it almost effortlessly - user.adjustStaminaLossBuffered(1) + if(!user.UseStaminaBuffer(1, warn = TRUE)) + return else - user.adjustStaminaLossBuffered(3) + if(!user.UseStaminaBuffer(1, warn = TRUE)) + return if(attacker_style && attacker_style.disarm_act(user,target)) return TRUE @@ -1766,9 +1780,10 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) if(CHECK_MOBILITY(user, MOBILITY_STAND)) to_chat(user, "You can only force yourself up if you're on the ground.") return + if(!user.UseStaminaBuffer(STAMINA_COST_SHOVE_UP, TRUE)) + return user.visible_message("[user] forces [p_them()]self up to [p_their()] feet!", "You force yourself up to your feet!") user.set_resting(FALSE, TRUE) - user.adjustStaminaLossBuffered(user.stambuffer) //Rewards good stamina management by making it easier to instantly get up from resting playsound(user, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) /datum/species/proc/altdisarm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style) @@ -1787,8 +1802,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) else if(user == target) return + if(!user.UseStaminaBuffer(4, warn = TRUE)) + return user.do_attack_animation(target, ATTACK_EFFECT_DISARM) - user.adjustStaminaLossBuffered(4) playsound(target, 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1) if(target.w_uniform) diff --git a/code/modules/mob/living/carbon/human/species_types/abductors.dm b/code/modules/mob/living/carbon/human/species_types/abductor.dm similarity index 90% rename from code/modules/mob/living/carbon/human/species_types/abductors.dm rename to code/modules/mob/living/carbon/human/species_types/abductor.dm index 38e10e8662..004ba267e8 100644 --- a/code/modules/mob/living/carbon/human/species_types/abductors.dm +++ b/code/modules/mob/living/carbon/human/species_types/abductor.dm @@ -1,12 +1,12 @@ /datum/species/abductor name = "Abductor" - id = "abductor" + id = SPECIES_ABDUCTOR say_mod = "gibbers" sexes = FALSE species_traits = list(NOBLOOD,NOEYES,NOGENITALS,NOAROUSAL,HAS_FLESH,HAS_BONE) inherent_traits = list(TRAIT_VIRUSIMMUNE,TRAIT_CHUNKYFINGERS,TRAIT_NOHUNGER,TRAIT_NOBREATH) mutanttongue = /obj/item/organ/tongue/abductor - species_type = "alien" + species_category = SPECIES_CATEGORY_ALIEN /datum/species/abductor/on_species_gain(mob/living/carbon/C, datum/species/old_species) . = ..() diff --git a/code/modules/mob/living/carbon/human/species_types/android.dm b/code/modules/mob/living/carbon/human/species_types/android.dm index e7c49f6d9c..187a0fdfec 100644 --- a/code/modules/mob/living/carbon/human/species_types/android.dm +++ b/code/modules/mob/living/carbon/human/species_types/android.dm @@ -1,6 +1,6 @@ /datum/species/android name = "Android" - id = "android" + id = SPECIES_ANDROID say_mod = "states" species_traits = list(NOBLOOD,NOGENITALS,NOAROUSAL,ROBOTIC_LIMBS) inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_NOFIRE,TRAIT_PIERCEIMMUNE,TRAIT_NOHUNGER,TRAIT_LIMBATTACHMENT) @@ -11,4 +11,4 @@ mutanttongue = /obj/item/organ/tongue/robot species_language_holder = /datum/language_holder/synthetic limbs_id = "synth" - species_type = "robotic" + species_category = SPECIES_CATEGORY_ROBOT \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/species_types/angel.dm b/code/modules/mob/living/carbon/human/species_types/angel.dm index 3cae574a90..9c87f3ad5d 100644 --- a/code/modules/mob/living/carbon/human/species_types/angel.dm +++ b/code/modules/mob/living/carbon/human/species_types/angel.dm @@ -1,6 +1,6 @@ /datum/species/angel name = "Angel" - id = "angel" + id = SPECIES_ANGEL default_color = "FFFFFF" species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,HAS_FLESH,HAS_BONE) mutant_bodyparts = list("tail_human" = "None", "ears" = "None", "wings" = "Angel") @@ -9,7 +9,7 @@ blacklisted = 1 limbs_id = "human" skinned_type = /obj/item/stack/sheet/animalhide/human - species_type = "human" //they're a kind of human + species_category = SPECIES_CATEGORY_BASIC //they're a kind of human var/datum/action/innate/flight/fly diff --git a/code/modules/mob/living/carbon/human/species_types/furrypeople.dm b/code/modules/mob/living/carbon/human/species_types/anthromorph.dm similarity index 87% rename from code/modules/mob/living/carbon/human/species_types/furrypeople.dm rename to code/modules/mob/living/carbon/human/species_types/anthromorph.dm index 534536d6e7..95aec26d9f 100644 --- a/code/modules/mob/living/carbon/human/species_types/furrypeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/anthromorph.dm @@ -1,6 +1,6 @@ /datum/species/mammal name = "Anthromorph" - id = "mammal" + id = SPECIES_MAMMAL default_color = "4B4B4B" species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR,HORNCOLOR,WINGCOLOR,HAS_FLESH,HAS_BONE) inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_BEAST @@ -15,6 +15,6 @@ tail_type = "mam_tail" wagging_type = "mam_waggingtail" - species_type = "furry" + species_category = SPECIES_CATEGORY_FURRY - allowed_limb_ids = list("mammal","aquatic","avian") \ No newline at end of file + allowed_limb_ids = list("mammal","aquatic","avian") diff --git a/code/modules/mob/living/carbon/human/species_types/bugmen.dm b/code/modules/mob/living/carbon/human/species_types/bugmen.dm index 6eccde61a9..773651d464 100644 --- a/code/modules/mob/living/carbon/human/species_types/bugmen.dm +++ b/code/modules/mob/living/carbon/human/species_types/bugmen.dm @@ -1,6 +1,6 @@ /datum/species/insect name = "Anthromorphic Insect" - id = "insect" + id = SPECIES_INSECT say_mod = "chitters" default_color = "00FF00" species_traits = list(LIPS,EYECOLOR,HAIR,FACEHAIR,MUTCOLORS,HORNCOLOR,WINGCOLOR,HAS_FLESH,HAS_BONE) @@ -18,7 +18,7 @@ tail_type = "mam_tail" wagging_type = "mam_waggingtail" - species_type = "insect" + species_category = SPECIES_CATEGORY_INSECT allowed_limb_ids = list("insect","apid","moth","moth_not_greyscale") diff --git a/code/modules/mob/living/carbon/human/species_types/corporate.dm b/code/modules/mob/living/carbon/human/species_types/corporate.dm index a2597ed286..e9baa786da 100644 --- a/code/modules/mob/living/carbon/human/species_types/corporate.dm +++ b/code/modules/mob/living/carbon/human/species_types/corporate.dm @@ -18,4 +18,4 @@ inherent_traits = list(TRAIT_RADIMMUNE,TRAIT_VIRUSIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOLIMBDISABLE,TRAIT_NOHUNGER) sexes = 0 gib_types = /obj/effect/gibspawner/robot - species_type = "robotic" \ No newline at end of file + species_category = SPECIES_CATEGORY_ROBOT diff --git a/code/modules/mob/living/carbon/human/species_types/dullahan.dm b/code/modules/mob/living/carbon/human/species_types/dullahan.dm index f3b499093b..f756fd8816 100644 --- a/code/modules/mob/living/carbon/human/species_types/dullahan.dm +++ b/code/modules/mob/living/carbon/human/species_types/dullahan.dm @@ -1,6 +1,6 @@ /datum/species/dullahan name = "Dullahan" - id = "dullahan" + id = SPECIES_DULLAHAN default_color = "FFFFFF" species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,HAS_FLESH,HAS_BONE) inherent_traits = list(TRAIT_NOHUNGER,TRAIT_NOBREATH) @@ -14,7 +14,7 @@ limbs_id = "human" skinned_type = /obj/item/stack/sheet/animalhide/human has_field_of_vision = FALSE //Too much of a trouble, their vision is already bound to their severed head. - species_type = "undead" + species_category = SPECIES_CATEGORY_UNDEAD var/pumpkin = FALSE var/obj/item/dullahan_relay/myhead diff --git a/code/modules/mob/living/carbon/human/species_types/dwarves.dm b/code/modules/mob/living/carbon/human/species_types/dwarves.dm index a465e7c3a9..ce67a947de 100644 --- a/code/modules/mob/living/carbon/human/species_types/dwarves.dm +++ b/code/modules/mob/living/carbon/human/species_types/dwarves.dm @@ -4,7 +4,7 @@ GLOBAL_LIST_INIT(dwarf_last, world.file2list("strings/names/dwarf_last.txt")) // /datum/species/dwarf //not to be confused with the genetic manlets name = "Dwarf" - id = "dwarf" //Also called Homo sapiens pumilionis + id = SPECIES_DWARF //Also called Homo sapiens pumilionis default_color = "FFFFFF" species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,HAS_FLESH,HAS_BONE) inherent_traits = list(TRAIT_DWARF,TRAIT_SNOB) @@ -18,7 +18,7 @@ GLOBAL_LIST_INIT(dwarf_last, world.file2list("strings/names/dwarf_last.txt")) // mutant_organs = list(/obj/item/organ/dwarfgland) //Dwarven alcohol gland, literal gland warrior mutantliver = /obj/item/organ/liver/dwarf //Dwarven super liver (Otherwise they r doomed) species_language_holder = /datum/language_holder/dwarf - species_type = "human" //a kind of human + species_category = SPECIES_CATEGORY_BASIC //a kind of human /mob/living/carbon/human/species/dwarf //species admin spawn path race = /datum/species/dwarf //and the race the path is set to. diff --git a/code/modules/mob/living/carbon/human/species_types/ethereal.dm b/code/modules/mob/living/carbon/human/species_types/ethereal.dm index c182defda4..d92f4ab14a 100644 --- a/code/modules/mob/living/carbon/human/species_types/ethereal.dm +++ b/code/modules/mob/living/carbon/human/species_types/ethereal.dm @@ -2,7 +2,7 @@ /datum/species/ethereal name = "Ethereal" - id = "ethereal" + id = SPECIES_ETHEREAL attack_verb = "burn" attack_sound = 'sound/weapons/etherealhit.ogg' miss_sound = 'sound/weapons/etherealmiss.ogg' diff --git a/code/modules/mob/living/carbon/human/species_types/felinid.dm b/code/modules/mob/living/carbon/human/species_types/felinid.dm index b760fd0aee..011b6b7642 100644 --- a/code/modules/mob/living/carbon/human/species_types/felinid.dm +++ b/code/modules/mob/living/carbon/human/species_types/felinid.dm @@ -1,7 +1,7 @@ //Subtype of human /datum/species/human/felinid name = "Felinid" - id = "felinid" + id = SPECIES_FELINID limbs_id = "human" mutant_bodyparts = list("mam_tail" = "Cat", "mam_ears" = "Cat", "deco_wings" = "None") @@ -11,7 +11,7 @@ tail_type = "mam_tail" wagging_type = "mam_waggingtail" - species_type = "furry" + species_category = SPECIES_CATEGORY_FURRY /datum/species/human/felinid/on_species_gain(mob/living/carbon/C, datum/species/old_species, pref_load) if(ishuman(C)) diff --git a/code/modules/mob/living/carbon/human/species_types/flypeople.dm b/code/modules/mob/living/carbon/human/species_types/flypeople.dm index c56adaf1b0..c3e406244b 100644 --- a/code/modules/mob/living/carbon/human/species_types/flypeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/flypeople.dm @@ -1,6 +1,6 @@ /datum/species/fly name = "Anthromorphic Fly" - id = "fly" + id = SPECIES_FLY say_mod = "buzzes" species_traits = list(NOEYES,HAS_FLESH,HAS_BONE) inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_BUG @@ -12,7 +12,7 @@ liked_food = GROSS exotic_bloodtype = "BUG" exotic_blood_color = BLOOD_COLOR_BUG - species_type = "insect" + species_category = SPECIES_CATEGORY_INSECT /datum/species/fly/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H) if(istype(chem, /datum/reagent/toxin/pestkiller)) diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm index 438eaf1eea..ff0287d7b9 100644 --- a/code/modules/mob/living/carbon/human/species_types/golems.dm +++ b/code/modules/mob/living/carbon/human/species_types/golems.dm @@ -1,7 +1,7 @@ /datum/species/golem // Animated beings of stone. They have increased defenses, and do not need to breathe. They're also slow as fuuuck. name = "Golem" - id = "iron golem" + id = SPECIES_GOLEM species_traits = list(NOBLOOD,MUTCOLORS,NO_UNDERWEAR,NOGENITALS,NOAROUSAL) inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOFIRE,TRAIT_CHUNKYFINGERS,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER) inherent_biotypes = MOB_HUMANOID|MOB_MINERAL @@ -32,7 +32,7 @@ var/special_name_chance = 5 var/owner //dobby is a free golem - species_type = "golem" + species_category = SPECIES_CATEGORY_GOLEM /datum/species/golem/random_name(gender,unique,lastname) var/golem_surname = pick(GLOB.golem_names) diff --git a/code/modules/mob/living/carbon/human/species_types/humans.dm b/code/modules/mob/living/carbon/human/species_types/humans.dm index f175ddb921..e8e0ff1a78 100644 --- a/code/modules/mob/living/carbon/human/species_types/humans.dm +++ b/code/modules/mob/living/carbon/human/species_types/humans.dm @@ -1,6 +1,6 @@ /datum/species/human name = "Human" - id = "human" + id = SPECIES_HUMAN default_color = "FFFFFF" species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,MUTCOLORS_PARTSONLY,WINGCOLOR,HAS_FLESH,HAS_BONE) @@ -12,7 +12,7 @@ tail_type = "tail_human" wagging_type = "waggingtail_human" - species_type = "human" + species_category = SPECIES_CATEGORY_BASIC /datum/species/human/spec_death(gibbed, mob/living/carbon/human/H) if(H) diff --git a/code/modules/mob/living/carbon/human/species_types/ipc.dm b/code/modules/mob/living/carbon/human/species_types/ipc.dm index 9bfe661f47..6353fd5184 100644 --- a/code/modules/mob/living/carbon/human/species_types/ipc.dm +++ b/code/modules/mob/living/carbon/human/species_types/ipc.dm @@ -1,6 +1,6 @@ /datum/species/ipc name = "I.P.C." - id = "ipc" + id = SPECIES_IPC say_mod = "beeps" default_color = "00FF00" blacklisted = 0 @@ -28,7 +28,7 @@ exotic_bloodtype = "HF" exotic_blood_color = BLOOD_COLOR_OIL - species_type = "robotic" + species_category = SPECIES_CATEGORY_ROBOT var/datum/action/innate/monitor_change/screen diff --git a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm index 6193172f06..58a10fb08e 100644 --- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm @@ -1,7 +1,7 @@ /datum/species/jelly // Entirely alien beings that seem to be made entirely out of gel. They have three eyes and a skeleton visible within them. name = "Xenobiological Jelly Entity" - id = "jelly" + id = SPECIES_JELLY default_color = "00FF90" say_mod = "chirps" species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,WINGCOLOR,HAS_FLESH) @@ -29,7 +29,7 @@ tail_type = "mam_tail" wagging_type = "mam_waggingtail" - species_type = "jelly" + species_category = SPECIES_CATEGORY_JELLY /obj/item/organ/brain/jelly name = "slime nucleus" @@ -158,7 +158,7 @@ /datum/species/jelly/slime name = "Xenobiological Slime Entity" - id = "slime" + id = SPECIES_SLIME default_color = "00FFFF" species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR) say_mod = "says" @@ -467,7 +467,7 @@ /datum/species/jelly/roundstartslime name = "Xenobiological Slime Hybrid" - id = "slimeperson" + id = SPECIES_SLIME_HYBRID limbs_id = "slime" default_color = "00FFFF" species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR) @@ -777,7 +777,7 @@ /datum/species/jelly/luminescent name = "Luminescent Slime Entity" - id = "lum" + id = SPECIES_SLIME_LUMI say_mod = "says" var/glow_intensity = LUMINESCENT_DEFAULT_GLOW var/obj/effect/dummy/luminescent_glow/glow @@ -944,7 +944,7 @@ /datum/species/jelly/stargazer name = "Stargazer Slime Entity" - id = "stargazer" + id = SPECIES_STARGAZER var/datum/action/innate/project_thought/project_thought var/datum/action/innate/link_minds/link_minds var/list/mob/living/linked_mobs = list() diff --git a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm index a8e3f89957..c37a24a93a 100644 --- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm @@ -1,7 +1,7 @@ /datum/species/lizard // Reptilian humanoids with scaled skin and tails. name = "Anthromorphic Lizard" - id = "lizard" + id = SPECIES_LIZARD say_mod = "hisses" default_color = "00FF00" species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,LIPS,HORNCOLOR,WINGCOLOR,HAS_FLESH,HAS_BONE) @@ -28,7 +28,7 @@ tail_type = "tail_lizard" wagging_type = "waggingtail_lizard" - species_type = "lizard" + species_category = "lizard" /datum/species/lizard/random_name(gender,unique,lastname) if(unique) @@ -46,7 +46,7 @@ */ /datum/species/lizard/ashwalker name = "Ash Walker" - id = "ashlizard" + id = SPECIES_ASHWALKER limbs_id = "lizard" species_traits = list(MUTCOLORS,EYECOLOR,LIPS,DIGITIGRADE) inherent_traits = list(TRAIT_CHUNKYFINGERS) diff --git a/code/modules/mob/living/carbon/human/species_types/mushpeople.dm b/code/modules/mob/living/carbon/human/species_types/mushpeople.dm index f91c3518a3..dcbdf91485 100644 --- a/code/modules/mob/living/carbon/human/species_types/mushpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/mushpeople.dm @@ -1,6 +1,6 @@ /datum/species/mush //mush mush codecuck name = "Anthromorphic Mushroom" - id = "mush" + id = SPECIES_MUSHROOM mutant_bodyparts = list("caps" = "Round") fixed_mut_color = "DBBF92" @@ -21,7 +21,7 @@ burnmod = 1.25 heatmod = 1.5 - species_type = "plant" + species_category = SPECIES_CATEGORY_PLANT mutanteyes = /obj/item/organ/eyes/night_vision/mushroom var/datum/martial_art/mushpunch/mush diff --git a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm index 8c30adb8f9..12a520b463 100644 --- a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm +++ b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm @@ -1,6 +1,6 @@ /datum/species/plasmaman name = "Plasmaman" - id = "plasmaman" + id = SPECIES_PLASMAMAN say_mod = "rattles" sexes = 0 meat = /obj/item/stack/sheet/mineral/plasma @@ -22,7 +22,7 @@ liked_food = VEGETABLES outfit_important_for_life = /datum/outfit/plasmaman - species_type = "skeleton" + species_category = SPECIES_CATEGORY_SKELETON /datum/species/plasmaman/spec_life(mob/living/carbon/human/H) var/datum/gas_mixture/environment = H.loc.return_air() diff --git a/code/modules/mob/living/carbon/human/species_types/podpeople.dm b/code/modules/mob/living/carbon/human/species_types/podpeople.dm index 0f62953e6c..fae8ebfb0d 100644 --- a/code/modules/mob/living/carbon/human/species_types/podpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/podpeople.dm @@ -1,7 +1,7 @@ /datum/species/pod // A mutation caused by a human being ressurected in a revival pod. These regain health in light, and begin to wither in darkness. name = "Anthromorphic Plant" - id = "pod" + id = SPECIES_POD default_color = "59CE00" species_traits = list(MUTCOLORS,EYECOLOR,CAN_SCAR,HAS_FLESH,HAS_BONE) attack_verb = "slash" @@ -19,7 +19,7 @@ var/light_burnheal = -1 var/light_bruteheal = -1 - species_type = "plant" + species_category = SPECIES_CATEGORY_PLANT allowed_limb_ids = list("pod","mush") @@ -66,7 +66,7 @@ /datum/species/pod/pseudo_weak name = "Anthromorphic Plant" - id = "podweak" + id = SPECIES_POD_WEAK species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,MUTCOLORS) mutant_bodyparts = list("mcolor" = "FFFFFF","mcolor2" = "FFFFFF","mcolor3" = "FFFFFF", "mam_snouts" = "Husky", "mam_tail" = "Husky", "mam_ears" = "Husky", "mam_body_markings" = "Husky", "taur" = "None", "legs" = "Normal Legs") limbs_id = "pod" diff --git a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm index a7d9ce4473..7dc8083264 100644 --- a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm @@ -4,7 +4,7 @@ /datum/species/shadow // Humans cursed to stay in the darkness, lest their life forces drain. They regain health in shadow and die in light. name = "???" - id = "shadow" + id = SPECIES_SHADOW sexes = 0 blacklisted = 1 ignored_by = list(/mob/living/simple_animal/hostile/faithless) @@ -15,7 +15,7 @@ dangerous_existence = 1 mutanteyes = /obj/item/organ/eyes/night_vision - species_type = "shadow" + species_category = SPECIES_CATEGORY_SHADOW /datum/species/shadow/on_species_gain(mob/living/carbon/C, datum/species/old_species) . = ..() @@ -32,7 +32,7 @@ /datum/species/shadow/nightmare name = "Nightmare" - id = "nightmare" + id = SPECIES_NIGHTMARE limbs_id = "shadow" burnmod = 1.5 blacklisted = TRUE diff --git a/code/modules/mob/living/carbon/human/species_types/skeletons.dm b/code/modules/mob/living/carbon/human/species_types/skeletons.dm index 1b6bef9dc6..b0673a7df4 100644 --- a/code/modules/mob/living/carbon/human/species_types/skeletons.dm +++ b/code/modules/mob/living/carbon/human/species_types/skeletons.dm @@ -1,6 +1,6 @@ /datum/species/skeleton name = "Skeleton" - id = "skeleton" + id = SPECIES_SKELETON say_mod = "rattles" blacklisted = 0 sexes = 0 @@ -15,7 +15,7 @@ brutemod = 1.25 burnmod = 1.25 - species_type = "skeleton" //they have their own category that's disassociated from undead, paired with plasmapeople + species_category = SPECIES_CATEGORY_SKELETON //they have their own category that's disassociated from undead, paired with plasmapeople /datum/species/skeleton/New() if(SSevents.holidays && SSevents.holidays[HALLOWEEN]) //skeletons are stronger during the spooky season! @@ -31,7 +31,7 @@ /datum/species/skeleton/space name = "Spooky Spacey Skeleton" - id = "spaceskeleton" + id = SPECIES_SKELETON_SPACE limbs_id = "skeleton" blacklisted = 1 inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NOHUNGER,TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT, TRAIT_FAKEDEATH, TRAIT_CALCIUM_HEALER) diff --git a/code/modules/mob/living/carbon/human/species_types/synthliz.dm b/code/modules/mob/living/carbon/human/species_types/synthliz.dm index b446e3796e..88781532d3 100644 --- a/code/modules/mob/living/carbon/human/species_types/synthliz.dm +++ b/code/modules/mob/living/carbon/human/species_types/synthliz.dm @@ -1,6 +1,6 @@ /datum/species/synthliz name = "Synthetic Lizardperson" - id = "synthliz" + id = SPECIES_SYNTH_LIZARD say_mod = "beeps" default_color = "00FF00" species_traits = list(MUTCOLORS,NOTRANSSTING,EYECOLOR,LIPS,HAIR,ROBOTIC_LIMBS,HAS_FLESH,HAS_BONE) @@ -27,4 +27,4 @@ tail_type = "mam_tail" wagging_type = "mam_waggingtail" - species_type = "robotic" + species_category = SPECIES_CATEGORY_ROBOT diff --git a/code/modules/mob/living/carbon/human/species_types/synths.dm b/code/modules/mob/living/carbon/human/species_types/synths.dm index 3d55ce1027..5d2b6f4c77 100644 --- a/code/modules/mob/living/carbon/human/species_types/synths.dm +++ b/code/modules/mob/living/carbon/human/species_types/synths.dm @@ -1,6 +1,6 @@ /datum/species/synth name = "Synthetic" //inherited from the real species, for health scanners and things - id = "synth" + id = SPECIES_SYNTH say_mod = "beep boops" //inherited from a user's real species sexes = 0 species_traits = list(NOTRANSSTING,NOGENITALS,NOAROUSAL) //all of these + whatever we inherit from the real species @@ -17,11 +17,11 @@ var/disguise_fail_health = 75 //When their health gets to this level their synthflesh partially falls off var/datum/species/fake_species = null //a species to do most of our work for us, unless we're damaged species_language_holder = /datum/language_holder/synthetic - species_type = "robotic" + species_category = SPECIES_CATEGORY_ROBOT /datum/species/synth/military name = "Military Synth" - id = "military_synth" + id = SPECIES_SYNTH_MIL armor = 25 punchdamagelow = 10 punchdamagehigh = 19 diff --git a/code/modules/mob/living/carbon/human/species_types/vampire.dm b/code/modules/mob/living/carbon/human/species_types/vampire.dm index 857fb6d8ed..4125d3beab 100644 --- a/code/modules/mob/living/carbon/human/species_types/vampire.dm +++ b/code/modules/mob/living/carbon/human/species_types/vampire.dm @@ -1,6 +1,6 @@ /datum/species/vampire name = "Vampire" - id = "vampire" + id = SPECIES_VAMPIRE default_color = "FFFFFF" species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,DRINKSBLOOD,HAS_FLESH,HAS_BONE) inherent_traits = list(TRAIT_NOHUNGER,TRAIT_NOBREATH) @@ -14,7 +14,7 @@ limbs_id = "human" skinned_type = /obj/item/stack/sheet/animalhide/human var/info_text = "You are a Vampire. You will slowly but constantly lose blood if outside of a coffin. If inside a coffin, you will slowly heal. You may gain more blood by grabbing a live victim and using your drain ability." - species_type = "undead" + species_category = SPECIES_CATEGORY_UNDEAD /datum/species/vampire/check_roundstart_eligible() if(SSevents.holidays && SSevents.holidays[HALLOWEEN]) diff --git a/code/modules/mob/living/carbon/human/species_types/xeno.dm b/code/modules/mob/living/carbon/human/species_types/xeno.dm index ddd1c86f0a..2757c624e7 100644 --- a/code/modules/mob/living/carbon/human/species_types/xeno.dm +++ b/code/modules/mob/living/carbon/human/species_types/xeno.dm @@ -1,7 +1,7 @@ /datum/species/xeno // A cloning mistake, crossing human and xenomorph DNA name = "Xenomorph Hybrid" - id = "xeno" + id = SPECIES_XENOHYBRID say_mod = "hisses" default_color = "00FF00" species_traits = list(MUTCOLORS,EYECOLOR,LIPS,CAN_SCAR) @@ -15,4 +15,4 @@ exotic_bloodtype = "X*" damage_overlay_type = "xeno" liked_food = MEAT - species_type = "alien" + species_category = SPECIES_CATEGORY_ALIEN diff --git a/code/modules/mob/living/carbon/human/species_types/zombies.dm b/code/modules/mob/living/carbon/human/species_types/zombies.dm index 8d86ad2fa9..f1c0b8e7c0 100644 --- a/code/modules/mob/living/carbon/human/species_types/zombies.dm +++ b/code/modules/mob/living/carbon/human/species_types/zombies.dm @@ -15,7 +15,7 @@ var/static/list/spooks = list('sound/hallucinations/growl1.ogg','sound/hallucinations/growl2.ogg','sound/hallucinations/growl3.ogg','sound/hallucinations/veryfar_noise.ogg','sound/hallucinations/wail.ogg') disliked_food = NONE liked_food = GROSS | MEAT | RAW - species_type = "undead" + species_category = SPECIES_CATEGORY_UNDEAD /datum/species/zombie/notspaceproof id = "notspaceproofzombie" @@ -98,7 +98,7 @@ // Your skin falls off /datum/species/krokodil_addict - name = "Human" + name = SPECIES_HUMAN id = "goofzombies" limbs_id = "zombie" //They look like zombies sexes = 0 diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index 8f181d47fd..30785a0103 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -502,19 +502,14 @@ GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put //this updates all special effects: stun, sleeping, knockdown, druggy, stuttering, etc.. /mob/living/carbon/handle_status_effects() ..() - if(getStaminaLoss() && !SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_ACTIVE)) //CIT CHANGE - prevents stamina regen while combat mode is active - adjustStaminaLoss(!CHECK_MOBILITY(src, MOBILITY_STAND) ? ((combat_flags & COMBAT_FLAG_HARD_STAMCRIT) ? STAM_RECOVERY_STAM_CRIT : STAM_RECOVERY_RESTING) : STAM_RECOVERY_NORMAL) + var/combat_mode = SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_ACTIVE) + if(getStaminaLoss() && !HAS_TRAIT(src, TRAIT_NO_STAMINA_REGENERATION)) + adjustStaminaLoss((!CHECK_MOBILITY(src, MOBILITY_STAND) ? ((combat_flags & COMBAT_FLAG_HARD_STAMCRIT) ? STAM_RECOVERY_STAM_CRIT : STAM_RECOVERY_RESTING) : STAM_RECOVERY_NORMAL) * (combat_mode? 0.25 : 1)) if(!(combat_flags & COMBAT_FLAG_HARD_STAMCRIT) && incomingstammult != 1) incomingstammult = max(0.01, incomingstammult) incomingstammult = min(1, incomingstammult*2) - //CIT CHANGES START HERE. STAMINA BUFFER STUFF - if(bufferedstam && world.time > stambufferregentime) - var/drainrate = max((bufferedstam*(bufferedstam/(5)))*0.1,1) - bufferedstam = max(bufferedstam - drainrate, 0) - //END OF CIT CHANGES - var/restingpwr = 1 + 4 * !CHECK_MOBILITY(src, MOBILITY_STAND) //Dizziness diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm index 1d78979cbd..4ee52a08a6 100644 --- a/code/modules/mob/living/emote.dm +++ b/code/modules/mob/living/emote.dm @@ -562,7 +562,7 @@ if(. && iscarbon(user)) var/mob/living/carbon/C = user if(isjellyperson(C)) - pick(playsound(C, 'sound/effects/attackblob.ogg', 50, 1),playsound(C, 'sound/effects/blobattack.ogg', 50, 1)) + playsound(C, 'sound/effects/attackblob.ogg', 50, 1) /datum/emote/living/audio_emote/blurp key = "blurp" diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 8dac56a8c9..57d688bde3 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -8,6 +8,8 @@ for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds) diag_hud.add_to_hud(src) faction += "[REF(src)]" + stamina_buffer = INFINITY + UpdateStaminaBuffer() GLOB.mob_living_list += src /mob/living/prepare_huds() @@ -842,12 +844,12 @@ return var/strip_mod = 1 var/strip_silence = FALSE - if (ishuman(src)) //carbon doesn't actually wear gloves + if(ishuman(src)) //carbon doesn't actually wear gloves var/mob/living/carbon/C = src - var/obj/item/clothing/gloves/g = C.gloves - if (istype(g)) - strip_mod = g.strip_mod - strip_silence = g.strip_silence + var/obj/item/clothing/gloves/G = C.gloves + if(istype(G)) + strip_mod = G.strip_mod + strip_silence = G.strip_silence if (!strip_silence) who.visible_message("[src] tries to remove [who]'s [what.name].", \ "[src] tries to remove your [what.name].", target = src, @@ -1257,7 +1259,7 @@ SetUnconscious(clamp_unconscious_to) HealAllImmobilityUpTo(clamp_immobility_to) adjustStaminaLoss(min(0, -stamina_boost)) - adjustStaminaLossBuffered(min(0, -stamina_buffer_boost)) + RechargeStaminaBuffer(stamina_buffer_boost) // this MUST GO AFTER ADJUSTSTAMINALOSS. if(scale_stamina_loss_recovery) adjustStaminaLoss(min(-((getStaminaLoss() - stamina_loss_recovery_bypass) * scale_stamina_loss_recovery), 0)) if(put_on_feet) diff --git a/code/modules/mob/living/living_active_block.dm b/code/modules/mob/living/living_active_block.dm index 8e8b94463b..db472df388 100644 --- a/code/modules/mob/living/living_active_block.dm +++ b/code/modules/mob/living/living_active_block.dm @@ -8,6 +8,8 @@ active_block_item = null REMOVE_TRAIT(src, TRAIT_MOBILITY_NOUSE, ACTIVE_BLOCK_TRAIT) REMOVE_TRAIT(src, TRAIT_SPRINT_LOCKED, ACTIVE_BLOCK_TRAIT) + REMOVE_TRAIT(src, TRAIT_NO_STAMINA_BUFFER_REGENERATION, ACTIVE_BLOCK_TRAIT) + REMOVE_TRAIT(src, TRAIT_NO_STAMINA_REGENERATION, ACTIVE_BLOCK_TRAIT) remove_movespeed_modifier(/datum/movespeed_modifier/active_block) var/datum/block_parry_data/data = I.get_block_parry_data() DelayNextAction(data.block_end_click_cd_add) @@ -27,6 +29,10 @@ ADD_TRAIT(src, TRAIT_MOBILITY_NOUSE, ACTIVE_BLOCK_TRAIT) //probably should be something else at some point if(data.block_lock_sprinting) ADD_TRAIT(src, TRAIT_SPRINT_LOCKED, ACTIVE_BLOCK_TRAIT) + if(data.block_no_stamina_regeneration) + ADD_TRAIT(src, TRAIT_NO_STAMINA_REGENERATION, ACTIVE_BLOCK_TRAIT) + if(data.block_no_stambuffer_regeneration) + ADD_TRAIT(src, TRAIT_NO_STAMINA_BUFFER_REGENERATION, ACTIVE_BLOCK_TRAIT) add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/active_block, multiplicative_slowdown = data.block_slowdown) active_block_effect_start() return TRUE @@ -192,7 +198,7 @@ var/held_index = C.get_held_index_of_item(src) var/obj/item/bodypart/BP = C.hand_bodyparts[held_index] if(!BP?.body_zone) - return C.adjustStaminaLossBuffered(stamina_amount) //nah + return C.adjustStaminaLoss(stamina_amount) //nah var/zone = BP.body_zone var/stamina_to_zone = data.block_stamina_limb_ratio * stamina_amount var/stamina_to_chest = stamina_amount - stamina_to_zone @@ -200,9 +206,9 @@ stamina_to_chest -= stamina_buffered C.apply_damage(stamina_to_zone, STAMINA, zone) C.apply_damage(stamina_to_chest, STAMINA, BODY_ZONE_CHEST) - C.adjustStaminaLossBuffered(stamina_buffered) + C.adjustStaminaLoss(stamina_buffered) else - owner.adjustStaminaLossBuffered(stamina_amount) + owner.adjustStaminaLoss(stamina_amount) /obj/item/proc/on_active_block(mob/living/owner, atom/object, damage, damage_blocked, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return, override_direction) return diff --git a/code/modules/mob/living/living_active_parry.dm b/code/modules/mob/living/living_active_parry.dm index 10dece1ffc..7353add745 100644 --- a/code/modules/mob/living/living_active_parry.dm +++ b/code/modules/mob/living/living_active_parry.dm @@ -68,12 +68,13 @@ // can always implement it later, whatever. if((data.parry_respect_clickdelay && !CheckActionCooldown()) || ((parry_end_time_last + data.parry_cooldown) > world.time)) to_chat(src, "You are not ready to parry (again)!") - return + return FALSE // Point of no return, make sure everything is set. parrying = method if(method == ITEM_PARRY) active_parry_item = using_item - adjustStaminaLossBuffered(data.parry_stamina_cost) + if(!UseStaminaBuffer(data.parry_stamina_cost, TRUE)) + return FALSE parry_start_time = world.time successful_parries = list() addtimer(CALLBACK(src, .proc/end_parry_sequence), full_parry_duration) diff --git a/code/modules/mob/living/living_blocking_parrying.dm b/code/modules/mob/living/living_blocking_parrying.dm index 47dae8849d..08ef674b33 100644 --- a/code/modules/mob/living/living_blocking_parrying.dm +++ b/code/modules/mob/living/living_blocking_parrying.dm @@ -74,8 +74,12 @@ GLOBAL_LIST_EMPTY(block_parry_data) /// Ratio of stamina incurred by chest (so after [block_stamina_limb_ratio] runs) that is buffered. var/block_stamina_buffer_ratio = 1 - /// Stamina dealt directly via adjustStaminaLossBuffered() per SECOND of block. + /// Stamina dealt directly via UseStaminaBuffer() per SECOND of block. var/block_stamina_cost_per_second = 1.5 + /// Prevent stamina buffer regeneration while block? + var/block_no_stambuffer_regeneration = TRUE + /// Prevent stamina regeneration while block? + var/block_no_stamina_regeneration = FALSE /// Bitfield for attack types that we can block while down. This will work in any direction. var/block_resting_attack_types_anydir = ATTACK_TYPE_MELEE | ATTACK_TYPE_UNARMED | ATTACK_TYPE_TACKLE @@ -307,7 +311,7 @@ GLOBAL_LIST_EMPTY(block_parry_data) /mob/living/proc/handle_block_parry(seconds = 1) if(combat_flags & COMBAT_FLAG_ACTIVE_BLOCKING) var/datum/block_parry_data/data = return_block_parry_datum(active_block_item.block_parry_data) - adjustStaminaLossBuffered(data.block_stamina_cost_per_second * seconds) + UseStaminaBuffer(data.block_stamina_cost_per_second * seconds) /mob/living/on_item_dropped(obj/item/I) if(I == active_block_item) diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm index 5495d37297..5621fab9c1 100644 --- a/code/modules/mob/living/living_defines.dm +++ b/code/modules/mob/living/living_defines.dm @@ -53,6 +53,7 @@ var/hallucination = 0 //Directly affects how long a mob will hallucinate for + var/last_special = 0 //Used by the resist verb, likely used to prevent players from bypassing next_move by logging in/out. var/timeofdeath = 0 //Allows mobs to move through dense areas without restriction. For instance, in space or out of holder objects. @@ -148,9 +149,6 @@ var/combatmessagecooldown = 0 var/incomingstammult = 1 - var/bufferedstam = 0 - var/stambuffer = 20 - var/stambufferregentime //Sprint buffer--- var/sprint_buffer = 42 //Tiles @@ -159,3 +157,13 @@ var/sprint_buffer_regen_last = 0 //last world.time this was regen'd for math. var/sprint_stamina_cost = 0.70 //stamina loss per tile while insufficient sprint buffer. //---End + + // Stamina Buffer--- + /// Our stamina buffer + var/stamina_buffer + /// Stamina buffer regen modifier + var/stamina_buffer_regen_mod = 1 + /// Last time stamina buffer regen was done + var/stamina_buffer_regen_last = 0 + /// Last time we used stamina buffer + var/stamina_buffer_last_use = 0 diff --git a/code/modules/mob/living/living_mobility.dm b/code/modules/mob/living/living_mobility.dm index 92de711c27..8c6cf9d207 100644 --- a/code/modules/mob/living/living_mobility.dm +++ b/code/modules/mob/living/living_mobility.dm @@ -176,4 +176,6 @@ else remove_movespeed_modifier(/datum/movespeed_modifier/limbless) + update_movespeed() + return mobility_flags diff --git a/code/modules/mob/living/living_sprint.dm b/code/modules/mob/living/living_sprint.dm index dc0f6d2767..3ef67c9edd 100644 --- a/code/modules/mob/living/living_sprint.dm +++ b/code/modules/mob/living/living_sprint.dm @@ -29,6 +29,7 @@ if(combat_flags & COMBAT_FLAG_SPRINT_ACTIVE) return ENABLE_BITFIELD(combat_flags, COMBAT_FLAG_SPRINT_ACTIVE) + add_movespeed_modifier(/datum/movespeed_modifier/sprinting) if(update_icon) update_sprint_icon() @@ -36,6 +37,7 @@ if(!(combat_flags & COMBAT_FLAG_SPRINT_ACTIVE) || (combat_flags & COMBAT_FLAG_SPRINT_FORCED)) return DISABLE_BITFIELD(combat_flags, COMBAT_FLAG_SPRINT_ACTIVE) + remove_movespeed_modifier(/datum/movespeed_modifier/sprinting) if(update_icon) update_sprint_icon() diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index 66c2cd96c7..4c03e74d70 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -82,6 +82,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list( return new_msg /mob/living/say(message, bubble_type,var/list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null) + set waitfor = FALSE var/static/list/crit_allowed_modes = list(MODE_WHISPER = TRUE, MODE_CHANGELING = TRUE, MODE_ALIEN = TRUE) var/static/list/unconscious_allowed_modes = list(MODE_CHANGELING = TRUE, MODE_ALIEN = TRUE) var/talk_key = get_key(message) diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 1eb308af00..83df3ffba5 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -1132,10 +1132,6 @@ bellyup = 1 update_icons() -/mob/living/silicon/robot/adjustStaminaLossBuffered(amount, updating_health = 1) - if(istype(cell)) - cell.charge -= amount * 5 - /mob/living/silicon/robot/verb/viewmanifest() set category = "Robot Commands" set name = "View Crew Manifest" diff --git a/code/modules/mob/living/simple_animal/bot/ed209bot.dm b/code/modules/mob/living/simple_animal/bot/ed209bot.dm index 3f28fd6e01..8375d621d4 100644 --- a/code/modules/mob/living/simple_animal/bot/ed209bot.dm +++ b/code/modules/mob/living/simple_animal/bot/ed209bot.dm @@ -236,7 +236,7 @@ Auto Patrol[]"}, if(targets.len>0) var/mob/living/carbon/t = pick(targets) if((t.stat!=2) && (t.lying != 1) && (!t.handcuffed)) //we don't shoot people who are dead, cuffed or lying down. - shootAt(t) + INVOKE_ASYNC(src, .proc/shootAt, t) switch(mode) if(BOT_IDLE) // idle @@ -254,7 +254,7 @@ Auto Patrol[]"}, if(target) // make sure target exists if(Adjacent(target) && isturf(target.loc)) // if right next to perp - stun_attack(target) + INVOKE_ASYNC(src, .proc/stun_attack, target) mode = BOT_PREP_ARREST anchored = TRUE diff --git a/code/modules/mob/living/simple_animal/hostile/wizard.dm b/code/modules/mob/living/simple_animal/hostile/wizard.dm index b3523fc42c..59bd67e42a 100644 --- a/code/modules/mob/living/simple_animal/hostile/wizard.dm +++ b/code/modules/mob/living/simple_animal/hostile/wizard.dm @@ -62,6 +62,9 @@ /mob/living/simple_animal/hostile/wizard/handle_automated_action() . = ..() + INVOKE_ASYNC(src, .proc/AutomatedCast) + +/mob/living/simple_animal/hostile/wizard/proc/AutomatedCast() if(target && next_cast < world.time) if((get_dir(src,target) in list(SOUTH,EAST,WEST,NORTH)) && fireball.cast_check(0,src)) //Lined up for fireball src.setDir(get_dir(src,target)) diff --git a/code/modules/mob/living/simple_animal/parrot.dm b/code/modules/mob/living/simple_animal/parrot.dm index 3ca29b6746..1ff7e2f799 100644 --- a/code/modules/mob/living/simple_animal/parrot.dm +++ b/code/modules/mob/living/simple_animal/parrot.dm @@ -436,12 +436,7 @@ newspeak.Add(possible_phrase) speak = newspeak - //Search for item to steal - parrot_interest = search_for_item() - if(parrot_interest) - emote("me", EMOTE_VISIBLE, "looks in [parrot_interest]'s direction and takes flight.") - parrot_state = PARROT_SWOOP | PARROT_STEAL - icon_state = icon_living + INVOKE_ASYNC(src, .proc/attempt_item_theft) return //-----WANDERING - This is basically a 'I dont know what to do yet' state @@ -620,6 +615,14 @@ parrot_lastmove = src.loc return 0 +/mob/living/simple_animal/parrot/proc/attempt_item_theft() + //Search for item to steal + search_for_item() + if(parrot_interest) + emote("me", EMOTE_VISIBLE, "looks in [parrot_interest]'s direction and takes flight.") + parrot_state = PARROT_SWOOP | PARROT_STEAL + icon_state = icon_living + /mob/living/simple_animal/parrot/proc/search_for_item() var/item for(var/atom/movable/AM in view(src)) diff --git a/code/modules/mob/living/stamina_buffer.dm b/code/modules/mob/living/stamina_buffer.dm new file mode 100644 index 0000000000..a410df582b --- /dev/null +++ b/code/modules/mob/living/stamina_buffer.dm @@ -0,0 +1,56 @@ +/** + * Attempts to use an amount of stamina from our stamina buffer. + * Does not use anything if we don't have enough. + * + * Returns TRUE or FALSE based on if we have it. + */ +/mob/living/proc/UseStaminaBuffer(amount, warn = FALSE, considered_action = TRUE) + if(!(combat_flags & COMBAT_FLAG_STAMINA_BUFFER)) + return TRUE + if(stamina_buffer < amount) + var/stamina_health = getStaminaLoss() + if(stamina_health > STAMINA_NO_OVERDRAW_THRESHOLD) + if(warn) + to_chat(src, "You do not have enough action stamina to do that!") + return FALSE + adjustStaminaLoss(amount * CONFIG_GET(number/stamina_combat/overdraw_penalty_factor)) + else + stamina_buffer -= amount + if(considered_action) + stamina_buffer_last_use = world.time + UpdateStaminaBuffer() + return TRUE + +/** + * Updates our stamina buffer amount. + */ +/mob/living/proc/UpdateStaminaBuffer(updating_hud = TRUE) + var/time = world.time - stamina_buffer_regen_last + CONFIG_CACHE_ENTRY_AND_FETCH_VALUE(number/stamina_combat/buffer_max, buffer_max) + stamina_buffer_regen_last = world.time + if((stamina_buffer >= buffer_max) || !(combat_flags & COMBAT_FLAG_STAMINA_BUFFER)) + stamina_buffer = buffer_max + return + else if(!time || HAS_TRAIT(src, TRAIT_NO_STAMINA_BUFFER_REGENERATION)) + return + CONFIG_CACHE_ENTRY_AND_FETCH_VALUE(number/stamina_combat/out_of_combat_timer, out_of_combat_timer) + CONFIG_CACHE_ENTRY_AND_FETCH_VALUE(number/stamina_combat/base_regeneration, base_regeneration) + CONFIG_CACHE_ENTRY_AND_FETCH_VALUE(number/stamina_combat/combat_regeneration, combat_regeneration) + CONFIG_CACHE_ENTRY_AND_FETCH_VALUE(number/stamina_combat/percent_regeneration_out_of_combat, percent_regeneration_out_of_combat) + CONFIG_CACHE_ENTRY_AND_FETCH_VALUE(number/stamina_combat/post_action_penalty_delay, post_action_penalty_delay) + CONFIG_CACHE_ENTRY_AND_FETCH_VALUE(number/stamina_combat/post_action_penalty_factor, post_action_penalty_factor) + var/base_regen = (SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))? base_regeneration : combat_regeneration + var/time_since_last_action = world.time - stamina_buffer_last_use + var/action_penalty = ((time_since_last_action) < (post_action_penalty_delay * 10))? post_action_penalty_factor : 1 + var/out_of_combat_bonus = (time_since_last_action < (out_of_combat_timer * 10))? 0 : ((buffer_max * percent_regeneration_out_of_combat * 0.01)) + var/regen = ((base_regen * action_penalty) + out_of_combat_bonus) * time * 0.1 * stamina_buffer_regen_mod + stamina_buffer += min((buffer_max - stamina_buffer), regen) + if(updating_hud) + hud_used?.staminabuffer?.mark_dirty() + +/** + * Boosts our stamina buffer by this much. + */ +/mob/living/proc/RechargeStaminaBuffer(amount) + stamina_buffer += abs(amount) + UpdateStaminaBuffer() diff --git a/code/modules/movespeed/_movespeed_modifier.dm b/code/modules/movespeed/_movespeed_modifier.dm index 3bc4463531..9c8036bd55 100644 --- a/code/modules/movespeed/_movespeed_modifier.dm +++ b/code/modules/movespeed/_movespeed_modifier.dm @@ -38,6 +38,12 @@ Key procs /// Multiplicative slowdown var/multiplicative_slowdown = 0 + /// Next two variables depend on this: Should we do advanced calculations? + var/complex_calculation = FALSE + /// Absolute max tiles we can boost to + var/absolute_max_tiles_per_second + /// Max tiles per second we can boost + var/max_tiles_per_second_boost /// Movetypes this applies to var/movetypes = ALL @@ -53,6 +59,16 @@ Key procs if(!id) id = "[type]" //We turn the path into a string. +/** + * Returns new multiplicative movespeed after modification. + */ +/datum/movespeed_modifier/proc/apply_multiplicative(existing, mob/target) + if(!complex_calculation || (multiplicative_slowdown > 0)) // we aren't limiting how much things can slowdown.. yet. + return existing + multiplicative_slowdown + var/current_tiles = 10 / max(existing, world.tick_lag) + var/minimum_speed = 10 / min(current_tiles + max_tiles_per_second_boost, max(current_tiles, absolute_max_tiles_per_second)) + return max(minimum_speed, existing + multiplicative_slowdown) + GLOBAL_LIST_EMPTY(movespeed_modification_cache) /// Grabs a STATIC MODIFIER datum from cache. YOU MUST NEVER EDIT THESE DATUMS, OR IT WILL AFFECT ANYTHING ELSE USING IT TOO! @@ -171,13 +187,15 @@ GLOBAL_LIST_EMPTY(movespeed_modification_cache) /// Set or update the global movespeed config on a mob /mob/proc/update_config_movespeed() add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/mob_config_speedmod, multiplicative_slowdown = get_config_multiplicative_speed()) + add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/mob_config_speedmod_floating, multiplicative_slowdown = get_config_multiplicative_speed(TRUE)) /// Get the global config movespeed of a mob by type -/mob/proc/get_config_multiplicative_speed() - if(!islist(GLOB.mob_config_movespeed_type_lookup) || !GLOB.mob_config_movespeed_type_lookup[type]) +/mob/proc/get_config_multiplicative_speed(floating = FALSE) + var/list/read = floating? GLOB.mob_config_movespeed_type_lookup_floating : GLOB.mob_config_movespeed_type_lookup + if(!islist(read) || !read[type]) return 0 else - return GLOB.mob_config_movespeed_type_lookup[type] + return read[type] /// Go through the list of movespeed modifiers and calculate a final movespeed. ANY ADD/REMOVE DONE IN UPDATE_MOVESPEED MUST HAVE THE UPDATE ARGUMENT SET AS FALSE! /mob/proc/update_movespeed() @@ -198,7 +216,7 @@ GLOBAL_LIST_EMPTY(movespeed_modification_cache) conflict_tracker[conflict] = amt else continue - . += amt + . = M.apply_multiplicative(., src) var/old = cached_multiplicative_slowdown // CITAEDL EDIT - To make things a bit less jarring, when in situations where // your delay decreases, "give" the delay back to the client cached_multiplicative_slowdown = . @@ -220,6 +238,13 @@ GLOBAL_LIST_EMPTY(movespeed_modification_cache) var/datum/movespeed_modifier/M = movespeed_modification[id] . += M.multiplicative_slowdown +/** + * Gets the movespeed modifier datum of a modifier on a mob. Returns null if not found. + * DANGER: IT IS UP TO THE PERSON USING THIS TO MAKE SURE THE MODIFIER IS NOT MODIFIED IF IT HAPPENS TO BE GLOBAL/CACHED. + */ +/mob/proc/get_movespeed_modifier_datum(id) + return movespeed_modification[id] + /// Checks if a move speed modifier is valid and not missing any data /proc/movespeed_data_null_check(datum/movespeed_modifier/M) //Determines if a data list is not meaningful and should be discarded. . = TRUE diff --git a/code/modules/movespeed/modifiers/items.dm b/code/modules/movespeed/modifiers/items.dm index 94dc2a1553..a8510ecd86 100644 --- a/code/modules/movespeed/modifiers/items.dm +++ b/code/modules/movespeed/modifiers/items.dm @@ -1,12 +1,13 @@ /datum/movespeed_modifier/jetpack conflicts_with = MOVE_CONFLICT_JETPACK movetypes = FLOATING + multiplicative_slowdown = -1 /datum/movespeed_modifier/jetpack/cybernetic - multiplicative_slowdown = -0.5 + multiplicative_slowdown = -1.25 /datum/movespeed_modifier/jetpack/fullspeed - multiplicative_slowdown = -2 + multiplicative_slowdown = -1.5 /datum/movespeed_modifier/die_of_fate multiplicative_slowdown = 1 diff --git a/code/modules/movespeed/modifiers/mobs.dm b/code/modules/movespeed/modifiers/mobs.dm index d17767bb1f..f6cf84eb83 100644 --- a/code/modules/movespeed/modifiers/mobs.dm +++ b/code/modules/movespeed/modifiers/mobs.dm @@ -111,6 +111,12 @@ /datum/movespeed_modifier/mob_config_speedmod variable = TRUE + blacklisted_movetypes = FLOATING + flags = IGNORE_NOSLOW + +/datum/movespeed_modifier/mob_config_speedmod_floating + variable = TRUE + movetypes = FLOATING flags = IGNORE_NOSLOW /datum/movespeed_modifier/liver_cirrhosis @@ -120,3 +126,30 @@ /datum/movespeed_modifier/active_block variable = TRUE flags = IGNORE_NOSLOW + +/datum/movespeed_modifier/sprinting + flags = IGNORE_NOSLOW + blacklisted_movetypes = FLOATING + priority = 100 + +/// for speed reasons this is sorta copypasty. +/datum/movespeed_modifier/sprinting/apply_multiplicative(existing, mob/target) + . = existing + if(target.m_intent != MOVE_INTENT_RUN) + return + if(isliving(target)) + var/mob/living/L = target + if(!(L.mobility_flags & MOBILITY_STAND)) + return + var/static/datum/config_entry/number/movedelay/sprint_max_tiles_increase/SMTI + if(!SMTI) + SMTI = CONFIG_GET_ENTRY(number/movedelay/sprint_max_tiles_increase) + var/static/datum/config_entry/number/movedelay/sprint_speed_increase/SSI + if(!SSI) + SSI = CONFIG_GET_ENTRY(number/movedelay/sprint_speed_increase) + var/static/datum/config_entry/number/movedelay/sprint_absolute_max_tiles/SAMT + if(!SAMT) + SAMT = CONFIG_GET_ENTRY(number/movedelay/sprint_absolute_max_tiles) + var/current_tiles = 10 / max(existing, world.tick_lag) + var/minimum_speed = 10 / min(max(SAMT.config_entry_value, current_tiles), current_tiles + SMTI.config_entry_value) + . = min(., max(minimum_speed, existing - SSI.config_entry_value)) diff --git a/code/modules/plumbing/plumbers/autohydro.dm b/code/modules/plumbing/plumbers/autohydro.dm index 20b8e6012a..9c358d8d6e 100644 --- a/code/modules/plumbing/plumbers/autohydro.dm +++ b/code/modules/plumbing/plumbers/autohydro.dm @@ -30,20 +30,8 @@ . = ..() START_PROCESSING(SSobj, src) create_reagents(100 , AMOUNT_VISIBLE) - AddComponent(/datum/component/plumbing/simple_demand) - -/obj/machinery/hydroponics/constructable/automagic/ComponentInitialize() - . = ..() - AddComponent(/datum/component/simple_rotation, ROTATION_ALTCLICK | ROTATION_CLOCKWISE | ROTATION_COUNTERCLOCKWISE | ROTATION_VERBS, null, CALLBACK(src, .proc/can_be_rotated)) - - -/obj/machinery/hydroponics/constructable/proc/can_be_rotated(mob/user, rotation_type) - return !anchored /obj/machinery/hydroponics/constructable/automagic/process() - if(reagents) - reagents.add_reagent(reagents) - reagents.clear_reagents() if(dead) dead = 0 qdel(myseed) diff --git a/code/modules/power/rtg.dm b/code/modules/power/rtg.dm index b558031fab..c19927e84c 100644 --- a/code/modules/power/rtg.dm +++ b/code/modules/power/rtg.dm @@ -53,6 +53,33 @@ power_gen = 1250 // 2500 on T1, 10000 on T4. circuit = /obj/item/circuitboard/machine/rtg/advanced +/obj/machinery/power/rtg/advanced/fullupgrade //fully ugpraded stock parts + desc = "An advanced RTG capable of moderating isotope decay, increasing power output but reducing lifetime. It uses plasma-fueled radiation collectors to increase output even further. This model is fully upgraded with the latest tech available in this quadrant." + +/obj/machinery/power/rtg/advanced/fullupgrade/Initialize() + . = ..() + //This looks terrifying. And apparently instancing vars and modifying the amount variable causes runtime errors. Guess we're sticking to copy pasta, thanks, byond. + component_parts = list() + component_parts += new /obj/item/circuitboard/machine/rtg/advanced(null) + component_parts += new /obj/item/stack/sheet/mineral/uranium(null) + component_parts += new /obj/item/stack/sheet/mineral/uranium(null) + component_parts += new /obj/item/stack/sheet/mineral/uranium(null) + component_parts += new /obj/item/stack/sheet/mineral/uranium(null) + component_parts += new /obj/item/stack/sheet/mineral/uranium(null) + component_parts += new /obj/item/stack/sheet/mineral/uranium(null) + component_parts += new /obj/item/stack/sheet/mineral/uranium(null) + component_parts += new /obj/item/stack/sheet/mineral/uranium(null) + component_parts += new /obj/item/stack/sheet/mineral/uranium(null) + component_parts += new /obj/item/stack/sheet/mineral/uranium(null) + component_parts += new /obj/item/stack/sheet/mineral/plasma(null) + component_parts += new /obj/item/stack/sheet/mineral/plasma(null) + component_parts += new /obj/item/stack/sheet/mineral/plasma(null) + component_parts += new /obj/item/stack/sheet/mineral/plasma(null) + component_parts += new /obj/item/stack/sheet/mineral/plasma(null) + component_parts += new /obj/item/stock_parts/capacitor/quadratic(null) + component_parts += new /obj/item/stock_parts/micro_laser/quadultra(null) + RefreshParts() + // Void Core, power source for Abductor ships and bases. // Provides a lot of power, but tends to explode when mistreated. diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm index e3fdbd3654..f385b640aa 100644 --- a/code/modules/power/supermatter/supermatter.dm +++ b/code/modules/power/supermatter/supermatter.dm @@ -928,8 +928,15 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) var/mob/living/user = AM if(user.status_flags & GODMODE) return - message_admins("[src] has consumed [key_name_admin(user)] [ADMIN_JMP(src)].") - investigate_log("has consumed [key_name(user)].", INVESTIGATE_SUPERMATTER) + var/add + if(user.mind?.assigned_role == "Clown") + var/denergy = rand(-1000, 1000) + var/ddamage = rand(-150, clamp(150, 0, (explosion_point - damage) + 150)) + power += denergy + damage += ddamage + add = ", adding [denergy] energy and [ddamage] damage to the crystal" + message_admins("[src] has consumed [key_name_admin(user)] [ADMIN_JMP(src)][add].") + investigate_log("has consumed [key_name(user)][add].", INVESTIGATE_SUPERMATTER) user.dust(force = TRUE) if(power_changes) matter_power += 200 diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 1369115b0d..1c3a0d230f 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -154,8 +154,8 @@ shake_camera(user, recoil + 1, recoil) if(stam_cost) //CIT CHANGE - makes gun recoil cause staminaloss - var/safe_cost = clamp(stam_cost, 0, STAMINA_NEAR_CRIT - user.getStaminaLoss())*(firing && burst_size >= 2 ? 1/burst_size : 1) - user.adjustStaminaLossBuffered(safe_cost) //CIT CHANGE - ditto + var/safe_cost = clamp(stam_cost, 0, user.stamina_buffer)*(firing && burst_size >= 2 ? 1/burst_size : 1) + user.UseStaminaBuffer(safe_cost) if(suppressed) playsound(user, fire_sound, 10, 1) @@ -590,6 +590,9 @@ update_icon() /obj/item/gun/proc/getinaccuracy(mob/living/user, bonus_spread, stamloss) + return 0 // Replacement TBD: Exponential curved aim instability system. + +/* if(inaccuracy_modifier == 0) return bonus_spread var/base_inaccuracy = weapon_weight * 25 * inaccuracy_modifier @@ -612,6 +615,7 @@ if(mult < 0) //accurate weapons should provide a proper bonus with negative inaccuracy. the opposite is true too. mult *= 1/inaccuracy_modifier return max(bonus_spread + (base_inaccuracy * mult), 0) //no negative spread. +*/ /obj/item/gun/proc/getstamcost(mob/living/carbon/user) . = recoil diff --git a/code/modules/projectiles/guns/ballistic/shotgun.dm b/code/modules/projectiles/guns/ballistic/shotgun.dm index ecf6e538b8..7b3ac36ef6 100644 --- a/code/modules/projectiles/guns/ballistic/shotgun.dm +++ b/code/modules/projectiles/guns/ballistic/shotgun.dm @@ -44,10 +44,9 @@ if(HAS_TRAIT(user, TRAIT_FAST_PUMP)) recentpump = world.time + 2 else + if(!user.UseStaminaBuffer(2, warn = TRUE)) + return recentpump = world.time + 10 - if(istype(user))//CIT CHANGE - makes pumping shotguns cost a lil bit of stamina. - user.adjustStaminaLossBuffered(2) //CIT CHANGE - DITTO. make this scale inversely to the strength stat when stats/skills are added - return /obj/item/gun/ballistic/shotgun/blow_up(mob/user) . = 0 diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm index 19ca42022d..cd91a7670d 100644 --- a/code/modules/projectiles/guns/energy/special.dm +++ b/code/modules/projectiles/guns/energy/special.dm @@ -233,7 +233,7 @@ p_blue.link_portal(p_orange) /obj/item/gun/energy/wormhole_projector/proc/create_portal(obj/item/projectile/beam/wormhole/W, turf/target) - var/obj/effect/portal/P = new /obj/effect/portal(target, src, 300, null, FALSE, null, atmos_link) + var/obj/effect/portal/P = new /obj/effect/portal(target, 300, null, FALSE, null, atmos_link) if(istype(W, /obj/item/projectile/beam/wormhole/orange)) qdel(p_orange) p_orange = P diff --git a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm index c2bb678904..86f6460ff7 100644 --- a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm @@ -2283,7 +2283,7 @@ All effects don't start immediately, but rather get worse over time; the rate is boozepwr = 50 /datum/reagent/consumable/ethanol/species_drink/on_mob_life(mob/living/carbon/C) - if(C.dna.species && C.dna.species.species_type == species_required) //species have a species_type variable that refers to one of the drinks + if(C.dna.species && C.dna.species.species_category == species_required) //species have a species_category variable that refers to one of the drinks quality = RACE_DRINK else C.adjust_disgust(disgust) diff --git a/code/modules/research/designs/biogenerator_designs.dm b/code/modules/research/designs/biogenerator_designs.dm index bdaf39732f..ed12d4945e 100644 --- a/code/modules/research/designs/biogenerator_designs.dm +++ b/code/modules/research/designs/biogenerator_designs.dm @@ -181,6 +181,14 @@ build_path = /obj/item/storage/belt/janitor category = list("initial","Organic Materials") +/datum/design/plantbelt + name = "Botanical Belt" + id = "plantbelt" + build_type = BIOGENERATOR + materials = list(/datum/material/biomass= 300) + build_path = /obj/item/storage/belt/plant + category = list("initial","Organic Materials") + /datum/design/s_holster name = "Shoulder Holster" id = "s_holster" diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm index 7013412e6d..b178f936b7 100644 --- a/code/modules/research/designs/medical_designs.dm +++ b/code/modules/research/designs/medical_designs.dm @@ -32,7 +32,7 @@ materials = list(/datum/material/glass = 3000, /datum/material/plasma = 3000, /datum/material/diamond = 250, /datum/material/bluespace = 250) build_path = /obj/item/reagent_containers/glass/beaker/bluespace category = list("Medical Designs") - departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE + departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_SERVICE /datum/design/noreactbeaker name = "Cryostasis Beaker" @@ -973,6 +973,10 @@ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL +///////////////////////////////////////// +//////////// Plumbing ////////// +///////////////////////////////////////// + /datum/design/acclimator name = "Plumbing Acclimator" desc = "A heating and cooling device for pipes!" @@ -1126,3 +1130,14 @@ build_path = /obj/item/construction/plumbing category = list("Misc","Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE + +/datum/design/rplunger + name = "Reinforced Plunger" + desc = "A plunger designed for heavy duty clogs." + id = "rplunger" + build_type = PROTOLATHE + materials = list(/datum/material/plasma = 1000, /datum/material/iron = 1000, /datum/material/glass = 1000) + construction_time = 15 + build_path = /obj/item/plunger/reinforced + category = list ("Misc","Medical Designs") + departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_CARGO diff --git a/code/modules/research/techweb/nodes/medical_nodes.dm b/code/modules/research/techweb/nodes/medical_nodes.dm index 150e420c09..7b9b2f2923 100644 --- a/code/modules/research/techweb/nodes/medical_nodes.dm +++ b/code/modules/research/techweb/nodes/medical_nodes.dm @@ -38,7 +38,7 @@ display_name = "Advanced Plumbing Technology" description = "Plumbing RCD." prereq_ids = list("plumbing", "adv_engi") - design_ids = list("plumb_rcd", "autohydrotray") + design_ids = list("plumb_rcd", "autohydrotray", "rplunger") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) //////////////////////Cybernetics///////////////////// diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm index e758a43589..3229304c13 100644 --- a/code/modules/unit_tests/_unit_tests.dm +++ b/code/modules/unit_tests/_unit_tests.dm @@ -2,13 +2,41 @@ //Keep this sorted alphabetically #ifdef UNIT_TESTS +/// Asserts that a condition is true +/// If the condition is not true, fails the test +#define TEST_ASSERT(assertion, reason) if (!(assertion)) { return Fail("Assertion failed: [reason || "No reason"]") } + +/// Asserts that the two parameters passed are equal, fails otherwise +/// Optionally allows an additional message in the case of a failure +#define TEST_ASSERT_EQUAL(a, b, message) if ((a) != (b)) { return Fail("Expected [isnull(a) ? "null" : a] to be equal to [isnull(b) ? "null" : b].[message ? " [message]" : ""]") } + #include "anchored_mobs.dm" +#include "bespoke_id.dm" +// #include "binary_insert.dm" +// #include "card_mismatch.dm" shame we don't have this! +#include "chain_pull_through_space.dm" #include "character_saving.dm" #include "component_tests.dm" +// #include "confusion.dm" +// #include "keybinding_init.dm" +#include "machine_disassembly.dm" +#include "medical_wounds.dm" +// #include "metabolizing.dm" +// #include "outfit_sanity.dm" +// #include "plantgrowth_tests.dm" +// #include "quick_swap_sanity.dm" - we don't have quick swap yet #include "reagent_id_typos.dm" #include "reagent_recipe_collisions.dm" +#include "resist.dm" +// #include "say.dm" //no saymods, someone update saycode please. +// #include "siunit.dm" #include "spawn_humans.dm" +// #include "species_whitelists.dm" #include "subsystem_init.dm" +#include "surgeries.dm" #include "timer_sanity.dm" #include "unit_test.dm" + +#undef TEST_ASSERT +#undef TEST_ASSERT_EQUAL #endif diff --git a/code/modules/unit_tests/anchored_mobs.dm b/code/modules/unit_tests/anchored_mobs.dm index 5324179bb7..103b97e7a9 100644 --- a/code/modules/unit_tests/anchored_mobs.dm +++ b/code/modules/unit_tests/anchored_mobs.dm @@ -6,4 +6,4 @@ L += "[i]" if(!L.len) return //passed! - Fail("The following mobs are defined as anchored. This is incompatible with the new move force/resist system and needs to be revised.: [L.Join(" ")]") \ No newline at end of file + Fail("The following mobs are defined as anchored. This is incompatible with the new move force/resist system and needs to be revised.: [L.Join(" ")]") diff --git a/code/modules/unit_tests/bespoke_id.dm b/code/modules/unit_tests/bespoke_id.dm new file mode 100644 index 0000000000..06676c626c --- /dev/null +++ b/code/modules/unit_tests/bespoke_id.dm @@ -0,0 +1,8 @@ +/datum/unit_test/bespoke_id/Run() + var/datum/element/base = /datum/element + var/base_index = initial(base.id_arg_index) + + for(var/i in subtypesof(/datum/element)) + var/datum/element/faketype = i + if((initial(faketype.element_flags) & ELEMENT_BESPOKE) && initial(faketype.id_arg_index) == base_index) + Fail("A bespoke element was not configured with a proper id_arg_index: [faketype]") diff --git a/code/modules/unit_tests/binary_insert.dm b/code/modules/unit_tests/binary_insert.dm new file mode 100644 index 0000000000..ac7f58208e --- /dev/null +++ b/code/modules/unit_tests/binary_insert.dm @@ -0,0 +1,26 @@ +/// A test to ensure the sanity of BINARY_INSERT +/datum/unit_test/binary_insert/Run() + var/list/datum/binary_insert_node/nodes = list() + + var/datum/binary_insert_node/node_a = new /datum/binary_insert_node(10) + BINARY_INSERT(node_a, nodes, /datum/binary_insert_node, node_a, x, COMPARE_KEY) + TEST_ASSERT_EQUAL(nodes.len, 1, "List should have one node") + + var/datum/binary_insert_node/node_b = new /datum/binary_insert_node(5) + BINARY_INSERT(node_b, nodes, /datum/binary_insert_node, node_b, x, COMPARE_KEY) + TEST_ASSERT_EQUAL(nodes.len, 2, "List should have two nodes") + TEST_ASSERT_EQUAL(nodes[1].x, 5, "The first node should be the one with 5") + TEST_ASSERT_EQUAL(nodes[2].x, 10, "The second node should be the one with 10") + + var/datum/binary_insert_node/node_c = new /datum/binary_insert_node(15) + BINARY_INSERT(node_c, nodes, /datum/binary_insert_node, node_c, x, COMPARE_KEY) + TEST_ASSERT_EQUAL(nodes.len, 3, "List should have three nodes") + TEST_ASSERT_EQUAL(nodes[1].x, 5, "The first node should be the one with 5") + TEST_ASSERT_EQUAL(nodes[2].x, 10, "The second node should be the one with 10") + TEST_ASSERT_EQUAL(nodes[3].x, 15, "The third node should be the one with 15") + +/datum/binary_insert_node + var/x + +/datum/binary_insert_node/New(_x) + x = _x diff --git a/code/modules/unit_tests/chain_pull_through_space.dm b/code/modules/unit_tests/chain_pull_through_space.dm new file mode 100644 index 0000000000..ffdd1bf7c9 --- /dev/null +++ b/code/modules/unit_tests/chain_pull_through_space.dm @@ -0,0 +1,62 @@ +/datum/unit_test/chain_pull_through_space + var/turf/open/space/space_tile + var/turf/claimed_tile + var/mob/living/carbon/human/alice + var/mob/living/carbon/human/bob + var/mob/living/carbon/human/charlie + +/datum/unit_test/chain_pull_through_space/New() + ..() + + // Create a space tile that goes to another z-level + claimed_tile = run_loc_bottom_left + + space_tile = new(locate(run_loc_bottom_left.x, run_loc_bottom_left.y, run_loc_bottom_left.z)) + space_tile.destination_x = 100 + space_tile.destination_y = 100 + space_tile.destination_z = 5 + + // Create our list of humans, all adjacent to one another + alice = new(locate(run_loc_bottom_left.x + 2, run_loc_bottom_left.y, run_loc_bottom_left.z)) + alice.name = "Alice" + + bob = new(locate(run_loc_bottom_left.x + 3, run_loc_bottom_left.y, run_loc_bottom_left.z)) + bob.name = "Bob" + + charlie = new(locate(run_loc_bottom_left.x + 4, run_loc_bottom_left.y, run_loc_bottom_left.z)) + charlie.name = "Charlie" + +/datum/unit_test/chain_pull_through_space/Destroy() + space_tile.copyTurf(claimed_tile) + qdel(alice) + qdel(bob) + qdel(charlie) + return ..() + +/datum/unit_test/chain_pull_through_space/Run() + // Alice pulls Bob, who pulls Charlie + // Normally, when Alice moves forward, the rest follow + alice.start_pulling(bob) + bob.start_pulling(charlie) + + // Walk normally to the left, make sure we're still a chain + alice.Move(locate(run_loc_bottom_left.x + 1, run_loc_bottom_left.y, run_loc_bottom_left.z)) + if (bob.x != run_loc_bottom_left.x + 2) + return Fail("During normal move, Bob was not at the correct x ([bob.x])") + if (charlie.x != run_loc_bottom_left.x + 3) + return Fail("During normal move, Charlie was not at the correct x ([charlie.x])") + + // We're going through the space turf now that should teleport us + alice.Move(run_loc_bottom_left) + if (alice.z != space_tile.destination_z) + return Fail("Alice did not teleport to the destination z-level. Current location: ([alice.x], [alice.y], [alice.z])") + + if (bob.z != space_tile.destination_z) + return Fail("Bob did not teleport to the destination z-level. Current location: ([bob.x], [bob.y], [bob.z])") + if (!bob.Adjacent(alice)) + return Fail("Bob is not adjacent to Alice. Bob is at [bob.x], Alice is at [alice.x]") + + if (charlie.z != space_tile.destination_z) + return Fail("Charlie did not teleport to the destination z-level. Current location: ([charlie.x], [charlie.y], [charlie.z])") + if (!charlie.Adjacent(bob)) + return Fail("Charlie is not adjacent to Bob. Charlie is at [charlie.x], Bob is at [bob.x]") diff --git a/code/modules/unit_tests/component_tests.dm b/code/modules/unit_tests/component_tests.dm index 409d7f4322..0099d7508c 100644 --- a/code/modules/unit_tests/component_tests.dm +++ b/code/modules/unit_tests/component_tests.dm @@ -9,4 +9,4 @@ if(dupe_type && !ispath(dupe_type)) bad_dts += t if(length(bad_dms) || length(bad_dts)) - Fail("Components with invalid dupe modes: ([bad_dms.Join(",")]) ||| Components with invalid dupe types: ([bad_dts.Join(",")])") \ No newline at end of file + Fail("Components with invalid dupe modes: ([bad_dms.Join(",")]) ||| Components with invalid dupe types: ([bad_dts.Join(",")])") diff --git a/code/modules/unit_tests/machine_disassembly.dm b/code/modules/unit_tests/machine_disassembly.dm new file mode 100644 index 0000000000..bcc769bcf2 --- /dev/null +++ b/code/modules/unit_tests/machine_disassembly.dm @@ -0,0 +1,13 @@ +/// Ensures that when disassembling a machine, all the parts are given back +/datum/unit_test/machine_disassembly/Run() + var/obj/machinery/freezer = allocate(/obj/machinery/atmospherics/components/unary/thermomachine/freezer) + + var/turf/freezer_location = freezer.loc + freezer_location.ChangeTurf(/turf/open/floor/plasteel) + freezer.deconstruct() + + // Check that the components are created + TEST_ASSERT(locate(/obj/item/stock_parts/micro_laser) in freezer_location, "Couldn't find micro-laser when disassembling freezer") + + // Check that the circuit board itself is created + TEST_ASSERT(locate(/obj/item/circuitboard/machine/thermomachine/freezer) in freezer_location, "Couldn't find the circuit board when disassembling freezer") diff --git a/code/modules/unit_tests/medical_wounds.dm b/code/modules/unit_tests/medical_wounds.dm new file mode 100644 index 0000000000..75c08931f1 --- /dev/null +++ b/code/modules/unit_tests/medical_wounds.dm @@ -0,0 +1,87 @@ +/// This test is used to make sure a flesh-and-bone base human can suffer all the types of wounds, and that suffering more severe wounds removes and replaces the lesser wound. Also tests that [/mob/living/carbon/proc/fully_heal] removes all wounds +/datum/unit_test/test_human_base/Run() + var/mob/living/carbon/human/victim = allocate(/mob/living/carbon/human) + + /// the limbs have no wound resistance like the chest and head do, so let's go with the r_arm + var/obj/item/bodypart/tested_part = victim.get_bodypart(BODY_ZONE_R_ARM) + /// In order of the wound types we're trying to inflict, what sharpness do we need to deal them? + var/list/sharps = list(SHARP_NONE, SHARP_EDGED, SHARP_POINTY, SHARP_NONE) + /// Since burn wounds need burn damage, duh + var/list/dam_types = list(BRUTE, BRUTE, BRUTE, BURN) + + var/i = 1 + var/list/iter_test_wound_list + + for(iter_test_wound_list in list(list(/datum/wound/blunt/moderate, /datum/wound/blunt/severe, /datum/wound/blunt/critical),\ + list(/datum/wound/slash/moderate, /datum/wound/slash/severe, /datum/wound/slash/critical),\ + list(/datum/wound/pierce/moderate, /datum/wound/pierce/severe, /datum/wound/pierce/critical),\ + list(/datum/wound/burn/moderate, /datum/wound/burn/severe, /datum/wound/burn/critical))) + + TEST_ASSERT_EQUAL(length(victim.all_wounds), 0, "Patient is somehow wounded before test") + var/datum/wound/iter_test_wound + var/threshold_penalty = 0 + + for(iter_test_wound in iter_test_wound_list) + var/threshold = initial(iter_test_wound.threshold_minimum) - threshold_penalty // just enough to guarantee the next tier of wound, given the existing wound threshold penalty + if(dam_types[i] == BRUTE) + tested_part.receive_damage(WOUND_MINIMUM_DAMAGE, 0, wound_bonus = threshold, sharpness=sharps[i]) + else if(dam_types[i] == BURN) + tested_part.receive_damage(0, WOUND_MINIMUM_DAMAGE, wound_bonus = threshold, sharpness=sharps[i]) + + TEST_ASSERT(length(victim.all_wounds), "Patient has no wounds when one wound is expected. Severity: [initial(iter_test_wound.severity)]") + TEST_ASSERT_EQUAL(length(victim.all_wounds), 1, "Patient has more than one wound when only one is expected. Severity: [initial(iter_test_wound.severity)]") + var/datum/wound/actual_wound = victim.all_wounds[1] + TEST_ASSERT_EQUAL(actual_wound.type, iter_test_wound, "Patient has wound of incorrect severity. Expected: [initial(iter_test_wound.name)] Got: [actual_wound]") + threshold_penalty = actual_wound.threshold_penalty + i++ + victim.fully_heal(TRUE) // should clear all wounds between types + + +/// This test is used for making sure species with bones but no flesh (skeletons, plasmamen) can only suffer BONE_WOUNDS, and nothing tagged with FLESH_WOUND (it's possible to require both) +/datum/unit_test/test_human_bone/Run() + var/mob/living/carbon/human/victim = allocate(/mob/living/carbon/human) + + /// the limbs have no wound resistance like the chest and head do, so let's go with the r_arm + var/obj/item/bodypart/tested_part = victim.get_bodypart(BODY_ZONE_R_ARM) + /// In order of the wound types we're trying to inflict, what sharpness do we need to deal them? + var/list/sharps = list(SHARP_NONE, SHARP_EDGED, SHARP_POINTY, SHARP_NONE) + /// Since burn wounds need burn damage, duh + var/list/dam_types = list(BRUTE, BRUTE, BRUTE, BURN) + + var/i = 1 + var/list/iter_test_wound_list + victim.dna.species.species_traits &= HAS_FLESH // take away the base human's flesh (ouchie!) ((not actually ouchie, this just affects their wounds and dismemberment handling)) + + for(iter_test_wound_list in list(list(/datum/wound/blunt/moderate, /datum/wound/blunt/severe, /datum/wound/blunt/critical),\ + list(/datum/wound/slash/moderate, /datum/wound/slash/severe, /datum/wound/slash/critical),\ + list(/datum/wound/pierce/moderate, /datum/wound/pierce/severe, /datum/wound/pierce/critical),\ + list(/datum/wound/burn/moderate, /datum/wound/burn/severe, /datum/wound/burn/critical))) + + TEST_ASSERT_EQUAL(length(victim.all_wounds), 0, "Patient is somehow wounded before test") + var/datum/wound/iter_test_wound + var/threshold_penalty = 0 + + for(iter_test_wound in iter_test_wound_list) + var/threshold = initial(iter_test_wound.threshold_minimum) - threshold_penalty // just enough to guarantee the next tier of wound, given the existing wound threshold penalty + if(dam_types[i] == BRUTE) + tested_part.receive_damage(WOUND_MINIMUM_DAMAGE, 0, wound_bonus = threshold, sharpness=sharps[i]) + else if(dam_types[i] == BURN) + tested_part.receive_damage(0, WOUND_MINIMUM_DAMAGE, wound_bonus = threshold, sharpness=sharps[i]) + + // so if we just tried to deal a flesh wound, make sure we didn't actually suffer it. We may have suffered a bone wound instead, but we just want to make sure we don't have a flesh wound + if(initial(iter_test_wound.wound_flags) & FLESH_WOUND) + if(!length(victim.all_wounds)) // not having a wound is good news + continue + else // we have to check that it's actually a bone wound and not the intended wound type + TEST_ASSERT_EQUAL(length(victim.all_wounds), 1, "Patient has more than one wound when only one is expected. Severity: [initial(iter_test_wound.severity)]") + var/datum/wound/actual_wound = victim.all_wounds[1] + TEST_ASSERT((actual_wound.wound_flags & ~FLESH_WOUND), "Patient has flesh wound despite no HAS_FLESH flag, expected either no wound or bone wound. Offending wound: [actual_wound]") + threshold_penalty = actual_wound.threshold_penalty + else // otherwise if it's a bone wound, check that we have it per usual + TEST_ASSERT(length(victim.all_wounds), "Patient has no wounds when one wound is expected. Severity: [initial(iter_test_wound.severity)]") + TEST_ASSERT_EQUAL(length(victim.all_wounds), 1, "Patient has more than one wound when only one is expected. Severity: [initial(iter_test_wound.severity)]") + var/datum/wound/actual_wound = victim.all_wounds[1] + TEST_ASSERT_EQUAL(actual_wound.type, iter_test_wound, "Patient has wound of incorrect severity. Expected: [initial(iter_test_wound.name)] Got: [actual_wound]") + threshold_penalty = actual_wound.threshold_penalty + i++ + victim.fully_heal(TRUE) // should clear all wounds between types diff --git a/code/modules/unit_tests/metabolizing.dm b/code/modules/unit_tests/metabolizing.dm new file mode 100644 index 0000000000..895762c0ec --- /dev/null +++ b/code/modules/unit_tests/metabolizing.dm @@ -0,0 +1,19 @@ +/datum/unit_test/metabolization/Run() + // Pause natural mob life so it can be handled entirely by the test + SSmobs.pause() + + var/mob/living/carbon/human/human = allocate(/mob/living/carbon/human) + var/mob/living/carbon/monkey/monkey = allocate(/mob/living/carbon/monkey) + + for (var/reagent_type in subtypesof(/datum/reagent)) + test_reagent(human, reagent_type) + test_reagent(monkey, reagent_type) + +/datum/unit_test/metabolization/proc/test_reagent(mob/living/carbon/C, reagent_type) + C.reagents.add_reagent(reagent_type, 10) + C.reagents.metabolize(C, can_overdose = TRUE) + C.reagents.clear_reagents() + +/datum/unit_test/metabolization/Destroy() + SSmobs.ignite() + return ..() diff --git a/code/modules/unit_tests/outfit_sanity.dm b/code/modules/unit_tests/outfit_sanity.dm new file mode 100644 index 0000000000..235820f9e9 --- /dev/null +++ b/code/modules/unit_tests/outfit_sanity.dm @@ -0,0 +1,50 @@ +#define CHECK_OUTFIT_SLOT(outfit_key, slot_name) if (outfit.##outfit_key) { \ + H.equip_to_slot_or_del(new outfit.##outfit_key(H), ##slot_name, TRUE); \ + /* We don't check the result of equip_to_slot_or_del because it returns false for random jumpsuits, as they delete themselves on init */ \ + if (!H.get_item_by_slot(##slot_name)) { \ + Fail("[outfit.name]'s [#outfit_key] is invalid!"); \ + } \ +} + +/datum/unit_test/outfit_sanity/Run() + var/mob/living/carbon/human/H = allocate(/mob/living/carbon/human) + + for (var/outfit_type in subtypesof(/datum/outfit)) + // Only make one human and keep undressing it because it's much faster + for (var/obj/item/I in H.get_equipped_items(include_pockets = TRUE)) + qdel(I) + + var/datum/outfit/outfit = new outfit_type + outfit.pre_equip(H, TRUE) + + CHECK_OUTFIT_SLOT(uniform, ITEM_SLOT_ICLOTHING) + CHECK_OUTFIT_SLOT(suit, ITEM_SLOT_OCLOTHING) + CHECK_OUTFIT_SLOT(back, ITEM_SLOT_BACK) + CHECK_OUTFIT_SLOT(belt, ITEM_SLOT_BELT) + CHECK_OUTFIT_SLOT(gloves, ITEM_SLOT_GLOVES) + CHECK_OUTFIT_SLOT(shoes, ITEM_SLOT_FEET) + CHECK_OUTFIT_SLOT(head, ITEM_SLOT_HEAD) + CHECK_OUTFIT_SLOT(mask, ITEM_SLOT_MASK) + CHECK_OUTFIT_SLOT(neck, ITEM_SLOT_NECK) + CHECK_OUTFIT_SLOT(ears, ITEM_SLOT_EARS) + CHECK_OUTFIT_SLOT(glasses, ITEM_SLOT_EYES) + CHECK_OUTFIT_SLOT(id, ITEM_SLOT_ID) + CHECK_OUTFIT_SLOT(suit_store, ITEM_SLOT_SUITSTORE) + CHECK_OUTFIT_SLOT(l_pocket, ITEM_SLOT_POCKET) + CHECK_OUTFIT_SLOT(r_pocket, ITEM_SLOT_POCKET) + + if (outfit.backpack_contents || outfit.box) + var/list/backpack_contents = outfit.backpack_contents?.Copy() + if (outfit.box) + if (!backpack_contents) + backpack_contents = list() + backpack_contents.Insert(1, outfit.box) + backpack_contents[outfit.box] = 1 + + for (var/path in backpack_contents) + var/number = backpack_contents[path] || 1 + for (var/_ in 1 to number) + if (!H.equip_to_slot_or_del(new path(H), ITEM_SLOT_BACKPACK, TRUE)) + Fail("[outfit.name]'s backpack_contents are invalid! Couldn't add [path] to backpack.") + +#undef CHECK_OUTFIT_SLOT diff --git a/code/modules/unit_tests/plantgrowth_tests.dm b/code/modules/unit_tests/plantgrowth_tests.dm new file mode 100644 index 0000000000..6b40236860 --- /dev/null +++ b/code/modules/unit_tests/plantgrowth_tests.dm @@ -0,0 +1,27 @@ + +// Checks plants for broken tray icons. Use Advanced Proc Call to activate. +// Maybe some day it would be used as unit test. +// -------- IT IS NOW! +/datum/unit_test/plantgrowth/Run() + var/list/states = icon_states('icons/obj/hydroponics/growing.dmi') + states |= icon_states('icons/obj/hydroponics/growing_fruits.dmi') + states |= icon_states('icons/obj/hydroponics/growing_flowers.dmi') + states |= icon_states('icons/obj/hydroponics/growing_mushrooms.dmi') + states |= icon_states('icons/obj/hydroponics/growing_vegetables.dmi') + states |= icon_states('goon/icons/obj/hydroponics.dmi') + var/list/paths = subtypesof(/obj/item/seeds) - /obj/item/seeds - typesof(/obj/item/seeds/sample) - /obj/item/seeds/lavaland + + for(var/seedpath in paths) + var/obj/item/seeds/seed = new seedpath + + for(var/i in 1 to seed.growthstages) + if("[seed.icon_grow][i]" in states) + continue + Fail("[seed.name] ([seed.type]) lacks the [seed.icon_grow][i] icon!") + + if(!(seed.icon_dead in states)) + Fail("[seed.name] ([seed.type]) lacks the [seed.icon_dead] icon!") + + if(seed.icon_harvest) // mushrooms have no grown sprites, same for items with no product + if(!(seed.icon_harvest in states)) + Fail("[seed.name] ([seed.type]) lacks the [seed.icon_harvest] icon!") diff --git a/code/modules/unit_tests/quick_swap_sanity.dm b/code/modules/unit_tests/quick_swap_sanity.dm new file mode 100644 index 0000000000..85e73f9b6a --- /dev/null +++ b/code/modules/unit_tests/quick_swap_sanity.dm @@ -0,0 +1,31 @@ +/// Test that quick swap correctly swaps items and invalidates suit storage +/datum/unit_test/quick_swap_sanity/Run() + // Create a human with a medical winter coat and a health analyzer in suit storage + var/mob/living/carbon/human/human = allocate(/mob/living/carbon/human) + + var/obj/item/coat = allocate(/obj/item/clothing/suit/hooded/wintercoat/medical) + TEST_ASSERT(human.equip_to_slot_if_possible(coat, ITEM_SLOT_OCLOTHING), "Couldn't equip winter coat") + + var/obj/item/analyzer = allocate(/obj/item/healthanalyzer) + TEST_ASSERT(human.equip_to_slot_if_possible(analyzer, ITEM_SLOT_SUITSTORE), "Couldn't equip health analyzer") + + // Then, have them quick swap between the coat and a space suit + var/obj/item/hardsuit = allocate(/obj/item/clothing/suit/space/hardsuit) + TEST_ASSERT(human.equip_to_appropriate_slot(hardsuit, swap = TRUE), "Couldn't quick swap to hardsuit") + + // Check if the human has the hardsuit on + TEST_ASSERT_EQUAL(human.wear_suit, hardsuit, "Human didn't equip the hardsuit") + + // Make sure the health analyzer was dropped as part of the swap + // Since health analyzers are an invalid suit storage item + TEST_ASSERT_EQUAL(human.s_store, null, "Human didn't drop the health analyzer") + + // Give the human an emergency oxygen tank + // This is valid suit storage for both the winter coat AND the hardsuit + var/obj/item/tank = allocate(/obj/item/tank/internals/emergency_oxygen) + TEST_ASSERT(human.equip_to_slot_if_possible(tank, ITEM_SLOT_SUITSTORE), "Couldn't equip emergency oxygen tank") + + // Now, quick swap back to the coat + // Since the tank is a valid suit storage item, it should not be dropped + TEST_ASSERT(human.equip_to_appropriate_slot(coat, swap = TRUE), "Couldn't quick swap to coat") + TEST_ASSERT_EQUAL(human.s_store, tank, "Human dropped the oxygen tank, when it was a valid item to keep in suit storage") diff --git a/code/modules/unit_tests/resist.dm b/code/modules/unit_tests/resist.dm new file mode 100644 index 0000000000..9fe5cd1114 --- /dev/null +++ b/code/modules/unit_tests/resist.dm @@ -0,0 +1,29 @@ +/// Test that stop, drop, and roll lowers fire stacks +/datum/unit_test/stop_drop_and_roll/Run() + var/mob/living/carbon/human/human = allocate(/mob/living/carbon/human) + + TEST_ASSERT_EQUAL(human.fire_stacks, 0, "Human does not have 0 fire stacks pre-ignition") + + human.adjust_fire_stacks(5) + human.IgniteMob() + + TEST_ASSERT_EQUAL(human.fire_stacks, 5, "Human does not have 5 fire stacks pre-resist") + + // Stop, drop, and roll has a sleep call. This would delay the test, and is not necessary. + CallAsync(human, /mob/living/verb/resist) + + TEST_ASSERT(human.fire_stacks < 5, "Human did not lower fire stacks after resisting") + +/// Test that you can resist out of a container +/datum/unit_test/container_resist/Run() + var/mob/living/carbon/human/human = allocate(/mob/living/carbon/human) + var/obj/structure/closet/closet = allocate(/obj/structure/closet, get_turf(human)) + + closet.open(human) + TEST_ASSERT(!(human in closet.contents), "Human was in the contents of an open closet") + + closet.close(human) + TEST_ASSERT(human in closet.contents, "Human was not in the contents of the closed closet") + + human.resist() + TEST_ASSERT(!(human in closet.contents), "Human resisted out of a standard closet, but was still in it") diff --git a/code/modules/unit_tests/say.dm b/code/modules/unit_tests/say.dm new file mode 100644 index 0000000000..3fe6675ab4 --- /dev/null +++ b/code/modules/unit_tests/say.dm @@ -0,0 +1,24 @@ +/// Test to verify message mods are parsed correctly +/datum/unit_test/get_message_mods + var/mob/host_mob + +/datum/unit_test/get_message_mods/Run() + host_mob = allocate(/mob/living/carbon/human) + + test("Hello", "Hello", list()) + test(";HELP", "HELP", list(MODE_HEADSET = TRUE)) + test(";%Never gonna give you up", "Never gonna give you up", list(MODE_HEADSET = TRUE, MODE_SING = TRUE)) + test(".s Gun plz", "Gun plz", list(RADIO_KEY = RADIO_KEY_SECURITY, RADIO_EXTENSION = RADIO_CHANNEL_SECURITY)) + test("...What", "...What", list()) + //note to lettern: add the ++, ||, __, and the verb*text checks + +/datum/unit_test/get_message_mods/proc/test(message, expected_message, list/expected_mods) + var/list/mods = list() + TEST_ASSERT_EQUAL(host_mob.get_message_mods(message, mods), expected_message, "Chopped message was not what we expected. Message: [message]") + + for (var/mod_key in mods) + TEST_ASSERT_EQUAL(mods[mod_key], expected_mods[mod_key], "The value for [mod_key] was not what we expected. Message: [message]") + expected_mods -= mod_key + + if (expected_mods.len) + Fail("Some message mods were expected, but were not returned by get_message_mods: [json_encode(expected_mods)]. Message: [message]") diff --git a/code/modules/unit_tests/spawn_humans.dm b/code/modules/unit_tests/spawn_humans.dm index 0500deae0a..7189e87277 100644 --- a/code/modules/unit_tests/spawn_humans.dm +++ b/code/modules/unit_tests/spawn_humans.dm @@ -1,7 +1,7 @@ /datum/unit_test/spawn_humans/Run() - var/locs = block(run_loc_bottom_left, run_loc_top_right) + var/locs = block(run_loc_bottom_left, run_loc_top_right) - for(var/I in 1 to 5) - new /mob/living/carbon/human(pick(locs)) + for(var/I in 1 to 5) + new /mob/living/carbon/human(pick(locs)) - sleep(50) + sleep(50) diff --git a/code/modules/unit_tests/subsystem_init.dm b/code/modules/unit_tests/subsystem_init.dm index f768f03f78..7d5473bc1b 100644 --- a/code/modules/unit_tests/subsystem_init.dm +++ b/code/modules/unit_tests/subsystem_init.dm @@ -4,4 +4,4 @@ if(ss.flags & SS_NO_INIT) continue if(!ss.initialized) - Fail("[ss]([ss.type]) is a subsystem meant to initialize but doesn't get set as initialized.") \ No newline at end of file + Fail("[ss]([ss.type]) is a subsystem meant to initialize but doesn't get set as initialized.") diff --git a/code/modules/unit_tests/surgeries.dm b/code/modules/unit_tests/surgeries.dm new file mode 100644 index 0000000000..491b0c5645 --- /dev/null +++ b/code/modules/unit_tests/surgeries.dm @@ -0,0 +1,79 @@ +/datum/unit_test/amputation/Run() + var/mob/living/carbon/human/patient = allocate(/mob/living/carbon/human) + var/mob/living/carbon/human/user = allocate(/mob/living/carbon/human) + + TEST_ASSERT_EQUAL(patient.get_missing_limbs().len, 0, "Patient is somehow missing limbs before surgery") + + var/datum/surgery/amputation/surgery = new(patient, BODY_ZONE_R_ARM, patient.get_bodypart(BODY_ZONE_R_ARM)) + + var/datum/surgery_step/sever_limb/sever_limb = new + sever_limb.success(user, patient, BODY_ZONE_R_ARM, null, surgery) + + TEST_ASSERT_EQUAL(patient.get_missing_limbs().len, 1, "Patient did not lose any limbs") + TEST_ASSERT_EQUAL(patient.get_missing_limbs()[1], BODY_ZONE_R_ARM, "Patient is missing a limb that isn't the one we operated on") + +/datum/unit_test/brain_surgery/Run() + var/mob/living/carbon/human/patient = allocate(/mob/living/carbon/human) + patient.gain_trauma_type(BRAIN_TRAUMA_MILD, TRAUMA_RESILIENCE_SURGERY) + patient.setOrganLoss(ORGAN_SLOT_BRAIN, 20) + + TEST_ASSERT(patient.has_trauma_type(), "Patient does not have any traumas, despite being given one") + + var/mob/living/carbon/human/user = allocate(/mob/living/carbon/human) + + var/datum/surgery_step/fix_brain/fix_brain = new + fix_brain.success(user, patient) + + TEST_ASSERT(!patient.has_trauma_type(), "Patient kept their brain trauma after brain surgery") + TEST_ASSERT(patient.getOrganLoss(ORGAN_SLOT_BRAIN) < 20, "Patient did not heal their brain damage after brain surgery") + +/datum/unit_test/multiple_surgeries/Run() + var/mob/living/carbon/human/user = allocate(/mob/living/carbon/human) + var/mob/living/carbon/human/patient_zero = allocate(/mob/living/carbon/human) + var/mob/living/carbon/human/patient_one = allocate(/mob/living/carbon/human) + + var/obj/item/scalpel/scalpel = allocate(/obj/item/scalpel) + + var/datum/surgery_step/incise/surgery_step = new + var/datum/surgery/organ_manipulation/surgery_for_zero = new + + INVOKE_ASYNC(surgery_step, /datum/surgery_step/proc/initiate, user, patient_zero, BODY_ZONE_CHEST, scalpel, surgery_for_zero) + TEST_ASSERT(surgery_for_zero.step_in_progress, "Surgery on patient zero was not initiated") + + var/datum/surgery/organ_manipulation/surgery_for_one = new + + // Without waiting for the incision to complete, try to start a new surgery + TEST_ASSERT(!surgery_step.initiate(user, patient_one, BODY_ZONE_CHEST, scalpel, surgery_for_one), "Was allowed to start a second surgery without the rod of asclepius") + TEST_ASSERT(!surgery_for_one.step_in_progress, "Surgery for patient one is somehow in progress, despite not initiating") + + user.apply_status_effect(STATUS_EFFECT_HIPPOCRATIC_OATH) + INVOKE_ASYNC(surgery_step, /datum/surgery_step/proc/initiate, user, patient_one, BODY_ZONE_CHEST, scalpel, surgery_for_one) + TEST_ASSERT(surgery_for_one.step_in_progress, "Surgery on patient one was not initiated, despite having rod of asclepius") + +/datum/unit_test/tend_wounds/Run() + var/mob/living/carbon/human/patient = allocate(/mob/living/carbon/human) + patient.take_overall_damage(100, 100) + + var/mob/living/carbon/human/user = allocate(/mob/living/carbon/human) + + // Test that tending wounds actually lowers damage + var/datum/surgery_step/heal/brute/basic/basic_brute_heal = new + basic_brute_heal.success(user, patient, BODY_ZONE_CHEST) + TEST_ASSERT(patient.getBruteLoss() < 100, "Tending brute wounds didn't lower brute damage ([patient.getBruteLoss()])") + + var/datum/surgery_step/heal/burn/basic/basic_burn_heal = new + basic_burn_heal.success(user, patient, BODY_ZONE_CHEST) + TEST_ASSERT(patient.getFireLoss() < 100, "Tending burn wounds didn't lower burn damage ([patient.getFireLoss()])") + + // Test that wearing clothing lowers heal amount + var/mob/living/carbon/human/naked_patient = allocate(/mob/living/carbon/human) + naked_patient.take_overall_damage(100) + + var/mob/living/carbon/human/clothed_patient = allocate(/mob/living/carbon/human) + clothed_patient.equipOutfit(/datum/outfit/job/doctor, TRUE) + clothed_patient.take_overall_damage(100) + + basic_brute_heal.success(user, naked_patient, BODY_ZONE_CHEST) + basic_brute_heal.success(user, clothed_patient, BODY_ZONE_CHEST) + + TEST_ASSERT(naked_patient.getBruteLoss() < clothed_patient.getBruteLoss(), "Naked patient did not heal more from wounds tending than a clothed patient") diff --git a/code/modules/unit_tests/unit_test.dm b/code/modules/unit_tests/unit_test.dm index 49974f2cb0..36b406e75e 100644 --- a/code/modules/unit_tests/unit_test.dm +++ b/code/modules/unit_tests/unit_test.dm @@ -1,14 +1,9 @@ /* - Usage: Override /Run() to run your test code - Call Fail() to fail the test (You should specify a reason) - You may use /New() and /Destroy() for setup/teardown respectively - You can use the run_loc_bottom_left and run_loc_top_right to get turfs for testing - */ GLOBAL_DATUM(current_test, /datum/unit_test) @@ -18,16 +13,18 @@ GLOBAL_VAR(test_log) /datum/unit_test //Bit of metadata for the future maybe var/list/procs_tested - + //usable vars var/turf/run_loc_bottom_left var/turf/run_loc_top_right //internal shit var/succeeded = TRUE + var/list/allocated var/list/fail_reasons /datum/unit_test/New() + allocated = new run_loc_bottom_left = locate(1, 1, 1) run_loc_top_right = locate(5, 5, 1) @@ -35,6 +32,7 @@ GLOBAL_VAR(test_log) //clear the test area for(var/atom/movable/AM in block(run_loc_bottom_left, run_loc_top_right)) qdel(AM) + QDEL_LIST(allocated) return ..() /datum/unit_test/proc/Run() @@ -48,6 +46,18 @@ GLOBAL_VAR(test_log) LAZYADD(fail_reasons, reason) +/// Allocates an instance of the provided type, and places it somewhere in an available loc +/// Instances allocated through this proc will be destroyed when the test is over +/datum/unit_test/proc/allocate(type, ...) + var/list/arguments = args.Copy(2) + if (!arguments.len) + arguments = list(run_loc_bottom_left) + else if (arguments[1] == null) + arguments[1] = run_loc_bottom_left + var/instance = new type(arglist(arguments)) + allocated += instance + return instance + /proc/RunUnitTests() CHECK_TICK diff --git a/code/modules/uplink/uplink_items/uplink_clothing.dm b/code/modules/uplink/uplink_items/uplink_clothing.dm index 745eddcc07..6163e5722a 100644 --- a/code/modules/uplink/uplink_items/uplink_clothing.dm +++ b/code/modules/uplink/uplink_items/uplink_clothing.dm @@ -92,8 +92,8 @@ cost = 6 exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) -/datum/uplink_item/device_tools/guerillagloves - name = "Guerilla Gloves" +/datum/uplink_item/device_tools/guerrillagloves + name = "Guerrilla Gloves" desc = "A pair of highly robust combat gripper gloves that excels at performing takedowns at close range, with an added lining of insulation. Careful not to hit a wall!" item = /obj/item/clothing/gloves/tackler/combat/insulated include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) diff --git a/html/changelogs/AutoChangeLog-pr-13014.yml b/html/changelogs/AutoChangeLog-pr-13014.yml new file mode 100644 index 0000000000..861e797669 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13014.yml @@ -0,0 +1,4 @@ +author: "Hatterhat" +delete-after: True +changes: + - rscadd: "The wastes of Lavaland and the icy caverns of Snow Taxi rumble in unison." diff --git a/html/changelogs/AutoChangeLog-pr-13193.yml b/html/changelogs/AutoChangeLog-pr-13193.yml new file mode 100644 index 0000000000..980a9366d8 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13193.yml @@ -0,0 +1,4 @@ +author: "silicons" +delete-after: True +changes: + - tweak: "medium screens are better now" diff --git a/html/changelogs/AutoChangeLog-pr-13233.yml b/html/changelogs/AutoChangeLog-pr-13233.yml new file mode 100644 index 0000000000..4366abec64 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13233.yml @@ -0,0 +1,6 @@ +author: "Hatterhat" +delete-after: True +changes: + - rscadd: "Changeling bone gauntlets! They punch the shit out of people really good." + - tweak: "Guerilla gloves and gorilla gloves inherit the strip modifiers of their predecessors, because apparently they had those." + - balance: "Pugilists now always hit the targeted limb and never miss." diff --git a/html/changelogs/AutoChangeLog-pr-13349.yml b/html/changelogs/AutoChangeLog-pr-13349.yml new file mode 100644 index 0000000000..2469b31ecd --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13349.yml @@ -0,0 +1,4 @@ +author: "LetterN" +delete-after: True +changes: + - code_imp: "Updates git and build tests." diff --git a/html/changelogs/AutoChangeLog-pr-13497.yml b/html/changelogs/AutoChangeLog-pr-13497.yml new file mode 100644 index 0000000000..c5f569bad3 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13497.yml @@ -0,0 +1,5 @@ +author: "Zandario" +delete-after: True +changes: + - code_imp: "Added some framework for future species expansions, including clothing refitting." + - refactor: "Made majority of the relevant Species IDs and Categories pre-defined, also for easier expansion and use." diff --git a/html/changelogs/AutoChangeLog-pr-13525.yml b/html/changelogs/AutoChangeLog-pr-13525.yml new file mode 100644 index 0000000000..eb441f04c3 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13525.yml @@ -0,0 +1,4 @@ +author: "Detective-Google" +delete-after: True +changes: + - bugfix: "Hilbert's jukebox works" diff --git a/html/changelogs/AutoChangeLog-pr-13527.yml b/html/changelogs/AutoChangeLog-pr-13527.yml new file mode 100644 index 0000000000..7e65116e83 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13527.yml @@ -0,0 +1,4 @@ +author: "ArchieBeepBoop" +delete-after: True +changes: + - rscadd: "Upgraded Advanced RTG Machine Preset" diff --git a/html/changelogs/AutoChangeLog-pr-13530.yml b/html/changelogs/AutoChangeLog-pr-13530.yml new file mode 100644 index 0000000000..b99ed1c545 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13530.yml @@ -0,0 +1,4 @@ +author: "silicons" +delete-after: True +changes: + - rscadd: "Clowns now have unpredictable effects on supermatter crystals when dusting from contact." diff --git a/html/changelogs/AutoChangeLog-pr-13533.yml b/html/changelogs/AutoChangeLog-pr-13533.yml new file mode 100644 index 0000000000..1ba14c689c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13533.yml @@ -0,0 +1,4 @@ +author: "shellspeed1" +delete-after: True +changes: + - rscadd: "A new recipe for a spicy has been given to us by a strange business man." diff --git a/html/changelogs/AutoChangeLog-pr-13535.yml b/html/changelogs/AutoChangeLog-pr-13535.yml new file mode 100644 index 0000000000..b020587eb8 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13535.yml @@ -0,0 +1,7 @@ +author: "Hatterhat" +delete-after: True +changes: + - rscadd: "Energy sabre reskin for the energy sword - access via alt-click." + - bugfix: "Alt-click reskins are fixed." + - tweak: "Defibrillators and their many, many overlays were moved to another .dmi." + - tweak: "You can now change the color of an energy sword via multitool. Not deswords. Yet." diff --git a/html/changelogs/AutoChangeLog-pr-13540.yml b/html/changelogs/AutoChangeLog-pr-13540.yml new file mode 100644 index 0000000000..0d7d9b8d2c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13540.yml @@ -0,0 +1,6 @@ +author: "ArcaneMusic, The0bserver-sys" +delete-after: True +changes: + - rscadd: "New from Hydrowear LLC: The Botanical Belt! This handy yellow belt lets you hold most of your botany gear, and a few beakers for reduced bag and floor clutter!" + - tweak: "Gives Hydrotrays plumbing pipes automatically, allowing you to make a self sustaining tray via plumbing." + - tweak: "Gives Service access to Bluespace Beakers, at last, gives Cargo, Science, and Medical the ability to construct reinforced plungers for use on lavaland." diff --git a/html/changelogs/AutoChangeLog-pr-13544.yml b/html/changelogs/AutoChangeLog-pr-13544.yml new file mode 100644 index 0000000000..61cf99090d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13544.yml @@ -0,0 +1,4 @@ +author: "DeltaFire15" +delete-after: True +changes: + - bugfix: "Portals no longer runtime because of incorrect args." diff --git a/icons/mob/actions/actions_changeling.dmi b/icons/mob/actions/actions_changeling.dmi index ce6b81e13b..2f384c6119 100644 Binary files a/icons/mob/actions/actions_changeling.dmi and b/icons/mob/actions/actions_changeling.dmi differ diff --git a/icons/mob/clothing/belt.dmi b/icons/mob/clothing/belt.dmi index 4ac82ca299..a25752c1d0 100644 Binary files a/icons/mob/clothing/belt.dmi and b/icons/mob/clothing/belt.dmi differ diff --git a/icons/mob/clothing/hands.dmi b/icons/mob/clothing/hands.dmi index 44499649f9..b95c377e12 100644 Binary files a/icons/mob/clothing/hands.dmi and b/icons/mob/clothing/hands.dmi differ diff --git a/icons/mob/inhands/weapons/swords_lefthand.dmi b/icons/mob/inhands/weapons/swords_lefthand.dmi index 23d80af9ef..5ff248de68 100644 Binary files a/icons/mob/inhands/weapons/swords_lefthand.dmi and b/icons/mob/inhands/weapons/swords_lefthand.dmi differ diff --git a/icons/mob/inhands/weapons/swords_righthand.dmi b/icons/mob/inhands/weapons/swords_righthand.dmi index 702c0299b5..0332e60fb5 100644 Binary files a/icons/mob/inhands/weapons/swords_righthand.dmi and b/icons/mob/inhands/weapons/swords_righthand.dmi differ diff --git a/icons/obj/clothing/belt_overlays.dmi b/icons/obj/clothing/belt_overlays.dmi index 1c22a0ad1b..cdb2567268 100644 Binary files a/icons/obj/clothing/belt_overlays.dmi and b/icons/obj/clothing/belt_overlays.dmi differ diff --git a/icons/obj/clothing/belts.dmi b/icons/obj/clothing/belts.dmi index 1a98872463..75fd20b856 100644 Binary files a/icons/obj/clothing/belts.dmi and b/icons/obj/clothing/belts.dmi differ diff --git a/icons/obj/clothing/gloves.dmi b/icons/obj/clothing/gloves.dmi index c0f78ee604..0feb6a75db 100644 Binary files a/icons/obj/clothing/gloves.dmi and b/icons/obj/clothing/gloves.dmi differ diff --git a/icons/obj/clothing/hats.dmi b/icons/obj/clothing/hats.dmi index 8fbb2abe1e..4f650f8561 100644 Binary files a/icons/obj/clothing/hats.dmi and b/icons/obj/clothing/hats.dmi differ diff --git a/icons/obj/defibrillators.dmi b/icons/obj/defibrillators.dmi new file mode 100644 index 0000000000..f838f40030 Binary files /dev/null and b/icons/obj/defibrillators.dmi differ diff --git a/icons/obj/food/soupsalad.dmi b/icons/obj/food/soupsalad.dmi index ca9c150480..c4d7c184b6 100644 Binary files a/icons/obj/food/soupsalad.dmi and b/icons/obj/food/soupsalad.dmi differ diff --git a/icons/obj/items_and_weapons.dmi b/icons/obj/items_and_weapons.dmi index c5aca2394f..9b73fa706b 100644 Binary files a/icons/obj/items_and_weapons.dmi and b/icons/obj/items_and_weapons.dmi differ diff --git a/modular_citadel/code/modules/mob/living/carbon/damage_procs.dm b/modular_citadel/code/modules/mob/living/carbon/damage_procs.dm index 17c3f17ad8..0457b853b7 100644 --- a/modular_citadel/code/modules/mob/living/carbon/damage_procs.dm +++ b/modular_citadel/code/modules/mob/living/carbon/damage_procs.dm @@ -1,16 +1,3 @@ -/mob/living/carbon/adjustStaminaLossBuffered(amount, updating_health = 1) - if(status_flags & GODMODE) - return 0 - if(CONFIG_GET(flag/disable_stambuffer)) - return - var/directstamloss = (bufferedstam + amount) - stambuffer - if(directstamloss > 0) - adjustStaminaLoss(directstamloss) - bufferedstam = clamp(bufferedstam + amount, 0, stambuffer) - stambufferregentime = world.time + 10 - if(updating_health) - update_health_hud() - /mob/living/carbon/adjustStaminaLoss(amount, updating_health = TRUE, forced = FALSE, affected_zone = BODY_ZONE_CHEST) if(!forced && (status_flags & GODMODE)) return FALSE diff --git a/modular_citadel/code/modules/mob/living/damage_procs.dm b/modular_citadel/code/modules/mob/living/damage_procs.dm deleted file mode 100644 index a399c17c71..0000000000 --- a/modular_citadel/code/modules/mob/living/damage_procs.dm +++ /dev/null @@ -1,2 +0,0 @@ -/mob/living/proc/adjustStaminaLossBuffered(amount, updating_health = TRUE, forced = FALSE) - return diff --git a/modular_citadel/code/modules/mob/living/living.dm b/modular_citadel/code/modules/mob/living/living.dm index 01867e9dcc..b5be028607 100644 --- a/modular_citadel/code/modules/mob/living/living.dm +++ b/modular_citadel/code/modules/mob/living/living.dm @@ -1,5 +1,3 @@ -/mob/living - /atom var/pseudo_z_axis @@ -24,26 +22,3 @@ if(.) pseudo_z_axis = newloc.get_fake_z() pixel_z = pseudo_z_axis - -/mob/living/carbon/update_stamina() - var/total_health = getStaminaLoss() - if(total_health >= STAMINA_SOFTCRIT) - if(!(combat_flags & COMBAT_FLAG_SOFT_STAMCRIT)) - ENABLE_BITFIELD(combat_flags, COMBAT_FLAG_SOFT_STAMCRIT) - else - if(combat_flags & COMBAT_FLAG_SOFT_STAMCRIT) - DISABLE_BITFIELD(combat_flags, COMBAT_FLAG_SOFT_STAMCRIT) - if(total_health) - if(!(combat_flags & COMBAT_FLAG_HARD_STAMCRIT) && total_health >= STAMINA_CRIT && !stat) - to_chat(src, "You're too exhausted to keep going...") - set_resting(TRUE, FALSE, FALSE) - SEND_SIGNAL(src, COMSIG_DISABLE_COMBAT_MODE) - ENABLE_BITFIELD(combat_flags, COMBAT_FLAG_HARD_STAMCRIT) - filters += CIT_FILTER_STAMINACRIT - update_mobility() - if((combat_flags & COMBAT_FLAG_HARD_STAMCRIT) && total_health <= STAMINA_SOFTCRIT) - to_chat(src, "You don't feel nearly as exhausted anymore.") - DISABLE_BITFIELD(combat_flags, COMBAT_FLAG_HARD_STAMCRIT | COMBAT_FLAG_SOFT_STAMCRIT) - filters -= CIT_FILTER_STAMINACRIT - update_mobility() - update_health_hud() diff --git a/modular_citadel/icons/ui/screen_gen.dmi b/modular_citadel/icons/ui/screen_gen.dmi index d006185a3c..510d312f1c 100644 Binary files a/modular_citadel/icons/ui/screen_gen.dmi and b/modular_citadel/icons/ui/screen_gen.dmi differ diff --git a/tgstation.dme b/tgstation.dme index c27d68e7bc..750486e032 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -108,6 +108,7 @@ #include "code\__DEFINES\sight.dm" #include "code\__DEFINES\sound.dm" #include "code\__DEFINES\spaceman_dmm.dm" +#include "code\__DEFINES\species.dm" #include "code\__DEFINES\stat.dm" #include "code\__DEFINES\stat_tracking.dm" #include "code\__DEFINES\status_effects.dm" @@ -138,6 +139,7 @@ #include "code\__DEFINES\combat\attack_types.dm" #include "code\__DEFINES\combat\block.dm" #include "code\__DEFINES\combat\block_parry.dm" +#include "code\__DEFINES\combat\stamina_combat.dm" #include "code\__DEFINES\dcs\flags.dm" #include "code\__DEFINES\dcs\helpers.dm" #include "code\__DEFINES\dcs\signals.dm" @@ -292,6 +294,7 @@ #include "code\controllers\configuration\entries\plushies.dm" #include "code\controllers\configuration\entries\policy.dm" #include "code\controllers\configuration\entries\resources.dm" +#include "code\controllers\configuration\entries\stamina_combat.dm" #include "code\controllers\subsystem\acid.dm" #include "code\controllers\subsystem\adjacent_air.dm" #include "code\controllers\subsystem\air.dm" @@ -326,6 +329,7 @@ #include "code\controllers\subsystem\materials.dm" #include "code\controllers\subsystem\medals.dm" #include "code\controllers\subsystem\minimaps.dm" +#include "code\controllers\subsystem\minimum_spawns.dm" #include "code\controllers\subsystem\minor_mapping.dm" #include "code\controllers\subsystem\mobs.dm" #include "code\controllers\subsystem\nightshift.dm" @@ -2281,7 +2285,6 @@ #include "code\modules\jobs\job_types\station_engineer.dm" #include "code\modules\jobs\job_types\virologist.dm" #include "code\modules\jobs\job_types\warden.dm" -#include "code\modules\jobs\map_changes\map_changes.dm" #include "code\modules\keybindings\bindings_atom.dm" #include "code\modules\keybindings\bindings_client.dm" #include "code\modules\keybindings\focus.dm" @@ -2463,6 +2466,7 @@ #include "code\modules\mob\living\login.dm" #include "code\modules\mob\living\logout.dm" #include "code\modules\mob\living\say.dm" +#include "code\modules\mob\living\stamina_buffer.dm" #include "code\modules\mob\living\status_procs.dm" #include "code\modules\mob\living\taste.dm" #include "code\modules\mob\living\update_icons.dm" @@ -2545,9 +2549,10 @@ #include "code\modules\mob\living\carbon\human\status_procs.dm" #include "code\modules\mob\living\carbon\human\typing_indicator.dm" #include "code\modules\mob\living\carbon\human\update_icons.dm" -#include "code\modules\mob\living\carbon\human\species_types\abductors.dm" +#include "code\modules\mob\living\carbon\human\species_types\abductor.dm" #include "code\modules\mob\living\carbon\human\species_types\android.dm" #include "code\modules\mob\living\carbon\human\species_types\angel.dm" +#include "code\modules\mob\living\carbon\human\species_types\anthromorph.dm" #include "code\modules\mob\living\carbon\human\species_types\bugmen.dm" #include "code\modules\mob\living\carbon\human\species_types\corporate.dm" #include "code\modules\mob\living\carbon\human\species_types\dullahan.dm" @@ -2555,7 +2560,6 @@ #include "code\modules\mob\living\carbon\human\species_types\ethereal.dm" #include "code\modules\mob\living\carbon\human\species_types\felinid.dm" #include "code\modules\mob\living\carbon\human\species_types\flypeople.dm" -#include "code\modules\mob\living\carbon\human\species_types\furrypeople.dm" #include "code\modules\mob\living\carbon\human\species_types\golems.dm" #include "code\modules\mob\living\carbon\human\species_types\humans.dm" #include "code\modules\mob\living\carbon\human\species_types\ipc.dm" @@ -3602,7 +3606,6 @@ #include "modular_citadel\code\modules\mentor\mentorpm.dm" #include "modular_citadel\code\modules\mentor\mentorsay.dm" #include "modular_citadel\code\modules\mob\cit_emotes.dm" -#include "modular_citadel\code\modules\mob\living\damage_procs.dm" #include "modular_citadel\code\modules\mob\living\living.dm" #include "modular_citadel\code\modules\mob\living\carbon\carbon.dm" #include "modular_citadel\code\modules\mob\living\carbon\damage_procs.dm" diff --git a/tools/travis/check_filedirs.sh b/tools/travis/check_filedirs.sh index 30df015763..b7bac4b7a2 100755 --- a/tools/travis/check_filedirs.sh +++ b/tools/travis/check_filedirs.sh @@ -1,15 +1,15 @@ + #!/bin/bash if [ -n "$1" ] then dme=$1 else - echo "Specify a DME to check" + echo "ERROR: Specify a DME to check" exit 1 fi if [[ $(awk '/BEGIN_FILE_DIR/{flag=1;next}/END_FILE_DIR/{flag=0}flag' $dme | wc -l) -ne 1 ]] then - echo "File DIR was ticked, please untick it, see: https://tgstation13.org/phpBB/viewtopic.php?f=5&t=321 for more" + echo "ERROR: File DIR was ticked, please untick it, see: https://tgstation13.org/phpBB/viewtopic.php?f=5&t=321 for more" exit 1 fi - diff --git a/tools/travis/check_grep.sh b/tools/travis/check_grep.sh index 2117b570eb..b85f775eb9 100755 --- a/tools/travis/check_grep.sh +++ b/tools/travis/check_grep.sh @@ -7,43 +7,70 @@ shopt -s globstar st=0 if grep -El '^\".+\" = \(.+\)' _maps/**/*.dmm; then - echo "Non-TGM formatted map detected. Please convert it using Map Merger!" + echo "ERROR: Non-TGM formatted map detected. Please convert it using Map Merger!" st=1 fi; if grep -P '^\ttag = \"icon' _maps/**/*.dmm; then - echo "tag vars from icon state generation detected in maps, please remove them." + echo "ERROR: tag vars from icon state generation detected in maps, please remove them." st=1 fi; -if grep 'step_[xy]' _maps/**/*.dmm; then - echo "step_x/step_y variables detected in maps, please remove them." +if grep -P 'step_[xy]' _maps/**/*.dmm; then + echo "ERROR: step_x/step_y variables detected in maps, please remove them." st=1 fi; -if grep 'pixel_[xy] = 0' _maps/**/*.dmm; then - echo "pixel_x/pixel_y = 0 variables detected in maps, please review to ensure they are not dirty varedits." +if grep -P 'pixel_[^xy]' _maps/**/*.dmm; then + echo "ERROR: incorrect pixel offset variables detected in maps, please remove them." + st=1 fi; if grep -P '\td[1-2] =' _maps/**/*.dmm; then - echo "d1/d2 cable variables detected in maps, please remove them." + echo "ERROR: d1/d2 cable variables detected in maps, please remove them." st=1 fi; -if grep '^/area/.+[\{]' _maps/**/*.dmm; then - echo "Vareditted /area path use detected in maps, please replace with proper paths." +if grep -P '^/area/.+[\{]' _maps/**/*.dmm; then + echo "WARNING: Vareditted /area path use detected in maps, please replace with proper paths." + #st=1 +fi; +if grep -P '\W\/turf\s*[,\){]' _maps/**/*.dmm; then + echo "ERROR: base /turf path use detected in maps, please replace with proper paths." st=1 fi; -if grep '\W\/turf\s*[,\){]' _maps/**/*.dmm; then - echo "base /turf path use detected in maps, please replace with proper paths." - st=1 -fi; -if grep '^/*var/' code/**/*.dm; then - echo "Unmanaged global var use detected in code, please use the helpers." +if grep -P '^/*var/' code/**/*.dm; then + echo "ERROR: Unmanaged global var use detected in code, please use the helpers." st=1 fi; +nl=' +' +nl=$'\n' +while read f; do + t=$(tail -c2 "$f"; printf x); r1="${nl}$"; r2="${nl}${r1}" + if [[ ! ${t%x} =~ $r1 ]]; then + echo "file $f is missing a trailing newline" + #st=1 + fi; +done < <(find . -type f -name '*.dm') if grep -i 'centcomm' code/**/*.dm; then - echo "Misspelling(s) of CENTCOM detected in code, please remove the extra M(s)." + echo "ERROR: Misspelling(s) of CENTCOM detected in code, please remove the extra M(s)." st=1 fi; if grep -i 'centcomm' _maps/**/*.dmm; then - echo "Misspelling(s) of CENTCOM detected in maps, please remove the extra M(s)." + echo "ERROR: Misspelling(s) of CENTCOM detected in maps, please remove the extra M(s)." st=1 fi; +if ls _maps/*.json | grep -P "[A-Z]"; then + echo "Uppercase in a map json detected, these must be all lowercase." + st=1 +fi; +for json in _maps/*.json +do + map_path=$(jq -r '.map_path' $json) + while read map_file; do + filename="_maps/$map_path/$map_file" + if [ ! -f $filename ] + then + echo "found invalid file reference to $filename in _maps/$json" + st=1 + fi + done < <(jq -r '[.map_file] | flatten | .[]' $json) +done exit $st diff --git a/tools/travis/install_dreamchecker.sh b/tools/travis/install_dreamchecker.sh deleted file mode 100755 index 4423e5aafb..0000000000 --- a/tools/travis/install_dreamchecker.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash -set -euo pipefail - -source dependencies.sh - -wget -O ~/dreamchecker "https://github.com/SpaceManiac/SpacemanDMM/releases/download/$SPACEMAN_DMM_VERSION/dreamchecker" -chmod +x ~/dreamchecker -~/dreamchecker --version diff --git a/tools/travis/install_spaceman_dmm.sh b/tools/travis/install_spaceman_dmm.sh new file mode 100755 index 0000000000..39464193f8 --- /dev/null +++ b/tools/travis/install_spaceman_dmm.sh @@ -0,0 +1,8 @@ +#!/bin/bash +set -euo pipefail + +source dependencies.sh + +wget -O ~/$1 "https://github.com/SpaceManiac/SpacemanDMM/releases/download/$SPACEMAN_DMM_VERSION/$1" +chmod +x ~/$1 +~/$1 --version diff --git a/tools/travis/run_server.sh b/tools/travis/run_server.sh index 975e8f6884..04c491cd5c 100755 --- a/tools/travis/run_server.sh +++ b/tools/travis/run_server.sh @@ -2,6 +2,7 @@ set -euo pipefail tools/deploy.sh travis_test +rm travis_test/*.dll mkdir travis_test/config #test config