diff --git a/.dockerignore b/.dockerignore index 2e6259d23d..9c6ac6b4aa 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,6 +1,5 @@ .dockerignore .editorconfig -.travis.yml GPLv3.txt LICENSE README.md @@ -26,5 +25,4 @@ tgstation.dyn.rsc libmariadb.dll rust_g.dll BSQL.dll -appveyor.yml Dockerfile diff --git a/.gitattributes b/.gitattributes index c447869d3e..b23dfe6932 100644 --- a/.gitattributes +++ b/.gitattributes @@ -38,5 +38,8 @@ *.dmm text eol=lf merge=dmm *.dmi binary merge=dmi +##Force tab indents on dm files +*.dm whitespace=indent-with-non-tab + ## Force changelog merging to use union html/changelog.html text eol=lf merge=union diff --git a/.github/workflows/ci_suite.yml b/.github/workflows/ci_suite.yml new file mode 100644 index 0000000000..76a1c26656 --- /dev/null +++ b/.github/workflows/ci_suite.yml @@ -0,0 +1,114 @@ +name: CI Suite +on: + push: + branches: + - master + pull_request: + branches: + - master +jobs: + run_linters: + if: "!contains(github.event.head_commit.message, '[ci skip]')" + name: Run Linters + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup cache + uses: actions/cache@v2 + with: + path: $HOME/SpacemanDMM + key: ${{ runner.os }}-spacemandmm + - name: Install Tools + run: | + pip3 install setuptools + bash tools/ci/install_build_tools.sh + bash tools/ci/install_spaceman_dmm.sh dreamchecker + pip3 install -r tools/mapmerge2/requirements.txt + - name: Run Linters + run: | + bash tools/ci/check_filedirs.sh tgstation.dme + bash tools/ci/check_changelogs.sh + find . -name "*.php" -print0 | xargs -0 -n1 php -l + find . -name "*.json" -not -path "*/node_modules/*" -print0 | xargs -0 python3 ./tools/json_verifier.py + bash tools/ci/build_tgui.sh + bash tools/ci/check_grep.sh + python3 tools/mapmerge2/dmi.py --test + ~/dreamchecker > ${GITHUB_WORKSPACE}/output-annotations.txt 2>&1 + - name: Annotate Lints + uses: yogstation13/DreamAnnotate@v1 + if: always() + with: + outputFile: output-annotations.txt + + compile_all_maps: + if: "!contains(github.event.head_commit.message, '[ci skip]')" + name: Compile Maps + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup cache + uses: actions/cache@v2 + with: + path: $HOME/BYOND + key: ${{ runner.os }}-byond + - name: Compile All Maps + run: | + bash tools/ci/install_byond.sh + source $HOME/BYOND/byond/bin/byondsetup + python3 tools/ci/template_dm_generator.py + bash tools/ci/dm.sh -DCIBUILDING -DCITESTING -DALL_MAPS tgstation.dme + run_all_tests: + if: "!contains(github.event.head_commit.message, '[ci skip]')" + name: Integration Tests + runs-on: ubuntu-latest + services: + mysql: + image: mysql:latest + env: + MYSQL_ROOT_PASSWORD: root + ports: + - 3306 + options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 + steps: + - uses: actions/checkout@v2 + - name: Setup cache + uses: actions/cache@v2 + with: + path: $HOME/BYOND + key: ${{ runner.os }}-byond + - name: Setup database + run: | + sudo systemctl start mysql + mysql -u root -proot -e 'CREATE DATABASE tg_ci;' + mysql -u root -proot tg_ci < SQL/tgstation_schema.sql + mysql -u root -proot -e 'CREATE DATABASE tg_ci_prefixed;' + mysql -u root -proot tg_ci_prefixed < SQL/tgstation_schema_prefixed.sql + - name: Install rust-g + run: | + sudo dpkg --add-architecture i386 + sudo apt update || true + sudo apt install libssl1.1:i386 + bash tools/ci/install_rust_g.sh + # - name: Compile and run tests + # run: | + # bash tools/ci/install_byond.sh + # source $HOME/BYOND/byond/bin/byondsetup + # bash tools/ci/dm.sh -DCIBUILDING tgstation.dme + # bash tools/ci/run_server.sh + test_windows: + if: "!contains(github.event.head_commit.message, '[ci skip]')" + name: Windows Build + runs-on: windows-latest + steps: + - uses: actions/checkout@v2 + - name: Compile + run: pwsh tools/ci/build.ps1 + - name: Create artifact + run: | + md deploy + bash tools/deploy.sh ./deploy + - name: Deploy artifact + uses: actions/upload-artifact@v2 + with: + name: deploy + path: deploy diff --git a/.github/workflows/compile_changelogs.yml b/.github/workflows/compile_changelogs.yml index 4fd396f133..c8756f0d28 100644 --- a/.github/workflows/compile_changelogs.yml +++ b/.github/workflows/compile_changelogs.yml @@ -15,7 +15,7 @@ jobs: CHANGELOG_ENABLER: ${{ secrets.CHANGELOG_ENABLER }} run: | unset SECRET_EXISTS - if [-n $CHANGELOG_ENABLER]; then SECRET_EXISTS='true' ; fi + if [ -n $CHANGELOG_ENABLER ]; then SECRET_EXISTS='true' ; fi echo ::set-output name=CL_ENABLED::${SECRET_EXISTS} - name: "Setup python" if: steps.value_holder.outputs.CL_ENABLED diff --git a/.github/workflows/docker_publish.yml b/.github/workflows/docker_publish.yml new file mode 100644 index 0000000000..7417a382c4 --- /dev/null +++ b/.github/workflows/docker_publish.yml @@ -0,0 +1,22 @@ +name: Docker Build + +on: + push: + branches: + - master + +jobs: + publish: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Build and Publish Docker Image to Registry + uses: elgohr/Publish-Docker-Github-Action@master + with: + name: tgstation/tgstation + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + dockerfile: Dockerfile + tags: "latest" + cache: true diff --git a/.github/workflows/generate_documentation.yml b/.github/workflows/generate_documentation.yml new file mode 100644 index 0000000000..d0d61be073 --- /dev/null +++ b/.github/workflows/generate_documentation.yml @@ -0,0 +1,31 @@ +name: Generate documentation +on: + push: + branches: + - master +jobs: + generate_documentation: + if: "!contains(github.event.head_commit.message, '[ci skip]')" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup cache + uses: actions/cache@v2 + with: + path: $HOME/SpacemanDMM + key: ${{ runner.os }}-spacemandmm + - name: Install SpacemanDMM + run: bash tools/ci/install_spaceman_dmm.sh dmdoc + - name: Generate documentation + run: | + ~/dmdoc + touch dmdoc/.nojekyll + echo codedocs.tgstation13.org > dmdoc/CNAME + - name: Deploy + uses: JamesIves/github-pages-deploy-action@3.7.1 + with: + BRANCH: gh-pages + CLEAN: true + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SINGLE_COMMIT: true + FOLDER: dmdoc diff --git a/.github/workflows/update_tgs_dmapi.yml b/.github/workflows/update_tgs_dmapi.yml index 6fe53f700c..c7bb5c970c 100644 --- a/.github/workflows/update_tgs_dmapi.yml +++ b/.github/workflows/update_tgs_dmapi.yml @@ -26,6 +26,7 @@ jobs: library-path: 'code/modules/tgs' - name: Commit and Push + continue-on-error: true run: | git config user.name tgstation-server git config user.email tgstation-server@users.noreply.github.com @@ -35,6 +36,7 @@ jobs: - name: Create Pull Request uses: repo-sync/pull-request@v2 + if: ${{ success() }} with: source_branch: "tgs-dmapi-update" destination_branch: "master" @@ -42,4 +44,4 @@ jobs: pr_body: "This pull request updates the TGS DMAPI to the latest version. Please note any breaking or unimplemented changes before merging." pr_label: "Tools" pr_allow_empty: false - github_token: ${{ secrets.GITHUB_TOKEN }} + github_token: ${{ secrets.TGS_UPDATER }} diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 83ef6fa8ff..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,102 +0,0 @@ -language: generic -os: linux -dist: xenial - -branches: - except: - - ___TGS3TempBranch - - ___TGSTempBranch - -jobs: - include: - - name: "Run Linters" - addons: - apt: - packages: - - python3 - - python3-pip - - python3-setuptools - - pcregrep - - rustc - - cargo - cache: - directories: - - $HOME/SpacemanDMM - install: - - tools/travis/install_build_tools.sh - - tools/travis/install_spaceman_dmm.sh dreamchecker - script: - - tools/travis/check_filedirs.sh tgstation.dme - - tools/travis/check_changelogs.sh - - find . -name "*.php" -print0 | xargs -0 -n1 php -l - - find . -name "*.json" -not -path "*/node_modules/*" -print0 | xargs -0 python3 ./tools/json_verifier.py - - tools/travis/build_tgui.sh - - tools/travis/check_grep.sh - - python3 tools/travis/check_line_endings.py - - ~/dreamchecker - - - name: "Compile All Maps" - addons: - apt: - packages: - - libstdc++6:i386 - cache: - directories: - - $HOME/BYOND - install: - - tools/travis/install_byond.sh - - source $HOME/BYOND/byond/bin/byondsetup - before_script: - - tools/travis/template_dm_generator.py - script: - - tools/travis/dm.sh -DTRAVISBUILDING -DTRAVISTESTING -DALL_MAPS tgstation.dme - - - name: "Compile and Run Tests" - addons: - mariadb: '10.2' - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - libstdc++6:i386 - - gcc-multilib - - g++-7 - - g++-7-multilib - - libmariadb-client-lgpl-dev:i386 - - libmariadbd-dev - cache: - directories: - - $HOME/BYOND - - $HOME/libmariadb - install: - - tools/travis/install_byond.sh - - source $HOME/BYOND/byond/bin/byondsetup - - tools/travis/install_libmariadb.sh - - tools/travis/install_rust_g.sh - before_script: - - mysql -u root -e 'CREATE DATABASE tg_travis;' - - mysql -u root tg_travis < SQL/tgstation_schema.sql - - mysql -u root -e 'CREATE DATABASE tg_travis_prefixed;' - - mysql -u root tg_travis_prefixed < SQL/tgstation_schema_prefixed.sql - - tools/travis/build_bsql.sh - 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/.vscode/extensions.json b/.vscode/extensions.json index f79100f563..bf0d9d2fb9 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,9 +1,10 @@ { - "recommendations": [ - "gbasood.byond-dm-language-support", - "platymuus.dm-langclient", + "recommendations": [ + "gbasood.byond-dm-language-support", + "platymuus.dm-langclient", "EditorConfig.EditorConfig", "arcanis.vscode-zipfs", - "dbaeumer.vscode-eslint" - ] + "dbaeumer.vscode-eslint", + "kevinkyang.auto-comment-blocks" + ] } diff --git a/Dockerfile b/Dockerfile index e8a5f44908..cca7e43a54 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,14 +1,12 @@ -FROM tgstation/byond:513.1508 as base +FROM tgstation/byond:513.1533 as base -FROM base as build_base +FROM base as rust_g RUN apt-get update \ && apt-get install -y --no-install-recommends \ git \ ca-certificates -FROM build_base as rust_g - WORKDIR /rust_g RUN apt-get install -y --no-install-recommends \ @@ -27,36 +25,6 @@ RUN /bin/bash -c "source dependencies.sh \ && git checkout FETCH_HEAD \ && ~/.cargo/bin/cargo build --release -FROM build_base as bsql - -WORKDIR /bsql - -RUN apt-get install -y --no-install-recommends software-properties-common \ - && add-apt-repository ppa:ubuntu-toolchain-r/test \ - && apt-get update \ - && apt-get install -y --no-install-recommends \ - cmake \ - make \ - g++-7 \ - libmariadb-client-lgpl-dev \ - && git init \ - && git remote add origin https://github.com/tgstation/BSQL - -COPY dependencies.sh . - -RUN /bin/bash -c "source dependencies.sh \ - && git fetch --depth 1 origin \$BSQL_VERSION" \ - && git checkout FETCH_HEAD - -WORKDIR /bsql/artifacts - -ENV CC=gcc-7 CXX=g++-7 - -RUN ln -s /usr/include/mariadb /usr/include/mysql \ - && ln -s /usr/lib/i386-linux-gnu /root/MariaDB \ - && cmake .. \ - && make - FROM base as dm_base WORKDIR /tgstation @@ -65,26 +33,30 @@ FROM dm_base as build COPY . . -RUN DreamMaker -max_errors 0 tgstation.dme && tools/deploy.sh /deploy +RUN DreamMaker -max_errors 0 tgstation.dme \ + && tools/deploy.sh /deploy \ + && rm /deploy/*.dll FROM dm_base EXPOSE 1337 RUN apt-get update \ + && apt-get install -y --no-install-recommends software-properties-common \ + && add-apt-repository ppa:ubuntu-toolchain-r/test \ + && apt-get update \ + && apt-get upgrade -y \ + && apt-get dist-upgrade -y \ && apt-get install -y --no-install-recommends \ + libmariadb2 \ mariadb-client \ libssl1.0.0 \ && rm -rf /var/lib/apt/lists/* \ && mkdir -p /root/.byond/bin COPY --from=rust_g /rust_g/target/release/librust_g.so /root/.byond/bin/rust_g -COPY --from=bsql /bsql/artifacts/src/BSQL/libBSQL.so ./ COPY --from=build /deploy ./ -#bsql fexists memes -RUN ln -s /tgstation/libBSQL.so /root/.byond/bin/libBSQL.so - VOLUME [ "/tgstation/config", "/tgstation/data" ] ENTRYPOINT [ "DreamDaemon", "tgstation.dmb", "-port", "1337", "-trusted", "-close", "-verbose" ] diff --git a/SpacemanDMM.toml b/SpacemanDMM.toml index b827472254..81aff0d557 100644 --- a/SpacemanDMM.toml +++ b/SpacemanDMM.toml @@ -1,2 +1,9 @@ [langserver] dreamchecker = true + +[code_standards] +disallow_relative_type_definitions = true +disallow_relative_proc_definitions = true + +[dmdoc] +use_typepath_names = true diff --git a/TGS3.json b/TGS3.json index 39b75bd913..228854a166 100644 --- a/TGS3.json +++ b/TGS3.json @@ -1,22 +1,9 @@ { "documentation": "/tg/station server 3 configuration file", - "changelog": { - "script": "tools/ss13_genchangelog.py", - "arguments": "html/changelog.html html/changelogs", - "pip_dependancies": [ - "PyYaml", - "beautifulsoup4" - ] - }, - "synchronize_paths": [ - "html/changelog.html", - "html/changelogs/*" - ], + "synchronize_paths": [], "static_directories": [ "config", "data" ], - "dlls": [ - "libmariadb.dll" - ] + "dlls": [] } diff --git a/_maps/RandomRuins/AnywhereRuins/golem_ship.dmm b/_maps/RandomRuins/AnywhereRuins/golem_ship.dmm index 37a89ba2ff..274c814cf5 100644 --- a/_maps/RandomRuins/AnywhereRuins/golem_ship.dmm +++ b/_maps/RandomRuins/AnywhereRuins/golem_ship.dmm @@ -18,7 +18,7 @@ /obj/item/mining_scanner, /obj/item/flashlight/lantern, /obj/item/card/id/mining, -/obj/item/gps/mining, +/obj/item/gps/mining/off, /turf/open/floor/plating, /area/ruin/powered/golem_ship) "d" = ( @@ -32,7 +32,7 @@ /obj/item/mining_scanner, /obj/item/flashlight/lantern, /obj/item/card/id/mining, -/obj/item/gps/mining, +/obj/item/gps/mining/off, /turf/open/floor/plating, /area/ruin/powered/golem_ship) "e" = ( @@ -71,8 +71,8 @@ /area/ruin/powered/golem_ship) "k" = ( /obj/machinery/computer/arcade/battle{ - icon_state = "arcade"; - dir = 4 + dir = 4; + icon_state = "arcade" }, /turf/open/floor/mineral/titanium/purple, /area/ruin/powered/golem_ship) @@ -112,8 +112,8 @@ /area/ruin/powered/golem_ship) "s" = ( /obj/machinery/computer/arcade/orion_trail{ - icon_state = "arcade"; - dir = 4 + dir = 4; + icon_state = "arcade" }, /turf/open/floor/mineral/titanium/purple, /area/ruin/powered/golem_ship) diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_alien_nest.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_alien_nest.dmm index eab08815f3..c2bdea157e 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_alien_nest.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_alien_nest.dmm @@ -111,6 +111,17 @@ /obj/structure/alien/resin/membrane, /turf/open/floor/plating/asteroid/basalt/lava_land_surface, /area/ruin/unpowered/xenonest) +"ax" = ( +/obj/structure/alien/weeds, +/obj/effect/decal/cleanable/blood/gibs, +/obj/structure/alien/weeds/node, +/mob/living/simple_animal/hostile/alien/drone, +/turf/open/floor/plating/asteroid/basalt/lava_land_surface, +/area/ruin/unpowered/xenonest) +"ay" = ( +/obj/structure/stone_tile/slab/cracked, +/turf/open/indestructible/boss, +/area/ruin/unpowered/xenonest) "aA" = ( /obj/structure/alien/weeds, /obj/item/flamethrower, @@ -130,6 +141,17 @@ }, /turf/open/floor/plating/asteroid/basalt/lava_land_surface, /area/ruin/unpowered/xenonest) +"aD" = ( +/obj/structure/stone_tile/surrounding_tile{ + dir = 1 + }, +/obj/structure/stone_tile/surrounding_tile, +/obj/structure/stone_tile/surrounding_tile/cracked{ + dir = 4 + }, +/obj/structure/stone_tile/center, +/turf/open/chasm/lavaland, +/area/ruin/unpowered/xenonest) "aE" = ( /obj/structure/alien/weeds, /obj/effect/decal/cleanable/ash, @@ -160,6 +182,19 @@ /obj/effect/decal/cleanable/blood, /turf/open/floor/plating/asteroid/basalt/lava_land_surface, /area/ruin/unpowered/xenonest) +"aK" = ( +/obj/structure/stone_tile/surrounding_tile/cracked{ + dir = 4 + }, +/obj/structure/stone_tile/surrounding_tile/cracked{ + dir = 8 + }, +/obj/structure/stone_tile/surrounding_tile/cracked{ + dir = 1 + }, +/obj/structure/stone_tile/center/cracked, +/turf/open/chasm/lavaland, +/area/ruin/unpowered/xenonest) "aL" = ( /obj/structure/alien/weeds, /obj/item/tank/internals/plasma, @@ -170,6 +205,26 @@ /obj/effect/decal/cleanable/blood/xeno, /turf/open/floor/plating/asteroid/basalt/lava_land_surface, /area/ruin/unpowered/xenonest) +"aN" = ( +/obj/structure/stone_tile/block{ + dir = 8 + }, +/obj/structure/stone_tile{ + dir = 1 + }, +/obj/structure/stone_tile/cracked, +/turf/open/indestructible/boss, +/area/ruin/unpowered/xenonest) +"aO" = ( +/obj/structure/alien/weeds, +/obj/effect/mob_spawn/alien/corpse/humanoid/sentinel, +/turf/open/floor/plating/asteroid/basalt/lava_land_surface, +/area/ruin/unpowered/xenonest) +"aP" = ( +/obj/structure/alien/weeds, +/obj/effect/mob_spawn/alien/corpse/humanoid/hunter, +/turf/open/floor/plating/asteroid/basalt/lava_land_surface, +/area/ruin/unpowered/xenonest) "aQ" = ( /obj/structure/alien/weeds, /obj/structure/bed/nest, @@ -215,13 +270,6 @@ /obj/effect/gibspawner/xeno, /turf/open/floor/plating/asteroid/basalt/lava_land_surface, /area/ruin/unpowered/xenonest) -"aY" = ( -/obj/structure/alien/weeds, -/obj/effect/decal/cleanable/blood/gibs, -/mob/living/simple_animal/hostile/alien/drone, -/obj/structure/alien/weeds/node, -/turf/open/floor/plating/asteroid/basalt/lava_land_surface, -/area/ruin/unpowered/xenonest) "aZ" = ( /turf/closed/indestructible/riveted/boss, /area/ruin/unpowered/xenonest) @@ -338,10 +386,6 @@ /obj/structure/stone_tile, /turf/open/indestructible/boss, /area/ruin/unpowered/xenonest) -"bm" = ( -/obj/structure/stone_tile/slab/cracked, -/turf/open/indestructible/boss, -/area/ruin/unpowered/xenonest) "bn" = ( /obj/structure/stone_tile/block{ dir = 4 @@ -365,12 +409,6 @@ /obj/structure/stone_tile/center, /turf/open/chasm/lavaland, /area/ruin/unpowered/xenonest) -"bp" = ( -/obj/structure/stone_tile/block{ - dir = 4 - }, -/turf/open/chasm/lavaland, -/area/ruin/unpowered/xenonest) "bq" = ( /turf/open/chasm/lavaland, /area/ruin/unpowered/xenonest) @@ -391,33 +429,6 @@ }, /turf/open/chasm/lavaland, /area/ruin/unpowered/xenonest) -"bt" = ( -/obj/structure/stone_tile/surrounding_tile{ - dir = 1 - }, -/obj/structure/stone_tile/surrounding_tile, -/obj/structure/stone_tile/surrounding_tile/cracked{ - dir = 4 - }, -/obj/structure/stone_tile/center, -/turf/open/chasm/lavaland, -/area/ruin/unpowered/xenonest) -"bu" = ( -/obj/structure/stone_tile/block/cracked{ - dir = 1 - }, -/turf/open/chasm/lavaland, -/area/ruin/unpowered/xenonest) -"bv" = ( -/obj/structure/stone_tile/block{ - dir = 8 - }, -/obj/structure/stone_tile{ - dir = 1 - }, -/obj/structure/stone_tile/cracked, -/turf/open/indestructible/boss, -/area/ruin/unpowered/xenonest) "bw" = ( /obj/structure/stone_tile/cracked{ dir = 4 @@ -492,19 +503,6 @@ /obj/structure/alien/weeds, /turf/template_noop, /area/ruin/unpowered/xenonest) -"bE" = ( -/obj/structure/stone_tile/surrounding_tile/cracked{ - dir = 4 - }, -/obj/structure/stone_tile/surrounding_tile/cracked{ - dir = 8 - }, -/obj/structure/stone_tile/surrounding_tile/cracked{ - dir = 1 - }, -/obj/structure/stone_tile/center/cracked, -/turf/open/chasm/lavaland, -/area/ruin/unpowered/xenonest) "dE" = ( /obj/structure/alien/weeds, /obj/structure/bed/nest, @@ -514,6 +512,12 @@ /obj/item/clothing/mask/facehugger/impregnated, /turf/open/floor/plating/asteroid/basalt/lava_land_surface, /area/ruin/unpowered/xenonest) +"gA" = ( +/obj/structure/alien/weeds, +/obj/structure/bed/nest, +/obj/effect/mob_spawn/alien/corpse/humanoid/sentinel, +/turf/open/floor/plating/asteroid/basalt/lava_land_surface, +/area/ruin/unpowered/xenonest) "iA" = ( /obj/structure/alien/weeds, /obj/structure/bed/nest, @@ -522,18 +526,24 @@ /obj/item/clothing/mask/facehugger/impregnated, /turf/open/floor/plating/asteroid/basalt/lava_land_surface, /area/ruin/unpowered/xenonest) -"kp" = ( -/obj/structure/alien/weeds, -/obj/item/reagent_containers/syringe/alien, -/turf/open/floor/plating/asteroid/basalt/lava_land_surface, -/area/ruin/unpowered/xenonest) "lG" = ( /obj/structure/alien/weeds, /obj/effect/mob_spawn/alien/corpse/humanoid/drone, /turf/open/floor/plating/asteroid/basalt/lava_land_surface, /area/ruin/unpowered/xenonest) -"pE" = ( -/obj/effect/mob_spawn/alien/corpse/humanoid/queen, +"lM" = ( +/obj/structure/stone_tile/block{ + dir = 4 + }, +/turf/open/chasm/lavaland, +/area/ruin/unpowered/xenonest) +"nj" = ( +/obj/effect/mob_spawn/alien/corpse/humanoid/praetorian, +/turf/open/floor/plating/asteroid/basalt/lava_land_surface, +/area/ruin/unpowered/xenonest) +"tY" = ( +/obj/structure/alien/weeds/node, +/obj/effect/mob_spawn/alien/corpse/humanoid/hunter, /turf/open/floor/plating/asteroid/basalt/lava_land_surface, /area/ruin/unpowered/xenonest) "wA" = ( @@ -546,12 +556,23 @@ /mob/living/simple_animal/hostile/alien/sentinel, /turf/open/floor/plating/asteroid/basalt/lava_land_surface, /area/ruin/unpowered/xenonest) +"zj" = ( +/obj/structure/stone_tile/block/cracked{ + dir = 1 + }, +/turf/open/chasm/lavaland, +/area/ruin/unpowered/xenonest) "Dd" = ( /obj/structure/alien/weeds, /obj/effect/decal/cleanable/blood/gibs, /obj/item/storage/backpack/duffelbag/sec/surgery, /turf/open/floor/plating/asteroid/basalt/lava_land_surface, /area/ruin/unpowered/xenonest) +"Ha" = ( +/obj/structure/alien/weeds, +/obj/item/reagent_containers/syringe/alien, +/turf/open/floor/plating/asteroid/basalt/lava_land_surface, +/area/ruin/unpowered/xenonest) "JM" = ( /obj/structure/alien/weeds/node, /obj/effect/mob_spawn/alien/corpse/humanoid/drone, @@ -1075,7 +1096,7 @@ ac ac ac bi -aY +ax ac ac ac @@ -1123,7 +1144,7 @@ an an ac ac -am +gA ac ac aJ @@ -1278,10 +1299,10 @@ ac Dd ag ak -ag +aP af ac -lG +ag ac ac an @@ -1357,7 +1378,7 @@ ab ac af ag -ar +tY lG ag ag @@ -1511,7 +1532,7 @@ ac ah af ah -JM +ar Vi ak ag @@ -1618,7 +1639,7 @@ ag wA ag ag -pE +nj ag at ag @@ -1640,7 +1661,7 @@ ab aZ aZ aZ -bm +ay aZ aZ aZ @@ -1718,7 +1739,7 @@ ah ar ah ak -kp +Ha at ag ag @@ -1742,8 +1763,8 @@ ac aZ bc bj -bp -bt +lM +aD bx aZ ab @@ -1794,7 +1815,7 @@ ba bd bk bq -bu +zj by aZ ab @@ -1823,7 +1844,7 @@ ac ag ar ag -ag +aO ac ab ab @@ -1845,7 +1866,7 @@ aZ be bo bs -bE +aK bz aZ ab @@ -1896,7 +1917,7 @@ aZ bf bl br -bv +aN bA aZ ab diff --git a/_maps/RandomRuins/SpaceRuins/skelter.dmm b/_maps/RandomRuins/SpaceRuins/skelter.dmm index f6e56a6348..77837392e4 100644 --- a/_maps/RandomRuins/SpaceRuins/skelter.dmm +++ b/_maps/RandomRuins/SpaceRuins/skelter.dmm @@ -2729,9 +2729,7 @@ /turf/open/floor/carpet, /area/ruin/space/has_grav/skelter/admin) "gx" = ( -/obj/machinery/door/firedoor{ - pixel_x = 0 - }, +/obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /obj/structure/cable/yellow{ icon_state = "1-2" @@ -2742,9 +2740,7 @@ /turf/open/floor/plasteel/showroomfloor, /area/ruin/space/has_grav/skelter/shields) "gy" = ( -/obj/machinery/door/firedoor{ - pixel_x = 0 - }, +/obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/supply/hidden, /obj/machinery/door/airlock/engineering{ name = "Shields" diff --git a/_maps/RandomRuins/StationRuins/Lavaland/Mining_Station/Mining_Station_Public_01.dmm b/_maps/RandomRuins/StationRuins/Lavaland/Mining_Station/Mining_Station_Public_01.dmm index 1aed2fdbb0..69cf7c0867 100644 --- a/_maps/RandomRuins/StationRuins/Lavaland/Mining_Station/Mining_Station_Public_01.dmm +++ b/_maps/RandomRuins/StationRuins/Lavaland/Mining_Station/Mining_Station_Public_01.dmm @@ -3170,7 +3170,9 @@ /turf/open/lava/smooth/lava_land_surface, /area/lavaland/surface/outdoors) "VY" = ( -/obj/structure/closet/emcloset, +/obj/structure/closet/emcloset{ + anchored = 1 + }, /obj/effect/turf_decal/tile/purple{ dir = 1 }, diff --git a/_maps/_basemap.dm b/_maps/_basemap.dm index 213211fc42..bf5b4f7d49 100644 --- a/_maps/_basemap.dm +++ b/_maps/_basemap.dm @@ -13,7 +13,7 @@ #include "map_files\BoxStation\BoxStation.dmm" #include "map_files\LambdaStation\lambda.dmm" - #ifdef TRAVISBUILDING + #ifdef CIBUILDING #include "templates.dm" #endif #endif diff --git a/_maps/map_files/BoxStation/BoxStation.dmm b/_maps/map_files/BoxStation/BoxStation.dmm index b81f55be21..612d4b757c 100644 --- a/_maps/map_files/BoxStation/BoxStation.dmm +++ b/_maps/map_files/BoxStation/BoxStation.dmm @@ -12995,22 +12995,35 @@ /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 4 }, -/turf/open/floor/plasteel/dark, +/obj/machinery/hydroponics/soil, +/turf/open/floor/grass, /area/chapel/main) "aCP" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 10 }, -/turf/open/floor/plasteel/dark, +/obj/structure/table/wood, +/obj/item/reagent_containers/food/snacks/grown/poppy{ + pixel_y = 5 + }, +/obj/item/reagent_containers/food/snacks/grown/harebell{ + pixel_y = 5 + }, +/obj/machinery/light{ + dir = 1 + }, +/turf/open/floor/wood/wood_large, /area/chapel/main) "aCQ" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 4 }, -/obj/machinery/light/small{ - dir = 1 +/obj/machinery/hydroponics/soil, +/obj/structure/window/reinforced{ + dir = 4; + pixel_x = 3 }, -/turf/open/floor/plasteel/dark, +/turf/open/floor/grass, /area/chapel/main) "aCR" = ( /turf/closed/wall, @@ -13536,7 +13549,7 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 4 }, -/turf/open/floor/plasteel/dark, +/turf/open/floor/wood/wood_large, /area/chapel/main) "aEi" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ @@ -13556,35 +13569,24 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 10 }, -/turf/open/floor/plasteel/dark, +/turf/open/floor/wood/wood_large, /area/chapel/main) "aEl" = ( /obj/effect/landmark/event_spawn, /turf/open/floor/plating, /area/maintenance/starboard/fore) "aEm" = ( -/obj/machinery/door/window{ - dir = 8; - name = "Mass Driver"; - req_access_txt = "22" +/obj/structure/bookcase, +/obj/machinery/camera{ + c_tag = "Chapel North" }, -/obj/machinery/mass_driver{ - dir = 4; - id = "chapelgun"; - name = "Holy Driver" - }, -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/turf/open/floor/plating, +/turf/open/floor/wood/wood_large, /area/chapel/main) "aEn" = ( -/obj/machinery/door/poddoor{ - id = "chapelgun"; - name = "Chapel Launcher Door" +/obj/structure/sign/warning/vacuum/external{ + pixel_y = 32 }, -/obj/structure/fans/tiny, -/turf/open/floor/plating, +/turf/open/floor/wood/wood_large, /area/chapel/main) "aEz" = ( /obj/machinery/power/apc{ @@ -13978,16 +13980,10 @@ /turf/open/floor/plasteel/dark, /area/chapel/main) "aFA" = ( -/obj/machinery/atmospherics/pipe/simple/supply/hidden, -/obj/machinery/computer/pod/old{ - density = 0; - icon = 'icons/obj/airlock_machines.dmi'; - icon_state = "airlock_control_standby"; - id = "chapelgun"; - name = "Mass Driver Controller"; - pixel_x = 24 +/obj/machinery/atmospherics/pipe/manifold/supply/hidden{ + dir = 8 }, -/turf/open/floor/plasteel/dark, +/turf/open/floor/wood/wood_large, /area/chapel/main) "aFB" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, @@ -14617,7 +14613,7 @@ departmentType = 2; pixel_y = 30 }, -/turf/open/floor/plasteel/grimy, +/turf/open/floor/wood/wood_large, /area/chapel/office) "aGV" = ( /obj/structure/disposalpipe/segment{ @@ -14652,7 +14648,7 @@ /obj/machinery/airalarm{ pixel_y = 25 }, -/turf/open/floor/plasteel/grimy, +/turf/open/floor/wood/wood_large, /area/chapel/office) "aGZ" = ( /obj/machinery/door/airlock/security{ @@ -14703,7 +14699,7 @@ pixel_y = 25 }, /obj/machinery/vending/wardrobe/chap_wardrobe, -/turf/open/floor/plasteel/grimy, +/turf/open/floor/wood/wood_large, /area/chapel/office) "aHg" = ( /obj/machinery/light_switch{ @@ -14712,7 +14708,7 @@ /obj/machinery/camera{ c_tag = "Chapel Office" }, -/turf/open/floor/plasteel/grimy, +/turf/open/floor/wood/wood_large, /area/chapel/office) "aHh" = ( /obj/structure/cable{ @@ -14724,9 +14720,9 @@ /turf/open/floor/plasteel, /area/gateway) "aHi" = ( -/obj/structure/closet/crate/coffin, -/obj/structure/window/reinforced{ - dir = 8 +/obj/machinery/door/morgue{ + name = "Confession Booth (Chaplain)"; + req_access_txt = "22" }, /turf/open/floor/plasteel/dark, /area/chapel/office) @@ -14743,42 +14739,47 @@ /turf/open/floor/plasteel, /area/gateway) "aHk" = ( -/obj/machinery/atmospherics/components/unary/vent_pump/on{ - dir = 4 - }, -/turf/open/floor/plasteel/dark, +/obj/effect/decal/cleanable/cobweb/cobweb2, +/obj/structure/table/wood, +/obj/item/clothing/under/misc/burial, +/obj/item/clothing/under/misc/burial, +/obj/item/clothing/under/misc/burial, +/obj/item/clothing/under/misc/burial, +/obj/item/clothing/under/misc/burial, +/obj/item/clothing/under/misc/burial, +/obj/item/clothing/under/misc/burial, +/turf/open/floor/wood/wood_large, /area/chapel/main) "aHl" = ( -/obj/structure/closet/crate/coffin, -/obj/machinery/door/window/eastleft{ - name = "Coffin Storage"; - req_access_txt = "22" +/obj/structure/chair/comfy/plywood, +/obj/machinery/light/floor, +/obj/item/radio/intercom{ + broadcasting = 1; + frequency = 1480; + name = "Confessional Intercom"; + pixel_x = 25 }, +/obj/effect/decal/cleanable/cobweb/cobweb2, /turf/open/floor/plasteel/dark, /area/chapel/office) "aHm" = ( -/obj/machinery/atmospherics/pipe/manifold/supply/hidden{ - dir = 4 - }, -/turf/open/floor/plasteel/dark, +/obj/structure/lattice, +/turf/closed/wall, /area/chapel/main) "aHn" = ( -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 4 +/obj/machinery/mass_driver{ + dir = 4; + id = "chapelgun"; + name = "Holy Driver" }, -/turf/open/floor/plasteel/dark, -/area/chapel/main) -"aHo" = ( -/obj/structure/table/glass, -/obj/item/reagent_containers/food/snacks/grown/poppy, -/obj/item/reagent_containers/food/snacks/grown/harebell, -/turf/open/floor/plasteel/chapel{ - dir = 4 +/obj/machinery/door/window{ + dir = 8; + name = "Mass Driver"; + req_access_txt = "22" + }, +/obj/effect/turf_decal/stripes/line{ + dir = 8 }, -/area/chapel/main) -"aHq" = ( -/obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/chapel/main) "aHu" = ( @@ -15278,9 +15279,14 @@ /turf/open/floor/plasteel/dark, /area/chapel/office) "aIz" = ( -/obj/machinery/disposal/bin, -/obj/structure/disposalpipe/trunk, -/turf/open/floor/plasteel/grimy, +/obj/structure/disposalpipe/segment{ + dir = 6 + }, +/obj/structure/table/wood, +/obj/item/storage/crayons{ + pixel_y = 8 + }, +/turf/open/floor/wood/wood_large, /area/chapel/office) "aIB" = ( /obj/structure/bodycontainer/crematorium{ @@ -15293,20 +15299,16 @@ /area/chapel/office) "aIC" = ( /obj/effect/landmark/start/chaplain, -/obj/structure/chair, -/turf/open/floor/plasteel/grimy, -/area/chapel/office) -"aID" = ( -/obj/structure/closet/crate/coffin, -/obj/structure/window/reinforced{ +/obj/structure/chair/comfy/plywood, +/obj/structure/disposalpipe/segment{ dir = 4 }, +/turf/open/floor/carpet, +/area/chapel/office) +"aID" = ( +/obj/effect/spawner/structure/window/reinforced/tinted, /turf/open/floor/plasteel/dark, /area/chapel/office) -"aIE" = ( -/obj/structure/table/glass, -/turf/open/floor/plasteel/chapel, -/area/chapel/main) "aIH" = ( /obj/structure/table, /obj/item/storage/box/lights/mixed, @@ -15328,7 +15330,7 @@ /area/construction/mining/aux_base) "aII" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on, -/turf/open/floor/plasteel/grimy, +/turf/open/floor/wood/wood_large, /area/chapel/office) "aIJ" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden, @@ -15783,15 +15785,14 @@ /area/hydroponics) "aJM" = ( /obj/structure/table/wood, -/obj/item/flashlight/lamp{ - pixel_y = 10 - }, /obj/structure/disposalpipe/segment, -/obj/item/nullrod, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 4 }, -/turf/open/floor/plasteel/grimy, +/obj/item/flashlight/lamp{ + pixel_y = 15 + }, +/turf/open/floor/wood/wood_large, /area/chapel/office) "aJO" = ( /obj/structure/table, @@ -15825,39 +15826,44 @@ /area/library) "aJT" = ( /obj/structure/table/wood, -/obj/item/paper_bin{ - pixel_x = -2; - pixel_y = 5 - }, -/obj/item/storage/crayons, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 4 }, -/turf/open/floor/plasteel/grimy, +/obj/item/paper_bin{ + pixel_y = 4 + }, +/obj/item/pen/fountain{ + pixel_y = 4 + }, +/turf/open/floor/carpet, /area/chapel/office) "aJU" = ( /obj/structure/table/wood, -/obj/item/pen, -/obj/item/reagent_containers/food/drinks/bottle/holywater, +/obj/item/reagent_containers/food/drinks/bottle/holywater{ + pixel_x = 9; + pixel_y = 4 + }, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 4 }, -/turf/open/floor/plasteel/grimy, +/obj/item/nullrod{ + pixel_x = -15; + pixel_y = 3 + }, +/turf/open/floor/carpet, /area/chapel/office) "aJV" = ( -/obj/structure/closet/crate/coffin, -/obj/machinery/door/window/eastleft{ - dir = 8; - name = "Coffin Storage"; - req_access_txt = "22" +/obj/effect/landmark/event_spawn, +/obj/effect/turf_decal/stripes/line{ + dir = 4 }, -/turf/open/floor/plasteel/dark, -/area/chapel/office) +/turf/open/floor/plating, +/area/chapel/main) "aJW" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 9 }, -/turf/open/floor/plasteel/grimy, +/turf/open/floor/wood/wood_large, /area/chapel/office) "aJX" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden, @@ -15916,10 +15922,10 @@ /turf/open/floor/plasteel, /area/gateway) "aKe" = ( -/obj/structure/table/glass, -/turf/open/floor/plasteel/chapel{ +/obj/structure/chair/wood/normal{ dir = 4 }, +/turf/open/floor/carpet, /area/chapel/main) "aKf" = ( /obj/structure/cable{ @@ -16248,7 +16254,7 @@ /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 4 }, -/turf/open/floor/plasteel/grimy, +/turf/open/floor/wood/wood_large, /area/chapel/office) "aLb" = ( /obj/structure/disposalpipe/segment{ @@ -16267,7 +16273,7 @@ /obj/machinery/atmospherics/components/unary/vent_pump/on{ dir = 8 }, -/turf/open/floor/plasteel/grimy, +/turf/open/floor/wood/wood_large, /area/chapel/office) "aLd" = ( /obj/structure/table, @@ -16286,13 +16292,13 @@ /turf/open/floor/plasteel, /area/hydroponics) "aLe" = ( -/obj/structure/chair{ - dir = 1 - }, /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 4 }, -/turf/open/floor/plasteel/grimy, +/obj/structure/chair/wood/normal{ + dir = 1 + }, +/turf/open/floor/wood/wood_large, /area/chapel/office) "aLf" = ( /obj/machinery/airalarm{ @@ -16816,13 +16822,14 @@ /obj/machinery/atmospherics/components/unary/vent_scrubber/on{ dir = 4 }, +/obj/structure/chair/wood/wings{ + dir = 8 + }, /turf/open/floor/plasteel/dark, /area/chapel/main) "aMM" = ( -/obj/machinery/camera{ - c_tag = "Chapel North" - }, -/turf/open/floor/plasteel/dark, +/obj/machinery/atmospherics/pipe/simple/supply/hidden, +/turf/open/floor/wood/wood_large, /area/chapel/main) "aMN" = ( /obj/machinery/chem_master/condimaster, @@ -16887,7 +16894,7 @@ /turf/open/floor/plasteel, /area/hallway/primary/port) "aMX" = ( -/turf/open/floor/plasteel/grimy, +/turf/open/floor/wood/wood_large, /area/chapel/office) "aMY" = ( /obj/machinery/atmospherics/pipe/manifold4w/scrubbers/hidden, @@ -17177,28 +17184,24 @@ /turf/open/floor/wood, /area/library) "aNW" = ( -/obj/machinery/door/airlock/public/glass{ - name = "Chapel Office"; +/turf/open/floor/wood/wood_large, +/area/chapel/main) +"aNX" = ( +/obj/structure/closet/crate/coffin, +/obj/machinery/door/window/eastright{ + dir = 8; + name = "Coffin Storage"; req_access_txt = "22" }, /turf/open/floor/plasteel/dark, -/area/chapel/office) -"aNX" = ( -/obj/item/radio/intercom{ - broadcasting = 1; - frequency = 1480; - name = "Confessional Intercom"; - pixel_x = 25 - }, -/obj/structure/chair, -/turf/open/floor/plasteel/dark, /area/chapel/main) "aNY" = ( -/obj/machinery/door/morgue{ - name = "Confession Booth (Chaplain)"; - req_access_txt = "22" +/obj/machinery/door/poddoor{ + id = "chapelgun"; + name = "Chapel Launcher Door" }, -/turf/open/floor/plasteel/dark, +/obj/structure/fans/tiny, +/turf/open/floor/plating, /area/chapel/main) "aNZ" = ( /obj/structure/chair, @@ -17679,7 +17682,12 @@ }, /area/chapel/main) "aPo" = ( -/obj/effect/spawner/structure/window/reinforced/tinted, +/obj/structure/closet/crate/coffin, +/obj/machinery/door/window/eastleft{ + dir = 8; + name = "Coffin Storage"; + req_access_txt = "22" + }, /turf/open/floor/plasteel/dark, /area/chapel/main) "aPp" = ( @@ -18085,7 +18093,11 @@ /area/chapel/main) "aQw" = ( /obj/structure/table/wood, -/turf/open/floor/plasteel/dark, +/obj/item/trash/candle{ + pixel_x = -5; + pixel_y = 2 + }, +/turf/open/floor/carpet, /area/chapel/main) "aQx" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden, @@ -18098,22 +18110,17 @@ }, /area/chapel/main) "aQz" = ( -/obj/item/radio/intercom{ - broadcasting = 1; - frequency = 1480; - name = "Confessional Intercom"; - pixel_x = 25 - }, -/obj/structure/chair{ - dir = 1 +/obj/structure/closet/crate/coffin, +/obj/structure/window/reinforced{ + dir = 8 }, /turf/open/floor/plasteel/dark, /area/chapel/main) "aQA" = ( -/obj/machinery/door/morgue{ - name = "Confession Booth" +/obj/machinery/atmospherics/components/unary/vent_pump/on{ + dir = 8 }, -/turf/open/floor/plasteel/dark, +/turf/open/floor/wood/wood_large, /area/chapel/main) "aQB" = ( /obj/effect/turf_decal/tile/red{ @@ -19111,24 +19118,32 @@ /turf/open/floor/plasteel/dark, /area/chapel/main) "aTf" = ( -/obj/structure/chair/stool, +/obj/structure/chair/pew/right{ + dir = 1 + }, /turf/open/floor/plasteel/chapel, /area/chapel/main) "aTg" = ( -/obj/structure/chair/stool, +/obj/structure/chair/pew/left{ + dir = 1 + }, /turf/open/floor/plasteel/chapel{ dir = 8 }, /area/chapel/main) "aTh" = ( -/obj/structure/chair/stool, /obj/machinery/atmospherics/pipe/simple/supply/hidden, +/obj/structure/chair/pew/right{ + dir = 1 + }, /turf/open/floor/plasteel/chapel, /area/chapel/main) "aTi" = ( -/obj/structure/chair/stool, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /obj/effect/landmark/start/assistant, +/obj/structure/chair/pew/left{ + dir = 1 + }, /turf/open/floor/plasteel/chapel{ dir = 8 }, @@ -19659,28 +19674,36 @@ /turf/open/floor/plasteel/dark, /area/chapel/main) "aUH" = ( -/obj/structure/chair/stool, /obj/effect/landmark/start/assistant, +/obj/structure/chair/pew/right{ + dir = 1 + }, /turf/open/floor/plasteel/chapel{ dir = 4 }, /area/chapel/main) "aUI" = ( -/obj/structure/chair/stool, +/obj/structure/chair/pew/left{ + dir = 1 + }, /turf/open/floor/plasteel/chapel{ dir = 1 }, /area/chapel/main) "aUJ" = ( -/obj/structure/chair/stool, /obj/machinery/atmospherics/pipe/simple/supply/hidden, +/obj/structure/chair/pew/right{ + dir = 1 + }, /turf/open/floor/plasteel/chapel{ dir = 4 }, /area/chapel/main) "aUK" = ( -/obj/structure/chair/stool, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, +/obj/structure/chair/pew/left{ + dir = 1 + }, /turf/open/floor/plasteel/chapel{ dir = 1 }, @@ -20207,8 +20230,10 @@ /turf/open/floor/wood, /area/library) "aVU" = ( -/obj/structure/chair/stool, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, +/obj/structure/chair/pew/left{ + dir = 1 + }, /turf/open/floor/plasteel/chapel{ dir = 8 }, @@ -21999,13 +22024,6 @@ }, /turf/open/floor/wood, /area/crew_quarters/heads/captain) -"bag" = ( -/obj/machinery/airalarm{ - dir = 1; - pixel_y = -22 - }, -/turf/open/floor/wood, -/area/crew_quarters/bar) "bah" = ( /obj/structure/extinguisher_cabinet{ pixel_y = -30 @@ -23874,14 +23892,15 @@ /turf/closed/wall, /area/maintenance/disposal) "bfb" = ( -/obj/structure/sign/warning/vacuum/external{ - pixel_y = 32 +/obj/machinery/computer/pod/old{ + density = 0; + icon = 'icons/obj/airlock_machines.dmi'; + icon_state = "airlock_control_standby"; + id = "chapelgun"; + name = "Mass Driver Controller"; + pixel_x = 24 }, -/obj/effect/landmark/event_spawn, -/obj/effect/turf_decal/stripes/line{ - dir = 4 - }, -/turf/open/floor/plating, +/turf/open/floor/wood/wood_large, /area/chapel/main) "bfc" = ( /obj/machinery/power/apc{ @@ -34004,9 +34023,6 @@ /area/medical/surgery) "bCJ" = ( /obj/machinery/atmospherics/pipe/manifold/supply/hidden, -/obj/machinery/light_switch{ - pixel_y = 26 - }, /turf/open/floor/plasteel/white, /area/medical/surgery) "bCK" = ( @@ -46267,7 +46283,7 @@ "chY" = ( /obj/machinery/shieldgen, /turf/open/floor/plating, -/area/engine/storage) +/area/engine/engineering) "cia" = ( /obj/effect/turf_decal/bot{ dir = 1 @@ -46617,7 +46633,7 @@ "ciW" = ( /obj/effect/landmark/blobstart, /turf/open/floor/plating, -/area/engine/storage) +/area/engine/engineering) "ciX" = ( /obj/structure/closet/crate, /obj/item/stack/sheet/metal/fifty, @@ -46632,14 +46648,14 @@ /obj/item/lightreplacer, /obj/item/lightreplacer, /turf/open/floor/plating, -/area/engine/storage) +/area/engine/engineering) "ciY" = ( /obj/machinery/door/poddoor{ id = "Secure Storage"; name = "secure storage" }, /turf/open/floor/plating, -/area/engine/storage) +/area/engine/engineering) "ciZ" = ( /turf/open/floor/plating, /area/engine/engineering) @@ -46947,7 +46963,7 @@ dir = 4 }, /turf/open/floor/plating, -/area/engine/storage) +/area/engine/engineering) "cjN" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 4 @@ -47234,11 +47250,11 @@ "ckB" = ( /obj/machinery/field/generator, /turf/open/floor/plating, -/area/engine/storage) +/area/engine/engineering) "ckC" = ( /obj/machinery/power/emitter, /turf/open/floor/plating, -/area/engine/storage) +/area/engine/engineering) "ckD" = ( /obj/effect/turf_decal/bot{ dir = 1 @@ -49323,9 +49339,12 @@ /turf/open/floor/plating, /area/ai_monitored/turret_protected/aisat_interior) "csT" = ( -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, -/obj/effect/landmark/xmastree, -/turf/open/floor/plasteel/dark, +/obj/structure/table/glass, +/obj/effect/decal/cleanable/cobweb/cobweb2, +/obj/item/storage/book/bible{ + pixel_y = -1 + }, +/turf/open/floor/wood/wood_large, /area/chapel/main) "csU" = ( /obj/structure/transit_tube/station/reverse, @@ -51957,14 +51976,11 @@ /turf/open/floor/plating, /area/maintenance/starboard/aft) "cBZ" = ( -/obj/structure/table/wood, -/obj/item/clothing/under/misc/burial, -/obj/item/clothing/under/misc/burial, -/obj/item/clothing/under/misc/burial, -/obj/item/clothing/under/misc/burial, -/obj/item/clothing/under/misc/burial, -/obj/item/clothing/under/misc/burial, -/turf/open/floor/plasteel/grimy, +/obj/structure/disposalpipe/trunk{ + dir = 8 + }, +/obj/machinery/disposal/bin, +/turf/open/floor/carpet, /area/chapel/office) "cCb" = ( /obj/structure/table, @@ -53407,10 +53423,6 @@ dir = 4 }, /obj/machinery/suit_storage_unit/atmos, -/obj/machinery/airalarm{ - dir = 1; - pixel_y = -22 - }, /obj/effect/turf_decal/stripes/line{ dir = 9 }, @@ -53432,6 +53444,10 @@ /obj/machinery/atmospherics/pipe/simple/supply/hidden, /turf/open/floor/plasteel/dark, /area/hallway/primary/central) +"dmX" = ( +/obj/effect/spawner/structure/window/reinforced, +/turf/open/floor/plating, +/area/chapel/main) "dnW" = ( /obj/effect/turf_decal/trimline/blue/filled/line{ dir = 8 @@ -53462,6 +53478,14 @@ icon_state = "carpetsymbol" }, /area/crew_quarters/theatre) +"dsJ" = ( +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, +/obj/structure/table/glass, +/obj/item/toy/figure/chaplain{ + pixel_y = -9 + }, +/turf/open/floor/wood/wood_large, +/area/chapel/main) "dtx" = ( /obj/structure/cable{ icon_state = "1-2" @@ -54381,8 +54405,9 @@ /turf/open/floor/plasteel, /area/security/range) "fsQ" = ( -/turf/open/floor/plating, -/area/engine/storage) +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, +/turf/open/floor/wood/wood_large, +/area/chapel/main) "fty" = ( /obj/structure/lattice, /obj/machinery/atmospherics/pipe/simple/orange/visible, @@ -56336,6 +56361,17 @@ /obj/machinery/atmospherics/pipe/simple/dark/visible, /turf/open/space/basic, /area/space/nearstation) +"kdF" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/closet/crate/coffin, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/effect/decal/cleanable/cobweb/cobweb2, +/turf/open/floor/plasteel/dark, +/area/chapel/main) "kdO" = ( /obj/machinery/pool/controller, /turf/open/floor/plasteel/yellowsiding, @@ -56734,6 +56770,10 @@ }, /turf/open/floor/plating, /area/maintenance/port/aft) +"kOL" = ( +/obj/structure/table/glass, +/turf/open/floor/wood/wood_large, +/area/chapel/main) "kPd" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on, /obj/structure/cable{ @@ -57074,6 +57114,15 @@ }, /turf/open/floor/plasteel, /area/science/circuit) +"lNB" = ( +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, +/obj/effect/landmark/xmastree{ + pixel_x = 14 + }, +/turf/open/floor/carpet, +/area/chapel/main) "lNH" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /obj/structure/cable{ @@ -57332,6 +57381,10 @@ /obj/effect/spawner/lootdrop/keg, /turf/open/floor/wood, /area/maintenance/bar) +"mtU" = ( +/obj/structure/sign/departments/holy, +/turf/closed/wall, +/area/chapel/main) "mug" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on{ dir = 8 @@ -57366,6 +57419,12 @@ /obj/machinery/atmospherics/pipe/simple/supply/hidden, /turf/open/floor/wood, /area/crew_quarters/theatre) +"mzv" = ( +/obj/machinery/door/morgue{ + name = "Confession Booth" + }, +/turf/open/floor/wood/wood_large, +/area/chapel/main) "mzB" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /obj/machinery/door/window, @@ -57575,6 +57634,14 @@ }, /turf/open/floor/plasteel, /area/crew_quarters/locker) +"mZx" = ( +/obj/structure/table/glass, +/obj/item/storage/box/matches{ + pixel_x = 4; + pixel_y = -8 + }, +/turf/open/floor/wood/wood_large, +/area/chapel/main) "naI" = ( /turf/open/space, /area/space/station_ruins) @@ -58844,6 +58911,14 @@ icon_state = "wood-broken2" }, /area/maintenance/port/fore) +"pXG" = ( +/obj/structure/table/wood, +/obj/item/candle{ + pixel_x = 5; + pixel_y = 2 + }, +/turf/open/floor/carpet, +/area/chapel/main) "pYQ" = ( /obj/structure/reagent_dispensers/watertank, /obj/item/reagent_containers/glass/bucket, @@ -58938,6 +59013,13 @@ }, /turf/open/floor/plating, /area/maintenance/port/fore) +"qkn" = ( +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, +/obj/machinery/light{ + dir = 8 + }, +/turf/open/floor/wood/wood_large, +/area/chapel/main) "qkC" = ( /obj/structure/cable{ icon_state = "4-8" @@ -59027,6 +59109,11 @@ /obj/structure/lattice, /turf/closed/wall/r_wall, /area/crew_quarters/heads/captain) +"qCR" = ( +/obj/structure/musician/piano, +/obj/effect/decal/cleanable/cobweb, +/turf/open/floor/plasteel/dark, +/area/chapel/main) "qEB" = ( /obj/machinery/hydroponics/soil{ pixel_y = 8 @@ -59160,6 +59247,13 @@ }, /turf/open/floor/plasteel/white, /area/medical/medbay/lobby) +"qUh" = ( +/obj/machinery/door/airlock/public/glass{ + name = "Chapel Office"; + req_access_txt = "22" + }, +/turf/open/floor/plasteel/dark, +/area/chapel/office) "qVP" = ( /obj/effect/spawner/structure/window, /obj/machinery/atmospherics/pipe/simple/supply/hidden{ @@ -59442,6 +59536,14 @@ }, /turf/open/floor/plasteel, /area/security/prison) +"rxF" = ( +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, +/obj/structure/table/glass, +/obj/item/storage/book/bible{ + pixel_y = 17 + }, +/turf/open/floor/wood/wood_large, +/area/chapel/main) "ryr" = ( /obj/effect/turf_decal/tile/blue, /obj/effect/turf_decal/tile/blue{ @@ -60469,6 +60571,12 @@ }, /turf/open/floor/wood, /area/maintenance/bar) +"tSm" = ( +/obj/item/kirbyplants{ + icon_state = "plant-18" + }, +/turf/open/floor/plasteel/dark, +/area/chapel/main) "tSo" = ( /obj/structure/lattice, /obj/machinery/atmospherics/pipe/simple/dark/visible{ @@ -61202,6 +61310,19 @@ /obj/item/clothing/under/misc/pj/blue, /turf/open/floor/plasteel, /area/crew_quarters/fitness) +"vqE" = ( +/obj/structure/chair/wood/normal{ + dir = 1 + }, +/obj/machinery/light/floor, +/obj/item/radio/intercom{ + broadcasting = 1; + frequency = 1480; + name = "Confessional Intercom"; + pixel_x = -25 + }, +/turf/open/floor/plasteel/dark, +/area/chapel/main) "vqP" = ( /obj/structure/bed/dogbed{ desc = "A comfy-looking pet bed. You can even strap your pet in, in case the gravity turns off."; @@ -62236,8 +62357,17 @@ /turf/open/floor/carpet, /area/library) "xES" = ( -/turf/closed/wall/r_wall, -/area/engine/storage) +/obj/structure/table/glass, +/obj/item/storage/fancy/candle_box{ + pixel_x = 5; + pixel_y = 4 + }, +/obj/item/storage/fancy/candle_box{ + pixel_x = 1; + pixel_y = 4 + }, +/turf/open/floor/wood/wood_large, +/area/chapel/main) "xFM" = ( /obj/item/clothing/gloves/color/rainbow, /obj/item/clothing/head/soft/rainbow, @@ -62327,6 +62457,12 @@ /obj/item/instrument/trombone, /turf/open/floor/wood, /area/crew_quarters/theatre) +"xRa" = ( +/obj/item/kirbyplants{ + icon_state = "plant-20" + }, +/turf/open/floor/plasteel/dark, +/area/chapel/main) "xSW" = ( /obj/effect/turf_decal/tile/red{ dir = 1 @@ -87889,14 +88025,14 @@ cdc cdZ bVI cay -xES -xES -xES -xES -xES -xES -xES -xES +ccw +ccw +ccw +ccw +ccw +ccw +ccw +ccw cfL coH cBO @@ -88146,14 +88282,14 @@ bWB cec bVI kNv -xES +ccw chY ciX cjM ckB ckB ckB -xES +ccw cnY coH cgR @@ -88403,14 +88539,14 @@ cde ceb bVI cay -xES +ccw chY -fsQ +ciZ ciW ckB ckB ckC -xES +ccw cnX coH cps @@ -88660,14 +88796,14 @@ cdf ced bVI cay -xES -fsQ -fsQ -fsQ +ccw +ciZ +ciZ +ciZ ckC ckC ckC -xES +ccw coa coJ clJ @@ -88917,14 +89053,14 @@ bWB bWB bVI cay -xES -xES +ccw +ccw ciY ciY -xES -xES -xES -xES +ccw +ccw +ccw +ccw cnZ coH cgI @@ -99147,7 +99283,7 @@ aSZ aQc qaY acN -bag +aKR aJC aYV aYV @@ -108390,7 +108526,7 @@ cBZ aJT aLc aFw -aFz +tSm aFz aFz aRR @@ -108400,7 +108536,7 @@ aFz aRS aXW baz -aCR +mtU bcx aXq aYV @@ -108646,7 +108782,7 @@ aGY aII aJW aMX -aNW +qUh aFz aPl aQv @@ -108656,7 +108792,7 @@ aUI aTg aRS aZf -aFz +xRa bbF aYV aXq @@ -108900,8 +109036,8 @@ aCM aEg aFw aHi -aHi -aJV +aFw +aFw aFw aFw aFz @@ -109158,18 +109294,18 @@ aEi aFw aHl aID -aID -aFw -aMM -aFz +vqE +aCR +qCR aFz +aRS aQw aRS aRS aRS aRS aRS -aZf +lNB aRS bbF aYV @@ -109412,15 +109548,15 @@ aAz asB aCO aEh -aFz -aHk -aFz -aFz -aTe +aCR +aCR +aCR +mzv +aCR aML aFz -aFz -aQw +aRS +pXG cdl aRS aRS @@ -109669,11 +109805,11 @@ aAA asB aCQ aEk -aFB -aHn -aFB -csT -aFB +fsQ +dsJ +rxF +fsQ +qkn aLr aFB aPn @@ -109925,12 +110061,12 @@ awO awO asB aCP -aEj +aMM aFA -aHm -aEj -aEj -aEj +aMM +aMM +aMM +aMM aEj aEj aPm @@ -109941,7 +110077,7 @@ aUJ aTh aXz aZg -aFz +xRa bbF aYV bdv @@ -110181,18 +110317,18 @@ ayj azx aAB asB -aCR aEm -aCR -aPl -aQv -aPl -aQv -aCR -aNY -aCR +aNW aQA -aCR +aNW +aNW +aNW +aNW +aFz +aFz +aFz +aFz +aFz aTj aFz aVV @@ -110438,14 +110574,14 @@ asB asB asB asB -aCR +aHk +aNW bfb -aCR -aHo -aIE aKe -aIE -aCR +aKe +aKe +aNW +kdF aNX aPo aQz @@ -110694,14 +110830,14 @@ atS aaf aaf aaf -atS +asB aCR aEn aCR -aHq -aHq -aHq -aHq +aKe +aKe +aKe +aNW aCR aCR aCR @@ -110951,14 +111087,14 @@ atS aoV aoV aaf -atS -aaf -aaa -aaf -aaa -aaa -aaa -aaa +gXs +aHm +aHn +dmX +aNW +aNW +aNW +aNW aMZ aNZ aPp @@ -111208,14 +111344,14 @@ aaH aoV aoV aaf -atS -aaf -aaa -aaf -aaa -aaa -aaa -aaf +gXs +aHm +aJV +dmX +csT +kOL +mZx +xES aMZ aOb aPr @@ -111465,14 +111601,14 @@ aaH aoV aoV aoV -atS -aaf -aaa -aaf -aaa -aaa -aaa -aaf +gXs +aHm +aNY +aCR +dmX +dmX +dmX +dmX aMZ aOa aVX @@ -111722,7 +111858,7 @@ atS aoV aoV aoV -atS +gXs aaf aaa aaf diff --git a/_maps/map_files/CogStation/CogStation.dmm b/_maps/map_files/CogStation/CogStation.dmm index 6f5bab0498..e41f6c7d89 100644 --- a/_maps/map_files/CogStation/CogStation.dmm +++ b/_maps/map_files/CogStation/CogStation.dmm @@ -6004,12 +6004,12 @@ c_tag = "Security Checkpoint"; pixel_x = 22 }, -/obj/machinery/newscaster/security_unit{ - pixel_y = 32 - }, /obj/structure/cable{ icon_state = "4-8" }, +/obj/machinery/airalarm{ + pixel_y = 23 + }, /turf/open/floor/plasteel, /area/security/checkpoint) "aoz" = ( @@ -32290,10 +32290,6 @@ dir = 8; light_color = "#e8eaff" }, -/obj/machinery/airalarm{ - dir = 4; - pixel_x = -22 - }, /turf/open/floor/plasteel, /area/hydroponics) "bsl" = ( @@ -71184,6 +71180,13 @@ /obj/machinery/atmospherics/pipe/simple/yellow/visible, /turf/open/floor/plasteel, /area/engine/atmos) +"pMW" = ( +/obj/machinery/airalarm{ + dir = 1; + pixel_y = -22 + }, +/turf/open/floor/plasteel, +/area/hydroponics) "pZq" = ( /obj/structure/disposalpipe/sorting/mail/flip{ dir = 8; @@ -121382,7 +121385,7 @@ amV aqI aqB aGO -auy +pMW aqB aqI amV diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index 07902b28b1..368b85938c 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -49530,7 +49530,7 @@ }, /obj/machinery/atmospherics/pipe/simple/supply/hidden, /obj/effect/turf_decal/stripes/line{ - dir = 10 + dir = 8 }, /turf/open/floor/plasteel, /area/engine/gravity_generator) @@ -113323,10 +113323,6 @@ /obj/item/clothing/gloves/color/black, /obj/item/storage/box/evidence, /obj/item/taperecorder, -/obj/machinery/airalarm{ - dir = 8; - pixel_x = 24 - }, /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 408efad32f..1b37eea20c 100644 --- a/_maps/map_files/KiloStation/KiloStation.dmm +++ b/_maps/map_files/KiloStation/KiloStation.dmm @@ -30529,9 +30529,6 @@ dir = 8 }, /obj/structure/closet/bombcloset, -/obj/machinery/airalarm{ - pixel_y = 24 - }, /turf/open/floor/plasteel/dark, /area/science/mixing) "aXC" = ( @@ -43701,10 +43698,6 @@ /obj/structure/window/reinforced{ dir = 1 }, -/obj/machinery/airalarm{ - dir = 4; - pixel_x = -22 - }, /mob/living/simple_animal/chicken{ desc = "The arch-nemesis of Kentucky."; name = "Popeye"; @@ -46363,9 +46356,6 @@ "bwK" = ( /obj/structure/flora/grass/jungle/b, /obj/structure/flora/ausbushes/sparsegrass, -/obj/machinery/airalarm{ - pixel_y = 22 - }, /turf/open/floor/grass, /area/chapel/main) "bwL" = ( @@ -48132,16 +48122,6 @@ }, /turf/open/floor/plasteel/showroomfloor, /area/security/brig) -"bzx" = ( -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/turf/closed/wall, -/area/crew_quarters/locker) "bzy" = ( /obj/machinery/light/small{ dir = 8 @@ -58156,10 +58136,6 @@ icon_state = "plant-02"; pixel_y = 3 }, -/obj/machinery/airalarm{ - dir = 4; - pixel_x = -22 - }, /obj/machinery/camera{ c_tag = "Prison Wing Cells"; dir = 4; @@ -61358,7 +61334,7 @@ dir = 10 }, /turf/open/floor/plasteel, -/area/space) +/area/security/warden) "bUs" = ( /obj/machinery/door/firedoor, /obj/machinery/door/airlock/command/glass{ @@ -67210,10 +67186,6 @@ /obj/structure/cable{ icon_state = "1-4" }, -/obj/machinery/airalarm{ - dir = 1; - pixel_y = -22 - }, /turf/open/floor/plasteel, /area/security/main) "cdU" = ( @@ -71327,9 +71299,9 @@ icon_gib = "magicarp_gib"; icon_living = "magicarp"; icon_state = "magicarp"; + maxHealth = 200; max_co2 = 5; max_tox = 2; - maxHealth = 200; melee_damage_lower = 15; melee_damage_upper = 20; min_oxy = 5; @@ -83281,10 +83253,6 @@ /obj/machinery/atmospherics/pipe/simple/yellow/visible{ dir = 5 }, -/obj/machinery/airalarm{ - dir = 4; - pixel_x = -23 - }, /obj/machinery/camera{ c_tag = "Atmospherics Port Tanks"; dir = 4; @@ -108992,7 +108960,7 @@ bss btV aEu bxW -bzx +bIV bKq bKq bKq diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index 958ab2dc5a..c2a0e5c353 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -1111,10 +1111,6 @@ /turf/open/floor/plasteel, /area/security/prison) "acx" = ( -/obj/machinery/airalarm{ - dir = 8; - pixel_x = 24 - }, /obj/machinery/cryopod{ dir = 8 }, @@ -40497,10 +40493,9 @@ /area/maintenance/port) "bBr" = ( /obj/machinery/airalarm{ - dir = 4; - pixel_x = -23 + dir = 1; + pixel_y = -22 }, -/obj/structure/displaycase/trophy, /turf/open/floor/wood, /area/library) "bBs" = ( @@ -45866,10 +45861,6 @@ /area/library) "bML" = ( /obj/machinery/light/small, -/obj/machinery/airalarm{ - dir = 1; - pixel_y = -22 - }, /turf/open/floor/wood, /area/library) "bMM" = ( @@ -59581,6 +59572,10 @@ /obj/structure/chair{ dir = 1 }, +/obj/machinery/airalarm{ + dir = 4; + pixel_x = -23 + }, /turf/open/floor/plasteel/dark, /area/medical/surgery) "coz" = ( @@ -60135,9 +60130,6 @@ /obj/structure/cable/yellow{ icon_state = "4-8" }, -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 4 - }, /obj/structure/disposalpipe/junction/flip{ dir = 8 }, @@ -60145,6 +60137,9 @@ /obj/effect/turf_decal/tile/purple{ dir = 4 }, +/obj/machinery/atmospherics/pipe/manifold/supply/hidden{ + dir = 1 + }, /turf/open/floor/plasteel/white, /area/science/research) "cpx" = ( @@ -60947,9 +60942,6 @@ /obj/structure/cable/yellow{ icon_state = "1-2" }, -/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{ - dir = 1 - }, /obj/structure/disposalpipe/segment, /obj/effect/turf_decal/tile/purple, /obj/effect/turf_decal/tile/purple{ @@ -60958,6 +60950,10 @@ /obj/effect/turf_decal/tile/purple{ dir = 8 }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 + }, /turf/open/floor/plasteel/white, /area/science/research) "cqP" = ( @@ -61465,7 +61461,6 @@ /obj/structure/cable/yellow{ icon_state = "1-2" }, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /obj/machinery/door/firedoor, /obj/structure/disposalpipe/segment, /obj/machinery/door/airlock/research{ @@ -61477,6 +61472,7 @@ name = "biohazard containment shutters" }, /obj/effect/turf_decal/delivery, +/obj/machinery/atmospherics/pipe/simple/supply/hidden, /turf/open/floor/plasteel, /area/science/storage) "crU" = ( @@ -61595,10 +61591,6 @@ /turf/open/floor/plasteel/white, /area/medical/surgery) "csl" = ( -/obj/machinery/airalarm{ - dir = 1; - pixel_y = -22 - }, /obj/structure/window/reinforced{ dir = 8 }, @@ -62156,11 +62148,11 @@ /obj/structure/cable/yellow{ icon_state = "1-2" }, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /obj/structure/disposalpipe/segment, /obj/effect/turf_decal/stripes/line{ dir = 9 }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden, /turf/open/floor/plasteel, /area/science/storage) "cth" = ( @@ -62531,24 +62523,21 @@ /obj/structure/cable/yellow{ icon_state = "1-4" }, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ - dir = 5 - }, /obj/structure/disposalpipe/segment{ dir = 5 }, /obj/effect/turf_decal/stripes/line{ dir = 8 }, +/obj/machinery/atmospherics/components/unary/vent_pump/on{ + dir = 1 + }, /turf/open/floor/plasteel, /area/science/storage) "ctY" = ( /obj/structure/cable/yellow{ icon_state = "4-8" }, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ - dir = 10 - }, /obj/structure/chair/stool, /obj/structure/disposalpipe/segment{ dir = 10 @@ -62568,10 +62557,6 @@ /area/science/storage) "cua" = ( /obj/machinery/portable_atmospherics/canister/oxygen, -/obj/machinery/airalarm{ - dir = 8; - pixel_x = 24 - }, /obj/effect/turf_decal/bot, /turf/open/floor/plasteel, /area/science/storage) @@ -63127,7 +63112,6 @@ /turf/open/floor/plasteel, /area/science/storage) "cuU" = ( -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /obj/structure/disposalpipe/segment, /obj/effect/turf_decal/stripes/line{ dir = 4 @@ -63668,12 +63652,12 @@ /turf/open/floor/plasteel, /area/science/storage) "cvW" = ( -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /obj/structure/disposalpipe/segment, /obj/effect/landmark/blobstart, /obj/effect/turf_decal/stripes/line{ dir = 4 }, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on, /turf/open/floor/plasteel, /area/science/storage) "cvX" = ( @@ -68931,13 +68915,13 @@ pixel_x = -25; pixel_y = -5 }, -/obj/machinery/airalarm{ - dir = 1; - pixel_y = -22 - }, /obj/effect/turf_decal/stripes/corner{ dir = 4 }, +/obj/machinery/airalarm/unlocked{ + dir = 1; + pixel_y = -22 + }, /turf/open/floor/plasteel/white, /area/science/mixing) "cGm" = ( @@ -102705,7 +102689,7 @@ bue bwa bxU bzD -bBr +dmD bSx bEw bzE @@ -103740,7 +103724,7 @@ bGs bHS bzE bLk -bzE +bBr bue bPS bPR @@ -117641,7 +117625,7 @@ cmQ cok cpy cqQ -cgq +crR cti ctZ cuV diff --git a/_maps/map_files/OmegaStation/OmegaStation.dmm b/_maps/map_files/OmegaStation/OmegaStation.dmm index f4d798511f..6f7f211b3e 100644 --- a/_maps/map_files/OmegaStation/OmegaStation.dmm +++ b/_maps/map_files/OmegaStation/OmegaStation.dmm @@ -4924,11 +4924,11 @@ /obj/effect/turf_decal/stripes/end{ dir = 1 }, -/obj/item/gun/energy/e_gun/hos, /obj/effect/turf_decal/tile/neutral, /obj/effect/turf_decal/tile/neutral{ dir = 4 }, +/obj/item/gun/energy/e_gun/hos, /turf/open/floor/plasteel/dark, /area/crew_quarters/heads/captain/private) "ahI" = ( @@ -40544,6 +40544,9 @@ name = "Starboard Quater Maintenance APC"; pixel_y = -26 }, +/obj/structure/cable/white{ + icon_state = "0-8" + }, /turf/open/floor/plating{ icon_state = "panelscorched" }, diff --git a/_maps/map_files/PubbyStation/PubbyStation.dmm b/_maps/map_files/PubbyStation/PubbyStation.dmm index 12ae0092f0..12c507c2bf 100644 --- a/_maps/map_files/PubbyStation/PubbyStation.dmm +++ b/_maps/map_files/PubbyStation/PubbyStation.dmm @@ -16530,6 +16530,9 @@ /obj/structure/cable{ icon_state = "4-8" }, +/obj/machinery/airalarm{ + pixel_y = 22 + }, /turf/open/floor/plasteel, /area/quartermaster/warehouse) "aMr" = ( @@ -47631,6 +47634,9 @@ pixel_x = -25; specialfunctions = 4 }, +/obj/machinery/airalarm{ + pixel_y = 22 + }, /turf/open/floor/plasteel/grimy, /area/chapel/main/monastery) "cgM" = ( @@ -47979,6 +47985,9 @@ pixel_x = -25; specialfunctions = 4 }, +/obj/machinery/airalarm{ + pixel_y = 22 + }, /turf/open/floor/plasteel/grimy, /area/chapel/main/monastery) "cip" = ( @@ -51466,6 +51475,10 @@ name = "Coffin Storage"; req_one_access_txt = "22" }, +/obj/machinery/airalarm{ + dir = 8; + pixel_x = 24 + }, /turf/open/floor/plasteel/dark, /area/chapel/main/monastery) "cvu" = ( @@ -59434,6 +59447,10 @@ /obj/effect/turf_decal/tile/yellow{ dir = 8 }, +/obj/machinery/airalarm{ + dir = 8; + pixel_x = 23 + }, /turf/open/floor/plasteel, /area/construction/mining/aux_base) "qXq" = ( diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index c9decee834..0000000000 --- a/appveyor.yml +++ /dev/null @@ -1,15 +0,0 @@ -version: '{build}' -skip_branch_with_pr: true -shallow_clone: true -branches: - except: - - ___TGS3TempBranch - - ___TGSTempBranch -cache: - - C:\byond\ -> dependencies.sh -build_script: - - ps: tools/appveyor/build.ps1 - - ps: "$deployPath = $env:APPVEYOR_BUILD_FOLDER + '/deploy'; bash tools/deploy.sh $deployPath" - - ps: "[System.IO.Compression.ZipFile]::CreateFromDirectory($env:APPVEYOR_BUILD_FOLDER + '/deploy', $env:APPVEYOR_BUILD_FOLDER + '/deploy.zip')" -artifacts: - - path: deploy.zip diff --git a/code/__DEFINES/MC.dm b/code/__DEFINES/MC.dm index bad64846d6..cad75fbfe4 100644 --- a/code/__DEFINES/MC.dm +++ b/code/__DEFINES/MC.dm @@ -22,49 +22,45 @@ #define START_PROCESSING(Processor, Datum) if (!(Datum.datum_flags & DF_ISPROCESSING)) {Datum.datum_flags |= DF_ISPROCESSING;Processor.processing += Datum} #define STOP_PROCESSING(Processor, Datum) Datum.datum_flags &= ~DF_ISPROCESSING;Processor.processing -= Datum;Processor.currentrun -= Datum -//SubSystem flags (Please design any new flags so that the default is off, to make adding flags to subsystems easier) +//! SubSystem flags (Please design any new flags so that the default is off, to make adding flags to subsystems easier) -//subsystem does not initialize. -#define SS_NO_INIT (1<<0) +/// subsystem does not initialize. +#define SS_NO_INIT 1 -//subsystem does not fire. -// (like can_fire = 0, but keeps it from getting added to the processing subsystems list) -// (Requires a MC restart to change) -#define SS_NO_FIRE (1<<1) +/** subsystem does not fire. */ +/// (like can_fire = 0, but keeps it from getting added to the processing subsystems list) +/// (Requires a MC restart to change) +#define SS_NO_FIRE 2 -//subsystem only runs on spare cpu (after all non-background subsystems have ran that tick) -// SS_BACKGROUND has its own priority bracket -#define SS_BACKGROUND (1<<2) +/** Subsystem only runs on spare cpu (after all non-background subsystems have ran that tick) */ +/// SS_BACKGROUND has its own priority bracket, this overrides SS_TICKER's priority bump +#define SS_BACKGROUND 4 -//subsystem does not tick check, and should not run unless there is enough time (or its running behind (unless background)) -#define SS_NO_TICK_CHECK (1<<3) +/// subsystem does not tick check, and should not run unless there is enough time (or its running behind (unless background)) +#define SS_NO_TICK_CHECK 8 -//Treat wait as a tick count, not DS, run every wait ticks. -// (also forces it to run first in the tick, above even SS_NO_TICK_CHECK subsystems) -// (implies all runlevels because of how it works) -// (overrides SS_BACKGROUND) -// This is designed for basically anything that works as a mini-mc (like SStimer) -#define SS_TICKER (1<<4) +/** Treat wait as a tick count, not DS, run every wait ticks. */ +/// (also forces it to run first in the tick (unless SS_BACKGROUND)) +/// (implies all runlevels because of how it works) +/// This is designed for basically anything that works as a mini-mc (like SStimer) +#define SS_TICKER 16 -//keep the subsystem's timing on point by firing early if it fired late last fire because of lag -// ie: if a 20ds subsystem fires say 5 ds late due to lag or what not, its next fire would be in 15ds, not 20ds. -#define SS_KEEP_TIMING (1<<5) +/** keep the subsystem's timing on point by firing early if it fired late last fire because of lag */ +/// ie: if a 20ds subsystem fires say 5 ds late due to lag or what not, its next fire would be in 15ds, not 20ds. +#define SS_KEEP_TIMING 32 -//Calculate its next fire after its fired. -// (IE: if a 5ds wait SS takes 2ds to run, its next fire should be 5ds away, not 3ds like it normally would be) -// This flag overrides SS_KEEP_TIMING -#define SS_POST_FIRE_TIMING (1<<6) +/** Calculate its next fire after its fired. */ +/// (IE: if a 5ds wait SS takes 2ds to run, its next fire should be 5ds away, not 3ds like it normally would be) +/// This flag overrides SS_KEEP_TIMING +#define SS_POST_FIRE_TIMING 64 -/// Show in stat() by default even if SS_NO_FIRE -#define SS_ALWAYS_SHOW_STAT (1<<7) - -//SUBSYSTEM STATES -#define SS_IDLE 0 //aint doing shit. -#define SS_QUEUED 1 //queued to run -#define SS_RUNNING 2 //actively running -#define SS_PAUSED 3 //paused by mc_tick_check -#define SS_SLEEPING 4 //fire() slept. -#define SS_PAUSING 5 //in the middle of pausing +//! SUBSYSTEM STATES +#define SS_IDLE 0 /// ain't doing shit. +#define SS_QUEUED 1 /// queued to run +#define SS_RUNNING 2 /// actively running +#define SS_PAUSED 3 /// paused by mc_tick_check +#define SS_SLEEPING 4 /// fire() slept. +#define SS_PAUSING 5 /// in the middle of pausing #define SUBSYSTEM_DEF(X) GLOBAL_REAL(SS##X, /datum/controller/subsystem/##X);\ /datum/controller/subsystem/##X/New(){\ diff --git a/code/__DEFINES/_extools.dm b/code/__DEFINES/_extools.dm index 4513243aae..e01e09a3d3 100644 --- a/code/__DEFINES/_extools.dm +++ b/code/__DEFINES/_extools.dm @@ -1 +1,38 @@ -#define EXTOOLS (world.system_type == MS_WINDOWS ? "byond-extools.dll" : "libbyond-extools.so") +// _extools_api.dm - DM API for extools extension library +// (blatently stolen from rust_g) +// +// To configure, create a `extools.config.dm` and set what you care about from +// the following options: +// +// #define EXTOOLS "path/to/extools" +// Override the .dll/.so detection logic with a fixed path or with detection +// logic of your own. + +#ifndef EXTOOLS +// Default automatic EXTOOLS detection. +// On Windows, looks in the standard places for `byond-extools.dll`. +// On Linux, looks in the standard places for`libbyond-extools.so`. + +/* This comment bypasses grep checks */ /var/__extools + +/proc/__detect_extools() + if (world.system_type == UNIX) + if (fexists("./libbyond-extools.so")) + // No need for LD_LIBRARY_PATH badness. + return __extools = "./libbyond-extools.so" + else + // It's not in the current directory, so try others + return __extools = "libbyond-extools.so" + else + return __extools = "byond-extools.dll" + +#define EXTOOLS (__extools || __detect_extools()) +#endif + +#ifndef UNIT_TESTS // use default logging as extools is broken on travis +#define EXTOOLS_LOGGING // rust_g is used as a fallback if this is undefined +#endif + +/proc/extools_log_write() + +/proc/extools_finalize_logging() diff --git a/code/__DEFINES/_flags/_flags.dm b/code/__DEFINES/_flags/_flags.dm index 6e018b1eeb..f12e3618f7 100644 --- a/code/__DEFINES/_flags/_flags.dm +++ b/code/__DEFINES/_flags/_flags.dm @@ -163,5 +163,19 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204 else if(!HAS_TRAIT(x, TRAIT_KEEP_TOGETHER))\ x.appearance_flags &= ~KEEP_TOGETHER +//dir macros +///Returns true if the dir is diagonal, false otherwise +#define ISDIAGONALDIR(d) (d&(d-1)) +///True if the dir is north or south, false therwise +#define NSCOMPONENT(d) (d&(NORTH|SOUTH)) +///True if the dir is east/west, false otherwise +#define EWCOMPONENT(d) (d&(EAST|WEST)) +///Flips the dir for north/south directions +#define NSDIRFLIP(d) (d^(NORTH|SOUTH)) +///Flips the dir for east/west directions +#define EWDIRFLIP(d) (d^(EAST|WEST)) +///Turns the dir by 180 degrees +#define DIRFLIP(d) turn(d, 180) + /// 33554431 (2^24 - 1) is the maximum value our bitflags can reach. #define MAX_BITFLAG_DIGITS 8 diff --git a/code/__DEFINES/admin.dm b/code/__DEFINES/admin.dm index 143063b4e9..f6293454ee 100644 --- a/code/__DEFINES/admin.dm +++ b/code/__DEFINES/admin.dm @@ -91,3 +91,6 @@ #define SPAM_TRIGGER_WARNING 5 //Number of identical messages required before the spam-prevention will warn you to stfu #define SPAM_TRIGGER_AUTOMUTE 10 //Number of identical messages required before the spam-prevention will automute you + +#define STICKYBAN_DB_CACHE_TIME 10 SECONDS +#define STICKYBAN_ROGUE_CHECK_TIME 5 diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm index 68515426c3..e71243994d 100644 --- a/code/__DEFINES/antagonists.dm +++ b/code/__DEFINES/antagonists.dm @@ -69,6 +69,9 @@ #define LINGBLOOD_EXPLOSION_THRESHOLD (LINGBLOOD_DETECTION_THRESHOLD * LINGBLOOD_EXPLOSION_MULT) //Hey, important to note here: the explosion threshold is explicitly more than, rather than more than or equal to. This stops a single loud ability from triggering the explosion threshold. ///Heretics -- +GLOBAL_LIST_EMPTY(living_heart_cache) //A list of all living hearts in existance, for us to iterate through. + + #define IS_HERETIC(mob) (mob.mind?.has_antag_datum(/datum/antagonist/heretic)) #define IS_HERETIC_MONSTER(mob) (mob.mind?.has_antag_datum(/datum/antagonist/heretic_monster)) diff --git a/code/__DEFINES/dcs/helpers.dm b/code/__DEFINES/dcs/helpers.dm index 182035db9b..ba2b9a704a 100644 --- a/code/__DEFINES/dcs/helpers.dm +++ b/code/__DEFINES/dcs/helpers.dm @@ -6,9 +6,16 @@ #define SEND_GLOBAL_SIGNAL(sigtype, arguments...) ( SEND_SIGNAL(SSdcs, sigtype, ##arguments) ) +/// Signifies that this proc is used to handle signals. +/// Every proc you pass to RegisterSignal must have this. +#define SIGNAL_HANDLER SHOULD_NOT_SLEEP(TRUE) + +/// Signifies that this proc is used to handle signals, but also sleeps. +/// Do not use this for new work. +#define SIGNAL_HANDLER_DOES_SLEEP + /// A wrapper for _AddElement that allows us to pretend we're using normal named arguments #define AddElement(arguments...) _AddElement(list(##arguments)) - /// A wrapper for _RemoveElement that allows us to pretend we're using normal named arguments #define RemoveElement(arguments...) _RemoveElement(list(##arguments)) diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index a084f2ae34..a1bb4122a8 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -541,6 +541,9 @@ #define COMSIG_XENO_TURF_CLICK_CTRL "xeno_turf_click_alt" //from turf AltClickOn(): (/mob) #define COMSIG_XENO_MONKEY_CLICK_CTRL "xeno_monkey_click_ctrl" //from monkey CtrlClickOn(): (/mob) +// /datum/element/ventcrawling signals +#define COMSIG_HANDLE_VENTCRAWL "handle_ventcrawl" //when atom with ventcrawling element attempts to ventcrawl +#define COMSIG_CHECK_VENTCRAWL "check_ventcrawl" //to check an atom's ventcrawling element tier (if applicable) // twitch plays /// Returns direction: (wipe_votes) #define COMSIG_TWITCH_PLAYS_MOVEMENT_DATA "twitch_plays_movement_data" diff --git a/code/__DEFINES/loadout.dm b/code/__DEFINES/loadout.dm index ecd043a66a..973457692e 100644 --- a/code/__DEFINES/loadout.dm +++ b/code/__DEFINES/loadout.dm @@ -72,9 +72,11 @@ #define LOADOUT_LIMBS list(LOADOUT_LIMB_NORMAL,LOADOUT_LIMB_PROSTHETIC,LOADOUT_LIMB_AMPUTATED) //you can amputate your legs/arms though //loadout saving/loading specific defines -#define MAXIMUM_LOADOUT_SAVES 5 -#define LOADOUT_ITEM "loadout_item" -#define LOADOUT_COLOR "loadout_color" +#define MAXIMUM_LOADOUT_SAVES 5 +#define LOADOUT_ITEM "loadout_item" +#define LOADOUT_COLOR "loadout_color" +#define LOADOUT_CUSTOM_NAME "loadout_custom_name" +#define LOADOUT_CUSTOM_DESCRIPTION "loadout_custom_description" //loadout item flags #define LOADOUT_CAN_NAME (1<<0) //renaming items diff --git a/code/__DEFINES/movement.dm b/code/__DEFINES/movement.dm new file mode 100644 index 0000000000..5bf7de8647 --- /dev/null +++ b/code/__DEFINES/movement.dm @@ -0,0 +1,26 @@ +/// The minimum for glide_size to be clamped to. +#define MIN_GLIDE_SIZE 1 +/// The maximum for glide_size to be clamped to. +/// This shouldn't be higher than the icon size, and generally you shouldn't be changing this, but it's here just in case. +#define MAX_GLIDE_SIZE 32 + +/// Compensating for time dialation +GLOBAL_VAR_INIT(glide_size_multiplier, 1.0) + +///Broken down, here's what this does: +/// divides the world icon_size (32) by delay divided by ticklag to get the number of pixels something should be moving each tick. +/// The division result is given a min value of 1 to prevent obscenely slow glide sizes from being set +/// Then that's multiplied by the global glide size multiplier. 1.25 by default feels pretty close to spot on. This is just to try to get byond to behave. +/// The whole result is then clamped to within the range above. +/// Not very readable but it works +#define DELAY_TO_GLIDE_SIZE(delay) (clamp(((32 / max((delay) / world.tick_lag, 1)) * GLOB.glide_size_multiplier), MIN_GLIDE_SIZE, MAX_GLIDE_SIZE)) + +/// Enables smooth movement +// #define SMOOTH_MOVEMENT + +/// Set appearance flags in vars +#ifdef SMOOTH_MOVEMENT + #define SET_APPEARANCE_FLAGS(_flags) appearance_flags = (_flags | LONG_GLIDE) +#else + #define SET_APPEARANCE_FLAGS(_flags) appearance_flags = _flags +#endif diff --git a/code/__DEFINES/rust_g.dm b/code/__DEFINES/rust_g.dm index 20e7975ec4..988acd3dae 100644 --- a/code/__DEFINES/rust_g.dm +++ b/code/__DEFINES/rust_g.dm @@ -1,19 +1,76 @@ // rust_g.dm - DM API for rust_g extension library -#define RUST_G "rust_g" +// +// To configure, create a `rust_g.config.dm` and set what you care about from +// the following options: +// +// #define RUST_G "path/to/rust_g" +// Override the .dll/.so detection logic with a fixed path or with detection +// logic of your own. +// +// #define RUSTG_OVERRIDE_BUILTINS +// Enable replacement rust-g functions for certain builtins. Off by default. -#define RUSTG_JOB_NO_RESULTS_YET "NO RESULTS YET" -#define RUSTG_JOB_NO_SUCH_JOB "NO SUCH JOB" -#define RUSTG_JOB_ERROR "JOB PANICKED" +#ifndef RUST_G +// Default automatic RUST_G detection. +// On Windows, looks in the standard places for `rust_g.dll`. +// On Linux, looks in `.`, `$LD_LIBRARY_PATH`, and `~/.byond/bin` for either of +// `librust_g.so` (preferred) or `rust_g` (old). + +/* This comment bypasses grep checks */ /var/__rust_g + +/proc/__detect_rust_g() + if (world.system_type == UNIX) + if (fexists("./librust_g.so")) + // No need for LD_LIBRARY_PATH badness. + return __rust_g = "./librust_g.so" + else if (fexists("./rust_g")) + // Old dumb filename. + return __rust_g = "./rust_g" + else if (fexists("[world.GetConfig("env", "HOME")]/.byond/bin/rust_g")) + // Old dumb filename in `~/.byond/bin`. + return __rust_g = "rust_g" + else + // It's not in the current directory, so try others + return __rust_g = "librust_g.so" + else + return __rust_g = "rust_g" + +#define RUST_G (__rust_g || __detect_rust_g()) +#endif + +/** + * This proc generates a cellular automata noise grid which can be used in procedural generation methods. + * + * Returns a single string that goes row by row, with values of 1 representing an alive cell, and a value of 0 representing a dead cell. + * + * Arguments: + * * percentage: The chance of a turf starting closed + * * smoothing_iterations: The amount of iterations the cellular automata simulates before returning the results + * * birth_limit: If the number of neighboring cells is higher than this amount, a cell is born + * * death_limit: If the number of neighboring cells is lower than this amount, a cell dies + * * width: The width of the grid. + * * height: The height of the grid. + */ +#define rustg_cnoise_generate(percentage, smoothing_iterations, birth_limit, death_limit, width, height) \ + call(RUST_G, "cnoise_generate")(percentage, smoothing_iterations, birth_limit, death_limit, width, height) #define rustg_dmi_strip_metadata(fname) call(RUST_G, "dmi_strip_metadata")(fname) #define rustg_dmi_create_png(path, width, height, data) call(RUST_G, "dmi_create_png")(path, width, height, data) +#define rustg_dmi_resize_png(path, width, height, resizetype) call(RUST_G, "dmi_resize_png")(path, width, height, resizetype) + +#define rustg_file_read(fname) call(RUST_G, "file_read")(fname) +#define rustg_file_exists(fname) call(RUST_G, "file_exists")(fname) +#define rustg_file_write(text, fname) call(RUST_G, "file_write")(text, fname) +#define rustg_file_append(text, fname) call(RUST_G, "file_append")(text, fname) + +#ifdef RUSTG_OVERRIDE_BUILTINS + #define file2text(fname) rustg_file_read("[fname]") + #define text2file(text, fname) rustg_file_append(text, "[fname]") +#endif #define rustg_git_revparse(rev) call(RUST_G, "rg_git_revparse")(rev) #define rustg_git_commit_date(rev) call(RUST_G, "rg_git_commit_date")(rev) -#define rustg_log_write(fname, text, format) call(RUST_G, "log_write")(fname, text, format) -/proc/rustg_log_close_all() return call(RUST_G, "log_close_all")() - #define RUSTG_HTTP_METHOD_GET "get" #define RUSTG_HTTP_METHOD_PUT "put" #define RUSTG_HTTP_METHOD_DELETE "delete" @@ -23,3 +80,22 @@ #define rustg_http_request_blocking(method, url, body, headers) call(RUST_G, "http_request_blocking")(method, url, body, headers) #define rustg_http_request_async(method, url, body, headers) call(RUST_G, "http_request_async")(method, url, body, headers) #define rustg_http_check_request(req_id) call(RUST_G, "http_check_request")(req_id) + +#define RUSTG_JOB_NO_RESULTS_YET "NO RESULTS YET" +#define RUSTG_JOB_NO_SUCH_JOB "NO SUCH JOB" +#define RUSTG_JOB_ERROR "JOB PANICKED" + +#define rustg_json_is_valid(text) (call(RUST_G, "json_is_valid")(text) == "true") + +#define rustg_log_write(fname, text, format) call(RUST_G, "log_write")(fname, text, format) +/proc/rustg_log_close_all() return call(RUST_G, "log_close_all")() + +#define rustg_noise_get_at_coordinates(seed, x, y) call(RUST_G, "noise_get_at_coordinates")(seed, x, y) + +#define rustg_sql_connect_pool(options) call(RUST_G, "sql_connect_pool")(options) +#define rustg_sql_query_async(handle, query, params) call(RUST_G, "sql_query_async")(handle, query, params) +#define rustg_sql_query_blocking(handle, query, params) call(RUST_G, "sql_query_blocking")(handle, query, params) +#define rustg_sql_connected(handle) call(RUST_G, "sql_connected")(handle) +#define rustg_sql_disconnect_pool(handle) call(RUST_G, "sql_disconnect_pool")(handle) +#define rustg_sql_check_query(job_id) call(RUST_G, "sql_check_query")("[job_id]") + diff --git a/code/__DEFINES/sound.dm b/code/__DEFINES/sound.dm index 73781154c5..1098a07b39 100644 --- a/code/__DEFINES/sound.dm +++ b/code/__DEFINES/sound.dm @@ -3,6 +3,7 @@ #define CHANNEL_ADMIN 1023 #define CHANNEL_VOX 1022 #define CHANNEL_JUKEBOX 1021 + #define CHANNEL_JUKEBOX_START 1016 //The gap between this and CHANNEL_JUKEBOX determines the amount of free jukebox channels. This currently allows 6 jukebox channels to exist. #define CHANNEL_JUSTICAR_ARK 1015 #define CHANNEL_HEARTBEAT 1014 //sound channel for heartbeats @@ -15,6 +16,17 @@ #define CHANNEL_DIGEST 1009 #define CHANNEL_PREYLOOP 1008 +///Default range of a sound. +#define SOUND_RANGE 17 +///default extra range for sounds considered to be quieter +#define SHORT_RANGE_SOUND_EXTRARANGE -9 +///The range deducted from sound range for things that are considered silent / sneaky +#define SILENCED_SOUND_EXTRARANGE -11 +///Percentage of sound's range where no falloff is applied +#define SOUND_DEFAULT_FALLOFF_DISTANCE 1 //For a normal sound this would be 1 tile of no falloff +///The default exponent of sound falloff +#define SOUND_FALLOFF_EXPONENT 6 + //THIS SHOULD ALWAYS BE THE LOWEST ONE! //KEEP IT UPDATED @@ -23,6 +35,7 @@ #define MAX_INSTRUMENT_CHANNELS (128 * 6) #define SOUND_MINIMUM_PRESSURE 10 +/// remove #define FALLOFF_SOUNDS 1 @@ -53,7 +66,8 @@ #define MINING list('sound/ambience/ambimine.ogg', 'sound/ambience/ambicave.ogg', 'sound/ambience/ambiruin.ogg',\ 'sound/ambience/ambiruin2.ogg', 'sound/ambience/ambiruin3.ogg', 'sound/ambience/ambiruin4.ogg',\ 'sound/ambience/ambiruin5.ogg', 'sound/ambience/ambiruin6.ogg', 'sound/ambience/ambiruin7.ogg',\ - 'sound/ambience/ambidanger.ogg', 'sound/ambience/ambidanger2.ogg', 'sound/ambience/ambimaint1.ogg', 'sound/ambience/ambilava.ogg') + 'sound/ambience/ambidanger.ogg', 'sound/ambience/ambidanger2.ogg', 'sound/ambience/ambimaint1.ogg',\ + 'sound/ambience/ambilava.ogg') #define MEDICAL list('sound/ambience/ambinice.ogg') @@ -80,3 +94,55 @@ 'sound/hallucinations/growl3.ogg', 'sound/hallucinations/im_here1.ogg', 'sound/hallucinations/im_here2.ogg', 'sound/hallucinations/i_see_you1.ogg', 'sound/hallucinations/i_see_you2.ogg',\ 'sound/hallucinations/look_up1.ogg', 'sound/hallucinations/look_up2.ogg', 'sound/hallucinations/over_here1.ogg', 'sound/hallucinations/over_here2.ogg', 'sound/hallucinations/over_here3.ogg',\ 'sound/hallucinations/turn_around1.ogg', 'sound/hallucinations/turn_around2.ogg', 'sound/hallucinations/veryfar_noise.ogg', 'sound/hallucinations/wail.ogg') + + +#define INTERACTION_SOUND_RANGE_MODIFIER -3 +#define EQUIP_SOUND_VOLUME 30 +#define PICKUP_SOUND_VOLUME 15 +#define DROP_SOUND_VOLUME 20 +#define YEET_SOUND_VOLUME 90 + + +//default byond sound environments +#define SOUND_ENVIRONMENT_NONE -1 +#define SOUND_ENVIRONMENT_GENERIC 0 +#define SOUND_ENVIRONMENT_PADDED_CELL 1 +#define SOUND_ENVIRONMENT_ROOM 2 +#define SOUND_ENVIRONMENT_BATHROOM 3 +#define SOUND_ENVIRONMENT_LIVINGROOM 4 +#define SOUND_ENVIRONMENT_STONEROOM 5 +#define SOUND_ENVIRONMENT_AUDITORIUM 6 +#define SOUND_ENVIRONMENT_CONCERT_HALL 7 +#define SOUND_ENVIRONMENT_CAVE 8 +#define SOUND_ENVIRONMENT_ARENA 9 +#define SOUND_ENVIRONMENT_HANGAR 10 +#define SOUND_ENVIRONMENT_CARPETED_HALLWAY 11 +#define SOUND_ENVIRONMENT_HALLWAY 12 +#define SOUND_ENVIRONMENT_STONE_CORRIDOR 13 +#define SOUND_ENVIRONMENT_ALLEY 14 +#define SOUND_ENVIRONMENT_FOREST 15 +#define SOUND_ENVIRONMENT_CITY 16 +#define SOUND_ENVIRONMENT_MOUNTAINS 17 +#define SOUND_ENVIRONMENT_QUARRY 18 +#define SOUND_ENVIRONMENT_PLAIN 19 +#define SOUND_ENVIRONMENT_PARKING_LOT 20 +#define SOUND_ENVIRONMENT_SEWER_PIPE 21 +#define SOUND_ENVIRONMENT_UNDERWATER 22 +#define SOUND_ENVIRONMENT_DRUGGED 23 +#define SOUND_ENVIRONMENT_DIZZY 24 +#define SOUND_ENVIRONMENT_PSYCHOTIC 25 +//If we ever make custom ones add them here + +//"sound areas": easy way of keeping different types of areas consistent. +#define SOUND_AREA_STANDARD_STATION SOUND_ENVIRONMENT_PARKING_LOT +#define SOUND_AREA_LARGE_ENCLOSED SOUND_ENVIRONMENT_QUARRY +#define SOUND_AREA_SMALL_ENCLOSED SOUND_ENVIRONMENT_BATHROOM +#define SOUND_AREA_TUNNEL_ENCLOSED SOUND_ENVIRONMENT_STONEROOM +#define SOUND_AREA_LARGE_SOFTFLOOR SOUND_ENVIRONMENT_CARPETED_HALLWAY +#define SOUND_AREA_MEDIUM_SOFTFLOOR SOUND_ENVIRONMENT_LIVINGROOM +#define SOUND_AREA_SMALL_SOFTFLOOR SOUND_ENVIRONMENT_ROOM +#define SOUND_AREA_ASTEROID SOUND_ENVIRONMENT_CAVE +#define SOUND_AREA_SPACE SOUND_ENVIRONMENT_UNDERWATER +#define SOUND_AREA_LAVALAND SOUND_ENVIRONMENT_MOUNTAINS +#define SOUND_AREA_ICEMOON SOUND_ENVIRONMENT_CAVE +#define SOUND_AREA_WOODFLOOR SOUND_ENVIRONMENT_CITY diff --git a/code/__DEFINES/spaceman_dmm.dm b/code/__DEFINES/spaceman_dmm.dm index e21f3dc1c1..087fa5e6e6 100644 --- a/code/__DEFINES/spaceman_dmm.dm +++ b/code/__DEFINES/spaceman_dmm.dm @@ -29,5 +29,5 @@ #endif /world/proc/enable_debugger() - if (fexists(EXTOOLS)) - call(EXTOOLS, "debug_initialize")() + if (fexists(EXTOOLS)) + call(EXTOOLS, "debug_initialize")() diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index b405db83b0..cbf701e1d3 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -1,40 +1,90 @@ -//Update this whenever the db schema changes -//make sure you add an update to the schema_version stable in the db changelog +//! Defines for subsystems and overlays +//! +//! Lots of important stuff in here, make sure you have your brain switched on +//! when editing this file + +//! ## DB defines +/** + * DB major schema version + * + * Update this whenever the db schema changes + * + * make sure you add an update to the schema_version stable in the db changelog + */ #define DB_MAJOR_VERSION 4 + +/** + * DB minor schema version + * + * Update this whenever the db schema changes + * + * make sure you add an update to the schema_version stable in the db changelog + */ #define DB_MINOR_VERSION 7 -//Timing subsystem -//Don't run if there is an identical unique timer active -//if the arguments to addtimer are the same as an existing timer, it doesn't create a new timer, and returns the id of the existing timer +//! ## Timing subsystem +/** + * Don't run if there is an identical unique timer active + * + * if the arguments to addtimer are the same as an existing timer, it doesn't create a new timer, + * and returns the id of the existing timer + */ #define TIMER_UNIQUE (1<<0) -//For unique timers: Replace the old timer rather then not start this one + +///For unique timers: Replace the old timer rather then not start this one #define TIMER_OVERRIDE (1<<1) -//Timing should be based on how timing progresses on clients, not the sever. -// tracking this is more expensive, -// should only be used in conjuction with things that have to progress client side, such as animate() or sound() + +/** + * Timing should be based on how timing progresses on clients, not the server. + * + * Tracking this is more expensive, + * should only be used in conjuction with things that have to progress client side, such as + * animate() or sound() + */ #define TIMER_CLIENT_TIME (1<<2) -//Timer can be stopped using deltimer() + +///Timer can be stopped using deltimer() #define TIMER_STOPPABLE (1<<3) -//To be used with TIMER_UNIQUE -//prevents distinguishing identical timers with the wait variable + +///prevents distinguishing identical timers with the wait variable +/// +///To be used with TIMER_UNIQUE #define TIMER_NO_HASH_WAIT (1<<4) -//Loops the timer repeatedly until qdeleted -//In most cases you want a subsystem instead + +///Loops the timer repeatedly until qdeleted +/// +///In most cases you want a subsystem instead, so don't use this unless you have a good reason #define TIMER_LOOP (1<<5) -#define TIMER_NO_INVOKE_WARNING 600 //number of byond ticks that are allowed to pass before the timer subsystem thinks it hung on something - +///Empty ID define #define TIMER_ID_NULL -1 -#define INITIALIZATION_INSSATOMS 0 //New should not call Initialize -#define INITIALIZATION_INNEW_MAPLOAD 2 //New should call Initialize(TRUE) -#define INITIALIZATION_INNEW_REGULAR 1 //New should call Initialize(FALSE) +//! ## Initialization subsystem -#define INITIALIZE_HINT_NORMAL 0 //Nothing happens -#define INITIALIZE_HINT_LATELOAD 1 //Call LateInitialize -#define INITIALIZE_HINT_QDEL 2 //Call qdel on the atom +///New should not call Initialize +#define INITIALIZATION_INSSATOMS 0 +///New should call Initialize(TRUE) +#define INITIALIZATION_INNEW_MAPLOAD 2 +///New should call Initialize(FALSE) +#define INITIALIZATION_INNEW_REGULAR 1 -//type and all subtypes should always call Initialize in New() +//! ### Initialization hints + +///Nothing happens +#define INITIALIZE_HINT_NORMAL 0 +/** + * call LateInitialize at the end of all atom Initalization + * + * The item will be added to the late_loaders list, this is iterated over after + * initalization of subsystems is complete and calls LateInitalize on the atom + * see [this file for the LateIntialize proc](atom.html#proc/LateInitialize) + */ +#define INITIALIZE_HINT_LATELOAD 1 + +///Call qdel on the atom after intialization +#define INITIALIZE_HINT_QDEL 2 + +///type and all subtypes should always immediately call Initialize in New() #define INITIALIZE_IMMEDIATE(X) ##X/New(loc, ...){\ ..();\ if(!(flags_1 & INITIALIZED_1)) {\ @@ -47,35 +97,40 @@ // Subsystems shutdown in the reverse of the order they initialize in // The numbers just define the ordering, they are meaningless otherwise. -#define INIT_ORDER_PROFILER 100 -#define INIT_ORDER_FAIL2TOPIC 99 -#define INIT_ORDER_TITLE 98 -#define INIT_ORDER_GARBAGE 95 -#define INIT_ORDER_DBCORE 94 -#define INIT_ORDER_STATPANELS 93 -#define INIT_ORDER_BLACKBOX 92 -#define INIT_ORDER_SERVER_MAINT 91 -#define INIT_ORDER_INPUT 90 -#define INIT_ORDER_SOUNDS 85 +#define INIT_ORDER_PROFILER 102 +#define INIT_ORDER_FAIL2TOPIC 101 +#define INIT_ORDER_TITLE 100 +#define INIT_ORDER_GARBAGE 99 +#define INIT_ORDER_DBCORE 95 +#define INIT_ORDER_BLACKBOX 94 +#define INIT_ORDER_SERVER_MAINT 93 +#define INIT_ORDER_INPUT 85 +#define INIT_ORDER_SOUNDS 83 +#define INIT_ORDER_INSTRUMENTS 82 #define INIT_ORDER_VIS 80 +// #define INIT_ORDER_ACHIEVEMENTS 77 #define INIT_ORDER_RESEARCH 75 #define INIT_ORDER_EVENTS 70 #define INIT_ORDER_JOBS 65 #define INIT_ORDER_QUIRKS 60 #define INIT_ORDER_TICKER 55 -#define INIT_ORDER_INSTRUMENTS 53 +// #define INIT_ORDER_TCG 55 #define INIT_ORDER_MAPPING 50 -#define INIT_ORDER_ECONOMY 45 -#define INIT_ORDER_NETWORKS 40 +#define INIT_ORDER_TIMETRACK 47 +#define INIT_ORDER_NETWORKS 45 +#define INIT_ORDER_ECONOMY 40 #define INIT_ORDER_HOLODECK 35 +// #define INIT_ORDER_OUTPUTS 35 #define INIT_ORDER_ATOMS 30 #define INIT_ORDER_LANGUAGE 25 #define INIT_ORDER_MACHINES 20 #define INIT_ORDER_CIRCUIT 15 +// #define INIT_ORDER_SKILLS 15 #define INIT_ORDER_TIMER 1 #define INIT_ORDER_DEFAULT 0 #define INIT_ORDER_AIR -1 #define INIT_ORDER_AIR_TURFS -2 +#define INIT_ORDER_PERSISTENCE -2 //before assets because some assets take data from SSPersistence #define INIT_ORDER_MINIMAP -3 #define INIT_ORDER_ASSETS -4 #define INIT_ORDER_ICON_SMOOTHING -5 @@ -86,7 +141,9 @@ #define INIT_ORDER_SHUTTLE -21 #define INIT_ORDER_MINOR_MAPPING -40 #define INIT_ORDER_PATH -50 -#define INIT_ORDER_PERSISTENCE -95 +// #define INIT_ORDER_DISCORD -60 +// #define INIT_ORDER_EXPLOSIONS -69 +#define INIT_ORDER_STATPANELS -98 #define INIT_ORDER_DEMO -99 // o avoid a bunch of changes related to initialization being written, do this last #define INIT_ORDER_CHAT -100 //Should be last to ensure chat remains smooth during init. @@ -102,6 +159,7 @@ #define FIRE_PRIORITY_GARBAGE 15 #define FIRE_PRIORITY_WET_FLOORS 20 #define FIRE_PRIORITY_AIR 20 +#define FIRE_PRIORITY_NPC 20 #define FIRE_PRIORITY_PROCESS 25 #define FIRE_PRIORITY_THROWING 25 #define FIRE_PRIORITY_SPACEDRIFT 30 @@ -116,7 +174,6 @@ #define FIRE_PRIORITY_AIR_TURFS 40 #define FIRE_PRIORITY_DEFAULT 50 #define FIRE_PRIORITY_PARALLAX 65 -#define FIRE_PRIORITY_NPC 80 #define FIRE_PRIORITY_MOBS 100 #define FIRE_PRIORITY_TGUI 110 #define FIRE_PRIORITY_PROJECTILES 200 @@ -126,6 +183,8 @@ #define FIRE_PRIORITY_CHAT 400 #define FIRE_PRIORITY_RUNECHAT 410 #define FIRE_PRIORITY_OVERLAYS 500 +// #define FIRE_PRIORITY_EXPLOSIONS 666 +#define FIRE_PRIORITY_TIMER 700 #define FIRE_PRIORITY_INPUT 1000 // This must always always be the max highest priority. Player input must never be lost. // SS runlevels @@ -138,6 +197,37 @@ #define RUNLEVELS_DEFAULT (RUNLEVEL_SETUP | RUNLEVEL_GAME | RUNLEVEL_POSTGAME) + + +//! ## Overlays subsystem + +///Compile all the overlays for an atom from the cache lists +// |= on overlays is not actually guaranteed to not add same appearances but we're optimistically using it anyway. +#define COMPILE_OVERLAYS(A)\ + if (TRUE) {\ + var/list/ad = A.add_overlays;\ + var/list/rm = A.remove_overlays;\ + if(LAZYLEN(rm)){\ + A.overlays -= rm;\ + rm.Cut();\ + }\ + if(LAZYLEN(ad)){\ + A.overlays |= ad;\ + ad.Cut();\ + }\ + A.flags_1 &= ~OVERLAY_QUEUED_1;\ + } + + +/** + Create a new timer and add it to the queue. + * Arguments: + * * callback the callback to call on timer finish + * * wait deciseconds to run the timer for + * * flags flags for this timer, see: code\__DEFINES\subsystems.dm +*/ +#define addtimer(args...) _addtimer(args, file = __FILE__, line = __LINE__) + // SSair run section #define SSAIR_PIPENETS 1 #define SSAIR_ATMOSMACHINERY 2 @@ -148,19 +238,3 @@ #define SSAIR_REBUILD_PIPENETS 7 #define SSAIR_EQUALIZE 8 #define SSAIR_ACTIVETURFS 9 - -// |= on overlays is not actually guaranteed to not add same appearances but we're optimistically using it anyway. -#define COMPILE_OVERLAYS(A)\ - if (TRUE) {\ - var/list/ad = A.add_overlays;\ - var/list/rm = A.remove_overlays;\ - if(LAZYLEN(rm)){\ - A.overlays -= rm;\ - A.remove_overlays = null;\ - }\ - if(LAZYLEN(ad)){\ - A.overlays |= ad;\ - A.add_overlays = null;\ - }\ - A.flags_1 &= ~OVERLAY_QUEUED_1;\ - } diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index 2275c4b90b..b7750556d5 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -253,6 +253,7 @@ // item traits #define TRAIT_NODROP "nodrop" +#define TRAIT_SPOOKY_THROW "spooky_throw" // common trait sources #define TRAIT_GENERIC "generic" diff --git a/code/__HELPERS/_extools_api.dm b/code/__HELPERS/_extools_api.dm deleted file mode 100644 index af348dc939..0000000000 --- a/code/__HELPERS/_extools_api.dm +++ /dev/null @@ -1,5 +0,0 @@ -#define EXTOOLS_LOGGING // rust_g is used as a fallback if this is undefined - -/proc/extools_log_write() - -/proc/extools_finalize_logging() diff --git a/code/__HELPERS/_lists.dm b/code/__HELPERS/_lists.dm index 3efb50ef65..a59ee9fcb0 100644 --- a/code/__HELPERS/_lists.dm +++ b/code/__HELPERS/_lists.dm @@ -37,7 +37,7 @@ * TYPECONT: The typepath of the contents of the list * COMPARE: The object to compare against, usualy the same as INPUT * COMPARISON: The variable on the objects to compare - * COMPTYPE: How the current bin item to compare against COMPARE is fetched. By key or value. + * COMPTYPE: How should the values be compared? Either COMPARE_KEY or COMPARE_VALUE. */ #define BINARY_INSERT(INPUT, LIST, TYPECONT, COMPARE, COMPARISON, COMPTYPE) \ do {\ @@ -49,7 +49,7 @@ var/__BIN_LEFT = 1;\ var/__BIN_RIGHT = __BIN_CTTL;\ var/__BIN_MID = (__BIN_LEFT + __BIN_RIGHT) >> 1;\ - var/##TYPECONT/__BIN_ITEM;\ + var ##TYPECONT/__BIN_ITEM;\ while(__BIN_LEFT < __BIN_RIGHT) {\ __BIN_ITEM = COMPTYPE;\ if(__BIN_ITEM.##COMPARISON <= COMPARE.##COMPARISON) {\ @@ -67,24 +67,25 @@ //Returns a list in plain english as a string /proc/english_list(list/input, nothing_text = "nothing", and_text = " and ", comma_text = ", ", final_comma_text = "" ) - var/total = input.len - if (!total) - return nothing_text - else if (total == 1) - return "[input[1]]" - else if (total == 2) - return "[input[1]][and_text][input[2]]" - else - var/output = "" - var/index = 1 - while (index < total) - if (index == total - 1) - comma_text = final_comma_text + var/total = length(input) + switch(total) + if (0) + return "[nothing_text]" + if (1) + return "[input[1]]" + if (2) + return "[input[1]][and_text][input[2]]" + else + var/output = "" + var/index = 1 + while (index < total) + if (index == total - 1) + comma_text = final_comma_text - output += "[input[index]][comma_text]" - index++ + output += "[input[index]][comma_text]" + index++ - return "[output][and_text][input[index]]" + return "[output][and_text][input[index]]" //Returns list element or null. Should prevent "index out of bounds" error. /proc/listgetindex(list/L, index) diff --git a/code/__HELPERS/_logging.dm b/code/__HELPERS/_logging.dm index 76ca97cd3a..18d02229dd 100644 --- a/code/__HELPERS/_logging.dm +++ b/code/__HELPERS/_logging.dm @@ -32,7 +32,7 @@ #define testing(msg) #endif -#ifdef UNIT_TESTS +#if defined(UNIT_TESTS) || defined(SPACEMAN_DMM) /proc/log_test(text) WRITE_LOG(GLOB.test_log, text) SEND_TEXT(world.log, text) @@ -191,6 +191,10 @@ /proc/log_mapping(text) WRITE_LOG(GLOB.world_map_error_log, text) +/proc/log_perf(list/perf_info) + . = "[perf_info.Join(",")]\n" + WRITE_LOG_NO_FORMAT(GLOB.perf_log, .) + /proc/log_reagent(text) WRITE_LOG(GLOB.reagent_log, text) diff --git a/code/__HELPERS/names.dm b/code/__HELPERS/names.dm index a61e3a6492..8ff610e68c 100644 --- a/code/__HELPERS/names.dm +++ b/code/__HELPERS/names.dm @@ -19,22 +19,6 @@ /proc/arachnid_name() return "[pick(GLOB.arachnid_first)] [pick(GLOB.arachnid_last)]" -/proc/church_name() - var/static/church_name - if (church_name) - return church_name - - var/name = "" - - name += pick("Holy", "United", "First", "Second", "Last") - - if (prob(20)) - name += " Space" - - name += " " + pick("Church", "Cathedral", "Body", "Worshippers", "Movement", "Witnesses") - name += " of [religion_name()]" - - return name GLOBAL_VAR(command_name) /proc/command_name() @@ -52,17 +36,6 @@ GLOBAL_VAR(command_name) return name -/proc/religion_name() - var/static/religion_name - if (religion_name) - return religion_name - - var/name = "" - - name += pick("bee", "science", "edu", "captain", "assistant", "monkey", "alien", "space", "unit", "sprocket", "gadget", "bomb", "revolution", "beyond", "station", "goon", "robot", "ivor", "hobnob") - name += pick("ism", "ia", "ology", "istism", "ites", "ick", "ian", "ity") - - return capitalize(name) /proc/station_name() if(!GLOB.station_name) diff --git a/code/__HELPERS/type2type.dm b/code/__HELPERS/type2type.dm index 0987e95dc9..87187a4c3d 100644 --- a/code/__HELPERS/type2type.dm +++ b/code/__HELPERS/type2type.dm @@ -78,21 +78,21 @@ //Turns a direction into text /proc/dir2text(direction) switch(direction) - if(1) + if(NORTH) return "north" - if(2) + if(SOUTH) return "south" - if(4) + if(EAST) return "east" - if(8) + if(WEST) return "west" - if(5) + if(NORTHEAST) return "northeast" - if(6) + if(SOUTHEAST) return "southeast" - if(9) + if(NORTHWEST) return "northwest" - if(10) + if(SOUTHWEST) return "southwest" else return @@ -101,21 +101,21 @@ /proc/text2dir(direction) switch(uppertext(direction)) if("NORTH") - return 1 + return NORTH if("SOUTH") - return 2 + return SOUTH if("EAST") - return 4 + return EAST if("WEST") - return 8 + return WEST if("NORTHEAST") - return 5 + return NORTHEAST if("NORTHWEST") - return 9 + return NORTHWEST if("SOUTHEAST") - return 6 + return SOUTHEAST if("SOUTHWEST") - return 10 + return SOUTHWEST else return diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index d95c89d19e..9f89920b46 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -1070,7 +1070,7 @@ B --><-- A return closest_atom -proc/pick_closest_path(value, list/matches = get_fancy_list_of_atom_types()) +/proc/pick_closest_path(value, list/matches = get_fancy_list_of_atom_types()) if (value == FALSE) //nothing should be calling us with a number, so this is safe value = input("Enter type to find (blank for all, cancel to cancel)", "Search for type") as null|text if (isnull(value)) @@ -1202,7 +1202,7 @@ GLOBAL_REAL_VAR(list/stack_trace_storage) GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new) //Version of view() which ignores darkness, because BYOND doesn't have it (I actually suggested it but it was tagged redundant, BUT HEARERS IS A T- /rant). -/proc/dview(var/range = world.view, var/center, var/invis_flags = 0) +/proc/dview(range = world.view, center, invis_flags = 0) if(!center) return @@ -1222,6 +1222,10 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new) var/ready_to_die = FALSE /mob/dview/Initialize() //Properly prevents this mob from gaining huds or joining any global lists + SHOULD_CALL_PARENT(FALSE) + if(flags_1 & INITIALIZED_1) + stack_trace("Warning: [src]([type]) initialized multiple times!") + flags_1 |= INITIALIZED_1 return INITIALIZE_HINT_NORMAL /mob/dview/Destroy(force = FALSE) diff --git a/code/_compile_options.dm b/code/_compile_options.dm index 0e0bd4ffaa..64b4129024 100644 --- a/code/_compile_options.dm +++ b/code/_compile_options.dm @@ -46,11 +46,11 @@ //Update this whenever you need to take advantage of more recent byond features #define MIN_COMPILER_VERSION 513 -#define MIN_COMPILER_BUILD 1508 +#define MIN_COMPILER_BUILD 1514 #if DM_VERSION < MIN_COMPILER_VERSION || DM_BUILD < MIN_COMPILER_BUILD //Don't forget to update this part #error Your version of BYOND is too out-of-date to compile this project. Go to https://secure.byond.com/download and update. -#error You need version 513.1508 or higher +#error You need version 513.1514 or higher #endif //Additional code for the above flags. @@ -62,10 +62,14 @@ #define FIND_REF_NO_CHECK_TICK #endif -#ifdef TRAVISBUILDING +#ifdef CIBUILDING #define UNIT_TESTS #endif -#ifdef TRAVISTESTING +#ifdef CITESTING #define TESTING #endif + +// A reasonable number of maximum overlays an object needs +// If you think you need more, rethink it +#define MAX_ATOM_OVERLAYS 100 diff --git a/code/_globalvars/admin.dm b/code/_globalvars/admin.dm new file mode 100644 index 0000000000..81037ff3dd --- /dev/null +++ b/code/_globalvars/admin.dm @@ -0,0 +1,12 @@ +GLOBAL_LIST_EMPTY(stickybanadminexemptions) //stores a list of ckeys exempted from a stickyban (workaround for a bug) +GLOBAL_LIST_EMPTY(stickybanadmintexts) //stores the entire stickyban list temporarily +GLOBAL_VAR(stickbanadminexemptiontimerid) //stores the timerid of the callback that restores all stickybans after an admin joins + +// /proc/init_smites() //todo: add on the second wave +// var/list/smites = list() +// for (var/_smite_path in subtypesof(/datum/smite)) +// var/datum/smite/smite_path = _smite_path +// smites[initial(smite_path.name)] = smite_path +// return smites + +// GLOBAL_LIST_INIT_TYPED(smites, /datum/smite, init_smites()) diff --git a/code/_globalvars/logging.dm b/code/_globalvars/logging.dm index e9f98f836e..78d802dbbf 100644 --- a/code/_globalvars/logging.dm +++ b/code/_globalvars/logging.dm @@ -8,6 +8,8 @@ GLOBAL_VAR(world_qdel_log) GLOBAL_PROTECT(world_qdel_log) GLOBAL_VAR(world_attack_log) GLOBAL_PROTECT(world_attack_log) +// GLOBAL_VAR(world_econ_log) +// GLOBAL_PROTECT(world_econ_log) GLOBAL_VAR(world_href_log) GLOBAL_PROTECT(world_href_log) GLOBAL_VAR(round_id) @@ -26,22 +28,28 @@ GLOBAL_VAR(query_debug_log) GLOBAL_PROTECT(query_debug_log) GLOBAL_VAR(world_job_debug_log) GLOBAL_PROTECT(world_job_debug_log) +// GLOBAL_VAR(world_mecha_log) +// GLOBAL_PROTECT(world_mecha_log) GLOBAL_VAR(world_virus_log) GLOBAL_PROTECT(world_virus_log) GLOBAL_VAR(world_asset_log) GLOBAL_PROTECT(world_asset_log) +// GLOBAL_VAR(world_cloning_log) +// GLOBAL_PROTECT(world_cloning_log) GLOBAL_VAR(world_map_error_log) GLOBAL_PROTECT(world_map_error_log) GLOBAL_VAR(world_paper_log) GLOBAL_PROTECT(world_paper_log) -GLOBAL_VAR(subsystem_log) -GLOBAL_PROTECT(subsystem_log) -GLOBAL_VAR(reagent_log) -GLOBAL_PROTECT(reagent_log) -GLOBAL_VAR(world_crafting_log) -GLOBAL_PROTECT(world_crafting_log) -GLOBAL_VAR(click_log) -GLOBAL_PROTECT(click_log) +GLOBAL_VAR(tgui_log) +GLOBAL_PROTECT(tgui_log) +GLOBAL_VAR(world_shuttle_log) +GLOBAL_PROTECT(world_shuttle_log) + +GLOBAL_VAR(perf_log) +GLOBAL_PROTECT(perf_log) + +// GLOBAL_VAR(demo_log) +// GLOBAL_PROTECT(demo_log) GLOBAL_LIST_EMPTY(bombers) GLOBAL_PROTECT(bombers) @@ -51,10 +59,7 @@ GLOBAL_LIST_EMPTY(lastsignalers) //keeps last 100 signals here in format: "[src] GLOBAL_PROTECT(lastsignalers) GLOBAL_LIST_EMPTY(lawchanges) //Stores who uploaded laws to which silicon-based lifeform, and what the law was GLOBAL_PROTECT(lawchanges) -GLOBAL_VAR(tgui_log) -GLOBAL_PROTECT(tgui_log) -GLOBAL_VAR(world_shuttle_log) -GLOBAL_PROTECT(world_shuttle_log) + GLOBAL_LIST_EMPTY(combatlog) GLOBAL_PROTECT(combatlog) GLOBAL_LIST_EMPTY(IClog) @@ -75,3 +80,13 @@ GLOBAL_PROTECT(picture_logging_id) GLOBAL_VAR(picture_logging_prefix) GLOBAL_PROTECT(picture_logging_prefix) ///// + +//// cit logging +GLOBAL_VAR(subsystem_log) +GLOBAL_PROTECT(subsystem_log) +GLOBAL_VAR(reagent_log) +GLOBAL_PROTECT(reagent_log) +GLOBAL_VAR(world_crafting_log) +GLOBAL_PROTECT(world_crafting_log) +GLOBAL_VAR(click_log) +GLOBAL_PROTECT(click_log) diff --git a/code/_globalvars/traits.dm b/code/_globalvars/traits.dm index 4e593ba904..f376ba50d7 100644 --- a/code/_globalvars/traits.dm +++ b/code/_globalvars/traits.dm @@ -130,7 +130,8 @@ GLOBAL_LIST_INIT(traits_by_type, list( ), /obj/item = list( "TRAIT_NODROP" = TRAIT_NODROP, - "TRAIT_NO_TELEPORT" = TRAIT_NO_TELEPORT + "TRAIT_NO_TELEPORT" = TRAIT_NO_TELEPORT, + "TRAIT_SPOOKY_THROW" = TRAIT_SPOOKY_THROW ) )) diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm index 5bd9632355..81d8593d4e 100644 --- a/code/_onclick/hud/alert.dm +++ b/code/_onclick/hud/alert.dm @@ -220,7 +220,7 @@ /obj/screen/alert/shiver name = "Shivering" - desc = "You're shivering! Get somewhere warmer and take off any insulating clothing like a space suit." + desc = "You're shivering! Get somewhere warmer and take off any insulating clothing like a space suit." /obj/screen/alert/lowpressure name = "Low Pressure" @@ -306,6 +306,39 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." if(CHECK_MOBILITY(L, MOBILITY_MOVE)) return L.resist_fire() //I just want to start a flame in your hearrrrrrtttttt. +/obj/screen/alert/give // information set when the give alert is made + icon_state = "default" + var/mob/living/carbon/giver + var/obj/item/receiving + +/** + * Handles assigning most of the variables for the alert that pops up when an item is offered + * + * Handles setting the name, description and icon of the alert and tracking the person giving + * and the item being offered, also registers a signal that removes the alert from anyone who moves away from the giver + * Arguments: + * * taker - The person receiving the alert + * * giver - The person giving the alert and item + * * receiving - The item being given by the giver + */ +/obj/screen/alert/give/proc/setup(mob/living/carbon/taker, mob/living/carbon/giver, obj/item/receiving) + name = "[giver] is offering [receiving]" + desc = "[giver] is offering [receiving]. Click this alert to take it." + icon_state = "template" + cut_overlays() + add_overlay(receiving) + src.receiving = receiving + src.giver = giver + RegisterSignal(taker, COMSIG_MOVABLE_MOVED, .proc/removeAlert) + +/obj/screen/alert/give/proc/removeAlert() + to_chat(usr, "You moved out of range of [giver]!") + usr.clear_alert("[giver]") + +/obj/screen/alert/give/Click(location, control, params) + . = ..() + var/mob/living/carbon/C = usr + C.take(giver, receiving) //ALIENS diff --git a/code/_onclick/hud/fullscreen.dm b/code/_onclick/hud/fullscreen.dm index d82f3e7cf5..076c949f8e 100644 --- a/code/_onclick/hud/fullscreen.dm +++ b/code/_onclick/hud/fullscreen.dm @@ -149,6 +149,15 @@ /obj/screen/fullscreen/color_vision/blue color = "#0000ff" +/obj/screen/fullscreen/cinematic_backdrop + icon = 'icons/mob/screen_gen.dmi' + screen_loc = "WEST,SOUTH to EAST,NORTH" + icon_state = "flash" + plane = SPLASHSCREEN_PLANE + layer = SPLASHSCREEN_LAYER - 1 + color = "#000000" + show_when_dead = TRUE + /obj/screen/fullscreen/lighting_backdrop icon = 'icons/mob/screen_gen.dmi' icon_state = "flash" diff --git a/code/_onclick/hud/parallax.dm b/code/_onclick/hud/parallax.dm index 9050bcb5f0..5d48f430d7 100755 --- a/code/_onclick/hud/parallax.dm +++ b/code/_onclick/hud/parallax.dm @@ -10,6 +10,8 @@ C.parallax_layers_cached += new /obj/screen/parallax_layer/layer_1(null, C.view) C.parallax_layers_cached += new /obj/screen/parallax_layer/layer_2(null, C.view) C.parallax_layers_cached += new /obj/screen/parallax_layer/planet(null, C.view) + if(SSparallax.random_layer) + C.parallax_layers_cached += new SSparallax.random_layer C.parallax_layers_cached += new /obj/screen/parallax_layer/layer_3(null, C.view) C.parallax_layers = C.parallax_layers_cached.Copy() @@ -52,12 +54,12 @@ switch(C.prefs.parallax) if (PARALLAX_INSANE) C.parallax_throttle = FALSE - C.parallax_layers_max = 4 + C.parallax_layers_max = 5 return TRUE if (PARALLAX_MED) C.parallax_throttle = PARALLAX_DELAY_MED - C.parallax_layers_max = 2 + C.parallax_layers_max = 3 return TRUE if (PARALLAX_LOW) @@ -68,8 +70,9 @@ if (PARALLAX_DISABLE) return FALSE + //This is high parallax. C.parallax_throttle = PARALLAX_DELAY_DEFAULT - C.parallax_layers_max = 3 + C.parallax_layers_max = 4 return TRUE /datum/hud/proc/update_parallax_pref(mob/viewmob) @@ -219,15 +222,14 @@ L.screen_loc = "CENTER-7:[round(L.offset_x,1)],CENTER-7:[round(L.offset_y,1)]" /atom/movable/proc/update_parallax_contents() - set waitfor = FALSE if(length(client_mobs_in_contents)) for(var/thing in client_mobs_in_contents) var/mob/M = thing - if(M && M.client && M.hud_used && length(M.client.parallax_layers)) + if(M?.client && M.hud_used && length(M.client.parallax_layers)) M.hud_used.update_parallax() /mob/proc/update_parallax_teleport() //used for arrivals shuttle - if(client && client.eye && hud_used && length(client.parallax_layers)) + if(client?.eye && hud_used && length(client.parallax_layers)) var/area/areaobj = get_area(client.eye) hud_used.set_parallax_movedir(areaobj.parallax_movedir, TRUE) @@ -287,6 +289,21 @@ speed = 1.4 layer = 3 +/obj/screen/parallax_layer/random + blend_mode = BLEND_OVERLAY + speed = 3 + layer = 3 + +/obj/screen/parallax_layer/random/space_gas + icon_state = "space_gas" + +/obj/screen/parallax_layer/random/space_gas/Initialize(mapload, view) + . = ..() + src.add_atom_colour(SSparallax.random_parallax_color, ADMIN_COLOUR_PRIORITY) + +/obj/screen/parallax_layer/random/asteroids + icon_state = "asteroids" + /obj/screen/parallax_layer/planet icon_state = "planet" blend_mode = BLEND_OVERLAY @@ -295,11 +312,11 @@ layer = 30 /obj/screen/parallax_layer/planet/update_status(mob/M) - var/turf/T = get_turf(M) - if(is_station_level(T.z)) - invisibility = 0 - else - invisibility = INVISIBILITY_ABSTRACT + var/client/C = M.client + var/turf/posobj = get_turf(C.eye) + if(!posobj) + return + invisibility = is_station_level(posobj.z) ? 0 : INVISIBILITY_ABSTRACT /obj/screen/parallax_layer/planet/update_o() - return //Shit wont move + return //Shit won't move diff --git a/code/_onclick/hud/plane_master.dm b/code/_onclick/hud/plane_master.dm index 7a8b0a1121..f5b8991e20 100644 --- a/code/_onclick/hud/plane_master.dm +++ b/code/_onclick/hud/plane_master.dm @@ -28,8 +28,6 @@ . = ..() filters += filter(type="alpha", render_source=FIELD_OF_VISION_RENDER_TARGET, flags=MASK_INVERSE) -/obj/screen/plane_master/openspace/backdrop(mob/mymob) - filters = list() filters += filter(type = "drop_shadow", color = "#04080FAA", size = -10) filters += filter(type = "drop_shadow", color = "#04080FAA", size = -15) filters += filter(type = "drop_shadow", color = "#04080FAA", size = -20) @@ -93,13 +91,6 @@ else remove_filter("ambient_occlusion") -//Reserved to chat messages, so they are still displayed above the field of vision masking. -/obj/screen/plane_master/chat_messages - name = "chat messages plane master" - plane = CHAT_PLANE - appearance_flags = PLANE_MASTER - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - ///Contains all shadow cone masks, whose image overrides are displayed only to their respective owners. /obj/screen/plane_master/field_of_vision name = "field of vision mask plane master" @@ -135,10 +126,14 @@ blend_mode = BLEND_MULTIPLY mouse_opacity = MOUSE_OPACITY_TRANSPARENT +/obj/screen/plane_master/lighting/backdrop(mob/mymob) + mymob.overlay_fullscreen("lighting_backdrop_lit", /obj/screen/fullscreen/lighting_backdrop/lit) + mymob.overlay_fullscreen("lighting_backdrop_unlit", /obj/screen/fullscreen/lighting_backdrop/unlit) + /obj/screen/plane_master/lighting/Initialize() . = ..() - filters += filter(type="alpha", render_source=EMISSIVE_RENDER_TARGET, flags=MASK_INVERSE) - filters += filter(type="alpha", render_source=EMISSIVE_UNBLOCKABLE_RENDER_TARGET, flags=MASK_INVERSE) + filters += filter(type="alpha", render_source = EMISSIVE_RENDER_TARGET, flags = MASK_INVERSE) + filters += filter(type="alpha", render_source = EMISSIVE_UNBLOCKABLE_RENDER_TARGET, flags = MASK_INVERSE) /** * Things placed on this mask the lighting plane. Doesn't render directly. @@ -186,7 +181,6 @@ render_target = EMISSIVE_BLOCKER_RENDER_TARGET ///Contains space parallax - /obj/screen/plane_master/parallax name = "parallax plane master" plane = PLANE_SPACE_PARALLAX @@ -197,12 +191,16 @@ name = "parallax whitifier plane master" plane = PLANE_SPACE -/obj/screen/plane_master/lighting/backdrop(mob/mymob) - mymob.overlay_fullscreen("lighting_backdrop_lit", /obj/screen/fullscreen/lighting_backdrop/lit) - mymob.overlay_fullscreen("lighting_backdrop_unlit", /obj/screen/fullscreen/lighting_backdrop/unlit) - /obj/screen/plane_master/camera_static name = "camera static plane master" plane = CAMERA_STATIC_PLANE appearance_flags = PLANE_MASTER blend_mode = BLEND_OVERLAY + + +//Reserved to chat messages, so they are still displayed above the field of vision masking. +/obj/screen/plane_master/chat_messages + name = "runechat plane master" + plane = CHAT_PLANE + appearance_flags = PLANE_MASTER + blend_mode = BLEND_OVERLAY diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index 2ed8c81ba2..53915ff42b 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -12,9 +12,14 @@ layer = HUD_LAYER plane = HUD_PLANE resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF + animate_movement = SLIDE_STEPS + speech_span = SPAN_ROBOT + vis_flags = VIS_INHERIT_PLANE appearance_flags = APPEARANCE_UI - var/obj/master = null //A reference to the object in the slot. Grabs or items, generally. - var/datum/hud/hud = null // A reference to the owner HUD, if any. + /// A reference to the object in the slot. Grabs or items, generally. + var/obj/master = null + /// A reference to the owner HUD, if any. + var/datum/hud/hud = null /** * Map name assigned to this object. * Automatically set by /client/proc/add_obj_to_map. @@ -60,7 +65,17 @@ name = "swap hand" /obj/screen/swap_hand/Click() - usr.swap_hand() + // At this point in client Click() code we have passed the 1/10 sec check and little else + // We don't even know if it's a middle click + // if(world.time <= usr.next_move) + // return 1 + + if(usr.incapacitated()) + return 1 + + if(ismob(usr)) + var/mob/M = usr + M.swap_hand() return 1 /obj/screen/craft @@ -96,17 +111,27 @@ H.open_language_menu(usr) /obj/screen/inventory - var/slot_id // The indentifier for the slot. It has nothing to do with ID cards. - var/icon_empty // Icon when empty. For now used only by humans. - var/icon_full // Icon when contains an item. For now used only by humans. + /// The identifier for the slot. It has nothing to do with ID cards. + var/slot_id + /// Icon when empty. For now used only by humans. + var/icon_empty + /// Icon when contains an item. For now used only by humans. + var/icon_full + /// The overlay when hovering over with an item in your hand var/list/object_overlays = list() layer = HUD_LAYER plane = HUD_PLANE /obj/screen/inventory/Click(location, control, params) - if(hud?.mymob && (hud.mymob != usr)) - return - // just redirect clicks + // At this point in client Click() code we have passed the 1/10 sec check and little else + // We don't even know if it's a middle click + // if(world.time <= usr.next_move) + // return TRUE + + if(usr.incapacitated()) // ignore_stasis = TRUE + return TRUE + if(ismecha(usr.loc)) // stops inventory actions in a mech + return TRUE if(hud?.mymob && slot_id) var/obj/item/inv_item = hud.mymob.get_item_by_slot(slot_id) @@ -150,12 +175,13 @@ var/image/item_overlay = image(holding) item_overlay.alpha = 92 - if(!user.can_equip(holding, slot_id, TRUE, TRUE, TRUE)) + if(!user.can_equip(holding, slot_id, TRUE)) item_overlay.color = "#FF0000" else item_overlay.color = "#00ff00" - object_overlays += item_overlay + cut_overlay(object_overlays) + // object_overlay = item_overlay add_overlay(object_overlays) /obj/screen/inventory/hand @@ -187,10 +213,17 @@ /obj/screen/inventory/hand/Click(location, control, params) - if(hud?.mymob && (hud.mymob != usr)) - return - var/mob/user = hud.mymob - // just redirect clicks + // At this point in client Click() code we have passed the 1/10 sec check and little else + // We don't even know if it's a middle click + var/mob/user = hud?.mymob + if(usr != user) + return TRUE + // if(world.time <= user.next_move) + // return TRUE + if(user.incapacitated()) + return TRUE + if (ismecha(user.loc)) // stops inventory actions in a mech + return TRUE if(user.active_hand_index == held_index) var/obj/item/I = user.get_active_held_item() diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index cd1ee56848..7a614da07b 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -85,7 +85,7 @@ 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 diff --git a/code/controllers/admin.dm b/code/controllers/admin.dm index 3782d8be94..19fef28597 100644 --- a/code/controllers/admin.dm +++ b/code/controllers/admin.dm @@ -3,7 +3,7 @@ name = "Initializing..." var/target -INITIALIZE_IMMEDIATE(/obj/effect/statclick) //it's new, but rebranded. +INITIALIZE_IMMEDIATE(/obj/effect/statclick) /obj/effect/statclick/Initialize(mapload, text, target) //Don't port this to Initialize it's too critical . = ..() @@ -33,14 +33,6 @@ INITIALIZE_IMMEDIATE(/obj/effect/statclick) //it's new, but rebranded. usr.client.debug_variables(target) message_admins("Admin [key_name_admin(usr)] is debugging the [target] [class].") -/obj/effect/statclick/misc_subsystems/Click() - if(!usr.client.holder) - return - var/subsystem = input(usr, "Debug which subsystem?", "Debug nonprocessing subsystem") as null|anything in (Master.subsystems - Master.statworthy_subsystems) - if(!subsystem) - return - usr.client.debug_variables(subsystem) - message_admins("Admin [key_name_admin(usr)] is debugging the [subsystem] subsystem.") // Debug verbs. /client/proc/restart_controller(controller in list("Master", "Failsafe")) diff --git a/code/controllers/failsafe.dm b/code/controllers/failsafe.dm index fdce9a1287..a15056e442 100644 --- a/code/controllers/failsafe.dm +++ b/code/controllers/failsafe.dm @@ -1,7 +1,7 @@ /** - * Failsafe - * - * Pretty much pokes the MC to make sure it's still alive. + * Failsafe + * + * Pretty much pokes the MC to make sure it's still alive. **/ GLOBAL_REAL(Failsafe, /datum/controller/failsafe) diff --git a/code/controllers/master.dm b/code/controllers/master.dm index 1b5c7e5e83..59ac68960c 100644 --- a/code/controllers/master.dm +++ b/code/controllers/master.dm @@ -1,10 +1,10 @@ - /** - * StonedMC - * - * Designed to properly split up a given tick among subsystems - * Note: if you read parts of this code and think "why is it doing it that way" - * Odds are, there is a reason - * +/** + * StonedMC + * + * Designed to properly split up a given tick among subsystems + * Note: if you read parts of this code and think "why is it doing it that way" + * Odds are, there is a reason + * **/ //This is the ABSOLUTE ONLY THING that should init globally like this @@ -28,8 +28,6 @@ GLOBAL_REAL(Master, /datum/controller/master) = new // List of subsystems to process(). var/list/subsystems - /// List of subsystems to include in the MC stat panel. - var/list/statworthy_subsystems // Vars for keeping track of tick drift. var/init_timeofday @@ -41,7 +39,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new ///Only run ticker subsystems for the next n ticks. var/skip_ticks = 0 - var/make_runtime = 0 + var/make_runtime = FALSE var/initializations_finished_with_no_players_logged_in //I wonder what this could be? @@ -67,9 +65,6 @@ GLOBAL_REAL(Master, /datum/controller/master) = new //used by CHECK_TICK as well so that the procs subsystems call can obey that SS's tick limits var/static/current_ticklimit = TICK_LIMIT_RUNNING - /// Statclick for misc subsystems - var/obj/effect/statclick/misc_subsystems/misc_statclick - /datum/controller/master/New() if(!config) config = new @@ -96,11 +91,6 @@ GLOBAL_REAL(Master, /datum/controller/master) = new _subsystems += new I Master = src - // We want to see all subsystems during init. - statworthy_subsystems = subsystems.Copy() - - misc_statclick = new(null, "Debug") - if(!GLOB) new /datum/controller/global_vars @@ -217,7 +207,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new // Sort subsystems by display setting for easy access. sortTim(subsystems, /proc/cmp_subsystem_display) // Set world options. - world.fps = CONFIG_GET(number/fps) + world.change_fps(CONFIG_GET(number/fps)) var/initialized_tod = REALTIMEOFDAY if(tgs_prime) @@ -271,14 +261,10 @@ GLOBAL_REAL(Master, /datum/controller/master) = new var/list/tickersubsystems = list() var/list/runlevel_sorted_subsystems = list(list()) //ensure we always have at least one runlevel var/timer = world.time - statworthy_subsystems = list() for (var/thing in subsystems) var/datum/controller/subsystem/SS = thing if (SS.flags & SS_NO_FIRE) - if(SS.flags & SS_ALWAYS_SHOW_STAT) - statworthy_subsystems += SS continue - statworthy_subsystems += SS SS.queued_time = 0 SS.queue_next = null SS.queue_prev = null diff --git a/code/controllers/subsystem.dm b/code/controllers/subsystem.dm index e49da32557..12798f3863 100644 --- a/code/controllers/subsystem.dm +++ b/code/controllers/subsystem.dm @@ -23,7 +23,7 @@ var/priority = FIRE_PRIORITY_DEFAULT /// [Subsystem Flags][SS_NO_INIT] to control binary behavior. Flags must be set at compile time or before preinit finishes to take full effect. (You can also restart the mc to force them to process again) - var/flags = 0 + var/flags = NONE /// This var is set to TRUE after the subsystem has been initialized. var/initialized = FALSE @@ -114,7 +114,7 @@ //previously, this would have been named 'process()' but that name is used everywhere for different things! //fire() seems more suitable. This is the procedure that gets called every 'wait' deciseconds. //Sleeping in here prevents future fires until returned. -/datum/controller/subsystem/proc/fire(resumed = 0) +/datum/controller/subsystem/proc/fire(resumed = FALSE) flags |= SS_NO_FIRE CRASH("Subsystem [src]([type]) does not fire() but did not set the SS_NO_FIRE flag. Please add the SS_NO_FIRE flag to any subsystem that doesn't fire so it doesn't get added to the processing list and waste cpu.") diff --git a/code/controllers/subsystem/air.dm b/code/controllers/subsystem/air.dm index f777c967ae..3c58c90452 100644 --- a/code/controllers/subsystem/air.dm +++ b/code/controllers/subsystem/air.dm @@ -241,7 +241,8 @@ SUBSYSTEM_DEF(air) return /datum/controller/subsystem/air/proc/process_turf_equalize(resumed = 0) - return process_turf_equalize_extools(resumed, (Master.current_ticklimit - TICK_USAGE) * 0.01 * world.tick_lag) + if(process_turf_equalize_extools(resumed, (Master.current_ticklimit - TICK_USAGE) * 0.01 * world.tick_lag)) + pause() /* //cache for sanic speed var/fire_count = times_fired @@ -260,7 +261,8 @@ SUBSYSTEM_DEF(air) */ /datum/controller/subsystem/air/proc/process_active_turfs(resumed = 0) - return process_active_turfs_extools(resumed, (Master.current_ticklimit - TICK_USAGE) * 0.01 * world.tick_lag) + if(process_active_turfs_extools(resumed, (Master.current_ticklimit - TICK_USAGE) * 0.01 * world.tick_lag)) + pause() /* //cache for sanic speed var/fire_count = times_fired @@ -278,7 +280,8 @@ SUBSYSTEM_DEF(air) */ /datum/controller/subsystem/air/proc/process_excited_groups(resumed = 0) - return process_excited_groups_extools(resumed, (Master.current_ticklimit - TICK_USAGE) * 0.01 * world.tick_lag) + if(process_excited_groups_extools(resumed, (Master.current_ticklimit - TICK_USAGE) * 0.01 * world.tick_lag)) + pause() /* if (!resumed) src.currentrun = excited_groups.Copy() diff --git a/code/controllers/subsystem/assets.dm b/code/controllers/subsystem/assets.dm index 4f02d32ad0..4b43f98290 100644 --- a/code/controllers/subsystem/assets.dm +++ b/code/controllers/subsystem/assets.dm @@ -11,7 +11,7 @@ SUBSYSTEM_DEF(assets) switch (CONFIG_GET(string/asset_transport)) if ("webroot") newtransporttype = /datum/asset_transport/webroot - + if (newtransporttype == transport.type) return diff --git a/code/controllers/subsystem/atoms.dm b/code/controllers/subsystem/atoms.dm index b9a4785f49..02aad6dec3 100644 --- a/code/controllers/subsystem/atoms.dm +++ b/code/controllers/subsystem/atoms.dm @@ -10,33 +10,37 @@ SUBSYSTEM_DEF(atoms) var/old_initialized - var/list/late_loaders + var/list/late_loaders = list() var/list/BadInitializeCalls = list() + initialized = INITIALIZATION_INSSATOMS + /datum/controller/subsystem/atoms/Initialize(timeofday) GLOB.fire_overlay.appearance_flags = RESET_COLOR - setupGenetics() + setupGenetics() //to set the mutations' sequence + initialized = INITIALIZATION_INNEW_MAPLOAD InitializeAtoms() + initialized = INITIALIZATION_INNEW_REGULAR return ..() /datum/controller/subsystem/atoms/proc/InitializeAtoms(list/atoms) if(initialized == INITIALIZATION_INSSATOMS) return + old_initialized = initialized initialized = INITIALIZATION_INNEW_MAPLOAD - LAZYINITLIST(late_loaders) - var/count var/list/mapload_arg = list(TRUE) + if(atoms) count = atoms.len - for(var/I in atoms) - var/atom/A = I + for(var/I in 1 to count) + var/atom/A = atoms[I] if(!(A.flags_1 & INITIALIZED_1)) - InitAtom(I, mapload_arg) + InitAtom(A, mapload_arg) CHECK_TICK else count = 0 @@ -49,15 +53,16 @@ SUBSYSTEM_DEF(atoms) testing("Initialized [count] atoms") pass(count) - initialized = INITIALIZATION_INNEW_REGULAR + initialized = old_initialized if(late_loaders.len) - for(var/I in late_loaders) - var/atom/A = I + for(var/I in 1 to late_loaders.len) + var/atom/A = late_loaders[I] A.LateInitialize() testing("Late initialized [late_loaders.len] atoms") late_loaders.Cut() +/// Init this specific atom /datum/controller/subsystem/atoms/proc/InitAtom(atom/A, list/arguments) var/the_type = A.type if(QDELING(A)) @@ -150,8 +155,3 @@ SUBSYSTEM_DEF(atoms) var/initlog = InitLog() if(initlog) text2file(initlog, "[GLOB.log_directory]/initialize.log") - -#undef BAD_INIT_QDEL_BEFORE -#undef BAD_INIT_DIDNT_INIT -#undef BAD_INIT_SLEPT -#undef BAD_INIT_NO_HINT diff --git a/code/controllers/subsystem/blackbox.dm b/code/controllers/subsystem/blackbox.dm index dc1f246e3d..bacccefc61 100644 --- a/code/controllers/subsystem/blackbox.dm +++ b/code/controllers/subsystem/blackbox.dm @@ -14,12 +14,14 @@ SUBSYSTEM_DEF(blackbox) "explosion" = 2, "time_dilation_current" = 3, "science_techweb_unlock" = 2, - "round_end_stats" = 2) //associative list of any feedback variables that have had their format changed since creation and their current version, remember to update this + "round_end_stats" = 2, + "testmerged_prs" = 2) //associative list of any feedback variables that have had their format changed since creation and their current version, remember to update this /datum/controller/subsystem/blackbox/Initialize() triggertime = world.time record_feedback("amount", "random_seed", Master.random_seed) record_feedback("amount", "dm_version", DM_VERSION) + record_feedback("amount", "dm_build", DM_BUILD) record_feedback("amount", "byond_version", world.byond_version) record_feedback("amount", "byond_build", world.byond_build) . = ..() @@ -39,10 +41,7 @@ SUBSYSTEM_DEF(blackbox) if(!SSdbcore.Connect()) return - var/playercount = 0 - for(var/mob/M in GLOB.player_list) - if(M.client) - playercount += 1 + var/playercount = LAZYLEN(GLOB.player_list) var/admincount = GLOB.admins.len var/datum/DBQuery/query_record_playercount = SSdbcore.NewQuery("INSERT INTO [format_table_name("legacy_population")] (playercount, admincount, time, server_ip, server_port, round_id) VALUES ([playercount], [admincount], '[SQLtime()]', INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')), '[world.port]', '[GLOB.round_id]')") query_record_playercount.Execute() @@ -88,18 +87,24 @@ SUBSYSTEM_DEF(blackbox) if (!SSdbcore.Connect()) return + // var/list/special_columns = list( + // "datetime" = "NOW()" + // ) var/list/sqlrowlist = list() - for (var/datum/feedback_variable/FV in feedback) - var/sqlversion = 1 - if(FV.key in versions) - sqlversion = versions[FV.key] - sqlrowlist += list(list("datetime" = "Now()", "round_id" = GLOB.round_id, "key_name" = "'[sanitizeSQL(FV.key)]'", "key_type" = "'[FV.key_type]'", "version" = "[sqlversion]", "json" = "'[sanitizeSQL(json_encode(FV.json))]'")) + sqlrowlist += list(list( + "datetime" = "Now()", //legacy + "round_id" = GLOB.round_id, + "key_name" = sanitizeSQL(FV.key), + "key_type" = FV.key_type, + "version" = versions[FV.key] || 1, + "json" = sanitizeSQL(json_encode(FV.json)) + )) if (!length(sqlrowlist)) return - SSdbcore.MassInsert(format_table_name("feedback"), sqlrowlist, ignore_errors = TRUE, delayed = TRUE) + SSdbcore.MassInsert(format_table_name("feedback"), sqlrowlist, ignore_errors = TRUE, delayed = TRUE)//, special_columns = special_columns) /datum/controller/subsystem/blackbox/proc/Seal() if(sealed) @@ -169,7 +174,7 @@ feedback data can be recorded in 5 formats: "tally" used to track the number of occurances of multiple related values i.e. how many times each type of gun is fired further calls to the same key will: - add or subtract from the saved value of the data key if it already exists + add or subtract from the saved value of the data key if it already exists append the key and it's value if it doesn't exist calls: SSblackbox.record_feedback("tally", "example", 1, "sample data") SSblackbox.record_feedback("tally", "example", 4, "sample data") @@ -181,7 +186,7 @@ feedback data can be recorded in 5 formats: the final element in the data list is used as the tracking key, all prior elements are used for nesting all data list elements must be strings further calls to the same key will: - add or subtract from the saved value of the data key if it already exists in the same multi-dimensional position + add or subtract from the saved value of the data key if it already exists in the same multi-dimensional position append the key and it's value if it doesn't exist calls: SSblackbox.record_feedback("nested tally", "example", 1, list("fruit", "orange", "apricot")) SSblackbox.record_feedback("nested tally", "example", 2, list("fruit", "orange", "orange")) @@ -270,6 +275,18 @@ Versioning /datum/feedback_variable/New(new_key, new_key_type) key = new_key key_type = new_key_type +/* +/datum/controller/subsystem/blackbox/proc/LogAhelp(ticket, action, message, recipient, sender) + if(!SSdbcore.Connect()) + return + + var/datum/db_query/query_log_ahelp = SSdbcore.NewQuery({" + INSERT INTO [format_table_name("ticket")] (ticket, action, message, recipient, sender, server_ip, server_port, round_id, timestamp) + VALUES (:ticket, :action, :message, :recipient, :sender, INET_ATON(:server_ip), :server_port, :round_id, :time) + "}, list("ticket" = ticket, "action" = action, "message" = message, "recipient" = recipient, "sender" = sender, "server_ip" = world.internet_address || "0", "server_port" = world.port, "round_id" = GLOB.round_id, "time" = SQLtime())) + query_log_ahelp.Execute() + qdel(query_log_ahelp) +*/ /datum/controller/subsystem/blackbox/proc/ReportDeath(mob/living/L) set waitfor = FALSE diff --git a/code/controllers/subsystem/chat.dm b/code/controllers/subsystem/chat.dm index f2e9da704f..0e4f8ecad2 100644 --- a/code/controllers/subsystem/chat.dm +++ b/code/controllers/subsystem/chat.dm @@ -1,4 +1,4 @@ -/** +/*! * Copyright (c) 2020 Aleksej Komarov * SPDX-License-Identifier: MIT */ diff --git a/code/controllers/subsystem/dbcore.dm b/code/controllers/subsystem/dbcore.dm index 4eff4fbf1d..c779c9f26d 100644 --- a/code/controllers/subsystem/dbcore.dm +++ b/code/controllers/subsystem/dbcore.dm @@ -177,6 +177,25 @@ SUBSYSTEM_DEF(dbcore) return FALSE return new /datum/DBQuery(sql_query, connection) +/datum/controller/subsystem/dbcore/proc/QuerySelect(list/querys, warn = FALSE, qdel = FALSE) + if (!islist(querys)) + if (!istype(querys, /datum/DBQuery)) + CRASH("Invalid query passed to QuerySelect: [querys]") + querys = list(querys) + + for (var/thing in querys) + var/datum/DBQuery/query = thing + if (warn) + INVOKE_ASYNC(query, /datum/DBQuery.proc/warn_execute) + else + INVOKE_ASYNC(query, /datum/DBQuery.proc/Execute) + + for (var/thing in querys) + var/datum/DBQuery/query = thing + UNTIL(!query.in_progress) + if (qdel) + qdel(query) + /* Takes a list of rows (each row being an associated list of column => value) and inserts them via a single mass query. Rows missing columns present in other rows will resolve to SQL NULL @@ -361,5 +380,5 @@ Delayed insert mode was removed in mysql 7 and only works with MyISAM type table //strip sensitive stuff if(findtext(message, ": CreateConnection(")) message = "CreateConnection CENSORED" - + log_sql("BSQL_DEBUG: [message]") diff --git a/code/controllers/subsystem/events.dm b/code/controllers/subsystem/events.dm index 9bc8a631c1..3660770596 100644 --- a/code/controllers/subsystem/events.dm +++ b/code/controllers/subsystem/events.dm @@ -25,7 +25,7 @@ SUBSYSTEM_DEF(events) return ..() -/datum/controller/subsystem/events/fire(resumed = 0) +/datum/controller/subsystem/events/fire(resumed = FALSE) if(!resumed) checkEvent() //only check these if we aren't resuming a paused fire src.currentrun = running.Copy() @@ -37,7 +37,7 @@ SUBSYSTEM_DEF(events) var/datum/thing = currentrun[currentrun.len] currentrun.len-- if(thing) - thing.process() + thing.process(wait * 0.1) else running.Remove(thing) if (MC_TICK_CHECK) @@ -91,13 +91,13 @@ SUBSYSTEM_DEF(events) if(. == EVENT_CANT_RUN)//we couldn't run this event for some reason, set its max_occurrences to 0 E.max_occurrences = 0 else if(. == EVENT_READY) - E.random = TRUE - E.runEvent(TRUE) + E.runEvent(random = TRUE) //allows a client to trigger an event //aka Badmin Central // > Not in modules/admin // REEEEEEEEE +// Why the heck is this here! Took me so damn long to find! /client/proc/forceEvent() set name = "Trigger Event" set category = "Admin.Events" diff --git a/code/controllers/subsystem/fire_burning.dm b/code/controllers/subsystem/fire_burning.dm index 3251285ade..f81c23d186 100644 --- a/code/controllers/subsystem/fire_burning.dm +++ b/code/controllers/subsystem/fire_burning.dm @@ -18,6 +18,7 @@ SUBSYSTEM_DEF(fire_burning) //cache for sanic speed (lists are references anyways) var/list/currentrun = src.currentrun + var/delta_time = wait * 0.1 while(currentrun.len) var/obj/O = currentrun[currentrun.len] @@ -28,10 +29,12 @@ SUBSYSTEM_DEF(fire_burning) return continue - if(O.resistance_flags & ON_FIRE) - O.take_damage(20, BURN, "fire", 0) - else - processing -= O + + if(O.resistance_flags & ON_FIRE) //in case an object is extinguished while still in currentrun + if(!(O.resistance_flags & FIRE_PROOF)) + O.take_damage(10 * delta_time, BURN, "fire", 0) + else + O.extinguish() if (MC_TICK_CHECK) return diff --git a/code/controllers/subsystem/garbage.dm b/code/controllers/subsystem/garbage.dm index da3bb24a2f..2d2fac1d13 100644 --- a/code/controllers/subsystem/garbage.dm +++ b/code/controllers/subsystem/garbage.dm @@ -1,3 +1,26 @@ +/*! +## Debugging GC issues + +In order to debug `qdel()` failures, there are several tools available. +To enable these tools, define `TESTING` in [_compile_options.dm](https://github.com/tgstation/-tg-station/blob/master/code/_compile_options.dm). + +First is a verb called "Find References", which lists **every** refererence to an object in the world. This allows you to track down any indirect or obfuscated references that you might have missed. + +Complementing this is another verb, "qdel() then Find References". +This does exactly what you'd expect; it calls `qdel()` on the object and then it finds all references remaining. +This is great, because it means that `Destroy()` will have been called before it starts to find references, +so the only references you'll find will be the ones preventing the object from `qdel()`ing gracefully. + +If you have a datum or something you are not destroying directly (say via the singulo), +the next tool is `QDEL_HINT_FINDREFERENCE`. You can return this in `Destroy()` (where you would normally `return ..()`), +to print a list of references once it enters the GC queue. + +Finally is a verb, "Show qdel() Log", which shows the deletion log that the garbage subsystem keeps. This is helpful if you are having race conditions or need to review the order of deletions. + +Note that for any of these tools to work `TESTING` must be defined. +By using these methods of finding references, you can make your life far, far easier when dealing with `qdel()` failures. +*/ + SUBSYSTEM_DEF(garbage) name = "Garbage" priority = FIRE_PRIORITY_GARBAGE @@ -6,7 +29,7 @@ SUBSYSTEM_DEF(garbage) runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY init_order = INIT_ORDER_GARBAGE - var/list/collection_timeout = list(15 SECONDS, 30 SECONDS) // deciseconds to wait before moving something up in the queue to the next level + var/list/collection_timeout = list(2 MINUTES, 10 SECONDS) // deciseconds to wait before moving something up in the queue to the next level //Stat tracking var/delslasttick = 0 // number of del()'s we've done this tick @@ -24,10 +47,8 @@ SUBSYSTEM_DEF(garbage) //Queue var/list/queues - #ifdef LEGACY_REFERENCE_TRACKING var/list/reference_find_on_fail = list() - var/list/reference_find_on_fail_types = list() #endif @@ -99,6 +120,9 @@ SUBSYSTEM_DEF(garbage) state = SS_RUNNING break + + + /datum/controller/subsystem/garbage/proc/HandleQueue(level = GC_QUEUE_CHECK) if (level == GC_QUEUE_CHECK) delslasttick = 0 @@ -139,7 +163,7 @@ SUBSYSTEM_DEF(garbage) ++totalgcs pass_counts[level]++ #ifdef LEGACY_REFERENCE_TRACKING - reference_find_on_fail -= refID //It's deleted we don't care anymore. + reference_find_on_fail -= refID //It's deleted we don't care anymore. #endif if (MC_TICK_CHECK) return @@ -153,10 +177,10 @@ SUBSYSTEM_DEF(garbage) D.find_references() #elif defined(LEGACY_REFERENCE_TRACKING) if(reference_find_on_fail[refID]) - D.find_references() + D.find_references_legacy() #ifdef GC_FAILURE_HARD_LOOKUP else - D.find_references() + D.find_references_legacy() #endif reference_find_on_fail -= refID #endif @@ -190,24 +214,6 @@ SUBSYSTEM_DEF(garbage) queue.Cut(1,count+1) count = 0 -/datum/controller/subsystem/garbage/proc/Queue(datum/D, level = GC_QUEUE_CHECK) - if (isnull(D)) - return - if (level > GC_QUEUE_COUNT) - HardDelete(D) - return - var/gctime = world.time - var/refid = "\ref[D]" - -#ifdef LEGACY_REFERENCE_TRACKING - if(reference_find_on_fail_types[D.type]) - reference_find_on_fail["\ref[D]"] = TRUE -#endif - - D.gc_destroyed = gctime - var/list/queue = queues[level] - queue[++queue.len] = list(gctime, refid) // not += for byond reasons - #ifdef LEGACY_REFERENCE_TRACKING /datum/controller/subsystem/garbage/proc/add_type_to_findref(type) if(!ispath(type)) @@ -223,6 +229,24 @@ SUBSYSTEM_DEF(garbage) reference_find_on_fail_types = list() #endif +/datum/controller/subsystem/garbage/proc/Queue(datum/D, level = GC_QUEUE_CHECK) + if (isnull(D)) + return + if (level > GC_QUEUE_COUNT) + HardDelete(D) + return + var/gctime = world.time + var/refid = "\ref[D]" + +#ifdef LEGACY_REFERENCE_TRACKING + if(reference_find_on_fail_types[D.type]) + SSgarbage.reference_find_on_fail[REF(D)] = TRUE +#endif + + D.gc_destroyed = gctime + var/list/queue = queues[level] + queue[++queue.len] = list(gctime, refid) // not += for byond reasons + //this is mainly to separate things profile wise. /datum/controller/subsystem/garbage/proc/HardDelete(datum/D) var/time = world.timeofday @@ -275,8 +299,10 @@ SUBSYSTEM_DEF(garbage) /datum/qdel_item/New(mytype) name = "[mytype]" -// Should be treated as a replacement for the 'del' keyword. -// Datums passed to this will be given a chance to clean up references to allow the GC to collect them. + +/// Should be treated as a replacement for the 'del' keyword. +/// +/// Datums passed to this will be given a chance to clean up references to allow the GC to collect them. /proc/qdel(datum/D, force=FALSE, ...) if(!istype(D)) del(D) @@ -331,9 +357,10 @@ SUBSYSTEM_DEF(garbage) #ifdef LEGACY_REFERENCE_TRACKING if (QDEL_HINT_FINDREFERENCE) //qdel will, if LEGACY_REFERENCE_TRACKING is enabled, display all references to this object, then queue the object for deletion. SSgarbage.Queue(D) + D.find_references_legacy() if (QDEL_HINT_IFFAIL_FINDREFERENCE) SSgarbage.Queue(D) - SSgarbage.reference_find_on_fail["\ref[D]"] = TRUE + SSgarbage.reference_find_on_fail[REF(D)] = TRUE #endif else #ifdef TESTING diff --git a/code/controllers/subsystem/idlenpcpool.dm b/code/controllers/subsystem/idlenpcpool.dm index 03b7931d82..ccdaa555a2 100644 --- a/code/controllers/subsystem/idlenpcpool.dm +++ b/code/controllers/subsystem/idlenpcpool.dm @@ -33,8 +33,9 @@ SUBSYSTEM_DEF(idlenpcpool) while(currentrun.len) var/mob/living/simple_animal/SA = currentrun[currentrun.len] --currentrun.len - if (!SA) + if (QDELETED(SA)) GLOB.simple_animals[AI_IDLE] -= SA + log_world("Found a null in simple_animals list!") continue if(!SA.ckey) diff --git a/code/controllers/subsystem/ipintel.dm b/code/controllers/subsystem/ipintel.dm index fca394924d..fb0ddead09 100644 --- a/code/controllers/subsystem/ipintel.dm +++ b/code/controllers/subsystem/ipintel.dm @@ -2,13 +2,13 @@ SUBSYSTEM_DEF(ipintel) name = "XKeyScore" init_order = INIT_ORDER_XKEYSCORE flags = SS_NO_FIRE - var/enabled = 0 //disable at round start to avoid checking reconnects + var/enabled = FALSE //disable at round start to avoid checking reconnects var/throttle = 0 var/errors = 0 var/list/cache = list() /datum/controller/subsystem/ipintel/Initialize(timeofday, zlevel) - enabled = 1 + enabled = TRUE . = ..() diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm index 779ee2fbac..165f6e9d81 100644 --- a/code/controllers/subsystem/job.dm +++ b/code/controllers/subsystem/job.dm @@ -691,21 +691,29 @@ SUBSYSTEM_DEF(job) if(!permitted) continue var/obj/item/I = new G.path - if(I && length(i[LOADOUT_COLOR])) //handle loadout colors - //handle polychromic items - if((G.loadout_flags & LOADOUT_CAN_COLOR_POLYCHROMIC) && length(G.loadout_initial_colors)) - var/datum/element/polychromic/polychromic = I.comp_lookup["item_worn_overlays"] //stupid way to do it but GetElement does not work for this - if(polychromic && istype(polychromic)) - var/list/polychromic_entry = polychromic.colors_by_atom[I] - if(polychromic_entry) - if(polychromic.suits_with_helmet_typecache[I.type]) //is this one of those toggleable hood/helmet things? - polychromic.connect_helmet(I,i[LOADOUT_COLOR]) - polychromic.colors_by_atom[I] = i[LOADOUT_COLOR] - I.update_icon() - else - //handle non-polychromic items (they only have one color) - I.add_atom_colour(i[LOADOUT_COLOR][1], FIXED_COLOUR_PRIORITY) - I.update_icon() + if(I) + if(length(i[LOADOUT_COLOR])) //handle loadout colors + //handle polychromic items + if((G.loadout_flags & LOADOUT_CAN_COLOR_POLYCHROMIC) && length(G.loadout_initial_colors)) + var/datum/element/polychromic/polychromic = I.comp_lookup["item_worn_overlays"] //stupid way to do it but GetElement does not work for this + if(polychromic && istype(polychromic)) + var/list/polychromic_entry = polychromic.colors_by_atom[I] + if(polychromic_entry) + if(polychromic.suits_with_helmet_typecache[I.type]) //is this one of those toggleable hood/helmet things? + polychromic.connect_helmet(I,i[LOADOUT_COLOR]) + polychromic.colors_by_atom[I] = i[LOADOUT_COLOR] + I.update_icon() + else + //handle non-polychromic items (they only have one color) + I.add_atom_colour(i[LOADOUT_COLOR][1], FIXED_COLOUR_PRIORITY) + I.update_icon() + //when inputting the data it's already sanitized + if(i[LOADOUT_CUSTOM_NAME]) + var/custom_name = i[LOADOUT_CUSTOM_NAME] + I.name = custom_name + if(i[LOADOUT_CUSTOM_DESCRIPTION]) + var/custom_description = i[LOADOUT_CUSTOM_DESCRIPTION] + I.desc = custom_description if(!M.equip_to_slot_if_possible(I, G.slot, disable_warning = TRUE, bypass_equip_delay_self = TRUE)) // If the job's dresscode compliant, try to put it in its slot, first if(iscarbon(M)) var/mob/living/carbon/C = M diff --git a/code/controllers/subsystem/jukeboxes.dm b/code/controllers/subsystem/jukeboxes.dm index 3ebeaf71ea..7be6d44a7f 100644 --- a/code/controllers/subsystem/jukeboxes.dm +++ b/code/controllers/subsystem/jukeboxes.dm @@ -94,8 +94,8 @@ SUBSYSTEM_DEF(jukeboxes) stack_trace("Nonexistant or invalid object associated with jukebox.") continue var/sound/song_played = sound(juketrack.song_path) - var/area/currentarea = get_area(jukebox) var/turf/currentturf = get_turf(jukebox) + var/area/currentarea = get_area(jukebox) var/list/hearerscache = hearers(7, jukebox) song_played.falloff = jukeinfo[4] @@ -116,7 +116,6 @@ SUBSYSTEM_DEF(jukeboxes) inrange = TRUE else song_played.status = SOUND_MUTE | SOUND_UPDATE //Setting volume = 0 doesn't let the sound properties update at all, which is lame. - M.playsound_local(currentturf, null, 100, channel = jukeinfo[2], S = song_played, envwet = (inrange ? -250 : 0), envdry = (inrange ? 0 : -10000)) CHECK_TICK return diff --git a/code/controllers/subsystem/lighting.dm b/code/controllers/subsystem/lighting.dm index e193c68536..19345f3c8d 100644 --- a/code/controllers/subsystem/lighting.dm +++ b/code/controllers/subsystem/lighting.dm @@ -6,6 +6,7 @@ SUBSYSTEM_DEF(lighting) name = "Lighting" wait = 2 init_order = INIT_ORDER_LIGHTING + flags = SS_TICKER /datum/controller/subsystem/lighting/stat_entry(msg) msg = "L:[length(GLOB.lighting_update_lights)]|C:[length(GLOB.lighting_update_corners)]|O:[length(GLOB.lighting_update_objects)]" diff --git a/code/controllers/subsystem/machines.dm b/code/controllers/subsystem/machines.dm index f356009569..23190574d8 100644 --- a/code/controllers/subsystem/machines.dm +++ b/code/controllers/subsystem/machines.dm @@ -2,6 +2,7 @@ SUBSYSTEM_DEF(machines) name = "Machines" init_order = INIT_ORDER_MACHINES flags = SS_KEEP_TIMING + wait = 2 SECONDS var/list/processing = list() var/list/currentrun = list() var/list/powernets = list() @@ -27,7 +28,7 @@ SUBSYSTEM_DEF(machines) return ..() -/datum/controller/subsystem/machines/fire(resumed = 0) +/datum/controller/subsystem/machines/fire(resumed = FALSE) if (!resumed) for(var/datum/powernet/Powernet in powernets) Powernet.reset() //reset the power state. @@ -36,11 +37,10 @@ SUBSYSTEM_DEF(machines) //cache for sanic speed (lists are references anyways) var/list/currentrun = src.currentrun - var/seconds = wait * 0.1 while(currentrun.len) var/obj/machinery/thing = currentrun[currentrun.len] currentrun.len-- - if(!QDELETED(thing) && thing.process(seconds) != PROCESS_KILL) + if(!QDELETED(thing) && thing.process(wait * 0.1) != PROCESS_KILL) if(thing.use_power) thing.auto_use_power() //add back the power state else diff --git a/code/controllers/subsystem/minimum_spawns.dm b/code/controllers/subsystem/minimum_spawns.dm index caab2b1949..b9d19b6cd2 100644 --- a/code/controllers/subsystem/minimum_spawns.dm +++ b/code/controllers/subsystem/minimum_spawns.dm @@ -1,7 +1,7 @@ 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 + flags = SS_BACKGROUND | SS_NO_FIRE wait = 2 var/where_we_droppin_boys_iterations = 0 var/snaxi_snowflake_check = FALSE @@ -71,7 +71,7 @@ GLOBAL_LIST_INIT(minimum_snow_under_spawns, list( continue if(typesof(/turf/open/lava) in orange(9, TT)) continue - valid_mining_turfs_2.Add(TT) + 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)) @@ -103,14 +103,14 @@ GLOBAL_LIST_INIT(minimum_snow_under_spawns, list( 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? + 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? + 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? @@ -127,7 +127,7 @@ GLOBAL_LIST_INIT(minimum_snow_under_spawns, list( 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? + 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? diff --git a/code/controllers/subsystem/minor_mapping.dm b/code/controllers/subsystem/minor_mapping.dm index bd950e453e..d6cbf99f97 100644 --- a/code/controllers/subsystem/minor_mapping.dm +++ b/code/controllers/subsystem/minor_mapping.dm @@ -1,3 +1,5 @@ +#define PROB_MOUSE_SPAWN 98 + SUBSYSTEM_DEF(minor_mapping) name = "Minor Mapping" init_order = INIT_ORDER_MINOR_MAPPING @@ -5,29 +7,43 @@ SUBSYSTEM_DEF(minor_mapping) /datum/controller/subsystem/minor_mapping/Initialize(timeofday) trigger_migration(CONFIG_GET(number/mice_roundstart)) + // place_satchels() return ..() /datum/controller/subsystem/minor_mapping/proc/trigger_migration(num_mice=10) var/list/exposed_wires = find_exposed_wires() - var/mob/living/simple_animal/mouse/M + var/mob/living/simple_animal/mouse/mouse var/turf/proposed_turf while((num_mice > 0) && exposed_wires.len) proposed_turf = pick_n_take(exposed_wires) - if(!M) - M = new(proposed_turf) - else - M.forceMove(proposed_turf) - if(M.environment_is_safe()) - num_mice -= 1 - M = null + if(prob(PROB_MOUSE_SPAWN)) + if(!mouse) + mouse = new(proposed_turf) + else + mouse.forceMove(proposed_turf) + // else + // mouse = new /mob/living/simple_animal/hostile/regalrat/controlled(proposed_turf) + if(mouse.environment_is_safe()) + num_mice -= 1 + mouse = null + +// /datum/controller/subsystem/minor_mapping/proc/place_satchels(amount=10) +// var/list/turfs = find_satchel_suitable_turfs() + +// while(turfs.len && amount > 0) +// var/turf/T = pick_n_take(turfs) +// var/obj/item/storage/backpack/satchel/flat/F = new(T) + +// SEND_SIGNAL(F, COMSIG_OBJ_HIDE, T.intact) +// amount-- /proc/find_exposed_wires() var/list/exposed_wires = list() - exposed_wires.Cut() + var/list/all_turfs - for (var/z in SSmapping.levels_by_trait(ZTRAIT_STATION)) + for(var/z in SSmapping.levels_by_trait(ZTRAIT_STATION)) all_turfs += block(locate(1,1,z), locate(world.maxx,world.maxy,z)) for(var/turf/open/floor/plating/T in all_turfs) if(is_blocked_turf(T)) @@ -36,3 +52,15 @@ SUBSYSTEM_DEF(minor_mapping) exposed_wires += T return shuffle(exposed_wires) + +// /proc/find_satchel_suitable_turfs() +// var/list/suitable = list() + +// for(var/z in SSmapping.levels_by_trait(ZTRAIT_STATION)) +// for(var/t in block(locate(1,1,z), locate(world.maxx,world.maxy,z))) +// if(isfloorturf(t) && !isplatingturf(t)) +// suitable += t + +// return shuffle(suitable) + +#undef PROB_MOUSE_SPAWN diff --git a/code/controllers/subsystem/overlays.dm b/code/controllers/subsystem/overlays.dm index b42a1e6b7e..74b60783c3 100644 --- a/code/controllers/subsystem/overlays.dm +++ b/code/controllers/subsystem/overlays.dm @@ -48,9 +48,16 @@ SUBSYSTEM_DEF(overlays) for (var/thing in queue) count++ if(thing) - STAT_START_STOPWATCH var/atom/A = thing + if(A.overlays.len >= MAX_ATOM_OVERLAYS) + //Break it real GOOD + stack_trace("Too many overlays on [A.type] - [A.overlays.len], refusing to update and cutting") + A.overlays.Cut() + continue + STAT_START_STOPWATCH COMPILE_OVERLAYS(A) + UNSETEMPTY(A.add_overlays) + UNSETEMPTY(A.remove_overlays) STAT_STOP_STOPWATCH STAT_LOG_ENTRY(stats, A.type) if(mc_check) @@ -117,9 +124,8 @@ SUBSYSTEM_DEF(overlays) #define QUEUE_FOR_COMPILE flags_1 |= OVERLAY_QUEUED_1; SSoverlays.queue += src; /atom/proc/cut_overlays() LAZYINITLIST(remove_overlays) - LAZYINITLIST(add_overlays) remove_overlays = overlays.Copy() - add_overlays.Cut() + add_overlays = null //If not already queued for work and there are overlays to remove if(NOT_QUEUED_ALREADY && remove_overlays.len) @@ -129,7 +135,7 @@ SUBSYSTEM_DEF(overlays) if(!overlays) return overlays = build_appearance_list(overlays) - LAZYINITLIST(add_overlays) //always initialized after this point + LAZYINITLIST(add_overlays) LAZYINITLIST(remove_overlays) var/a_len = add_overlays.len var/r_len = remove_overlays.len @@ -140,8 +146,9 @@ SUBSYSTEM_DEF(overlays) var/fr_len = remove_overlays.len //If not already queued and there is work to be done - if(NOT_QUEUED_ALREADY && (fa_len != a_len || fr_len != r_len)) + if(NOT_QUEUED_ALREADY && (fa_len != a_len || fr_len != r_len )) QUEUE_FOR_COMPILE + UNSETEMPTY(add_overlays) /atom/proc/add_overlay(list/overlays) if(!overlays) diff --git a/code/controllers/subsystem/parallax.dm b/code/controllers/subsystem/parallax.dm index 64299fda38..7096c667e1 100644 --- a/code/controllers/subsystem/parallax.dm +++ b/code/controllers/subsystem/parallax.dm @@ -7,13 +7,21 @@ SUBSYSTEM_DEF(parallax) var/list/currentrun var/planet_x_offset = 128 var/planet_y_offset = 128 + var/random_layer + var/random_parallax_color -/datum/controller/subsystem/parallax/Initialize(timeofday) + +//These are cached per client so needs to be done asap so people joining at roundstart do not miss these. +/datum/controller/subsystem/parallax/PreInit() . = ..() + if(prob(70)) //70% chance to pick a special extra layer + random_layer = pick(/obj/screen/parallax_layer/random/space_gas, /obj/screen/parallax_layer/random/asteroids) + random_parallax_color = pick(COLOR_TEAL, COLOR_GREEN, COLOR_YELLOW, COLOR_CYAN, COLOR_ORANGE, COLOR_PURPLE)//Special color for random_layer1. Has to be done here so everyone sees the same color. [COLOR_SILVER] planet_y_offset = rand(100, 160) planet_x_offset = rand(100, 160) -/datum/controller/subsystem/parallax/fire(resumed = 0) + +/datum/controller/subsystem/parallax/fire(resumed = FALSE) if (!resumed) src.currentrun = GLOB.clients.Copy() @@ -21,24 +29,27 @@ SUBSYSTEM_DEF(parallax) var/list/currentrun = src.currentrun while(length(currentrun)) - var/client/C = currentrun[currentrun.len] + var/client/processing_client = currentrun[currentrun.len] currentrun.len-- - if (!C || !C.eye) + if (QDELETED(processing_client) || !processing_client.eye) if (MC_TICK_CHECK) return continue - var/atom/movable/A = C.eye - if(!istype(A)) - continue - for (A; isloc(A.loc) && !isturf(A.loc); A = A.loc); - if(A != C.movingmob) - if(C.movingmob != null) - C.movingmob.client_mobs_in_contents -= C.mob - UNSETEMPTY(C.movingmob.client_mobs_in_contents) - LAZYINITLIST(A.client_mobs_in_contents) - A.client_mobs_in_contents += C.mob - C.movingmob = A + var/atom/movable/movable_eye = processing_client.eye + if(!istype(movable_eye)) + continue + + for (movable_eye; isloc(movable_eye.loc) && !isturf(movable_eye.loc); movable_eye = movable_eye.loc); + + if(movable_eye == processing_client.movingmob) + if (MC_TICK_CHECK) + return + continue + if(!isnull(processing_client.movingmob)) + LAZYREMOVE(processing_client.movingmob.client_mobs_in_contents, processing_client.mob) + LAZYADD(movable_eye.client_mobs_in_contents, processing_client.mob) + processing_client.movingmob = movable_eye if (MC_TICK_CHECK) return currentrun = null diff --git a/code/controllers/subsystem/pathfinder.dm b/code/controllers/subsystem/pathfinder.dm index 8e1cf946ae..ccbea79306 100644 --- a/code/controllers/subsystem/pathfinder.dm +++ b/code/controllers/subsystem/pathfinder.dm @@ -18,7 +18,7 @@ SUBSYSTEM_DEF(pathfinder) var/free var/list/flow -/datum/flowcache/New(var/n) +/datum/flowcache/New(n) . = ..() lcount = n run = 0 diff --git a/code/controllers/subsystem/persistence/_persistence.dm b/code/controllers/subsystem/persistence/_persistence.dm index 741d1dd72a..e8faf80e5d 100644 --- a/code/controllers/subsystem/persistence/_persistence.dm +++ b/code/controllers/subsystem/persistence/_persistence.dm @@ -58,6 +58,7 @@ SUBSYSTEM_DEF(persistence) if(CONFIG_GET(flag/use_antag_rep)) LoadAntagReputation() LoadRandomizedRecipes() + LoadPaintings() /** * Saves persistent data relevant to the server: Configurations, past gamemodes, votes, antag rep, etc diff --git a/code/controllers/subsystem/processing/fastprocess.dm b/code/controllers/subsystem/processing/fastprocess.dm index 9622e02146..1b30ca44c2 100644 --- a/code/controllers/subsystem/processing/fastprocess.dm +++ b/code/controllers/subsystem/processing/fastprocess.dm @@ -1,6 +1,4 @@ -//Fires five times every second. - PROCESSING_SUBSYSTEM_DEF(fastprocess) name = "Fast Processing" - wait = 2 + wait = 0.2 SECONDS stat_tag = "FP" diff --git a/code/controllers/subsystem/processing/nanites.dm b/code/controllers/subsystem/processing/nanites.dm index c34e7f7806..8a55491f5f 100644 --- a/code/controllers/subsystem/processing/nanites.dm +++ b/code/controllers/subsystem/processing/nanites.dm @@ -1,7 +1,7 @@ PROCESSING_SUBSYSTEM_DEF(nanites) name = "Nanites" flags = SS_BACKGROUND|SS_POST_FIRE_TIMING|SS_NO_INIT - wait = 10 + wait = 1 SECONDS var/list/datum/nanite_cloud_backup/cloud_backups = list() var/list/mob/living/nanite_monitored_mobs = list() diff --git a/code/controllers/subsystem/processing/obj.dm b/code/controllers/subsystem/processing/obj.dm index 26021fb267..3566e8a4dc 100644 --- a/code/controllers/subsystem/processing/obj.dm +++ b/code/controllers/subsystem/processing/obj.dm @@ -2,4 +2,4 @@ PROCESSING_SUBSYSTEM_DEF(obj) name = "Objects" priority = FIRE_PRIORITY_OBJ flags = SS_NO_INIT - wait = 20 + wait = 2 SECONDS diff --git a/code/controllers/subsystem/processing/processing.dm b/code/controllers/subsystem/processing/processing.dm index 637b04993d..5cefd3a148 100644 --- a/code/controllers/subsystem/processing/processing.dm +++ b/code/controllers/subsystem/processing/processing.dm @@ -1,10 +1,10 @@ -//Used to process objects. Fires once every second. +//Used to process objects. SUBSYSTEM_DEF(processing) name = "Processing" priority = FIRE_PRIORITY_PROCESS flags = SS_BACKGROUND|SS_POST_FIRE_TIMING|SS_NO_INIT - wait = 10 + wait = 1 SECONDS var/stat_tag = "P" //Used for logging var/list/processing = list() @@ -14,9 +14,10 @@ SUBSYSTEM_DEF(processing) msg = "[stat_tag]:[length(processing)]" return ..() -/datum/controller/subsystem/processing/fire(resumed = 0) +/datum/controller/subsystem/processing/fire(resumed = FALSE) if (!resumed) currentrun = processing.Copy() + var/delta_time = (flags & SS_TICKER)? (wait * world.tick_lag * 0.1) : (wait * 0.1) //cache for sanic speed (lists are references anyways) var/list/current_run = currentrun @@ -25,12 +26,26 @@ SUBSYSTEM_DEF(processing) current_run.len-- if(QDELETED(thing)) processing -= thing - else if(thing.process(wait) == PROCESS_KILL) + else if(thing.process(delta_time) == PROCESS_KILL) // fully stop so that a future START_PROCESSING will work STOP_PROCESSING(src, thing) if (MC_TICK_CHECK) return -/datum/proc/process() - set waitfor = 0 + +/** + * This proc is called on a datum on every "cycle" if it is being processed by a subsystem. The time between each cycle is determined by the subsystem's "wait" setting. + * You can start and stop processing a datum using the START_PROCESSING and STOP_PROCESSING defines. + * + * Since the wait setting of a subsystem can be changed at any time, it is important that any rate-of-change that you implement in this proc is multiplied by the delta_time that is sent as a parameter, + * Additionally, any "prob" you use in this proc should instead use the DT_PROB define to make sure that the final probability per second stays the same even if the subsystem's wait is altered. + * Examples where this must be considered: + * - Implementing a cooldown timer, use `mytimer -= delta_time`, not `mytimer -= 1`. This way, `mytimer` will always have the unit of seconds + * - Damaging a mob, do `L.adjustFireLoss(20 * delta_time)`, not `L.adjustFireLoss(20)`. This way, the damage per second stays constant even if the wait of the subsystem is changed + * - Probability of something happening, do `if(DT_PROB(25, delta_time))`, not `if(prob(25))`. This way, if the subsystem wait is e.g. lowered, there won't be a higher chance of this event happening per second + * + * If you override this do not call parent, as it will return PROCESS_KILL. This is done to prevent objects that dont override process() from staying in the processing list + */ +/datum/proc/process(delta_time) + set waitfor = FALSE return PROCESS_KILL diff --git a/code/controllers/subsystem/processing/quirks.dm b/code/controllers/subsystem/processing/quirks.dm index c57bac5526..74cd53b0ae 100644 --- a/code/controllers/subsystem/processing/quirks.dm +++ b/code/controllers/subsystem/processing/quirks.dm @@ -5,8 +5,8 @@ PROCESSING_SUBSYSTEM_DEF(quirks) name = "Quirks" init_order = INIT_ORDER_QUIRKS flags = SS_BACKGROUND - wait = 10 runlevels = RUNLEVEL_GAME + wait = 1 SECONDS var/list/quirks = list() //Assoc. list of all roundstart quirk datum types; "name" = /path/ var/list/quirk_names_by_path = list() diff --git a/code/controllers/subsystem/profiler.dm b/code/controllers/subsystem/profiler.dm index 81fa77dc6c..7533e9663f 100644 --- a/code/controllers/subsystem/profiler.dm +++ b/code/controllers/subsystem/profiler.dm @@ -18,7 +18,7 @@ SUBSYSTEM_DEF(profiler) if(CONFIG_GET(flag/auto_profile)) StartProfiling() else - StopProfiling() //Stop the early start from world/New + StopProfiling() //Stop the early start profiler return ..() /datum/controller/subsystem/profiler/fire() @@ -31,12 +31,23 @@ SUBSYSTEM_DEF(profiler) return ..() /datum/controller/subsystem/profiler/proc/StartProfiling() +#if DM_BUILD < 1506 + stack_trace("Auto profiling unsupported on this byond version") + CONFIG_SET(flag/auto_profile, FALSE) +#else world.Profile(PROFILE_START) +#endif /datum/controller/subsystem/profiler/proc/StopProfiling() +#if DM_BUILD >= 1506 world.Profile(PROFILE_STOP) +#endif /datum/controller/subsystem/profiler/proc/DumpFile() +#if DM_BUILD < 1506 + stack_trace("Auto profiling unsupported on this byond version") + CONFIG_SET(flag/auto_profile, FALSE) +#else var/timer = TICK_USAGE_REAL var/current_profile_data = world.Profile(PROFILE_REFRESH,format="json") fetch_cost = MC_AVERAGE(fetch_cost, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) @@ -49,3 +60,4 @@ SUBSYSTEM_DEF(profiler) timer = TICK_USAGE_REAL WRITE_FILE(json_file, current_profile_data) write_cost = MC_AVERAGE(write_cost, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) +#endif diff --git a/code/controllers/subsystem/radiation.dm b/code/controllers/subsystem/radiation.dm index f29fe72e80..2d764d84dd 100644 --- a/code/controllers/subsystem/radiation.dm +++ b/code/controllers/subsystem/radiation.dm @@ -1,6 +1,7 @@ PROCESSING_SUBSYSTEM_DEF(radiation) name = "Radiation" flags = SS_NO_INIT | SS_BACKGROUND + wait = 1 SECONDS var/list/warned_atoms = list() @@ -13,5 +14,5 @@ PROCESSING_SUBSYSTEM_DEF(radiation) warned_atoms[ref] = TRUE var/atom/master = contamination.parent SSblackbox.record_feedback("tally", "contaminated", 1, master.type) - var/msg = "has become contamintaed with enough radiation to contaminate other objects. || Source: [contamination.source] || Strength: [contamination.strength]" + var/msg = "has become contaminated with enough radiation to contaminate other objects. || Source: [contamination.source] || Strength: [contamination.strength]" master.investigate_log(msg, INVESTIGATE_RADIATION) diff --git a/code/controllers/subsystem/runechat.dm b/code/controllers/subsystem/runechat.dm index ec296e7d32..9bd665e5ee 100644 --- a/code/controllers/subsystem/runechat.dm +++ b/code/controllers/subsystem/runechat.dm @@ -6,15 +6,15 @@ #define BUCKET_LIMIT (world.time + TICKS2DS(min(BUCKET_LEN - (SSrunechat.practical_offset - DS2TICKS(world.time - SSrunechat.head_offset)) - 1, BUCKET_LEN - 1))) /** - * # Runechat Subsystem - * - * Maintains a timer-like system to handle destruction of runechat messages. Much of this code is modeled - * after or adapted from the timer subsystem. - * - * Note that this has the same structure for storing and queueing messages as the timer subsystem does - * for handling timers: the bucket_list is a list of chatmessage datums, each of which are the head - * of a circularly linked list. Any given index in bucket_list could be null, representing an empty bucket. - */ + * # Runechat Subsystem + * + * Maintains a timer-like system to handle destruction of runechat messages. Much of this code is modeled + * after or adapted from the timer subsystem. + * + * Note that this has the same structure for storing and queueing messages as the timer subsystem does + * for handling timers: the bucket_list is a list of chatmessage datums, each of which are the head + * of a circularly linked list. Any given index in bucket_list could be null, representing an empty bucket. + */ SUBSYSTEM_DEF(runechat) name = "Runechat" flags = SS_TICKER | SS_NO_INIT @@ -131,14 +131,14 @@ SUBSYSTEM_DEF(runechat) bucket_resolution = world.tick_lag /** - * Enters the runechat subsystem with this chatmessage, inserting it into the end-of-life queue - * - * This will also account for a chatmessage already being registered, and in which case - * the position will be updated to remove it from the previous location if necessary - * - * Arguments: - * * new_sched_destruction Optional, when provided is used to update an existing message with the new specified time - */ + * Enters the runechat subsystem with this chatmessage, inserting it into the end-of-life queue + * + * This will also account for a chatmessage already being registered, and in which case + * the position will be updated to remove it from the previous location if necessary + * + * Arguments: + * * new_sched_destruction Optional, when provided is used to update an existing message with the new specified time + */ /datum/chatmessage/proc/enter_subsystem(new_sched_destruction = 0) // Get local references from subsystem as they are faster to access than the datum references var/list/bucket_list = SSrunechat.bucket_list @@ -169,7 +169,7 @@ SUBSYSTEM_DEF(runechat) // Handle insertion into the secondary queue if the required time is outside our tracked amounts if (scheduled_destruction >= BUCKET_LIMIT) - BINARY_INSERT(src, SSrunechat.second_queue, datum/chatmessage, src, scheduled_destruction, COMPARE_KEY) + BINARY_INSERT(src, SSrunechat.second_queue, /datum/chatmessage, src, scheduled_destruction, COMPARE_KEY) return // Get bucket position and a local reference to the datum var, it's faster to access this way @@ -194,8 +194,8 @@ SUBSYSTEM_DEF(runechat) /** - * Removes this chatmessage datum from the runechat subsystem - */ + * Removes this chatmessage datum from the runechat subsystem + */ /datum/chatmessage/proc/leave_subsystem() // Attempt to find the bucket that contains this chat message var/bucket_pos = BUCKET_POS(scheduled_destruction) diff --git a/code/controllers/subsystem/server_maint.dm b/code/controllers/subsystem/server_maint.dm index 2427fbd277..7eb81003f1 100644 --- a/code/controllers/subsystem/server_maint.dm +++ b/code/controllers/subsystem/server_maint.dm @@ -56,12 +56,13 @@ SUBSYSTEM_DEF(server_maint) for(var/I in currentrun) var/client/C = I //handle kicking inactive players - if(round_started && kick_inactive && C.is_afk(afk_period)) + if(round_started && kick_inactive && !C.holder && C.is_afk(afk_period)) var/cmob = C.mob - if(!(isobserver(cmob) || (isdead(cmob) && C.holder))) + if (!isnewplayer(cmob) || !SSticker.queued_players.Find(cmob)) log_access("AFK: [key_name(C)]") - to_chat(C, "You have been inactive for more than [DisplayTimeText(afk_period)] and have been disconnected.") - qdel(C) + to_chat(C, "You have been inactive for more than [DisplayTimeText(afk_period)] and have been disconnected.
You may reconnect via the button in the file menu or by clicking here to reconnect.") + QDEL_IN(C, 1) //to ensure they get our message before getting disconnected + continue if (!(!C || world.time - C.connection_time < PING_BUFFER_TIME || C.inactivity >= (wait-1))) winset(C, null, "command=.update_ping+[world.time+world.tick_lag*TICK_USAGE_REAL/100]") @@ -83,4 +84,15 @@ SUBSYSTEM_DEF(server_maint) if(tgsversion) SSblackbox.record_feedback("text", "server_tools", 1, tgsversion.raw_parameter) + +/datum/controller/subsystem/server_maint/proc/UpdateHubStatus() + // if(!CONFIG_GET(flag/hub) || !CONFIG_GET(number/max_hub_pop)) + // return FALSE //no point, hub / auto hub controls are disabled + + // var/max_pop = CONFIG_GET(number/max_hub_pop) + + // if(GLOB.clients.len > max_pop) + // world.update_hub_visibility(FALSE) + // else + // world.update_hub_visibility(TRUE) #undef PING_BUFFER_TIME diff --git a/code/controllers/subsystem/sounds.dm b/code/controllers/subsystem/sounds.dm index 5e7c5e6545..fa9ba3c472 100644 --- a/code/controllers/subsystem/sounds.dm +++ b/code/controllers/subsystem/sounds.dm @@ -5,34 +5,48 @@ SUBSYSTEM_DEF(sounds) flags = SS_NO_FIRE init_order = INIT_ORDER_SOUNDS var/static/using_channels_max = CHANNEL_HIGHEST_AVAILABLE //BYOND max channels + /// Amount of channels to reserve for random usage rather than reservations being allowed to reserve all channels. Also a nice safeguard for when someone screws up. + var/static/random_channels_min = 50 // Hey uh these two needs to be initialized fast because the whole "things get deleted before init" thing. - /// Assoc list, "[channel]" = either the datum using it or TRUE for an unsafe-reserved (datumless reservation) channel - var/list/using_channels = list() + /// Assoc list, `"[channel]" =` either the datum using it or TRUE for an unsafe-reserved (datumless reservation) channel + var/list/using_channels /// Assoc list datum = list(channel1, channel2, ...) for what channels something reserved. - var/list/using_channels_by_datum = list() - /// List of all available channels with associations set to TRUE for fast lookups/allocation. - var/list/available_channels + var/list/using_channels_by_datum + // Special datastructure for fast channel management + /// List of all channels as numbers + var/list/channel_list + /// Associative list of all reserved channels associated to their position. `"[channel_number]" =` index as number + var/list/reserved_channels + /// lower iteration position - Incremented and looped to get "random" sound channels for normal sounds. The channel at this index is returned when asking for a random channel. + var/channel_random_low + /// higher reserve position - decremented and incremented to reserve sound channels, anything above this is reserved. The channel at this index is the highest unreserved channel. + var/channel_reserve_high /datum/controller/subsystem/sounds/Initialize() setup_available_channels() return ..() /datum/controller/subsystem/sounds/proc/setup_available_channels() - available_channels = list() + channel_list = list() + reserved_channels = list() + using_channels = list() + using_channels_by_datum = list() for(var/i in 1 to using_channels_max) - available_channels[num2text(i)] = TRUE + channel_list += i + channel_random_low = 1 + channel_reserve_high = length(channel_list) /// Removes a channel from using list. /datum/controller/subsystem/sounds/proc/free_sound_channel(channel) - channel = num2text(channel) - var/using = using_channels[channel] - using_channels -= channel - if(using) + var/text_channel = num2text(channel) + var/using = using_channels[text_channel] + using_channels -= text_channel + if(using != TRUE) // datum channel using_channels_by_datum[using] -= channel if(!length(using_channels_by_datum[using])) using_channels_by_datum -= using - available_channels[channel] = TRUE + free_channel(channel) /// Frees all the channels a datum is using. /datum/controller/subsystem/sounds/proc/free_datum_channels(datum/D) @@ -40,8 +54,8 @@ SUBSYSTEM_DEF(sounds) if(!L) return for(var/channel in L) - using_channels -= channel - available_channels[channel] = TRUE + using_channels -= num2text(channel) + free_channel(channel) using_channels_by_datum -= D /// Frees all datumless channels @@ -50,42 +64,72 @@ SUBSYSTEM_DEF(sounds) /// NO AUTOMATIC CLEANUP - If you use this, you better manually free it later! Returns an integer for channel. /datum/controller/subsystem/sounds/proc/reserve_sound_channel_datumless() - var/channel = random_available_channel_text() - if(!channel) //oh no.. + . = reserve_channel() + if(!.) //oh no.. return FALSE - available_channels -= channel - using_channels[channel] = DATUMLESS + var/text_channel = num2text(.) + using_channels[text_channel] = DATUMLESS LAZYINITLIST(using_channels_by_datum[DATUMLESS]) - using_channels_by_datum[DATUMLESS] += channel - return text2num(channel) + using_channels_by_datum[DATUMLESS] += . /// Reserves a channel for a datum. Automatic cleanup only when the datum is deleted. Returns an integer for channel. /datum/controller/subsystem/sounds/proc/reserve_sound_channel(datum/D) if(!D) //i don't like typechecks but someone will fuck it up CRASH("Attempted to reserve sound channel without datum using the managed proc.") - var/channel = random_available_channel_text() - if(!channel) + .= reserve_channel() + if(!.) return FALSE - available_channels -= channel - using_channels[channel] = D + var/text_channel = num2text(.) + using_channels[text_channel] = D LAZYINITLIST(using_channels_by_datum[D]) - using_channels_by_datum[D] += channel - return text2num(channel) + using_channels_by_datum[D] += . + +/** + * Reserves a channel and updates the datastructure. Private proc. + */ +/datum/controller/subsystem/sounds/proc/reserve_channel() + PRIVATE_PROC(TRUE) + if(channel_reserve_high <= random_channels_min) // out of channels + return + var/channel = channel_list[channel_reserve_high] + reserved_channels[num2text(channel)] = channel_reserve_high-- + return channel + +/** + * Frees a channel and updates the datastructure. Private proc. + */ +/datum/controller/subsystem/sounds/proc/free_channel(number) + PRIVATE_PROC(TRUE) + var/text_channel = num2text(number) + var/index = reserved_channels[text_channel] + if(!index) + CRASH("Attempted to (internally) free a channel that wasn't reserved.") + reserved_channels -= text_channel + // push reserve index up, which makes it now on a channel that is reserved + channel_reserve_high++ + // swap the reserved channel wtih the unreserved channel so the reserve index is now on an unoccupied channel and the freed channel is next to be used. + channel_list.Swap(channel_reserve_high, index) + // now, an existing reserved channel will likely (exception: unreserving last reserved channel) be at index + // get it, and update position. + var/text_reserved = num2text(channel_list[index]) + if(!reserved_channels[text_reserved]) //if it isn't already reserved make sure we don't accidently mistakenly put it on reserved list! + return + reserved_channels[text_reserved] = index /// Random available channel, returns text. /datum/controller/subsystem/sounds/proc/random_available_channel_text() - return pick(available_channels) + if(channel_random_low > channel_reserve_high) + channel_random_low = 1 + . = "[channel_list[channel_random_low++]]" /// Random available channel, returns number /datum/controller/subsystem/sounds/proc/random_available_channel() - return text2num(pick(available_channels)) - -/// If a channel is available -/datum/controller/subsystem/sounds/proc/is_channel_available(channel) - return available_channels[num2text(channel)] + if(channel_random_low > channel_reserve_high) + channel_random_low = 1 + . = channel_list[channel_random_low++] /// How many channels we have left. /datum/controller/subsystem/sounds/proc/available_channels_left() - return length(available_channels) + return length(channel_list) - random_channels_min #undef DATUMLESS diff --git a/code/controllers/subsystem/spacedrift.dm b/code/controllers/subsystem/spacedrift.dm index c3261df304..e84a70a45f 100644 --- a/code/controllers/subsystem/spacedrift.dm +++ b/code/controllers/subsystem/spacedrift.dm @@ -13,7 +13,7 @@ SUBSYSTEM_DEF(spacedrift) return ..() -/datum/controller/subsystem/spacedrift/fire(resumed = 0) +/datum/controller/subsystem/spacedrift/fire(resumed = FALSE) if (!resumed) src.currentrun = processing.Copy() @@ -47,6 +47,7 @@ SUBSYSTEM_DEF(spacedrift) var/old_dir = AM.dir var/old_loc = AM.loc AM.inertia_moving = TRUE + AM.set_glide_size(DELAY_TO_GLIDE_SIZE(AM.inertia_move_delay), FALSE) step(AM, AM.inertia_dir) AM.inertia_moving = FALSE AM.inertia_next_move = world.time + AM.inertia_move_delay diff --git a/code/controllers/subsystem/statpanel.dm b/code/controllers/subsystem/statpanel.dm index 13e9ff50a2..d0d5579611 100644 --- a/code/controllers/subsystem/statpanel.dm +++ b/code/controllers/subsystem/statpanel.dm @@ -203,3 +203,4 @@ SUBSYSTEM_DEF(statpanels) set hidden = TRUE statbrowser_ready = TRUE + init_verbs() diff --git a/code/controllers/subsystem/stickyban.dm b/code/controllers/subsystem/stickyban.dm index 189efa99fe..0c71777bc0 100644 --- a/code/controllers/subsystem/stickyban.dm +++ b/code/controllers/subsystem/stickyban.dm @@ -1,34 +1,231 @@ SUBSYSTEM_DEF(stickyban) - name = "Sticky Ban" + name = "PRISM" init_order = INIT_ORDER_STICKY_BAN flags = SS_NO_FIRE var/list/cache = list() + var/list/dbcache = list() + var/list/confirmed_exempt = list() + var/dbcacheexpire = 0 + /datum/controller/subsystem/stickyban/Initialize(timeofday) - var/list/bannedkeys = world.GetConfig("ban") + if (length(GLOB.stickybanadminexemptions)) + restore_stickybans() + var/list/bannedkeys = sticky_banned_ckeys() //sanitize the sticky ban list + + //delete db bans that no longer exist in the database and add new legacy bans to the database + if (SSdbcore.Connect() || length(SSstickyban.dbcache)) + if (length(GLOB.stickybanadminexemptions)) + restore_stickybans() + for (var/oldban in (world.GetConfig("ban") - bannedkeys)) + var/ckey = ckey(oldban) + if (ckey != oldban && (ckey in bannedkeys)) + continue + + var/list/ban = params2list(world.GetConfig("ban", oldban)) + if (ban && !ban["fromdb"]) + if (!import_raw_stickyban_to_db(ckey, ban)) + log_world("Could not import stickyban on [oldban] into the database. Ignoring") + continue + dbcacheexpire = 0 + bannedkeys += ckey + world.SetConfig("ban", oldban, null) + + if (length(GLOB.stickybanadminexemptions)) //the previous loop can sleep + restore_stickybans() + for (var/bannedkey in bannedkeys) var/ckey = ckey(bannedkey) - var/list/ban = stickyban2list(world.GetConfig("ban", bannedkey)) + var/list/ban = get_stickyban_from_ckey(bannedkey) - //byond stores sticky bans by key, that can end up confusing things - //i also remove it here so that if any stickybans cause a runtime, they just stop existing - world.SetConfig("ban", bannedkey, null) + //byond stores sticky bans by key, that's lame + if (ckey != bannedkey) + world.SetConfig("ban", bannedkey, null) if (!ban["ckey"]) ban["ckey"] = ckey - //storing these can break things and isn't needed for sticky ban tracking - ban -= "IP" - ban -= "computer_id" - ban["matches_this_round"] = list() ban["existing_user_matches_this_round"] = list() ban["admin_matches_this_round"] = list() + ban["pending_matches_this_round"] = list() + cache[ckey] = ban - - for (var/bannedckey in cache) - world.SetConfig("ban", bannedckey, list2stickyban(cache[bannedckey])) + world.SetConfig("ban", ckey, list2stickyban(ban)) return ..() + +/datum/controller/subsystem/stickyban/proc/Populatedbcache() + var/newdbcache = list() //so if we runtime or the db connection dies we don't kill the existing cache + + // var/datum/db_query/query_stickybans = SSdbcore.NewQuery("SELECT ckey, reason, banning_admin, datetime FROM [format_table_name("stickyban")] ORDER BY ckey") + // var/datum/db_query/query_ckey_matches = SSdbcore.NewQuery("SELECT stickyban, matched_ckey, first_matched, last_matched, exempt FROM [format_table_name("stickyban_matched_ckey")] ORDER BY first_matched") + // var/datum/db_query/query_cid_matches = SSdbcore.NewQuery("SELECT stickyban, matched_cid, first_matched, last_matched FROM [format_table_name("stickyban_matched_cid")] ORDER BY first_matched") + // var/datum/db_query/query_ip_matches = SSdbcore.NewQuery("SELECT stickyban, INET_NTOA(matched_ip), first_matched, last_matched FROM [format_table_name("stickyban_matched_ip")] ORDER BY first_matched") + + var/datum/DBQuery/query_stickybans = SSdbcore.NewQuery("SELECT ckey, reason, banning_admin, datetime FROM [format_table_name("stickyban")] ORDER BY ckey") + var/datum/DBQuery/query_ckey_matches = SSdbcore.NewQuery("SELECT stickyban, matched_ckey, first_matched, last_matched, exempt FROM [format_table_name("stickyban_matched_ckey")] ORDER BY first_matched") + var/datum/DBQuery/query_cid_matches = SSdbcore.NewQuery("SELECT stickyban, matched_cid, first_matched, last_matched FROM [format_table_name("stickyban_matched_cid")] ORDER BY first_matched") + var/datum/DBQuery/query_ip_matches = SSdbcore.NewQuery("SELECT stickyban, INET_NTOA(matched_ip), first_matched, last_matched FROM [format_table_name("stickyban_matched_ip")] ORDER BY first_matched") + + SSdbcore.QuerySelect(list(query_stickybans, query_ckey_matches, query_cid_matches, query_ip_matches)) + + if (query_stickybans.last_error) + qdel(query_stickybans) + qdel(query_ckey_matches) + qdel(query_cid_matches) + qdel(query_ip_matches) + return + + while (query_stickybans.NextRow()) + var/list/ban = list() + + ban["ckey"] = query_stickybans.item[1] + ban["message"] = query_stickybans.item[2] + ban["reason"] = "(InGameBan)([query_stickybans.item[3]])" + ban["admin"] = query_stickybans.item[3] + ban["datetime"] = query_stickybans.item[4] + ban["type"] = list("sticky") + + newdbcache["[query_stickybans.item[1]]"] = ban + + + if (!query_ckey_matches.last_error) + while (query_ckey_matches.NextRow()) + var/list/match = list() + + match["stickyban"] = query_ckey_matches.item[1] + match["matched_ckey"] = query_ckey_matches.item[2] + match["first_matched"] = query_ckey_matches.item[3] + match["last_matched"] = query_ckey_matches.item[4] + match["exempt"] = text2num(query_ckey_matches.item[5]) + + var/ban = newdbcache[query_ckey_matches.item[1]] + if (!ban) + continue + var/keys = ban[text2num(query_ckey_matches.item[5]) ? "whitelist" : "keys"] + if (!keys) + keys = ban[text2num(query_ckey_matches.item[5]) ? "whitelist" : "keys"] = list() + keys[query_ckey_matches.item[2]] = match + + if (!query_cid_matches.last_error) + while (query_cid_matches.NextRow()) + var/list/match = list() + + match["stickyban"] = query_cid_matches.item[1] + match["matched_cid"] = query_cid_matches.item[2] + match["first_matched"] = query_cid_matches.item[3] + match["last_matched"] = query_cid_matches.item[4] + + var/ban = newdbcache[query_cid_matches.item[1]] + if (!ban) + continue + var/computer_ids = ban["computer_id"] + if (!computer_ids) + computer_ids = ban["computer_id"] = list() + computer_ids[query_cid_matches.item[2]] = match + + + if (!query_ip_matches.last_error) + while (query_ip_matches.NextRow()) + var/list/match = list() + + match["stickyban"] = query_ip_matches.item[1] + match["matched_ip"] = query_ip_matches.item[2] + match["first_matched"] = query_ip_matches.item[3] + match["last_matched"] = query_ip_matches.item[4] + + var/ban = newdbcache[query_ip_matches.item[1]] + if (!ban) + continue + var/IPs = ban["IP"] + if (!IPs) + IPs = ban["IP"] = list() + IPs[query_ip_matches.item[2]] = match + + dbcache = newdbcache + dbcacheexpire = world.time+STICKYBAN_DB_CACHE_TIME + + qdel(query_stickybans) + qdel(query_ckey_matches) + qdel(query_cid_matches) + qdel(query_ip_matches) + + +/datum/controller/subsystem/stickyban/proc/import_raw_stickyban_to_db(ckey, list/ban) + . = FALSE + if (!ban["admin"]) + ban["admin"] = "LEGACY" + if (!ban["message"]) + ban["message"] = "Evasion" + + // TODO: USE NEW DB IMPLEMENTATION + var/datum/DBQuery/query_create_stickyban = SSdbcore.NewQuery( + "INSERT IGNORE INTO [format_table_name("stickyban")] (ckey, reason, banning_admin) VALUES ([ckey], [ban["message"]], ban["admin"]))" + ) + + if (query_create_stickyban.warn_execute()) + qdel(query_create_stickyban) + return + qdel(query_create_stickyban) + + // var/datum/db_query/query_create_stickyban = SSdbcore.NewQuery( + // "INSERT IGNORE INTO [format_table_name("stickyban")] (ckey, reason, banning_admin) VALUES (:ckey, :message, :admin)", + // list("ckey" = ckey, "message" = ban["message"], "admin" = ban["admin"]) + // ) + // if (!query_create_stickyban.warn_execute()) + // qdel(query_create_stickyban) + // return + // qdel(query_create_stickyban) + + var/list/sqlckeys = list() + var/list/sqlcids = list() + var/list/sqlips = list() + + if (ban["keys"]) + var/list/keys = splittext(ban["keys"], ",") + for (var/key in keys) + var/list/sqlckey = list() + sqlckey["stickyban"] = ckey + sqlckey["matched_ckey"] = ckey(key) + sqlckey["exempt"] = FALSE + sqlckeys[++sqlckeys.len] = sqlckey + + if (ban["whitelist"]) + var/list/keys = splittext(ban["whitelist"], ",") + for (var/key in keys) + var/list/sqlckey = list() + sqlckey["stickyban"] = ckey + sqlckey["matched_ckey"] = ckey(key) + sqlckey["exempt"] = TRUE + sqlckeys[++sqlckeys.len] = sqlckey + + if (ban["computer_id"]) + var/list/cids = splittext(ban["computer_id"], ",") + for (var/cid in cids) + var/list/sqlcid = list() + sqlcid["stickyban"] = ckey + sqlcid["matched_cid"] = cid + sqlcids[++sqlcids.len] = sqlcid + + if (ban["IP"]) + var/list/ips = splittext(ban["IP"], ",") + for (var/ip in ips) + var/list/sqlip = list() + sqlip["stickyban"] = ckey + sqlip["matched_ip"] = ip + sqlips[++sqlips.len] = sqlip + + if (length(sqlckeys)) + SSdbcore.MassInsert(format_table_name("stickyban_matched_ckey"), sqlckeys, ignore_errors = TRUE) + + if (length(sqlcids)) + SSdbcore.MassInsert(format_table_name("stickyban_matched_cid"), sqlcids, ignore_errors = TRUE) + + if (length(sqlips)) + SSdbcore.MassInsert(format_table_name("stickyban_matched_ip"), sqlips, ignore_errors = TRUE) + + + return TRUE diff --git a/code/controllers/subsystem/throwing.dm b/code/controllers/subsystem/throwing.dm index 8c5abc5469..0fa8035d72 100644 --- a/code/controllers/subsystem/throwing.dm +++ b/code/controllers/subsystem/throwing.dm @@ -57,6 +57,7 @@ SUBSYSTEM_DEF(throwing) var/dx var/dy var/force = MOVE_FORCE_DEFAULT + var/gentle = FALSE var/pure_diagonal var/diagonal_error var/datum/callback/callback @@ -64,15 +65,44 @@ SUBSYSTEM_DEF(throwing) var/delayed_time = 0 var/last_move = 0 + +/datum/thrownthing/New(thrownthing, target, target_turf, init_dir, maxrange, speed, thrower, diagonals_first, force, gentle, callback, target_zone) + . = ..() + src.thrownthing = thrownthing + RegisterSignal(thrownthing, COMSIG_PARENT_QDELETING, .proc/on_thrownthing_qdel) + src.target = target + src.target_turf = target_turf + src.init_dir = init_dir + src.maxrange = maxrange + src.speed = speed + src.thrower = thrower + src.diagonals_first = diagonals_first + src.force = force + src.gentle = gentle + src.callback = callback + src.target_zone = target_zone + + /datum/thrownthing/Destroy() + if(HAS_TRAIT_FROM(thrownthing, TRAIT_SPOOKY_THROW, "revenant")) + REMOVE_TRAIT(thrownthing, TRAIT_SPOOKY_THROW, "revenant") SSthrowing.processing -= thrownthing thrownthing.throwing = null thrownthing = null target = null thrower = null - callback = null + if(callback) + QDEL_NULL(callback) //It stores a reference to the thrownthing, its source. Let's clean that. return ..() + +///Defines the datum behavior on the thrownthing's qdeletion event. +/datum/thrownthing/proc/on_thrownthing_qdel(atom/movable/source, force) + SIGNAL_HANDLER + + qdel(src) + + /datum/thrownthing/proc/tick() var/atom/movable/AM = thrownthing if (!isturf(AM.loc) || !AM.throwing) @@ -112,7 +142,7 @@ SUBSYSTEM_DEF(throwing) finalize() return - AM.Move(step, get_dir(AM, step)) + AM.Move(step, get_dir(AM, step), DELAY_TO_GLIDE_SIZE(1 / speed)) if (!AM.throwing) // we hit something during our move finalize(hit = TRUE) @@ -136,15 +166,21 @@ SUBSYSTEM_DEF(throwing) if (A == target) hit = TRUE thrownthing.throw_impact(A, src) + if(QDELETED(thrownthing)) //throw_impact can delete things, such as glasses smashing + return //deletion should already be handled by on_thrownthing_qdel() break if (!hit) thrownthing.throw_impact(get_turf(thrownthing), src) // we haven't hit something yet and we still must, let's hit the ground. + if(QDELETED(thrownthing)) //throw_impact can delete things, such as glasses smashing + return //deletion should already be handled by on_thrownthing_qdel() thrownthing.newtonian_move(init_dir) else thrownthing.newtonian_move(init_dir) if(target) thrownthing.throw_impact(target, src) + if(QDELETED(thrownthing)) //throw_impact can delete things, such as glasses smashing + return //deletion should already be handled by on_thrownthing_qdel() if (callback) callback.Invoke() diff --git a/code/controllers/subsystem/time_track.dm b/code/controllers/subsystem/time_track.dm index 2f4949fc1e..8a0a351d48 100644 --- a/code/controllers/subsystem/time_track.dm +++ b/code/controllers/subsystem/time_track.dm @@ -1,7 +1,8 @@ SUBSYSTEM_DEF(time_track) name = "Time Tracking" - wait = 1 SECONDS - flags = SS_NO_INIT|SS_NO_TICK_CHECK + wait = 10 + flags = SS_NO_TICK_CHECK + init_order = INIT_ORDER_TIMETRACK runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT var/time_dilation_current = 0 @@ -16,33 +17,81 @@ SUBSYSTEM_DEF(time_track) var/last_tick_byond_time = 0 var/last_tick_tickcount = 0 - var/last_measurement = 0 - var/measurement_delay = 60 - - var/stat_time_text - var/time_dilation_text +/datum/controller/subsystem/time_track/Initialize(start_timeofday) + . = ..() + GLOB.perf_log = "[GLOB.log_directory]/perf-[GLOB.round_id ? GLOB.round_id : "NULL"]-[SSmapping.config?.map_name].csv" + log_perf( + list( + "time", + "players", + "tidi", + "tidi_fastavg", + "tidi_avg", + "tidi_slowavg", + "maptick", + "num_timers", + "air_turf_cost", + "air_eg_cost", + "air_highpressure_cost", + "air_hotspots_cost", + "air_superconductivity_cost", + "air_pipenets_cost", + "air_rebuilds_cost", + "air_turf_count", + "air_eg_count", + "air_hotspot_count", + "air_network_count", + "air_delta_count", + "air_superconductive_count" + ) + ) /datum/controller/subsystem/time_track/fire() - stat_time_text = "Server Time: [time2text(world.timeofday, "YYYY-MM-DD hh:mm:ss")]\n\nRound Time: [DisplayTimeText(world.time - SSticker.round_start_time, 1)] \n\nStation Time: [STATION_TIME_TIMESTAMP("hh:mm:ss", world.time)]\n\n[time_dilation_text]" - if(++last_measurement == measurement_delay) - last_measurement = 0 - var/current_realtime = REALTIMEOFDAY - var/current_byondtime = world.time - var/current_tickcount = world.time/world.tick_lag + var/current_realtime = REALTIMEOFDAY + var/current_byondtime = world.time + var/current_tickcount = world.time/world.tick_lag + GLOB.glide_size_multiplier = (current_byondtime - last_tick_byond_time) / (current_realtime - last_tick_realtime) - if (!first_run) - var/tick_drift = max(0, (((current_realtime - last_tick_realtime) - (current_byondtime - last_tick_byond_time)) / world.tick_lag)) + if(times_fired % 10) // everything else is once every 10 seconds + return - time_dilation_current = tick_drift / (current_tickcount - last_tick_tickcount) * 100 + if (!first_run) + var/tick_drift = max(0, (((current_realtime - last_tick_realtime) - (current_byondtime - last_tick_byond_time)) / world.tick_lag)) - time_dilation_avg_fast = MC_AVERAGE_FAST(time_dilation_avg_fast, time_dilation_current) - time_dilation_avg = MC_AVERAGE(time_dilation_avg, time_dilation_avg_fast) - time_dilation_avg_slow = MC_AVERAGE_SLOW(time_dilation_avg_slow, time_dilation_avg) - else - first_run = FALSE - last_tick_realtime = current_realtime - last_tick_byond_time = current_byondtime - last_tick_tickcount = current_tickcount - SSblackbox.record_feedback("associative", "time_dilation_current", 1, list("[SQLtime()]" = list("current" = "[time_dilation_current]", "avg_fast" = "[time_dilation_avg_fast]", "avg" = "[time_dilation_avg]", "avg_slow" = "[time_dilation_avg_slow]"))) - time_dilation_text = "Time Dilation: [round(time_dilation_current,1)]% AVG:([round(time_dilation_avg_fast,1)]%, [round(time_dilation_avg,1)]%, [round(time_dilation_avg_slow,1)]%)" + time_dilation_current = tick_drift / (current_tickcount - last_tick_tickcount) * 100 + + time_dilation_avg_fast = MC_AVERAGE_FAST(time_dilation_avg_fast, time_dilation_current) + time_dilation_avg = MC_AVERAGE(time_dilation_avg, time_dilation_avg_fast) + time_dilation_avg_slow = MC_AVERAGE_SLOW(time_dilation_avg_slow, time_dilation_avg) + else + first_run = FALSE + last_tick_realtime = current_realtime + last_tick_byond_time = current_byondtime + last_tick_tickcount = current_tickcount + SSblackbox.record_feedback("associative", "time_dilation_current", 1, list("[SQLtime()]" = list("current" = "[time_dilation_current]", "avg_fast" = "[time_dilation_avg_fast]", "avg" = "[time_dilation_avg]", "avg_slow" = "[time_dilation_avg_slow]"))) + log_perf( + list( + world.time, + length(GLOB.clients), + time_dilation_current, + time_dilation_avg_fast, + time_dilation_avg, + time_dilation_avg_slow, + MAPTICK_LAST_INTERNAL_TICK_USAGE, + length(SStimer.timer_id_dict), + SSair.cost_turfs, + SSair.cost_groups, + SSair.cost_highpressure, + SSair.cost_hotspots, + SSair.cost_superconductivity, + SSair.cost_pipenets, + SSair.cost_rebuilds, + SSair.get_active_turfs(), //does not return a list, which is what we want + SSair.get_amt_excited_groups(), + length(SSair.hotspots), + length(SSair.networks), + length(SSair.high_pressure_delta), + length(SSair.active_super_conductivity) + ) + ) diff --git a/code/controllers/subsystem/timer.dm b/code/controllers/subsystem/timer.dm index 398e23cdc1..48165be960 100644 --- a/code/controllers/subsystem/timer.dm +++ b/code/controllers/subsystem/timer.dm @@ -1,31 +1,51 @@ -#define BUCKET_LEN (world.fps*1*60) //how many ticks should we keep in the bucket. (1 minutes worth) +/// Controls how many buckets should be kept, each representing a tick. (1 minutes worth) +#define BUCKET_LEN (world.fps*1*60) +/// Helper for getting the correct bucket for a given timer #define BUCKET_POS(timer) (((round((timer.timeToRun - SStimer.head_offset) / world.tick_lag)+1) % BUCKET_LEN)||BUCKET_LEN) +/// Gets the maximum time at which timers will be invoked from buckets, used for deferring to secondary queue #define TIMER_MAX (world.time + TICKS2DS(min(BUCKET_LEN-(SStimer.practical_offset-DS2TICKS(world.time - SStimer.head_offset))-1, BUCKET_LEN-1))) -#define TIMER_ID_MAX (2**24) //max float with integer precision +/// Max float with integer precision +#define TIMER_ID_MAX (2**24) +/** + * # Timer Subsystem + * + * Handles creation, callbacks, and destruction of timed events. + * + * It is important to understand the buckets used in the timer subsystem are just a series of circular doubly-linked + * lists. The object at a given index in bucket_list is a /datum/timedevent, the head of a circular list, which has prev + * and next references for the respective elements in that bucket's circular list. + */ SUBSYSTEM_DEF(timer) name = "Timer" - wait = 1 //SS_TICKER subsystem, so wait is in ticks + wait = 1 // SS_TICKER subsystem, so wait is in ticks init_order = INIT_ORDER_TIMER - + priority = FIRE_PRIORITY_TIMER flags = SS_TICKER|SS_NO_INIT - var/list/datum/timedevent/second_queue = list() //awe, yes, you've had first queue, but what about second queue? + /// Queue used for storing timers that do not fit into the current buckets + var/list/datum/timedevent/second_queue = list() + /// A hashlist dictionary used for storing unique timers var/list/hashes = list() - - var/head_offset = 0 //world.time of the first entry in the the bucket. - var/practical_offset = 1 //index of the first non-empty item in the bucket. - var/bucket_resolution = 0 //world.tick_lag the bucket was designed for - var/bucket_count = 0 //how many timers are in the buckets - - var/list/bucket_list = list() //list of buckets, each bucket holds every timer that has to run that byond tick. - - var/list/timer_id_dict = list() //list of all active timers assoicated to their timer id (for easy lookup) - - var/list/clienttime_timers = list() //special snowflake timers that run on fancy pansy "client time" - + /// world.time of the first entry in the bucket list, effectively the 'start time' of the current buckets + var/head_offset = 0 + /// Index of the wrap around pivot for buckets. buckets before this are later running buckets wrapped around from the end of the bucket list. + var/practical_offset = 1 + /// world.tick_lag the bucket was designed for + var/bucket_resolution = 0 + /// How many timers are in the buckets + var/bucket_count = 0 + /// List of buckets, each bucket holds every timer that has to run that byond tick + var/list/bucket_list = list() + /// List of all active timers associated to their timer ID (for easy lookup) + var/list/timer_id_dict = list() + /// Special timers that run in real-time, not BYOND time; these are more expensive to run and maintain + var/list/clienttime_timers = list() + /// Contains the last time that a timer's callback was invoked, or the last tick the SS fired if no timers are being processed var/last_invoke_tick = 0 + /// Contains the last time that a warning was issued for not invoking callbacks var/static/last_invoke_warning = 0 + /// Boolean operator controlling if the timer SS will automatically reset buckets if it fails to invoke callbacks for an extended period of time var/static/bucket_auto_reset = TRUE /datum/controller/subsystem/timer/PreInit() @@ -38,44 +58,53 @@ SUBSYSTEM_DEF(timer) return ..() /datum/controller/subsystem/timer/fire(resumed = FALSE) + // Store local references to datum vars as it is faster to access them var/lit = last_invoke_tick - var/last_check = world.time - TICKS2DS(BUCKET_LEN*1.5) var/list/bucket_list = src.bucket_list + var/last_check = world.time - TICKS2DS(BUCKET_LEN * 1.5) + // If there are no timers being tracked, then consider now to be the last invoked time if(!bucket_count) last_invoke_tick = world.time + // Check that we have invoked a callback in the last 1.5 minutes of BYOND time, + // and throw a warning and reset buckets if this is true if(lit && lit < last_check && head_offset < last_check && last_invoke_warning < last_check) last_invoke_warning = world.time - var/msg = "No regular timers processed in the last [BUCKET_LEN*1.5] ticks[bucket_auto_reset ? ", resetting buckets" : ""]!" + var/msg = "No regular timers processed in the last [BUCKET_LEN * 1.5] ticks[bucket_auto_reset ? ", resetting buckets" : ""]!" message_admins(msg) WARNING(msg) if(bucket_auto_reset) bucket_resolution = 0 - log_world("Timer bucket reset. world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]") + var/list/to_log = list("Timer bucket reset. world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]") for (var/i in 1 to length(bucket_list)) var/datum/timedevent/bucket_head = bucket_list[i] if (!bucket_head) continue - log_world("Active timers at index [i]:") - + to_log += "Active timers at index [i]:" var/datum/timedevent/bucket_node = bucket_head var/anti_loop_check = 1000 do - log_world(get_timer_debug_string(bucket_node)) + to_log += get_timer_debug_string(bucket_node) bucket_node = bucket_node.next anti_loop_check-- while(bucket_node && bucket_node != bucket_head && anti_loop_check) - log_world("Active timers in the second_queue queue:") + + to_log += "Active timers in the second_queue queue:" for(var/I in second_queue) - log_world(get_timer_debug_string(I)) + to_log += get_timer_debug_string(I) - var/next_clienttime_timer_index = 0 - var/len = length(clienttime_timers) + // Dump all the logged data to the world log + log_world(to_log.Join("\n")) - for (next_clienttime_timer_index in 1 to len) + // Process client-time timers + var/static/next_clienttime_timer_index = 0 + if (next_clienttime_timer_index) + clienttime_timers.Cut(1, next_clienttime_timer_index+1) + next_clienttime_timer_index = 0 + for (next_clienttime_timer_index in 1 to length(clienttime_timers)) if (MC_TICK_CHECK) next_clienttime_timer_index-- break @@ -86,8 +115,8 @@ SUBSYSTEM_DEF(timer) var/datum/callback/callBack = ctime_timer.callBack if (!callBack) - clienttime_timers.Cut(next_clienttime_timer_index,next_clienttime_timer_index+1) - CRASH("Invalid timer: [get_timer_debug_string(ctime_timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset], REALTIMEOFDAY: [REALTIMEOFDAY]") + CRASH("Invalid timer: [get_timer_debug_string(ctime_timer)] world.time: [world.time], \ + head_offset: [head_offset], practical_offset: [practical_offset], REALTIMEOFDAY: [REALTIMEOFDAY]") ctime_timer.spent = REALTIMEOFDAY callBack.InvokeAsync() @@ -95,135 +124,93 @@ SUBSYSTEM_DEF(timer) if(ctime_timer.flags & TIMER_LOOP) ctime_timer.spent = 0 ctime_timer.timeToRun = REALTIMEOFDAY + ctime_timer.wait - BINARY_INSERT(ctime_timer, clienttime_timers, datum/timedevent, ctime_timer, timeToRun, COMPARE_KEY) + BINARY_INSERT(ctime_timer, clienttime_timers, /datum/timedevent, ctime_timer, timeToRun, COMPARE_KEY) else qdel(ctime_timer) - + // Remove invoked client-time timers if (next_clienttime_timer_index) clienttime_timers.Cut(1, next_clienttime_timer_index+1) + next_clienttime_timer_index = 0 if (MC_TICK_CHECK) return - var/static/list/spent = list() - var/static/datum/timedevent/timer + // Check for when we need to loop the buckets, this occurs when + // the head_offset is approaching BUCKET_LEN ticks in the past if (practical_offset > BUCKET_LEN) head_offset += TICKS2DS(BUCKET_LEN) practical_offset = 1 resumed = FALSE + // Check for when we have to reset buckets, typically from auto-reset if ((length(bucket_list) != BUCKET_LEN) || (world.tick_lag != bucket_resolution)) reset_buckets() bucket_list = src.bucket_list resumed = FALSE - if (!resumed) - timer = null - - while (practical_offset <= BUCKET_LEN && head_offset + ((practical_offset-1)*world.tick_lag) <= world.time) - var/datum/timedevent/head = bucket_list[practical_offset] - if (!timer || !head || timer == head) - head = bucket_list[practical_offset] - timer = head - while (timer) + // Iterate through each bucket starting from the practical offset + while (practical_offset <= BUCKET_LEN && head_offset + ((practical_offset - 1) * world.tick_lag) <= world.time) + var/datum/timedevent/timer + while ((timer = bucket_list[practical_offset])) var/datum/callback/callBack = timer.callBack if (!callBack) - bucket_resolution = null //force bucket recreation - CRASH("Invalid timer: [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]") + bucket_resolution = null // force bucket recreation + CRASH("Invalid timer: [get_timer_debug_string(timer)] world.time: [world.time], \ + head_offset: [head_offset], practical_offset: [practical_offset]") + timer.bucketEject() //pop the timer off of the bucket list. + + // Invoke callback if possible if (!timer.spent) - spent += timer timer.spent = world.time callBack.InvokeAsync() last_invoke_tick = world.time - if (MC_TICK_CHECK) - return - - timer = timer.next - if (timer == head) - break - - - bucket_list[practical_offset++] = null - - //we freed up a bucket, lets see if anything in second_queue needs to be shifted to that bucket. - var/i = 0 - var/L = length(second_queue) - for (i in 1 to L) - timer = second_queue[i] - if (timer.timeToRun >= TIMER_MAX) - i-- - break - - if (timer.timeToRun < head_offset) - bucket_resolution = null //force bucket recreation - stack_trace("[i] Invalid timer state: Timer in long run queue with a time to run less then head_offset. [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]") - - if (timer.callBack && !timer.spent) - timer.callBack.InvokeAsync() - spent += timer - bucket_count++ - else if(!QDELETED(timer)) - qdel(timer) - continue - - if (timer.timeToRun < head_offset + TICKS2DS(practical_offset-1)) - bucket_resolution = null //force bucket recreation - stack_trace("[i] Invalid timer state: Timer in long run queue that would require a backtrack to transfer to short run queue. [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]") - if (timer.callBack && !timer.spent) - timer.callBack.InvokeAsync() - spent += timer - bucket_count++ - else if(!QDELETED(timer)) - qdel(timer) - continue - - bucket_count++ - var/bucket_pos = max(1, BUCKET_POS(timer)) - - var/datum/timedevent/bucket_head = bucket_list[bucket_pos] - if (!bucket_head) - bucket_list[bucket_pos] = timer - timer.next = null - timer.prev = null - continue - - if (!bucket_head.prev) - bucket_head.prev = bucket_head - timer.next = bucket_head - timer.prev = bucket_head.prev - timer.next.prev = timer - timer.prev.next = timer - if (i) - second_queue.Cut(1, i+1) - - timer = null - - bucket_count -= length(spent) - - for (var/i in spent) - var/datum/timedevent/qtimer = i - if(QDELETED(qtimer)) - bucket_count++ - continue - if(!(qtimer.flags & TIMER_LOOP)) - qdel(qtimer) - else - bucket_count++ - qtimer.spent = 0 - qtimer.bucketEject() - if(qtimer.flags & TIMER_CLIENT_TIME) - qtimer.timeToRun = REALTIMEOFDAY + qtimer.wait + if (timer.flags & TIMER_LOOP) // Prepare looping timers to re-enter the queue + timer.spent = 0 + timer.timeToRun = world.time + timer.wait + timer.bucketJoin() else - qtimer.timeToRun = world.time + qtimer.wait - qtimer.bucketJoin() + qdel(timer) - spent.len = 0 + if (MC_TICK_CHECK) + break -//formated this way to be runtime resistant + if (!bucket_list[practical_offset]) + // Empty the bucket, check if anything in the secondary queue should be shifted to this bucket + bucket_list[practical_offset++] = null + var/i = 0 + for (i in 1 to length(second_queue)) + timer = second_queue[i] + if (timer.timeToRun >= TIMER_MAX) + i-- + break + + // Check for timers that are scheduled to run in the past + if (timer.timeToRun < head_offset) + bucket_resolution = null // force bucket recreation + stack_trace("[i] Invalid timer state: Timer in long run queue with a time to run less then head_offset. \ + [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]") + break + + // Check for timers that are not capable of being scheduled to run without rebuilding buckets + if (timer.timeToRun < head_offset + TICKS2DS(practical_offset - 1)) + bucket_resolution = null // force bucket recreation + stack_trace("[i] Invalid timer state: Timer in long run queue that would require a backtrack to transfer to \ + short run queue. [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]") + break + + timer.bucketJoin() + if (i) + second_queue.Cut(1, i+1) + if (MC_TICK_CHECK) + break + +/** + * Generates a string with details about the timed event for debugging purposes + */ /datum/controller/subsystem/timer/proc/get_timer_debug_string(datum/timedevent/TE) . = "Timer: [TE]" . += "Prev: [TE.prev ? TE.prev : "NULL"], Next: [TE.next ? TE.next : "NULL"]" @@ -234,12 +221,16 @@ SUBSYSTEM_DEF(timer) if(!TE.callBack) . += ", NO CALLBACK" +/** + * Destroys the existing buckets and creates new buckets from the existing timed events + */ /datum/controller/subsystem/timer/proc/reset_buckets() - var/list/bucket_list = src.bucket_list + var/list/bucket_list = src.bucket_list // Store local reference to datum var, this is faster var/list/alltimers = list() - //collect the timers currently in the bucket + + // Get all timers currently in the buckets for (var/bucket_head in bucket_list) - if (!bucket_head) + if (!bucket_head) // if bucket is empty for this tick continue var/datum/timedevent/bucket_node = bucket_head do @@ -247,25 +238,38 @@ SUBSYSTEM_DEF(timer) bucket_node = bucket_node.next while(bucket_node && bucket_node != bucket_head) + // Empty the list by zeroing and re-assigning the length bucket_list.len = 0 bucket_list.len = BUCKET_LEN + // Reset values for the subsystem to their initial values practical_offset = 1 bucket_count = 0 head_offset = world.time bucket_resolution = world.tick_lag + // Add all timed events from the secondary queue as well alltimers += second_queue + + // If there are no timers being tracked by the subsystem, + // there is no need to do any further rebuilding if (!length(alltimers)) return + // Sort all timers by time to run sortTim(alltimers, .proc/cmp_timer) + // Get the earliest timer, and if the TTR is earlier than the current world.time, + // then set the head offset appropriately to be the earliest time tracked by the + // current set of buckets var/datum/timedevent/head = alltimers[1] - if (head.timeToRun < head_offset) head_offset = head.timeToRun + // Iterate through each timed event and insert it into an appropriate bucket, + // up unto the point that we can no longer insert into buckets as the TTR + // is outside the range we are tracking, then insert the remainder into the + // secondary queue var/new_bucket_count var/i = 1 for (i in 1 to length(alltimers)) @@ -273,34 +277,38 @@ SUBSYSTEM_DEF(timer) if (!timer) continue - var/bucket_pos = BUCKET_POS(timer) + // Check that the TTR is within the range covered by buckets, when exceeded we've finished if (timer.timeToRun >= TIMER_MAX) i-- break - + // Check that timer has a valid callback and hasn't been invoked if (!timer.callBack || timer.spent) - WARNING("Invalid timer: [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]") + WARNING("Invalid timer: [get_timer_debug_string(timer)] world.time: [world.time], \ + head_offset: [head_offset], practical_offset: [practical_offset]") if (timer.callBack) qdel(timer) continue + // Insert the timer into the bucket, and perform necessary circular doubly-linked list operations new_bucket_count++ + var/bucket_pos = BUCKET_POS(timer) var/datum/timedevent/bucket_head = bucket_list[bucket_pos] if (!bucket_head) bucket_list[bucket_pos] = timer timer.next = null timer.prev = null continue - if (!bucket_head.prev) bucket_head.prev = bucket_head timer.next = bucket_head timer.prev = bucket_head.prev timer.next.prev = timer timer.prev.next = timer + + // Cut the timers that are tracked by the buckets from the secondary queue if (i) - alltimers.Cut(1, i+1) + alltimers.Cut(1, i + 1) second_queue = alltimers bucket_count = new_bucket_count @@ -311,45 +319,64 @@ SUBSYSTEM_DEF(timer) timer_id_dict |= SStimer.timer_id_dict bucket_list |= SStimer.bucket_list +/** + * # Timed Event + * + * This is the actual timer, it contains the callback and necessary data to maintain + * the timer. + * + * See the documentation for the timer subsystem for an explanation of the buckets referenced + * below in next and prev + */ /datum/timedevent + /// ID used for timers when the TIMER_STOPPABLE flag is present var/id + /// The callback to invoke after the timer completes var/datum/callback/callBack + /// The time at which the callback should be invoked at var/timeToRun + /// The length of the timer var/wait + /// Unique hash generated when TIMER_UNIQUE flag is present var/hash + /// The source of the timedevent, whatever called addtimer + var/source + /// Flags associated with the timer, see _DEFINES/subsystems.dm var/list/flags - var/spent = 0 //time we ran the timer. - var/name //for easy debugging. - //cicular doublely linked list + /// Time at which the timer was invoked or destroyed + var/spent = 0 + /// An informative name generated for the timer as its representation in strings, useful for debugging + var/name + /// Next timed event in the bucket var/datum/timedevent/next + /// Previous timed event in the bucket var/datum/timedevent/prev -/datum/timedevent/New(datum/callback/callBack, wait, flags, hash) +/datum/timedevent/New(datum/callback/callBack, wait, flags, hash, source) var/static/nextid = 1 id = TIMER_ID_NULL src.callBack = callBack src.wait = wait src.flags = flags src.hash = hash + src.source = source - if (flags & TIMER_CLIENT_TIME) - timeToRun = REALTIMEOFDAY + wait - else - timeToRun = world.time + wait + // Determine time at which the timer's callback should be invoked + timeToRun = (flags & TIMER_CLIENT_TIME ? REALTIMEOFDAY : world.time) + wait + // Include the timer in the hash table if the timer is unique if (flags & TIMER_UNIQUE) SStimer.hashes[hash] = src + // Generate ID for the timer if the timer is stoppable, include in the timer id dictionary if (flags & TIMER_STOPPABLE) id = num2text(nextid, 100) if (nextid >= SHORT_REAL_LIMIT) - nextid += min(1, 2**round(nextid/SHORT_REAL_LIMIT)) + nextid += min(1, 2 ** round(nextid / SHORT_REAL_LIMIT)) else nextid++ SStimer.timer_id_dict[id] = src - name = "Timer: [id] (\ref[src]), TTR: [timeToRun], Flags: [jointext(bitfield2list(flags, list("TIMER_UNIQUE", "TIMER_OVERRIDE", "TIMER_CLIENT_TIME", "TIMER_STOPPABLE", "TIMER_NO_HASH_WAIT", "TIMER_LOOP")), ", ")], callBack: \ref[callBack], callBack.object: [callBack.object]\ref[callBack.object]([getcallingtype()]), callBack.delegate:[callBack.delegate]([callBack.arguments ? callBack.arguments.Join(", ") : ""])" - if ((timeToRun < world.time || timeToRun < SStimer.head_offset) && !(flags & TIMER_CLIENT_TIME)) CRASH("Invalid timer state: Timer created that would require a backtrack to run (addtimer would never let this happen): [SStimer.get_timer_debug_string(src)]") @@ -390,23 +417,39 @@ SUBSYSTEM_DEF(timer) prev = null return QDEL_HINT_IWILLGC +/** + * Removes this timed event from any relevant buckets, or the secondary queue + */ /datum/timedevent/proc/bucketEject() + // Attempt to find bucket that contains this timed event var/bucketpos = BUCKET_POS(src) + + // Store local references for the bucket list and secondary queue + // This is faster than referencing them from the datum itself var/list/bucket_list = SStimer.bucket_list var/list/second_queue = SStimer.second_queue + + // Attempt to get the head of the bucket var/datum/timedevent/buckethead if(bucketpos > 0) buckethead = bucket_list[bucketpos] + + // Decrement the number of timers in buckets if the timed event is + // the head of the bucket, or has a TTR less than TIMER_MAX implying it fits + // into an existing bucket, or is otherwise not present in the secondary queue if(buckethead == src) bucket_list[bucketpos] = next SStimer.bucket_count-- - else if(timeToRun < TIMER_MAX || next || prev) + else if(timeToRun < TIMER_MAX) SStimer.bucket_count-- else var/l = length(second_queue) second_queue -= src if(l == length(second_queue)) SStimer.bucket_count-- + + // Remove the timed event from the bucket, ensuring to maintain + // the integrity of the bucket's list if relevant if(prev != next) prev.next = next next.prev = prev @@ -415,32 +458,47 @@ SUBSYSTEM_DEF(timer) next?.prev = null prev = next = null +/** + * Attempts to add this timed event to a bucket, will enter the secondary queue + * if there are no appropriate buckets at this time. + * + * Secondary queueing of timed events will occur when the timespan covered by the existing + * buckets is exceeded by the time at which this timed event is scheduled to be invoked. + * If the timed event is tracking client time, it will be added to a special bucket. + */ /datum/timedevent/proc/bucketJoin() - var/list/L + // Generate debug-friendly name for timer + var/static/list/bitfield_flags = list("TIMER_UNIQUE", "TIMER_OVERRIDE", "TIMER_CLIENT_TIME", "TIMER_STOPPABLE", "TIMER_NO_HASH_WAIT", "TIMER_LOOP") + name = "Timer: [id] (\ref[src]), TTR: [timeToRun], wait:[wait] Flags: [jointext(bitfield2list(flags, bitfield_flags), ", ")], \ + callBack: \ref[callBack], callBack.object: [callBack.object]\ref[callBack.object]([getcallingtype()]), \ + callBack.delegate:[callBack.delegate]([callBack.arguments ? callBack.arguments.Join(", ") : ""]), source: [source]" + // Check if this timed event should be diverted to the client time bucket, or the secondary queue + var/list/L if (flags & TIMER_CLIENT_TIME) L = SStimer.clienttime_timers else if (timeToRun >= TIMER_MAX) L = SStimer.second_queue - if(L) - BINARY_INSERT(src, L, datum/timedevent, src, timeToRun, COMPARE_KEY) + BINARY_INSERT(src, L, /datum/timedevent, src, timeToRun, COMPARE_KEY) return - //get the list of buckets + // Get a local reference to the bucket list, this is faster than referencing the datum var/list/bucket_list = SStimer.bucket_list - //calculate our place in the bucket list + // Find the correct bucket for this timed event var/bucket_pos = BUCKET_POS(src) - - //get the bucket for our tick var/datum/timedevent/bucket_head = bucket_list[bucket_pos] SStimer.bucket_count++ - //empty bucket, we will just add ourselves + + // If there is no timed event at this position, then the bucket is 'empty' + // and we can just set this event to that position if (!bucket_head) bucket_list[bucket_pos] = src return - //other wise, lets do a simplified linked list add. + + // Otherwise, we merely add this timed event into the bucket, which is a + // circularly doubly-linked list if (!bucket_head.prev) bucket_head.prev = bucket_head next = bucket_head @@ -448,7 +506,9 @@ SUBSYSTEM_DEF(timer) next.prev = src prev.next = src -///Returns a string of the type of the callback for this timer +/** + * Returns a string of the type of the callback for this timer + */ /datum/timedevent/proc/getcallingtype() . = "ERROR" if (callBack.object == GLOBAL_PROC) @@ -457,14 +517,15 @@ SUBSYSTEM_DEF(timer) . = "[callBack.object.type]" /** - * Create a new timer and insert it in the queue - * - * Arguments: - * * callback the callback to call on timer finish - * * wait deciseconds to run the timer for - * * flags flags for this timer, see: code\__DEFINES\subsystems.dm - */ -/proc/addtimer(datum/callback/callback, wait = 0, flags = 0) + * Create a new timer and insert it in the queue. + * You should not call this directly, and should instead use the addtimer macro, which includes source information. + * + * Arguments: + * * callback the callback to call on timer finish + * * wait deciseconds to run the timer for + * * flags flags for this timer, see: code\__DEFINES\subsystems.dm + */ +/proc/_addtimer(datum/callback/callback, wait = 0, flags = 0, file, line) if (!callback) CRASH("addtimer called without a callback") @@ -472,31 +533,30 @@ SUBSYSTEM_DEF(timer) stack_trace("addtimer called with a negative wait. Converting to [world.tick_lag]") if (callback.object != GLOBAL_PROC && QDELETED(callback.object) && !QDESTROYING(callback.object)) - stack_trace("addtimer called with a callback assigned to a qdeleted object. In the future such timers will not be supported and may refuse to run or run with a 0 wait") + stack_trace("addtimer called with a callback assigned to a qdeleted object. In the future such timers will not \ + be supported and may refuse to run or run with a 0 wait") wait = max(CEILING(wait, world.tick_lag), world.tick_lag) if(wait >= INFINITY) CRASH("Attempted to create timer with INFINITY delay") + // Generate hash if relevant for timed events with the TIMER_UNIQUE flag var/hash - if (flags & TIMER_UNIQUE) - var/list/hashlist - if(flags & TIMER_NO_HASH_WAIT) - hashlist = list(callback.object, "([REF(callback.object)])", callback.delegate, flags & TIMER_CLIENT_TIME) - else - hashlist = list(callback.object, "([REF(callback.object)])", callback.delegate, wait, flags & TIMER_CLIENT_TIME) + var/list/hashlist = list(callback.object, "([REF(callback.object)])", callback.delegate, flags & TIMER_CLIENT_TIME) + if(!(flags & TIMER_NO_HASH_WAIT)) + hashlist += wait hashlist += callback.arguments hash = hashlist.Join("|||||||") var/datum/timedevent/hash_timer = SStimer.hashes[hash] if(hash_timer) - if (hash_timer.spent) //it's pending deletion, pretend it doesn't exist. - hash_timer.hash = null //but keep it from accidentally deleting us + if (hash_timer.spent) // it's pending deletion, pretend it doesn't exist. + hash_timer.hash = null // but keep it from accidentally deleting us else if (flags & TIMER_OVERRIDE) - hash_timer.hash = null //no need having it delete it's hash if we are going to replace it + hash_timer.hash = null // no need having it delete it's hash if we are going to replace it qdel(hash_timer) else if (hash_timer.flags & TIMER_STOPPABLE) @@ -505,24 +565,23 @@ SUBSYSTEM_DEF(timer) else if(flags & TIMER_OVERRIDE) stack_trace("TIMER_OVERRIDE used without TIMER_UNIQUE") - var/datum/timedevent/timer = new(callback, wait, flags, hash) + var/datum/timedevent/timer = new(callback, wait, flags, hash, file && "[file]:[line]") return timer.id /** - * Delete a timer - * - * Arguments: - * * id a timerid or a /datum/timedevent - */ + * Delete a timer + * + * Arguments: + * * id a timerid or a /datum/timedevent + */ /proc/deltimer(id) if (!id) return FALSE if (id == TIMER_ID_NULL) CRASH("Tried to delete a null timerid. Use TIMER_STOPPABLE flag") - if (!istext(id)) - if (istype(id, /datum/timedevent)) - qdel(id) - return TRUE + if (istype(id, /datum/timedevent)) + qdel(id) + return TRUE //id is string var/datum/timedevent/timer = SStimer.timer_id_dict[id] if (timer && !timer.spent) @@ -531,25 +590,22 @@ SUBSYSTEM_DEF(timer) return FALSE /** - * Get the remaining deciseconds on a timer - * - * Arguments: - * * id a timerid or a /datum/timedevent - */ + * Get the remaining deciseconds on a timer + * + * Arguments: + * * id a timerid or a /datum/timedevent + */ /proc/timeleft(id) if (!id) return null if (id == TIMER_ID_NULL) CRASH("Tried to get timeleft of a null timerid. Use TIMER_STOPPABLE flag") - if (!istext(id)) - if (istype(id, /datum/timedevent)) - var/datum/timedevent/timer = id - return timer.timeToRun - world.time + if (istype(id, /datum/timedevent)) + var/datum/timedevent/timer = id + return timer.timeToRun - world.time //id is string var/datum/timedevent/timer = SStimer.timer_id_dict[id] - if (timer && !timer.spent) - return timer.timeToRun - world.time - return null + return (timer && !timer.spent) ? timer.timeToRun - world.time : null #undef BUCKET_LEN #undef BUCKET_POS diff --git a/code/controllers/subsystem/title.dm b/code/controllers/subsystem/title.dm index bd843f959d..996f73ccf6 100644 --- a/code/controllers/subsystem/title.dm +++ b/code/controllers/subsystem/title.dm @@ -25,12 +25,12 @@ SUBSYSTEM_DEF(title) SSmapping.HACK_LoadMapConfig() for(var/S in provisional_title_screens) var/list/L = splittext(S,"+") - if((L.len == 1 && L[1] != "blank.png")|| (L.len > 1 && ((use_rare_screens && lowertext(L[1]) == "rare") || (lowertext(L[1]) == lowertext(SSmapping.config.map_name))))) + if((L.len == 1 && (L[1] != "exclude" && L[1] != "blank.png"))|| (L.len > 1 && ((use_rare_screens && lowertext(L[1]) == "rare") || (lowertext(L[1]) == lowertext(SSmapping.config.map_name))))) title_screens += S if(length(title_screens)) file_path = "[global.config.directory]/title_screens/images/[pick(title_screens)]" - + if(!file_path) file_path = "icons/default_title.dmi" diff --git a/code/controllers/subsystem/vis_overlays.dm b/code/controllers/subsystem/vis_overlays.dm index 0635709074..b0e5d6c689 100644 --- a/code/controllers/subsystem/vis_overlays.dm +++ b/code/controllers/subsystem/vis_overlays.dm @@ -5,10 +5,12 @@ SUBSYSTEM_DEF(vis_overlays) init_order = INIT_ORDER_VIS var/list/vis_overlay_cache + var/list/unique_vis_overlays var/list/currentrun /datum/controller/subsystem/vis_overlays/Initialize() vis_overlay_cache = list() + unique_vis_overlays = list() return ..() /datum/controller/subsystem/vis_overlays/fire(resumed = FALSE) @@ -29,31 +31,45 @@ SUBSYSTEM_DEF(vis_overlays) return //the "thing" var can be anything with vis_contents which includes images -/datum/controller/subsystem/vis_overlays/proc/add_vis_overlay(atom/movable/thing, icon, iconstate, layer, plane, dir, alpha = 255, add_appearance_flags = NONE) - . = "[icon]|[iconstate]|[layer]|[plane]|[dir]|[alpha]|[add_appearance_flags]" - var/obj/effect/overlay/vis/overlay = vis_overlay_cache[.] - if(!overlay) - overlay = new - overlay.icon = icon - overlay.icon_state = iconstate - overlay.layer = layer - overlay.plane = plane - overlay.dir = dir - overlay.alpha = alpha - overlay.appearance_flags |= add_appearance_flags - vis_overlay_cache[.] = overlay +/datum/controller/subsystem/vis_overlays/proc/add_vis_overlay(atom/movable/thing, icon, iconstate, layer, plane, dir, alpha = 255, add_appearance_flags = NONE, unique = FALSE) + var/obj/effect/overlay/vis/overlay + if(!unique) + . = "[icon]|[iconstate]|[layer]|[plane]|[dir]|[alpha]|[add_appearance_flags]" + overlay = vis_overlay_cache[.] + if(!overlay) + overlay = _create_new_vis_overlay(icon, iconstate, layer, plane, dir, alpha, add_appearance_flags) + vis_overlay_cache[.] = overlay + else + overlay.unused = 0 else - overlay.unused = 0 + overlay = _create_new_vis_overlay(icon, iconstate, layer, plane, dir, alpha, add_appearance_flags) + overlay.cache_expiration = -1 + var/cache_id = "\ref[overlay]@{[world.time]}" + unique_vis_overlays += overlay + vis_overlay_cache[cache_id] = overlay + . = overlay thing.vis_contents += overlay if(!isatom(thing)) // Automatic rotation is not supported on non atoms - return + return overlay if(!thing.managed_vis_overlays) thing.managed_vis_overlays = list(overlay) - RegisterSignal(thing, COMSIG_ATOM_DIR_CHANGE, .proc/rotate_vis_overlay) else thing.managed_vis_overlays += overlay + return overlay + +/datum/controller/subsystem/vis_overlays/proc/_create_new_vis_overlay(icon, iconstate, layer, plane, dir, alpha, add_appearance_flags) + var/obj/effect/overlay/vis/overlay = new + overlay.icon = icon + overlay.icon_state = iconstate + overlay.layer = layer + overlay.plane = plane + overlay.dir = dir + overlay.alpha = alpha + overlay.appearance_flags |= add_appearance_flags + return overlay + /datum/controller/subsystem/vis_overlays/proc/remove_vis_overlay(atom/movable/thing, list/overlays) thing.vis_contents -= overlays @@ -62,15 +78,3 @@ SUBSYSTEM_DEF(vis_overlays) thing.managed_vis_overlays -= overlays if(!length(thing.managed_vis_overlays)) thing.managed_vis_overlays = null - UnregisterSignal(thing, COMSIG_ATOM_DIR_CHANGE) - -/datum/controller/subsystem/vis_overlays/proc/rotate_vis_overlay(atom/thing, old_dir, new_dir) - if(old_dir == new_dir) - return - var/rotation = dir2angle(old_dir) - dir2angle(new_dir) - var/list/overlays_to_remove = list() - for(var/i in thing.managed_vis_overlays) - var/obj/effect/overlay/vis/overlay = i - add_vis_overlay(thing, overlay.icon, overlay.icon_state, overlay.layer, overlay.plane, turn(overlay.dir, rotation), overlay.alpha, overlay.appearance_flags) - overlays_to_remove += overlay - remove_vis_overlay(thing, overlays_to_remove) diff --git a/code/datums/brain_damage/imaginary_friend.dm b/code/datums/brain_damage/imaginary_friend.dm index e5e1434ab8..f35389f171 100644 --- a/code/datums/brain_damage/imaginary_friend.dm +++ b/code/datums/brain_damage/imaginary_friend.dm @@ -92,7 +92,7 @@ trauma = _trauma owner = trauma.owner - setup_friend() + INVOKE_ASYNC(src, .proc/setup_friend) join = new join.Grant(src) diff --git a/code/datums/cinematic.dm b/code/datums/cinematic.dm index 7b3081cb33..2648ae1eab 100644 --- a/code/datums/cinematic.dm +++ b/code/datums/cinematic.dm @@ -30,7 +30,7 @@ /datum/cinematic var/id = CINEMATIC_DEFAULT var/list/watching = list() //List of clients watching this - var/list/locked = list() //Who had mob_transforming set during the cinematic + var/list/locked = list() //Who had mob_transforming set during the cinematic var/is_global = FALSE //Global cinematics will override mob-specific ones var/obj/screen/cinematic/screen var/datum/callback/special_callback //For special effects synced with animation (explosions after the countdown etc) @@ -45,7 +45,7 @@ if(!CC) continue var/client/C = CC - //C.mob.clear_fullscreen("cinematic") + C.mob.clear_fullscreen("cinematic") C.screen -= screen watching = null QDEL_NULL(screen) @@ -54,7 +54,7 @@ if(!MM) continue var/mob/M = MM - M.mob_transforming = FALSE + M.mob_transforming = FALSE locked = null return ..() @@ -93,7 +93,7 @@ toggle_ooc(TRUE) /datum/cinematic/proc/show_to(mob/M, client/C) - //SIGNAL_HANDLER //must not wait. + SIGNAL_HANDLER if(!M.mob_transforming) locked += M @@ -101,7 +101,7 @@ if(!C) return watching += C - //M.overlay_fullscreen("cinematic",/obj/screen/fullscreen/cinematic_backdrop) + M.overlay_fullscreen("cinematic",/obj/screen/fullscreen/cinematic_backdrop) C.screen += screen //Sound helper @@ -122,7 +122,7 @@ sleep(50) /datum/cinematic/proc/replacement_cinematic(datum/source, datum/cinematic/other) - //SIGNAL_HANDLER + SIGNAL_HANDLER if(!is_global && other.is_global) //Allow it to play if we're local and it's global return NONE @@ -210,6 +210,20 @@ special() screen.icon_state = "summary_cult" +// /datum/cinematic/cult_fail +// id = CINEMATIC_CULT_FAIL + +// /datum/cinematic/cult_fail/content() +// screen.icon_state = "station_intact" +// sleep(20) +// cinematic_sound(sound('sound/creatures/narsie_rises.ogg')) +// sleep(60) +// cinematic_sound(sound('sound/effects/explosion_distant.ogg')) +// sleep(10) +// cinematic_sound(sound('sound/magic/demon_dies.ogg')) +// sleep(30) +// special() + /datum/cinematic/nuke_annihilation id = CINEMATIC_ANNIHILATION diff --git a/code/datums/components/combat_mode.dm b/code/datums/components/combat_mode.dm index b9952e9133..29d90fd509 100644 --- a/code/datums/components/combat_mode.dm +++ b/code/datums/components/combat_mode.dm @@ -125,7 +125,7 @@ ///Changes the user direction to (try) keep match the pointer. /datum/component/combat_mode/proc/on_move(atom/movable/source, dir, atom/oldloc, forced) var/mob/living/L = source - if(mode_flags & COMBAT_MODE_ACTIVE && L.client && lastmousedir && lastmousedir != dir) + if((mode_flags & COMBAT_MODE_ACTIVE) && L.client) L.setDir(lastmousedir, ismousemovement = TRUE) /// Added movement delay if moving backward. diff --git a/code/datums/components/footstep.dm b/code/datums/components/footstep.dm index f767c607a5..8b326ac424 100644 --- a/code/datums/components/footstep.dm +++ b/code/datums/components/footstep.dm @@ -46,7 +46,7 @@ var/mob/living/LM = parent if(!T.footstep || LM.buckled || !CHECK_MOBILITY(LM, MOBILITY_STAND) || LM.buckled || LM.throwing || (LM.movement_type & (VENTCRAWLING | FLYING))) if (LM.lying && !LM.buckled && !(!T.footstep || LM.movement_type & (VENTCRAWLING | FLYING))) //play crawling sound if we're lying - playsound(T, 'sound/effects/footstep/crawl1.ogg', 15 * volume) + playsound(T, 'sound/effects/footstep/crawl1.ogg', 15 * volume, falloff_distance = 1) return if(HAS_TRAIT(LM, TRAIT_SILENT_STEP)) @@ -75,7 +75,7 @@ if(!T) return if(isfile(footstep_sounds) || istext(footstep_sounds)) - playsound(T, footstep_sounds, volume) + playsound(T, footstep_sounds, volume, falloff_distance = 1) return var/turf_footstep switch(footstep_type) @@ -89,7 +89,7 @@ turf_footstep = T.footstep if(!turf_footstep) return - playsound(T, pick(footstep_sounds[turf_footstep][1]), footstep_sounds[turf_footstep][2] * volume, TRUE, footstep_sounds[turf_footstep][3] + e_range) + playsound(T, pick(footstep_sounds[turf_footstep][1]), footstep_sounds[turf_footstep][2] * volume, TRUE, footstep_sounds[turf_footstep][3] + e_range, falloff_distance = 1) /datum/component/footstep/proc/play_humanstep() var/turf/open/T = prepare_step() @@ -114,10 +114,10 @@ turf_footstep = T.footstep L = GLOB.footstep if(FOOTSTEP_MOB_SLIME) - playsound(T, 'sound/effects/footstep/slime1.ogg', 50 * volume) + playsound(T, 'sound/effects/footstep/slime1.ogg', 50 * volume, falloff_distance = 1) return if(FOOTSTEP_MOB_CRAWL) - playsound(T, 'sound/effects/footstep/crawl1.ogg', 50 * volume) + playsound(T, 'sound/effects/footstep/crawl1.ogg', 50 * volume, falloff_distance = 1) return special = TRUE else @@ -126,13 +126,13 @@ playsound(T, pick(GLOB.footstep[T.footstep][1]), GLOB.footstep[T.footstep][2] * volume, TRUE, - GLOB.footstep[T.footstep][3] + e_range) + GLOB.footstep[T.footstep][3] + e_range, falloff_distance = 1) return if(!special && H.dna.species.special_step_sounds) - playsound(T, pick(H.dna.species.special_step_sounds), 50, TRUE) + playsound(T, pick(H.dna.species.special_step_sounds), 50, TRUE, falloff_distance = 1) else playsound(T, pick(L[turf_footstep][1]), L[turf_footstep][2] * volume, TRUE, - L[turf_footstep][3] + e_range) + L[turf_footstep][3] + e_range, falloff_distance = 1) diff --git a/code/datums/components/gps.dm b/code/datums/components/gps.dm index c2b3ad1f30..61098c8b66 100644 --- a/code/datums/components/gps.dm +++ b/code/datums/components/gps.dm @@ -21,7 +21,7 @@ GLOBAL_LIST_EMPTY(GPS_list) var/updating = TRUE //Automatic updating of GPS list. Can be set to manual by user. var/global_mode = TRUE //If disabled, only GPS signals of the same Z level are shown -/datum/component/gps/item/Initialize(_gpstag = "COM0", emp_proof = FALSE) +/datum/component/gps/item/Initialize(_gpstag = "COM0", emp_proof = FALSE, starton = TRUE) . = ..() if(. == COMPONENT_INCOMPATIBLE || !isitem(parent)) return COMPONENT_INCOMPATIBLE @@ -33,6 +33,8 @@ GLOBAL_LIST_EMPTY(GPS_list) RegisterSignal(parent, COMSIG_ATOM_EMP_ACT, .proc/on_emp_act) RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/on_examine) RegisterSignal(parent, COMSIG_CLICK_ALT, .proc/on_AltClick) + if(!starton) + tracking = FALSE ///Called on COMSIG_ITEM_ATTACK_SELF /datum/component/gps/item/proc/interact(datum/source, mob/user) diff --git a/code/datums/components/riding.dm b/code/datums/components/riding.dm index 03f3820a9b..e9aa5afe92 100644 --- a/code/datums/components/riding.dm +++ b/code/datums/components/riding.dm @@ -36,15 +36,15 @@ if(del_on_unbuckle_all && !AM.has_buckled_mobs()) qdel(src) -/datum/component/riding/proc/vehicle_mob_buckle(datum/source, mob/living/M, force = FALSE) +/datum/component/riding/proc/vehicle_mob_buckle(datum/source, mob/living/M, force) handle_vehicle_offsets() -/datum/component/riding/proc/handle_vehicle_layer() +/datum/component/riding/proc/handle_vehicle_layer(dir) var/atom/movable/AM = parent var/static/list/defaults = list(TEXT_NORTH = OBJ_LAYER, TEXT_SOUTH = ABOVE_MOB_LAYER, TEXT_EAST = ABOVE_MOB_LAYER, TEXT_WEST = ABOVE_MOB_LAYER) - . = defaults["[AM.dir]"] - if(directional_vehicle_layers["[AM.dir]"]) - . = directional_vehicle_layers["[AM.dir]"] + . = defaults["[dir]"] + if(directional_vehicle_layers["[dir]"]) + . = directional_vehicle_layers["[dir]"] if(isnull(.)) //you can set it to null to not change it. . = AM.layer AM.layer = . @@ -52,12 +52,17 @@ /datum/component/riding/proc/set_vehicle_dir_layer(dir, layer) directional_vehicle_layers["[dir]"] = layer -/datum/component/riding/proc/vehicle_moved(datum/source) +/datum/component/riding/proc/vehicle_moved(datum/source, oldLoc, dir) + SIGNAL_HANDLER + var/atom/movable/AM = parent + if (isnull(dir)) + dir = AM.dir + AM.set_glide_size(DELAY_TO_GLIDE_SIZE(vehicle_move_delay), FALSE) for(var/i in AM.buckled_mobs) ride_check(i) - handle_vehicle_offsets() - handle_vehicle_layer() + handle_vehicle_offsets(dir) + handle_vehicle_layer(dir) /datum/component/riding/proc/ride_check(mob/living/M) var/atom/movable/AM = parent @@ -74,9 +79,9 @@ /datum/component/riding/proc/additional_offset_checks() return TRUE -/datum/component/riding/proc/handle_vehicle_offsets() +/datum/component/riding/proc/handle_vehicle_offsets(dir) var/atom/movable/AM = parent - var/AM_dir = "[AM.dir]" + var/AM_dir = "[dir]" var/passindex = 0 if(AM.has_buckled_mobs()) for(var/m in AM.buckled_mobs) @@ -177,8 +182,8 @@ else last_move_diagonal = FALSE - handle_vehicle_offsets() - handle_vehicle_layer() + handle_vehicle_offsets(direction) + handle_vehicle_layer(direction) else to_chat(user, "You'll need the keys in one of your hands to [drive_verb] [AM].") diff --git a/code/datums/components/squeak.dm b/code/datums/components/squeak.dm index 0552a791ea..a285b7d3f2 100644 --- a/code/datums/components/squeak.dm +++ b/code/datums/components/squeak.dm @@ -19,7 +19,14 @@ /// chance we'll be stopped from squeaking by cooldown when something crossing us squeaks var/cross_squeak_delay_chance = 33 // about 3 things can squeak at a time -/datum/component/squeak/Initialize(custom_sounds, volume_override, chance_override, step_delay_override, use_delay_override) + ///extra-range for this component's sound + var/sound_extra_range = -1 + ///when sounds start falling off for the squeak + var/sound_falloff_distance = SOUND_DEFAULT_FALLOFF_DISTANCE + ///sound exponent for squeak. Defaults to 10 as squeaking is loud and annoying enough. + var/sound_falloff_exponent = 10 + +/datum/component/squeak/Initialize(custom_sounds, volume_override, chance_override, step_delay_override, use_delay_override, extrarange, falloff_exponent, fallof_distance) if(!isatom(parent)) return COMPONENT_INCOMPATIBLE RegisterSignal(parent, list(COMSIG_ATOM_ENTERED, COMSIG_ATOM_BLOB_ACT, COMSIG_ATOM_HULK_ATTACK, COMSIG_PARENT_ATTACKBY), .proc/play_squeak) @@ -45,6 +52,12 @@ step_delay = step_delay_override if(isnum(use_delay_override)) use_delay = use_delay_override + if(isnum(extrarange)) + sound_extra_range = extrarange + if(isnum(falloff_exponent)) + sound_falloff_exponent = falloff_exponent + if(isnum(fallof_distance)) + sound_falloff_distance = fallof_distance /datum/component/squeak/UnregisterFromParent() if(!isatom(parent)) @@ -62,6 +75,7 @@ return ..() /datum/component/squeak/proc/play_squeak() + SIGNAL_HANDLER do_play_squeak() /datum/component/squeak/proc/do_play_squeak(bypass_cooldown = FALSE) @@ -69,14 +83,16 @@ return FALSE if(prob(squeak_chance)) if(!override_squeak_sounds) - playsound(parent, pickweight(default_squeak_sounds), volume, 1, -1) + playsound(parent, pickweight(default_squeak_sounds), volume, TRUE, sound_extra_range, sound_falloff_exponent, falloff_distance = sound_falloff_distance) else - playsound(parent, pickweight(override_squeak_sounds), volume, 1, -1) + playsound(parent, pickweight(override_squeak_sounds), volume, TRUE, sound_extra_range, sound_falloff_exponent, falloff_distance = sound_falloff_distance) last_squeak = world.time return TRUE return FALSE /datum/component/squeak/proc/step_squeak() + SIGNAL_HANDLER + if(steps > step_delay) do_play_squeak(TRUE) steps = 0 @@ -84,20 +100,22 @@ steps++ /datum/component/squeak/proc/play_squeak_crossed(datum/source, atom/movable/AM) + SIGNAL_HANDLER + if(isitem(AM)) var/obj/item/I = AM if(I.item_flags & ABSTRACT) return - else if(istype(AM, /obj/item/projectile)) - var/obj/item/projectile/P = AM - if(P.original != parent) - return + if(AM.movement_type & (FLYING|FLOATING) || !AM.has_gravity()) + return var/atom/current_parent = parent if(isturf(current_parent.loc)) if(do_play_squeak()) SEND_SIGNAL(AM, COMSIG_CROSS_SQUEAKED) /datum/component/squeak/proc/use_squeak() + SIGNAL_HANDLER + if(last_use + use_delay < world.time) last_use = world.time play_squeak() @@ -118,6 +136,8 @@ RegisterSignal(holder, COMSIG_ATOM_DIR_CHANGE, .proc/holder_dir_change) /datum/component/squeak/proc/holder_dir_change(datum/source, old_dir, new_dir) + SIGNAL_HANDLER + //If the dir changes it means we're going through a bend in the pipes, let's pretend we bumped the wall if(old_dir != new_dir) play_squeak() diff --git a/code/datums/components/storage/storage.dm b/code/datums/components/storage/storage.dm index f93d40bb04..2fa5a20d7a 100644 --- a/code/datums/components/storage/storage.dm +++ b/code/datums/components/storage/storage.dm @@ -449,6 +449,10 @@ // this must come before the screen objects only block, dunno why it wasn't before if(over_object == M) user_show_to_mob(M) + return + if(isrevenant(M)) + RevenantThrow(over_object, M, source) + return if(!M.incapacitated()) if(!istype(over_object, /obj/screen)) dump_content_at(over_object, M) diff --git a/code/datums/components/tackle.dm b/code/datums/components/tackle.dm index c69df4f5e3..10ff5bda3d 100644 --- a/code/datums/components/tackle.dm +++ b/code/datums/components/tackle.dm @@ -85,6 +85,10 @@ to_chat(user, "You're not ready to tackle!") return + if(!user.mob_has_gravity() ||!user.loc.has_gravity() || isspaceturf(user.loc)) + to_chat(user, "You can't find your footing without gravity!") + return + if(user.has_status_effect(STATUS_EFFECT_TASED)) // can't tackle if you just got tased to_chat(user, "You can't tackle while tased!") return diff --git a/code/datums/datum.dm b/code/datums/datum.dm index d11532a883..42580425ce 100644 --- a/code/datums/datum.dm +++ b/code/datums/datum.dm @@ -77,21 +77,21 @@ /** - * Default implementation of clean-up code. - * - * This should be overridden to remove all references pointing to the object being destroyed, if - * you do override it, make sure to call the parent and return it's return value by default - * - * Return an appropriate [QDEL_HINT][QDEL_HINT_QUEUE] to modify handling of your deletion; - * in most cases this is [QDEL_HINT_QUEUE]. - * - * The base case is responsible for doing the following - * * Erasing timers pointing to this datum - * * Erasing compenents on this datum - * * Notifying datums listening to signals from this datum that we are going away - * - * Returns [QDEL_HINT_QUEUE] - */ + * Default implementation of clean-up code. + * + * This should be overridden to remove all references pointing to the object being destroyed, if + * you do override it, make sure to call the parent and return it's return value by default + * + * Return an appropriate [QDEL_HINT][QDEL_HINT_QUEUE] to modify handling of your deletion; + * in most cases this is [QDEL_HINT_QUEUE]. + * + * The base case is responsible for doing the following + * * Erasing timers pointing to this datum + * * Erasing compenents on this datum + * * Notifying datums listening to signals from this datum that we are going away + * + * Returns [QDEL_HINT_QUEUE] + */ /datum/proc/Destroy(force=FALSE, ...) SHOULD_CALL_PARENT(TRUE) tag = null @@ -138,8 +138,6 @@ UnregisterSignal(target, signal_procs[target]) //END: ECS SHIT - SSsounds.free_datum_channels(src) //?? (not on tg) - return QDEL_HINT_QUEUE #ifdef DATUMVAR_DEBUGGING_MODE diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm index a91549ab4c..0bb803ddb3 100644 --- a/code/datums/datumvars.dm +++ b/code/datums/datumvars.dm @@ -4,7 +4,7 @@ /datum/proc/can_vv_get(var_name) return TRUE -/datum/proc/vv_edit_var(var_name, var_value) //called whenever a var is edited +/datum/proc/vv_edit_var(var_name, var_value, massedit) //called whenever a var is edited if(var_name == NAMEOF(src, vars)) return FALSE vars[var_name] = var_value diff --git a/code/datums/diseases/heart_failure.dm b/code/datums/diseases/heart_failure.dm index aabb9ed144..952ce4f18d 100644 --- a/code/datums/diseases/heart_failure.dm +++ b/code/datums/diseases/heart_failure.dm @@ -37,7 +37,7 @@ to_chat(H, "You feel [pick("full", "nauseated", "sweaty", "weak", "tired", "short on breath", "uneasy")].") if(3 to 4) if(!sound) - H.playsound_local(H, 'sound/health/slowbeat.ogg',40,0, channel = CHANNEL_HEARTBEAT) + H.playsound_local(H, 'sound/health/slowbeat.ogg', 40, FALSE, channel = CHANNEL_HEARTBEAT) sound = TRUE if(prob(3)) to_chat(H, "You feel a sharp pain in your chest!") @@ -53,7 +53,7 @@ H.emote("cough") if(5) H.stop_sound_channel(CHANNEL_HEARTBEAT) - H.playsound_local(H, 'sound/effects/singlebeat.ogg', 100, 0) + H.playsound_local(H, 'sound/effects/singlebeat.ogg', 100, FALSE) if(H.stat == CONSCIOUS) H.visible_message("[H] clutches at [H.p_their()] chest as if [H.p_their()] heart is stopping!") H.adjustStaminaLoss(60) diff --git a/code/datums/diseases/transformation.dm b/code/datums/diseases/transformation.dm index 44775ed031..8dca59ea94 100644 --- a/code/datums/diseases/transformation.dm +++ b/code/datums/diseases/transformation.dm @@ -121,7 +121,7 @@ add_monkey(affected_mob.mind) if(ishuman(affected_mob)) var/mob/living/carbon/monkey/M = affected_mob.monkeyize(TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPORGANS | TR_KEEPDAMAGE | TR_KEEPVIRUS | TR_KEEPSE) - M.ventcrawler = VENTCRAWLER_ALWAYS + M.AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) /datum/disease/transformation/jungle_fever/stage_act() diff --git a/code/datums/elements/bed_tucking.dm b/code/datums/elements/bed_tucking.dm index 602c93fab3..4a498b2ed8 100644 --- a/code/datums/elements/bed_tucking.dm +++ b/code/datums/elements/bed_tucking.dm @@ -57,4 +57,4 @@ tucked.transform = turn(tucked.transform, -rotation_degree) - UnregisterSignal(tucked, COMSIG_ITEM_PICKUP) \ No newline at end of file + UnregisterSignal(tucked, COMSIG_ITEM_PICKUP) diff --git a/code/datums/elements/mob_holder.dm b/code/datums/elements/mob_holder.dm index d770e0f30d..619f674969 100644 --- a/code/datums/elements/mob_holder.dm +++ b/code/datums/elements/mob_holder.dm @@ -141,7 +141,7 @@ /obj/item/clothing/head/mob_holder/dropped(mob/user) . = ..() - if(held_mob && isturf(loc))//don't release on soft-drops + if(held_mob && !ismob(loc))//don't release on soft-drops release() /obj/item/clothing/head/mob_holder/proc/release() diff --git a/code/datums/elements/ventcrawling.dm b/code/datums/elements/ventcrawling.dm new file mode 100644 index 0000000000..254345a97f --- /dev/null +++ b/code/datums/elements/ventcrawling.dm @@ -0,0 +1,36 @@ +/datum/element/ventcrawling + element_flags = ELEMENT_BESPOKE|ELEMENT_DETACH + id_arg_index = 2 + var/tier + +/datum/element/ventcrawling/Attach(datum/target, duration = 0, given_tier = VENTCRAWLER_NUDE) + . = ..() + + var/mob/living/person = target + if(!istype(person)) + return FALSE + + src.tier = given_tier + + RegisterSignal(target, COMSIG_HANDLE_VENTCRAWL, .proc/handle_ventcrawl) + RegisterSignal(target, COMSIG_CHECK_VENTCRAWL, .proc/check_ventcrawl) + to_chat(target, "You can ventcrawl! Use alt+click on vents to quickly travel about the station.") + + if(duration!=0) + addtimer(CALLBACK(src, .proc/Detach, target), duration) + +/datum/element/ventcrawling/Detach(datum/target) + UnregisterSignal(target, list(COMSIG_HANDLE_VENTCRAWL, COMSIG_CHECK_VENTCRAWL)) + to_chat(target, "You can no longer ventcrawl.") + + return ..() + +/datum/element/ventcrawling/proc/handle_ventcrawl(datum/target,atom/A) + var/mob/living/person = target + if(!istype(person)) + return FALSE + + person.handle_ventcrawl(A,tier) + +/datum/element/ventcrawling/proc/check_ventcrawl() + return tier diff --git a/code/datums/explosion.dm b/code/datums/explosion.dm index ca65186063..9a29158b33 100644 --- a/code/datums/explosion.dm +++ b/code/datums/explosion.dm @@ -33,6 +33,14 @@ GLOBAL_LIST_EMPTY(explosions) EX_PREPROCESS_EXIT_CHECK\ } +#define CREAK_DELAY 5 SECONDS //Time taken for the creak to play after explosion, if applicable. +#define FAR_UPPER 60 //Upper limit for the far_volume, distance, clamped. +#define FAR_LOWER 40 //lower limit for the far_volume, distance, clamped. +#define PROB_SOUND 75 //The probability modifier for a sound to be an echo, or a far sound. (0-100) +#define SHAKE_CLAMP 2.5 //The limit for how much the camera can shake for out of view booms. +#define FREQ_UPPER 40 //The upper limit for the randomly selected frequency. +#define FREQ_LOWER 25 //The lower of the above. + /datum/explosion/New(atom/epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range, adminlog, ignorecap, flame_range, silent, smoke) set waitfor = FALSE @@ -89,7 +97,7 @@ GLOBAL_LIST_EMPTY(explosions) if(adminlog) message_admins("Explosion with size ([devastation_range], [heavy_impact_range], [light_impact_range], [flame_range]) in [ADMIN_VERBOSEJMP(epicenter)]") log_game("Explosion with size ([devastation_range], [heavy_impact_range], [light_impact_range], [flame_range]) in [loc_name(epicenter)]") - + deadchat_broadcast("An explosion with size ([devastation_range], [heavy_impact_range], [light_impact_range], [flame_range]) has occured at ([get_area(epicenter)])", turf_target = get_turf(epicenter)) var/x0 = epicenter.x @@ -115,13 +123,14 @@ GLOBAL_LIST_EMPTY(explosions) var/sound/creaking_explosion_sound = sound(get_sfx("explosion_creaking")) var/sound/hull_creaking_sound = sound(get_sfx("hull_creaking")) var/sound/explosion_echo_sound = sound('sound/effects/explosion_distant.ogg') - var/on_station = SSmapping.level_trait(epicenter.z, ZTRAIT_STATION) + var/on_station = SSmapping.level_trait(epicenter.z, ZTRAIT_STATION) var/creaking_explosion = FALSE if(prob(devastation_range*30+heavy_impact_range*5) && on_station) // Huge explosions are near guaranteed to make the station creak and whine, smaller ones might. creaking_explosion = TRUE // prob over 100 always returns true - for(var/mob/M in GLOB.player_list) + for(var/MN in GLOB.player_list) + var/mob/M = MN // Double check for client var/turf/M_turf = get_turf(M) if(M_turf && M_turf.z == z0) @@ -131,15 +140,15 @@ GLOBAL_LIST_EMPTY(explosions) baseshakeamount = sqrt((orig_max_distance - dist)*0.1) // If inside the blast radius + world.view - 2 if(dist <= round(max_range + world.view - 2, 1)) - M.playsound_local(epicenter, null, 100, 1, frequency, falloff = 5, S = explosion_sound) + M.playsound_local(epicenter, null, 100, 1, frequency, S = explosion_sound) if(baseshakeamount > 0) shake_camera(M, 25, clamp(baseshakeamount, 0, 10)) // You hear a far explosion if you're outside the blast radius. Small bombs shouldn't be heard all over the station. else if(dist <= far_dist) - var/far_volume = clamp(far_dist/2, 40, 60) // Volume is based on explosion size and dist + var/far_volume = clamp(far_dist/2, FAR_LOWER, FAR_UPPER) // Volume is based on explosion size and dist if(creaking_explosion) M.playsound_local(epicenter, null, far_volume, 1, frequency, S = creaking_explosion_sound, distance_multiplier = 0) - else if(prob(75)) + else if(prob(PROB_SOUND)) // Sound variety during meteor storm/tesloose/other bad event M.playsound_local(epicenter, null, far_volume, 1, frequency, S = far_explosion_sound, distance_multiplier = 0) // Far sound else M.playsound_local(epicenter, null, far_volume, 1, frequency, S = explosion_echo_sound, distance_multiplier = 0) // Echo sound @@ -147,18 +156,18 @@ GLOBAL_LIST_EMPTY(explosions) if(baseshakeamount > 0 || devastation_range) if(!baseshakeamount) // Devastating explosions rock the station and ground baseshakeamount = devastation_range*3 - shake_camera(M, 10, clamp(baseshakeamount*0.25, 0, 2.5)) - - else if(M.can_hear() && !isspaceturf(get_turf(M)) && heavy_impact_range) // Big enough explosions echo throughout the hull + shake_camera(M, 10, clamp(baseshakeamount*0.25, 0, SHAKE_CLAMP)) + else if(!isspaceturf(get_turf(M)) && heavy_impact_range) // Big enough explosions echo throughout the hull var/echo_volume = 40 if(devastation_range) baseshakeamount = devastation_range - shake_camera(M, 10, clamp(baseshakeamount*0.25, 0, 2.5)) + shake_camera(M, 10, clamp(baseshakeamount*0.25, 0, SHAKE_CLAMP)) echo_volume = 60 M.playsound_local(epicenter, null, echo_volume, 1, frequency, S = explosion_echo_sound, distance_multiplier = 0) if(creaking_explosion) // 5 seconds after the bang, the station begins to creak - addtimer(CALLBACK(M, /mob/proc/playsound_local, epicenter, null, rand(25, 40), 1, frequency, null, null, FALSE, hull_creaking_sound, null, null, null, null, 0), 5 SECONDS) + addtimer(CALLBACK(M, /mob/proc/playsound_local, epicenter, null, rand(FREQ_LOWER, FREQ_UPPER), 1, frequency, null, null, FALSE, hull_creaking_sound, 0), CREAK_DELAY) + EX_PREPROCESS_CHECK_TICK //postpone processing for a bit @@ -230,8 +239,13 @@ GLOBAL_LIST_EMPTY(explosions) atoms += A for(var/i in atoms) var/atom/A = i - if(!QDELETED(A)) - A.ex_act(dist) + if(QDELETED(A)) + continue + A.ex_act(dist, null, src) + if(QDELETED(A) || !ismovable(A)) + continue + var/atom/movable/AM = A + LAZYADD(AM.acted_explosions, explosion_id) if(flame_dist && prob(40) && !isspaceturf(T) && !T.density) new /obj/effect/hotspot(T) //Mostly for ambience! @@ -316,6 +330,14 @@ GLOBAL_LIST_EMPTY(explosions) ++stopped qdel(src) +#undef CREAK_DELAY +#undef FAR_UPPER +#undef FAR_LOWER +#undef PROB_SOUND +#undef SHAKE_CLAMP +#undef FREQ_UPPER +#undef FREQ_LOWER + #undef EX_PREPROCESS_EXIT_CHECK #undef EX_PREPROCESS_CHECK_TICK diff --git a/code/datums/holocall.dm b/code/datums/holocall.dm index 4bf02e8587..c54f6c971a 100644 --- a/code/datums/holocall.dm +++ b/code/datums/holocall.dm @@ -237,7 +237,7 @@ /obj/item/disk/holodisk/Initialize(mapload) . = ..() if(preset_record_text) - build_record() + INVOKE_ASYNC(src, .proc/build_record) /obj/item/disk/holodisk/Destroy() QDEL_NULL(record) @@ -425,42 +425,42 @@ "} /obj/item/disk/holodisk/ruin/snowengieruin - name = "Blackbox Print-out #EB412" - desc = "A holodisk containing the last moments of EB412. There's a bloody fingerprint on it." - preset_image_type = /datum/preset_holoimage/engineer - preset_record_text = {" - NAME Dave Tundrale - SAY Maria, how's Build? - DELAY 10 - NAME Maria Dell - PRESET /datum/preset_holoimage/engineer/atmos - SAY It's fine, don't worry. I've got Plastic on it. And frankly, i'm kinda busy with, the, uhhm, incinerator. - DELAY 30 - NAME Dave Tundrale - PRESET /datum/preset_holoimage/engineer - SAY Aight, wonderful. The science mans been kinda shit though. No RCDs- - DELAY 20 - NAME Maria Dell - PRESET /datum/preset_holoimage/engineer/atmos - SAY Enough about your RCDs. They're not even that important, just bui- - DELAY 15 - SOUND explosion - DELAY 10 - SAY Oh, shit! - DELAY 10 - PRESET /datum/preset_holoimage/engineer/atmos/rig - LANGUAGE /datum/language/narsie - NAME Unknown - SAY RISE, MY LORD!! - DELAY 10 - LANGUAGE /datum/language/common - NAME Plastic - PRESET /datum/preset_holoimage/engineer/rig - SAY Fuck, fuck, fuck! - DELAY 20 - SAY It's loose! CALL THE FUCKING SHUTT- - DELAY 10 - PRESET /datum/preset_holoimage/corgi - NAME Blackbox Automated Message - SAY Connection lost. Dumping audio logs to disk. - DELAY 50"} + name = "Blackbox Print-out #EB412" + desc = "A holodisk containing the last moments of EB412. There's a bloody fingerprint on it." + preset_image_type = /datum/preset_holoimage/engineer + preset_record_text = {" + NAME Dave Tundrale + SAY Maria, how's Build? + DELAY 10 + NAME Maria Dell + PRESET /datum/preset_holoimage/engineer/atmos + SAY It's fine, don't worry. I've got Plastic on it. And frankly, i'm kinda busy with, the, uhhm, incinerator. + DELAY 30 + NAME Dave Tundrale + PRESET /datum/preset_holoimage/engineer + SAY Aight, wonderful. The science mans been kinda shit though. No RCDs- + DELAY 20 + NAME Maria Dell + PRESET /datum/preset_holoimage/engineer/atmos + SAY Enough about your RCDs. They're not even that important, just bui- + DELAY 15 + SOUND explosion + DELAY 10 + SAY Oh, shit! + DELAY 10 + PRESET /datum/preset_holoimage/engineer/atmos/rig + LANGUAGE /datum/language/narsie + NAME Unknown + SAY RISE, MY LORD!! + DELAY 10 + LANGUAGE /datum/language/common + NAME Plastic + PRESET /datum/preset_holoimage/engineer/rig + SAY Fuck, fuck, fuck! + DELAY 20 + SAY It's loose! CALL THE FUCKING SHUTT- + DELAY 10 + PRESET /datum/preset_holoimage/corgi + NAME Blackbox Automated Message + SAY Connection lost. Dumping audio logs to disk. + DELAY 50"} diff --git a/code/datums/looping_sounds/_looping_sound.dm b/code/datums/looping_sounds/_looping_sound.dm index 8bee4f3d1c..6af3b3c993 100644 --- a/code/datums/looping_sounds/_looping_sound.dm +++ b/code/datums/looping_sounds/_looping_sound.dm @@ -18,8 +18,12 @@ var/list/atom/output_atoms var/mid_sounds var/mid_length + ///Override for volume of start sound + var/start_volume var/start_sound var/start_length + ///Override for volume of end sound + var/end_volume var/end_sound var/chance var/volume = 100 @@ -27,10 +31,9 @@ var/max_loops var/direct var/extra_range = 0 - var/falloff - + var/falloff_exponent var/timerid - var/init_timerid + var/falloff_distance /datum/looping_sound/New(list/_output_atoms=list(), start_immediately=FALSE, _direct=FALSE) if(!mid_sounds) @@ -51,16 +54,13 @@ /datum/looping_sound/proc/start(atom/add_thing) if(add_thing) output_atoms |= add_thing - if(timerid || init_timerid) + if(timerid) return on_start() /datum/looping_sound/proc/stop(atom/remove_thing) if(remove_thing) output_atoms -= remove_thing - if(init_timerid) - deltimer(init_timerid) - init_timerid = null if(!timerid) return on_stop() @@ -76,18 +76,18 @@ if(!timerid) timerid = addtimer(CALLBACK(src, .proc/sound_loop, world.time), mid_length, TIMER_CLIENT_TIME | TIMER_STOPPABLE | TIMER_LOOP) -/datum/looping_sound/proc/play(soundfile) +/datum/looping_sound/proc/play(soundfile, volume_override) var/list/atoms_cache = output_atoms var/sound/S = sound(soundfile) if(direct) S.channel = SSsounds.random_available_channel() - S.volume = volume + S.volume = volume_override || volume //Use volume as fallback if theres no override for(var/i in 1 to atoms_cache.len) var/atom/thing = atoms_cache[i] if(direct) SEND_SOUND(thing, S) else - playsound(thing, S, volume, vary, extra_range, falloff) + playsound(thing, S, volume, vary, extra_range, falloff_exponent = falloff_exponent, falloff_distance = falloff_distance) /datum/looping_sound/proc/get_sound(starttime, _mid_sounds) . = _mid_sounds || mid_sounds @@ -97,10 +97,10 @@ /datum/looping_sound/proc/on_start() var/start_wait = 0 if(start_sound) - play(start_sound) + play(start_sound, start_volume) start_wait = start_length - init_timerid = addtimer(CALLBACK(src, .proc/sound_loop), start_wait, TIMER_CLIENT_TIME | TIMER_STOPPABLE) + addtimer(CALLBACK(src, .proc/sound_loop), start_wait, TIMER_CLIENT_TIME) /datum/looping_sound/proc/on_stop() if(end_sound) - play(end_sound) + play(end_sound, end_volume) diff --git a/code/datums/looping_sounds/machinery_sounds.dm b/code/datums/looping_sounds/machinery_sounds.dm index 4f6996bfdd..f7a3b46118 100644 --- a/code/datums/looping_sounds/machinery_sounds.dm +++ b/code/datums/looping_sounds/machinery_sounds.dm @@ -4,7 +4,7 @@ mid_sounds = list('sound/machines/shower/shower_mid1.ogg'=1,'sound/machines/shower/shower_mid2.ogg'=1,'sound/machines/shower/shower_mid3.ogg'=1) mid_length = 10 end_sound = 'sound/machines/shower/shower_end.ogg' - volume = 10 + volume = 20 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -12,6 +12,28 @@ mid_sounds = list('sound/machines/sm/supermatter1.ogg'=1,'sound/machines/sm/supermatter2.ogg'=1,'sound/machines/sm/supermatter3.ogg'=1) mid_length = 10 volume = 1 + extra_range = 25 + falloff_exponent = 10 + falloff_distance = 5 + vary = TRUE + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/datum/looping_sound/destabilized_crystal + mid_sounds = list('sound/machines/sm/loops/delamming.ogg' = 1) + mid_length = 60 + volume = 55 + extra_range = 15 + vary = TRUE + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// /datum/looping_sound/hypertorus +// mid_sounds = list('sound/machines/hypertorus/loops/hypertorus_nominal.ogg' = 1) +// mid_length = 60 +// volume = 55 +// extra_range = 15 +// vary = TRUE /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -32,7 +54,22 @@ mid_sounds = list('sound/machines/fryer/deep_fryer_1.ogg' = 1, 'sound/machines/fryer/deep_fryer_2.ogg' = 1) mid_length = 2 end_sound = 'sound/machines/fryer/deep_fryer_emerge.ogg' - volume = 5 + volume = 15 + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +/datum/looping_sound/grill + mid_sounds = list('sound/machines/grill/grillsizzle.ogg' = 1) + mid_length = 18 + volume = 50 + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/datum/looping_sound/deep_fryer + mid_length = 2 + mid_sounds = list('sound/machines/fryer/deep_fryer_1.ogg' = 1, 'sound/machines/fryer/deep_fryer_2.ogg' = 1) + volume = 30 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -46,9 +83,39 @@ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -/datum/looping_sound/grill - mid_length = 2 - mid_sounds = list('sound/machines/fryer/deep_fryer_1.ogg' = 1, 'sound/machines/fryer/deep_fryer_2.ogg' = 1) - volume = 10 +// /datum/looping_sound/jackpot +// mid_length = 11 +// mid_sounds = list('sound/machines/roulettejackpot.ogg') +// volume = 85 +// vary = TRUE -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* +/datum/looping_sound/server + mid_sounds = list('sound/machines/tcomms/tcomms_mid1.ogg'=1,'sound/machines/tcomms/tcomms_mid2.ogg'=1,'sound/machines/tcomms/tcomms_mid3.ogg'=1,'sound/machines/tcomms/tcomms_mid4.ogg'=1,\ + 'sound/machines/tcomms/tcomms_mid5.ogg'=1,'sound/machines/tcomms/tcomms_mid6.ogg'=1,'sound/machines/tcomms/tcomms_mid7.ogg'=1) + mid_length = 1.8 SECONDS + extra_range = -11 + falloff_distance = 1 + falloff_exponent = 5 + volume = 50 +*/ +// /datum/looping_sound/computer +// start_sound = 'sound/machines/computer/computer_start.ogg' +// start_length = 7.2 SECONDS +// start_volume = 10 +// mid_sounds = list('sound/machines/computer/computer_mid1.ogg'=1, 'sound/machines/computer/computer_mid2.ogg'=1) +// mid_length = 1.8 SECONDS +// end_sound = 'sound/machines/computer/computer_end.ogg' +// end_volume = 10 +// volume = 2 +// falloff_exponent = 5 //Ultra quiet very fast +// extra_range = -12 +// falloff_distance = 1 //Instant falloff after initial tile + +// /datum/looping_sound/gravgen +// mid_sounds = list('sound/machines/gravgen/gravgen_mid1.ogg'=1,'sound/machines/gravgen/gravgen_mid2.ogg'=1,'sound/machines/gravgen/gravgen_mid3.ogg'=1,'sound/machines/gravgen/gravgen_mid4.ogg'=1,) +// mid_length = 1.8 SECONDS +// extra_range = 10 +// volume = 70 +// falloff_distance = 5 +// falloff_exponent = 20 diff --git a/code/datums/skills/_skill_modifier.dm b/code/datums/skills/_skill_modifier.dm index c38cbf23c6..fd8de29f28 100644 --- a/code/datums/skills/_skill_modifier.dm +++ b/code/datums/skills/_skill_modifier.dm @@ -47,7 +47,7 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill) if(!mod_L) mod_L = GLOB.potential_mods_per_skill[target_skills] = list() else - BINARY_INSERT(identifier, mod_L, datum/skill_modifier, src, priority, COMPARE_VALUE) + BINARY_INSERT(identifier, mod_L, /datum/skill_modifier, src, priority, COMPARE_VALUE) mod_L[identifier] = src GLOB.potential_skills_per_mod[target_skills_key] = list(target_skills) else //Should be a list. @@ -66,7 +66,7 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill) if(!mod_L) mod_L = GLOB.potential_mods_per_skill[path] = list() else - BINARY_INSERT(identifier, mod_L, datum/skill_modifier, src, priority, COMPARE_VALUE) + BINARY_INSERT(identifier, mod_L, /datum/skill_modifier, src, priority, COMPARE_VALUE) mod_L[identifier] = src /datum/skill_modifier/Destroy() diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm index 19b12410bc..fe59bbe14a 100644 --- a/code/datums/status_effects/debuffs.dm +++ b/code/datums/status_effects/debuffs.dm @@ -887,7 +887,7 @@ L.remove_status_effect(STATUS_EFFECT_CHOKINGSTRAND) -datum/status_effect/pacify +/datum/status_effect/pacify id = "pacify" status_type = STATUS_EFFECT_REPLACE tick_interval = 1 diff --git a/code/game/alternate_appearance.dm b/code/game/alternate_appearance.dm index d7c34da34a..a1746001b9 100644 --- a/code/game/alternate_appearance.dm +++ b/code/game/alternate_appearance.dm @@ -168,7 +168,7 @@ GLOBAL_LIST_EMPTY(active_alternate_appearances) return TRUE return FALSE -datum/atom_hud/alternate_appearance/basic/onePerson +/datum/atom_hud/alternate_appearance/basic/onePerson var/mob/seer /datum/atom_hud/alternate_appearance/basic/onePerson/mobShouldSee(mob/M) diff --git a/code/game/area/Space_Station_13_areas.dm b/code/game/area/Space_Station_13_areas.dm index 2c2cc46344..b2673c960e 100644 --- a/code/game/area/Space_Station_13_areas.dm +++ b/code/game/area/Space_Station_13_areas.dm @@ -45,6 +45,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station ambientsounds = SPACE blob_allowed = FALSE //Eating up space doesn't count for victory as a blob. considered_hull_exterior = TRUE + sound_environment = SOUND_AREA_SPACE /area/space/nearstation icon_state = "space_near" @@ -70,6 +71,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station blob_allowed = FALSE //Nope, no winning on the asteroid as a blob. Gotta eat the station. valid_territory = FALSE ambientsounds = MINING + sound_environment = SOUND_AREA_ASTEROID /area/asteroid/nearstation dynamic_lighting = DYNAMIC_LIGHTING_FORCED @@ -107,7 +109,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station /area/maintenance ambientsounds = MAINTENANCE valid_territory = FALSE - + sound_environment = SOUND_AREA_TUNNEL_ENCLOSED //Departments @@ -122,6 +124,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station /area/maintenance/department/crew_quarters/bar name = "Bar Maintenance" icon_state = "maint_bar" + sound_environment = SOUND_AREA_WOODFLOOR /area/maintenance/department/crew_quarters/dorms name = "Dormitory Maintenance" @@ -265,6 +268,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station /area/hallway nightshift_public_area = NIGHTSHIFT_AREA_PUBLIC + sound_environment = SOUND_AREA_STANDARD_STATION /area/hallway/primary/aft name = "Aft Primary Hallway" @@ -333,30 +337,36 @@ NOTE: there are two lists of areas in the end of this file: centcom and station name = "Bridge" icon_state = "bridge" music = "signal" + sound_environment = SOUND_AREA_STANDARD_STATION /area/bridge/meeting_room name = "Heads of Staff Meeting Room" icon_state = "meeting" music = null + sound_environment = SOUND_AREA_MEDIUM_SOFTFLOOR /area/bridge/meeting_room/council name = "Council Chamber" icon_state = "meeting" music = null + sound_environment = SOUND_AREA_MEDIUM_SOFTFLOOR /area/bridge/showroom/corporate name = "Corporate Showroom" icon_state = "showroom" music = null + sound_environment = SOUND_AREA_MEDIUM_SOFTFLOOR /area/crew_quarters/heads/captain name = "Captain's Office" icon_state = "captain" clockwork_warp_allowed = FALSE + sound_environment = SOUND_AREA_WOODFLOOR /area/crew_quarters/heads/captain/private name = "Captain's Quarters" icon_state = "captain" + sound_environment = SOUND_AREA_WOODFLOOR /area/crew_quarters/heads/chief name = "Chief Engineer's Office" @@ -401,10 +411,12 @@ NOTE: there are two lists of areas in the end of this file: centcom and station /area/comms name = "Communications Relay" icon_state = "tcomsatcham" + sound_environment = SOUND_AREA_STANDARD_STATION /area/server name = "Messaging Server Room" icon_state = "server" + sound_environment = SOUND_AREA_STANDARD_STATION //Crew @@ -413,6 +425,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station icon_state = "Sleep" safe = TRUE nightshift_public_area = NIGHTSHIFT_AREA_RECREATION + sound_environment = SOUND_AREA_STANDARD_STATION /area/crew_quarters/dorms/male name = "Male Dorm" @@ -431,6 +444,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station /area/crew_quarters/toilet name = "Dormitory Toilets" icon_state = "toilet" + sound_environment = SOUND_AREA_SMALL_ENCLOSED /area/crew_quarters/toilet/auxiliary name = "Auxiliary Restrooms" @@ -465,6 +479,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station name = "Lounge" icon_state = "yellow" nightshift_public_area = NIGHTSHIFT_AREA_RECREATION + sound_environment = SOUND_AREA_SMALL_SOFTFLOOR /area/crew_quarters/arcade name = "Arcade" @@ -502,15 +517,18 @@ NOTE: there are two lists of areas in the end of this file: centcom and station /area/crew_quarters/kitchen/backroom name = "Kitchen Coldroom" icon_state = "kitchen" + sound_environment = SOUND_AREA_SMALL_ENCLOSED /area/crew_quarters/bar name = "Bar" icon_state = "bar" nightshift_public_area = NIGHTSHIFT_AREA_RECREATION + sound_environment = SOUND_AREA_WOODFLOOR /area/crew_quarters/bar/atrium name = "Atrium" icon_state = "bar" + sound_environment = SOUND_AREA_WOODFLOOR /area/crew_quarters/electronic_marketing_den name = "Electronic Marketing Den" @@ -526,6 +544,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station /area/crew_quarters/theatre name = "Theatre" icon_state = "Theatre" + sound_environment = SOUND_AREA_WOODFLOOR /area/crew_quarters/theatre/abandoned name = "Abandoned Theatre" @@ -546,10 +565,12 @@ NOTE: there are two lists of areas in the end of this file: centcom and station icon_state = "library" flags_1 = NONE nightshift_public_area = NIGHTSHIFT_AREA_RECREATION + sound_environment = SOUND_AREA_LARGE_SOFTFLOOR /area/library/lounge name = "Library Lounge" icon_state = "library" + sound_environment = SOUND_AREA_SMALL_SOFTFLOOR /area/library/abandoned name = "Abandoned Library" @@ -564,6 +585,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station clockwork_warp_allowed = FALSE clockwork_warp_fail = "The consecration here prevents you from warping in." nightshift_public_area = NIGHTSHIFT_AREA_RECREATION + sound_environment = SOUND_AREA_LARGE_ENCLOSED /area/chapel/main name = "Chapel" @@ -579,6 +601,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station /area/chapel/asteroid name = "Chapel Asteroid" icon_state = "explored" + sound_environment = SOUND_AREA_ASTEROID /area/chapel/asteroid/monastery name = "Monastery Asteroid" @@ -590,12 +613,14 @@ NOTE: there are two lists of areas in the end of this file: centcom and station /area/lawoffice name = "Law Office" icon_state = "law" + sound_environment = SOUND_AREA_SMALL_SOFTFLOOR //Engineering /area/engine ambientsounds = ENGINEERING + sound_environment = SOUND_AREA_LARGE_ENCLOSED /area/engine/engine_smes name = "Engineering SMES" @@ -613,14 +638,17 @@ NOTE: there are two lists of areas in the end of this file: centcom and station /area/engine/atmospherics_engine name = "Atmospherics Engine" icon_state = "atmos_engine" + sound_environment = SOUND_AREA_LARGE_ENCLOSED /area/engine/supermatter name = "Supermatter Engine" icon_state = "engine_sm" + sound_environment = SOUND_AREA_SMALL_ENCLOSED /area/engine/break_room name = "Engineering Foyer" icon_state = "engine_foyer" + sound_environment = SOUND_AREA_SMALL_ENCLOSED /area/engine/gravity_generator name = "Gravity Generator Room" @@ -635,6 +663,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station /area/engine/storage name = "Engineering Storage" icon_state = "engi_storage" + sound_environment = SOUND_AREA_SMALL_ENCLOSED /area/engine/storage_shared name = "Shared Engineering Storage" @@ -654,10 +683,12 @@ NOTE: there are two lists of areas in the end of this file: centcom and station blob_allowed = FALSE flags_1 = NONE ambientsounds = ENGINEERING + sound_environment = SOUND_AREA_SPACE /area/solar/fore name = "Fore Solar Array" icon_state = "yellow" + sound_environment = SOUND_AREA_STANDARD_STATION /area/solar/aft name = "Aft Solar Array" @@ -763,6 +794,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station icon_state = "gateway" music = "signal" ambientsounds = ENGINEERING + sound_environment = SOUND_AREA_STANDARD_STATION //MedBay @@ -770,6 +802,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station name = "Medical" icon_state = "medbay3" ambientsounds = MEDICAL + sound_environment = SOUND_AREA_STANDARD_STATION /area/medical/clinic name = "Clinic" @@ -780,6 +813,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station name = "Abandoned Medbay" icon_state = "medbay3" music = 'sound/ambience/signal.ogg' + sound_environment = SOUND_AREA_SMALL_ENCLOSED /area/medical/medbay/central name = "Medbay Central" @@ -821,6 +855,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station /area/medical/patients_rooms name = "Patients' Rooms" icon_state = "patients" + sound_environment = SOUND_AREA_SMALL_SOFTFLOOR /area/medical/patients_rooms/room_a name = "Patient Room A" @@ -839,6 +874,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station name = "Morgue" icon_state = "morgue" ambientsounds = SPOOKY + sound_environment = SOUND_AREA_SMALL_ENCLOSED /area/medical/chemistry name = "Chemistry" @@ -879,6 +915,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station name = "Security" icon_state = "security" ambientsounds = HIGHSEC + sound_environment = SOUND_AREA_STANDARD_STATION /area/security/main name = "Security Office" @@ -891,6 +928,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station /area/security/courtroom name = "Courtroom" icon_state = "courtroom" + sound_environment = SOUND_AREA_LARGE_ENCLOSED /area/security/prison name = "Prison Wing" @@ -903,10 +941,12 @@ NOTE: there are two lists of areas in the end of this file: centcom and station /area/security/processing/cremation name = "Security Crematorium" icon_state = "sec_prison" + sound_environment = SOUND_AREA_SMALL_ENCLOSED /area/security/warden name = "Brig Control" icon_state = "Warden" + sound_environment = SOUND_AREA_SMALL_SOFTFLOOR /area/security/armory name = "Armory" @@ -920,6 +960,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station /area/security/detectives_office/private_investigators_office name = "Private Investigator's Office" icon_state = "detective" + sound_environment = SOUND_AREA_SMALL_SOFTFLOOR /area/security/range name = "Firing Range" @@ -997,18 +1038,17 @@ NOTE: there are two lists of areas in the end of this file: centcom and station /area/quartermaster name = "Quartermasters" icon_state = "quart" - -///////////WORK IN PROGRESS////////// + sound_environment = SOUND_AREA_STANDARD_STATION /area/quartermaster/sorting name = "Delivery Office" icon_state = "cargo_delivery" + sound_environment = SOUND_AREA_STANDARD_STATION /area/quartermaster/warehouse name = "Warehouse" icon_state = "cargo_warehouse" - -////////////WORK IN PROGRESS////////// + sound_environment = SOUND_AREA_LARGE_ENCLOSED /area/quartermaster/office name = "Cargo Office" @@ -1017,6 +1057,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station /area/quartermaster/storage name = "Cargo Bay" icon_state = "cargo_bay" + sound_environment = SOUND_AREA_LARGE_ENCLOSED /area/quartermaster/qm name = "Quartermaster's Office" @@ -1046,6 +1087,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station name = "Custodial Closet" icon_state = "janitor" flags_1 = NONE + sound_environment = SOUND_AREA_SMALL_ENCLOSED /area/janitor/aux name = "Auxiliary Custodial Closet" @@ -1055,6 +1097,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station /area/hydroponics name = "Hydroponics" icon_state = "hydro" + sound_environment = SOUND_AREA_STANDARD_STATION /area/hydroponics/lobby name = "Hydroponics Lobby" @@ -1067,6 +1110,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station /area/hydroponics/garden/abandoned name = "Abandoned Garden" icon_state = "abandoned_garden" + sound_environment = SOUND_AREA_SMALL_ENCLOSED /area/hydroponics/garden/monastery name = "Monastery Garden" @@ -1077,6 +1121,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station /area/science name = "Science Division" icon_state = "toxlab" + sound_environment = SOUND_AREA_STANDARD_STATION /area/science/observatory name = "Research Observatory" @@ -1167,12 +1212,15 @@ NOTE: there are two lists of areas in the end of this file: centcom and station /area/science/research/abandoned name = "Abandoned Research Lab" icon_state = "medresearch" + sound_environment = SOUND_AREA_SMALL_ENCLOSED /area/science/nanite name = "Nanite Lab" icon_state = "toxmisc" //Storage +/area/storage + sound_environment = SOUND_AREA_STANDARD_STATION /area/storage/tools name = "Auxiliary Tool Storage" @@ -1242,6 +1290,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station name = "Construction Area" icon_state = "yellow" ambientsounds = ENGINEERING + sound_environment = SOUND_AREA_STANDARD_STATION /area/construction/minisat_exterior name = "Minisat Exterior" @@ -1250,6 +1299,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station /area/construction/mining/aux_base name = "Auxiliary Base Construction" icon_state = "yellow" + sound_environment = SOUND_AREA_MEDIUM_SOFTFLOOR /area/construction/mining/aux_base/closet name = "Auxiliary Closet Construction" @@ -1305,6 +1355,8 @@ NOTE: there are two lists of areas in the end of this file: centcom and station //AI +/area/ai_monitored + sound_environment = SOUND_AREA_STANDARD_STATION /area/ai_monitored/security/armory name = "Armory" @@ -1329,10 +1381,12 @@ NOTE: there are two lists of areas in the end of this file: centcom and station /area/ai_monitored/turret_protected/ai_upload name = "AI Upload Chamber" icon_state = "ai_upload" + sound_environment = SOUND_AREA_SMALL_ENCLOSED /area/ai_monitored/turret_protected/ai_upload_foyer name = "AI Upload Access" icon_state = "ai_foyer" + sound_environment = SOUND_AREA_SMALL_ENCLOSED /area/ai_monitored/turret_protected/ai name = "AI Chamber" @@ -1341,6 +1395,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station /area/ai_monitored/turret_protected/aisat name = "AI Satellite" icon_state = "ai" + sound_environment = SOUND_ENVIRONMENT_ROOM /area/ai_monitored/turret_protected/aisat/atmos name = "AI Satellite Atmos" @@ -1365,6 +1420,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station /area/ai_monitored/turret_protected/aisat_interior name = "AI Satellite Antechamber" icon_state = "ai" + sound_environment = SOUND_AREA_LARGE_ENCLOSED /area/ai_monitored/turret_protected/AIsatextFP name = "AI Sat Ext" @@ -1418,6 +1474,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station /area/tcommsat/computer name = "Telecomms Control Room" icon_state = "tcomsatcomp" + sound_environment = SOUND_AREA_MEDIUM_SOFTFLOOR /area/tcommsat/server name = "Telecomms Server Room" diff --git a/code/game/area/ai_monitored.dm b/code/game/area/ai_monitored.dm index 558a4b1026..48e77e1623 100644 --- a/code/game/area/ai_monitored.dm +++ b/code/game/area/ai_monitored.dm @@ -3,6 +3,7 @@ clockwork_warp_allowed = FALSE var/list/obj/machinery/camera/motioncameras = list() var/list/datum/weakref/motionTargets = list() + sound_environment = SOUND_ENVIRONMENT_ROOM /area/ai_monitored/Initialize(mapload) . = ..() diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index ff177898cb..4790d20f64 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -1,16 +1,72 @@ -// Areas.dm - - +/** + * # area + * + * A grouping of tiles into a logical space, mostly used by map editors + */ /area - level = null name = "Space" icon = 'icons/turf/areas.dmi' icon_state = "unknown" layer = AREA_LAYER - plane = BLACKNESS_PLANE //Keeping this on the default plane, GAME_PLANE, will make area overlays fail to render on FLOOR_PLANE. + //Keeping this on the default plane, GAME_PLANE, will make area overlays fail to render on FLOOR_PLANE. + plane = BLACKNESS_PLANE mouse_opacity = MOUSE_OPACITY_TRANSPARENT invisibility = INVISIBILITY_LIGHTING + var/fire = null + ///Whether there is an atmos alarm in this area + var/atmosalm = FALSE + var/poweralm = FALSE + var/lightswitch = TRUE + + /// All beauty in this area combined, only includes indoor area. + var/totalbeauty = 0 + /// Beauty average per open turf in the area + var/beauty = 0 + /// If a room is too big it doesn't have beauty. + var/beauty_threshold = 150 + + /// For space, the asteroid, lavaland, etc. Used with blueprints or with weather to determine if we are adding a new area (vs editing a station room) + var/outdoors = FALSE + + /// Size of the area in open turfs, only calculated for indoors areas. + var/areasize = 0 + + /// Bonus mood for being in this area + var/mood_bonus = 0 + /// Mood message for being here, only shows up if mood_bonus != 0 + var/mood_message = "This area is pretty nice!\n" + + ///Will objects this area be needing power? + var/requires_power = TRUE + /// This gets overridden to 1 for space in area/Initialize(). + var/always_unpowered = FALSE + + var/power_equip = TRUE + var/power_light = TRUE + var/power_environ = TRUE + + var/has_gravity = FALSE + + var/parallax_movedir = 0 + + var/list/ambientsounds = GENERIC + flags_1 = CAN_BE_DIRTY_1 + + var/list/firedoors + var/list/cameras + var/list/firealarms + var/firedoors_last_closed_on = 0 + + + ///This datum, if set, allows terrain generation behavior to be ran on Initialize() + // var/datum/map_generator/map_generator + + ///Used to decide what kind of reverb the area makes sound have + var/sound_environment = SOUND_ENVIRONMENT_NONE + + /// CIT SPECIFIC VARS + /// Set in New(); preserves the name set by the map maker, even if renamed by the Blueprints. var/map_name @@ -41,29 +97,8 @@ /// Considered space for hull shielding var/considered_hull_exterior = FALSE - var/fire = null var/atmos = TRUE - var/atmosalm = FALSE - var/poweralm = TRUE - var/lightswitch = TRUE - var/totalbeauty = 0 //All beauty in this area combined, only includes indoor area. - var/beauty = 0 // Beauty average per open turf in the area - var/beauty_threshold = 150 //If a room is too big it doesn't have beauty. - - var/requires_power = TRUE - /// This gets overridden to 1 for space in area/Initialize(). - var/always_unpowered = FALSE - - /// For space, the asteroid, lavaland, etc. Used with blueprints to determine if we are adding a new area (vs editing a station room) - var/outdoors = FALSE - - /// Size of the area in open turfs, only calculated for indoors areas. - var/areasize = 0 - - var/power_equip = TRUE - var/power_light = TRUE - var/power_environ = TRUE var/music = null var/used_equip = 0 var/used_light = 0 @@ -72,7 +107,6 @@ var/static_light = 0 var/static_environ - var/has_gravity = 0 /// Are you forbidden from teleporting to the area? (centcom, mobs, wizard, hand teleporter) var/noteleport = FALSE /// Hides area from player Teleport function. @@ -84,15 +118,6 @@ var/no_air = null - var/parallax_movedir = 0 - - var/list/ambientsounds = GENERIC - flags_1 = CAN_BE_DIRTY_1 - - var/list/firedoors - var/list/cameras - var/list/firealarms - var/firedoors_last_closed_on = 0 var/xenobiology_compatible = FALSE //Can the Xenobio management console transverse this area by default? var/list/canSmoothWithAreas //typecache to limit the areas that atoms in this area can smooth with @@ -111,10 +136,24 @@ var/nightshift_public_area = NIGHTSHIFT_AREA_NONE //considered a public area for nightshift -/*Adding a wizard area teleport list because motherfucking lag -- Urist*/ -/*I am far too lazy to make it a proper list of areas so I'll just make it run the usual telepot routine at the start of the game*/ + +/** + * A list of teleport locations + * + * Adding a wizard area teleport list because motherfucking lag -- Urist + * I am far too lazy to make it a proper list of areas so I'll just make it run the usual telepot routine at the start of the game + */ GLOBAL_LIST_EMPTY(teleportlocs) +/** + * Generate a list of turfs you can teleport to from the areas list + * + * Includes areas if they're not a shuttle or not not teleport or have no contents + * + * The chosen turf is the first item in the areas contents that is a station level + * + * The returned list of turfs is sorted by name + */ /proc/process_teleport_locs() for(var/V in GLOB.sortedAreas) var/area/AR = V @@ -128,11 +167,19 @@ GLOBAL_LIST_EMPTY(teleportlocs) if (picked && is_station_level(picked.z)) GLOB.teleportlocs[AR.name] = AR - sortTim(GLOB.teleportlocs, /proc/cmp_text_dsc) - -// === + sortTim(GLOB.teleportlocs, /proc/cmp_text_asc) +/** + * Called when an area loads + * + * Adds the item to the GLOB.areas_by_type list based on area type + */ /area/New() + // This interacts with the map loader, so it needs to be set immediately + // rather than waiting for atoms to initialize. + if (unique) + GLOB.areas_by_type[type] = src + if(!minimap_color) // goes in New() because otherwise it doesn't fucking work // generate one using the icon_state if(icon_state && icon_state != "unknown") @@ -141,14 +188,18 @@ GLOBAL_LIST_EMPTY(teleportlocs) minimap_color = I.GetPixel(1,1) else // no icon state? use random. minimap_color = rgb(rand(50,70),rand(50,70),rand(50,70)) // This interacts with the map loader, so it needs to be set immediately - // rather than waiting for atoms to initialize. - if (unique) - GLOB.areas_by_type[type] = src return ..() +/** + * Initalize this area + * + * intializes the dynamic area lighting and also registers the area with the z level via + * reg_in_areas_in_z + * + * returns INITIALIZE_HINT_LATELOAD + */ /area/Initialize() icon_state = "" - layer = AREA_LAYER map_name = name // Save the initial (the name set in the map) name of the area. canSmoothWithAreas = typecacheof(canSmoothWithAreas) @@ -202,29 +253,55 @@ GLOBAL_LIST_EMPTY(teleportlocs) return INITIALIZE_HINT_LATELOAD +/** + * Sets machine power levels in the area + */ /area/LateInitialize() if(!base_area) //we don't want to run it twice. power_change() // all machines set to current power level, also updates icon update_beauty() -/area/proc/reg_in_areas_in_z() - if(contents.len) - var/list/areas_in_z = SSmapping.areas_in_z - var/z - update_areasize() - for(var/i in 1 to contents.len) - var/atom/thing = contents[i] - if(!thing) - continue - z = thing.z - break - if(!z) - WARNING("No z found for [src]") - return - if(!areas_in_z["[z]"]) - areas_in_z["[z]"] = list() - areas_in_z["[z]"] += src +/// Soon ™ +/area/proc/RunGeneration() + // if(map_generator) + // map_generator = new map_generator() + // var/list/turfs = list() + // for(var/turf/T in contents) + // turfs += T + // map_generator.generate_terrain(turfs) +/area/proc/test_gen() + // if(map_generator) + // var/list/turfs = list() + // for(var/turf/T in contents) + // turfs += T + // map_generator.generate_terrain(turfs) + +/** + * Register this area as belonging to a z level + * + * Ensures the item is added to the SSmapping.areas_in_z list for this z + */ +/area/proc/reg_in_areas_in_z() + if(!length(contents)) + return + var/list/areas_in_z = SSmapping.areas_in_z + update_areasize() + if(!z) + WARNING("No z found for [src]") + return + if(!areas_in_z["[z]"]) + areas_in_z["[z]"] = list() + areas_in_z["[z]"] += src + +/** + * Destroy an area and clean it up + * + * Removes the area from GLOB.areas_by_type and also stops it processing on SSobj + * + * This is despite the fact that no code appears to put it on SSobj, but + * who am I to argue with old coders + */ /area/Destroy() if(GLOB.areas_by_type[type] == src) GLOB.areas_by_type[type] = null @@ -244,6 +321,11 @@ GLOBAL_LIST_EMPTY(teleportlocs) STOP_PROCESSING(SSobj, src) return ..() +/** + * Generate a power alert for this area + * + * Sends to all ai players, alert consoles, drones and alarm monitor programs in the world + */ /area/proc/poweralert(state, obj/source) if (state != poweralm) poweralm = state @@ -525,6 +607,13 @@ GLOBAL_LIST_EMPTY(teleportlocs) used_environ += amount +/** + * Call back when an atom enters an area + * + * Sends signals COMSIG_AREA_ENTERED and COMSIG_ENTER_AREA (to the atom) + * + * If the area has ambience, then it plays some ambience music to the ambience channel + */ /area/Entered(atom/movable/M, atom/OldLoc) set waitfor = FALSE SEND_SIGNAL(src, COMSIG_AREA_ENTERED, M) @@ -567,6 +656,12 @@ GLOBAL_LIST_EMPTY(teleportlocs) return FALSE //Too big beauty = totalbeauty / areasize + +/** + * Called when an atom exits an area + * + * Sends signals COMSIG_AREA_EXITED and COMSIG_EXIT_AREA (to the atom) + */ /area/Exited(atom/movable/M) SEND_SIGNAL(src, COMSIG_AREA_EXITED, M) SEND_SIGNAL(M, COMSIG_EXIT_AREA, src) //The atom that exits the area diff --git a/code/game/area/areas/away_content.dm b/code/game/area/areas/away_content.dm index 27a73ae5f1..63beaec412 100644 --- a/code/game/area/areas/away_content.dm +++ b/code/game/area/areas/away_content.dm @@ -9,6 +9,7 @@ Unused icons for new areas are "awaycontent1" ~ "awaycontent30" icon_state = "away" has_gravity = STANDARD_GRAVITY ambientsounds = AWAY_MISSION + sound_environment = SOUND_ENVIRONMENT_ROOM /area/awaymission/beach name = "Beach" diff --git a/code/game/area/areas/holodeck.dm b/code/game/area/areas/holodeck.dm index 9eec00460a..c0819d29b9 100644 --- a/code/game/area/areas/holodeck.dm +++ b/code/game/area/areas/holodeck.dm @@ -4,6 +4,7 @@ dynamic_lighting = DYNAMIC_LIGHTING_DISABLED flags_1 = 0 hidden = TRUE + sound_environment = SOUND_ENVIRONMENT_PADDED_CELL var/obj/machinery/computer/holodeck/linked var/restricted = 0 // if true, program goes on emag list diff --git a/code/game/area/areas/mining.dm b/code/game/area/areas/mining.dm index 70e0910dde..520c7ba59f 100644 --- a/code/game/area/areas/mining.dm +++ b/code/game/area/areas/mining.dm @@ -19,6 +19,7 @@ flags_1 = NONE ambientsounds = MINING flora_allowed = FALSE + sound_environment = SOUND_AREA_STANDARD_STATION /area/mine/unexplored name = "Mine" @@ -86,6 +87,7 @@ has_gravity = STANDARD_GRAVITY flags_1 = NONE flora_allowed = TRUE + sound_environment = SOUND_AREA_LAVALAND /area/lavaland/surface name = "Lavaland" @@ -139,6 +141,7 @@ flags_1 = NONE flora_allowed = TRUE blob_allowed = FALSE + sound_environment = SOUND_AREA_ICEMOON /area/icemoon/surface name = "Icemoon" diff --git a/code/game/area/areas/ruins/_ruins.dm b/code/game/area/areas/ruins/_ruins.dm index b97c3f0ef4..17ba4f7721 100644 --- a/code/game/area/areas/ruins/_ruins.dm +++ b/code/game/area/areas/ruins/_ruins.dm @@ -7,6 +7,7 @@ hidden = TRUE dynamic_lighting = DYNAMIC_LIGHTING_FORCED ambientsounds = RUINS + sound_environment = SOUND_ENVIRONMENT_STONEROOM /area/ruin/unpowered diff --git a/code/game/area/areas/shuttles.dm b/code/game/area/areas/shuttles.dm index e7f8c63d4a..9a890ead75 100644 --- a/code/game/area/areas/shuttles.dm +++ b/code/game/area/areas/shuttles.dm @@ -12,6 +12,7 @@ icon_state = "shuttle" // Loading the same shuttle map at a different time will produce distinct area instances. unique = FALSE + sound_environment = SOUND_ENVIRONMENT_ROOM /area/shuttle/Initialize() if(!canSmoothWithAreas) diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 7fbfe48f4e..189640a1c6 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -1,12 +1,22 @@ +/** + * The base type for nearly all physical objects in SS13 + + * Lots and lots of functionality lives here, although in general we are striving to move + * as much as possible to the components/elements system + */ /atom layer = TURF_LAYER plane = GAME_PLANE - var/level = 2 - var/article // If non-null, overrides a/an/some in all cases + appearance_flags = TILE_BOUND + var/level = 2 + ///If non-null, overrides a/an/some in all cases + var/article + + ///First atom flags var var/flags_1 = NONE + ///Intearaction flags var/interaction_flags_atom = NONE - var/datum/reagents/reagents = null var/flags_ricochet = NONE @@ -15,35 +25,52 @@ ///When a projectile ricochets off this atom, it deals the normal damage * this modifier to this atom var/ricochet_damage_mod = 0.33 - //This atom's HUD (med/sec, etc) images. Associative list. + ///Reagents holder + var/datum/reagents/reagents = null + + ///This atom's HUD (med/sec, etc) images. Associative list. var/list/image/hud_list = null - //HUD images that this atom can provide. + ///HUD images that this atom can provide. var/list/hud_possible - //Value used to increment ex_act() if reactionary_explosions is on + ///Value used to increment ex_act() if reactionary_explosions is on var/explosion_block = 0 - var/list/atom_colours //used to store the different colors on an atom - //its inherent color, the colored paint applied on it, special color effect etc... + /** + * used to store the different colors on an atom + * + * its inherent color, the colored paint applied on it, special color effect etc... + */ + var/list/atom_colours - var/list/remove_overlays // a very temporary list of overlays to remove - var/list/add_overlays // a very temporary list of overlays to add - var/list/managed_vis_overlays //vis overlays managed by SSvis_overlays to automaticaly turn them like other overlays - ///overlays managed by update_overlays() to prevent removing overlays that weren't added by the same proc + /// a very temporary list of overlays to remove + var/list/remove_overlays + /// a very temporary list of overlays to add + var/list/add_overlays + + ///vis overlays managed by SSvis_overlays to automaticaly turn them like other overlays + var/list/managed_vis_overlays + ///overlays managed by [update_overlays][/atom/proc/update_overlays] to prevent removing overlays that weren't added by the same proc var/list/managed_overlays + ///Proximity monitor associated with this atom var/datum/proximity_monitor/proximity_monitor + ///Last fingerprints to touch this atom var/fingerprintslast var/list/filter_data //For handling persistent filters + ///Price of an item in a vending machine, overriding the base vending machine price. Define in terms of paycheck defines as opposed to raw numbers. var/custom_price + ///Price of an item in a vending machine, overriding the premium vending machine price. Define in terms of paycheck defines as opposed to raw numbers. var/custom_premium_price + //List of datums orbiting this atom var/datum/component/orbiter/orbiters var/rad_flags = NONE // Will move to flags_1 when i can be arsed to + /// Radiation insulation types var/rad_insulation = RAD_NO_INSULATION ///The custom materials this atom is made of, used by a lot of things like furniture, walls, and floors (if I finish the functionality, that is.) @@ -72,6 +99,16 @@ ///Mobs that are currently do_after'ing this atom, to be cleared from on Destroy() var/list/targeted_by +/** + * Called when an atom is created in byond (built in engine proc) + * + * Not a lot happens here in SS13 code, as we offload most of the work to the + * [Intialization][/atom/proc/Initialize] proc, mostly we run the preloader + * if the preloader is being used and then call [InitAtom][/datum/controller/subsystem/atoms/proc/InitAtom] of which the ultimate + * result is that the Intialize proc is called. + * + * We also generate a tag here if the DF_USE_TAG flag is set on the atom + */ /atom/New(loc, ...) //atom creation method that preloads variables at creation if(GLOB.use_preloader && (src.type == GLOB._preloader.target_path))//in case the instanciated atom is creating other atoms in New() @@ -87,24 +124,50 @@ //we were deleted return -//Called after New if the map is being loaded. mapload = TRUE -//Called from base of New if the map is not being loaded. mapload = FALSE -//This base must be called or derivatives must set initialized to TRUE -//must not sleep -//Other parameters are passed from New (excluding loc), this does not happen if mapload is TRUE -//Must return an Initialize hint. Defined in __DEFINES/subsystems.dm - -//Note: the following functions don't call the base for optimization and must copypasta: -// /turf/Initialize -// /turf/open/space/Initialize - +/** + * The primary method that objects are setup in SS13 with + * + * we don't use New as we have better control over when this is called and we can choose + * to delay calls or hook other logic in and so forth + * + * During roundstart map parsing, atoms are queued for intialization in the base atom/New(), + * After the map has loaded, then Initalize is called on all atoms one by one. NB: this + * is also true for loading map templates as well, so they don't Initalize until all objects + * in the map file are parsed and present in the world + * + * If you're creating an object at any point after SSInit has run then this proc will be + * immediately be called from New. + * + * mapload: This parameter is true if the atom being loaded is either being intialized during + * the Atom subsystem intialization, or if the atom is being loaded from the map template. + * If the item is being created at runtime any time after the Atom subsystem is intialized then + * it's false. + * + * You must always call the parent of this proc, otherwise failures will occur as the item + * will not be seen as initalized (this can lead to all sorts of strange behaviour, like + * the item being completely unclickable) + * + * You must not sleep in this proc, or any subprocs + * + * Any parameters from new are passed through (excluding loc), naturally if you're loading from a map + * there are no other arguments + * + * Must return an [initialization hint][INITIALIZE_HINT_NORMAL] or a runtime will occur. + * + * Note: the following functions don't call the base for optimization and must copypasta handling: + * * [/turf/proc/Initialize] + * * [/turf/open/space/proc/Initialize] + */ /atom/proc/Initialize(mapload, ...) + // SHOULD_NOT_SLEEP(TRUE) + SHOULD_CALL_PARENT(TRUE) if(flags_1 & INITIALIZED_1) stack_trace("Warning: [src]([type]) initialized multiple times!") flags_1 |= INITIALIZED_1 if(loc) SEND_SIGNAL(loc, COMSIG_ATOM_CREATED, src) /// Sends a signal that the new atom `src`, has been created at `loc` + //atom color stuff if(color) add_atom_colour(color, FIXED_COLOUR_PRIORITY) @@ -126,14 +189,34 @@ return INITIALIZE_HINT_NORMAL -//called if Initialize returns INITIALIZE_HINT_LATELOAD +/** + * Late Intialization, for code that should run after all atoms have run Intialization + * + * To have your LateIntialize proc be called, your atoms [Initalization][/atom/proc/Initialize] + * proc must return the hint + * [INITIALIZE_HINT_LATELOAD] otherwise you will never be called. + * + * useful for doing things like finding other machines on GLOB.machines because you can guarantee + * that all atoms will actually exist in the "WORLD" at this time and that all their Intialization + * code has been run + */ /atom/proc/LateInitialize() - return + set waitfor = FALSE -// Put your AddComponent() calls here +/// Put your [AddComponent] calls here /atom/proc/ComponentInitialize() return +/** + * Top level of the destroy chain for most atoms + * + * Cleans up the following: + * * Removes alternate apperances from huds that see them + * * qdels the reagent holder from atoms if it exists + * * clears the orbiters list + * * clears overlays and priority overlays + * * clears the light object + */ /atom/Destroy() if(alternate_appearances) for(var/K in alternate_appearances) @@ -143,6 +226,8 @@ if(reagents) qdel(reagents) + orbiters = null // The component is attached to us normaly and will be deleted elsewhere + LAZYCLEARLIST(overlays) for(var/i in targeted_by) @@ -179,6 +264,16 @@ /atom/proc/CanPass(atom/movable/mover, turf/target) return !density +/** + * Is this atom currently located on centcom + * + * Specifically, is it on the z level and within the centcom areas + * + * You can also be in a shuttleshuttle during endgame transit + * + * Used in gamemode to identify mobs who have escaped and for some other areas of the code + * who don't want atoms where they shouldn't be + */ /atom/proc/onCentCom() var/turf/T = get_turf(src) if(!T) @@ -209,6 +304,13 @@ if(T in shuttle_area) return TRUE +/** + * Is the atom in any of the centcom syndicate areas + * + * Either in the syndie base on centcom, or any of their shuttles + * + * Also used in gamemode code for win conditions + */ /atom/proc/onSyndieBase() var/turf/T = get_turf(src) if(!T) @@ -222,6 +324,23 @@ return FALSE +/** + * Is the atom in an away mission + * + * Must be in the away mission z-level to return TRUE + * + * Also used in gamemode code for win conditions + */ +/atom/proc/onAwayMission() + var/turf/T = get_turf(src) + if(!T) + return FALSE + + if(is_away_level(T.z)) + return TRUE + + return FALSE + /atom/proc/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE) SEND_SIGNAL(src, COMSIG_ATOM_HULK_ATTACK, user) if(does_attack_animation) @@ -415,7 +534,7 @@ /// Updates the overlays of the atom /atom/proc/update_overlays() - SHOULD_CALL_PARENT(1) + SHOULD_CALL_PARENT(TRUE) . = list() SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_OVERLAYS, .) @@ -429,7 +548,7 @@ /atom/proc/contents_explosion(severity, target) return //For handling the effects of explosions on contents that would not normally be effected -/atom/proc/ex_act(severity, target) +/atom/proc/ex_act(severity, target, datum/explosion/E) set waitfor = FALSE contents_explosion(severity, target) SEND_SIGNAL(src, COMSIG_ATOM_EX_ACT, severity, target) diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 4715c3bed3..a582fa03e4 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -1,5 +1,7 @@ /atom/movable layer = OBJ_LAYER + glide_size = 8 + SET_APPEARANCE_FLAGS(TILE_BOUND | PIXEL_SCALE) var/last_move = null var/last_move_time = 0 var/anchored = FALSE @@ -28,10 +30,15 @@ var/atom/movable/moving_from_pull //attempt to resume grab after moving instead of before. var/list/client_mobs_in_contents // This contains all the client mobs within this container var/list/acted_explosions //for explosion dodging - glide_size = 8 - appearance_flags = TILE_BOUND|PIXEL_SCALE var/datum/forced_movement/force_moving = null //handled soley by forced_movement.dm - var/movement_type = GROUND //Incase you have multiple types, you automatically use the most useful one. IE: Skating on ice, flippers on water, flying over chasm/space, etc. + + /** + * In case you have multiple types, you automatically use the most useful one. + * IE: Skating on ice, flippers on water, flying over chasm/space, etc. + * I reccomend you use the movetype_handler system and not modify this directly, especially for living mobs. + */ + var/movement_type = GROUND + var/atom/movable/pulling var/grab_state = 0 var/throwforce = 0 @@ -59,6 +66,42 @@ em_block = new(src, render_target) vis_contents += em_block + +/atom/movable/Destroy(force) + QDEL_NULL(proximity_monitor) + QDEL_NULL(language_holder) + QDEL_NULL(em_block) + + unbuckle_all_mobs(force = TRUE) + + if(loc) + //Restore air flow if we were blocking it (movables with ATMOS_PASS_PROC will need to do this manually if necessary) + if(((CanAtmosPass == ATMOS_PASS_DENSITY && density) || CanAtmosPass == ATMOS_PASS_NO) && isturf(loc)) + CanAtmosPass = ATMOS_PASS_YES + air_update_turf(TRUE) + loc.handle_atom_del(src) + + // if(opacity) + // RemoveElement(/datum/element/light_blocking) + + invisibility = INVISIBILITY_ABSTRACT + + if(pulledby) + pulledby.stop_pulling() + + if(orbiting) + orbiting.end_orbit(src) + orbiting = null + + . = ..() + + for(var/movable_content in contents) + qdel(movable_content) + + LAZYCLEARLIST(client_mobs_in_contents) + + moveToNullspace() + /atom/movable/proc/update_emissive_block() if(blocks_emissive != EMISSIVE_BLOCK_GENERIC) return @@ -113,40 +156,52 @@ return FALSE return T.zPassOut(src, direction, destination) && destination.zPassIn(src, direction, T) -/atom/movable/vv_edit_var(var_name, var_value) - var/static/list/banned_edits = list("step_x", "step_y", "step_size") - var/static/list/careful_edits = list("bound_x", "bound_y", "bound_width", "bound_height") - if(var_name in banned_edits) +/atom/movable/vv_edit_var(var_name, var_value, massedit) + var/static/list/banned_edits = list("step_x" = TRUE, "step_y" = TRUE, "step_size" = TRUE, "bounds" = TRUE) + var/static/list/careful_edits = list("bound_x" = TRUE, "bound_y" = TRUE, "bound_width" = TRUE, "bound_height" = TRUE) + if(banned_edits[var_name]) return FALSE //PLEASE no. - if((var_name in careful_edits) && (var_value % world.icon_size) != 0) + if((careful_edits[var_name]) && (var_value % world.icon_size) != 0) return FALSE + switch(var_name) if(NAMEOF(src, x)) var/turf/T = locate(var_value, y, z) if(T) - forceMove(T) + admin_teleport(T, !massedit) return TRUE return FALSE if(NAMEOF(src, y)) var/turf/T = locate(x, var_value, z) if(T) - forceMove(T) + admin_teleport(T, !massedit) return TRUE return FALSE if(NAMEOF(src, z)) var/turf/T = locate(x, y, var_value) if(T) - forceMove(T) + admin_teleport(T, !massedit) return TRUE return FALSE if(NAMEOF(src, loc)) - if(istype(var_value, /atom)) - forceMove(var_value) - return TRUE - else if(isnull(var_value)) - moveToNullspace() + if(isatom(var_value) || isnull(var_value)) + admin_teleport(var_value, !massedit) return TRUE return FALSE + if(NAMEOF(src, anchored)) + set_anchored(var_value) + . = TRUE + if(NAMEOF(src, pulledby)) + set_pulledby(var_value) + . = TRUE + if(NAMEOF(src, glide_size)) + set_glide_size(var_value) + . = TRUE + + if(!isnull(.)) + datum_flags |= DF_VAR_EDITED + return + return ..() /atom/movable/proc/start_pulling(atom/movable/AM, state, force = move_force, supress_message = FALSE) @@ -168,48 +223,73 @@ AMob.grabbedby(src) return TRUE stop_pulling() + + // SEND_SIGNAL(src, COMSIG_ATOM_START_PULL, AM, state, force) + if(AM.pulledby) log_combat(AM, AM.pulledby, "pulled from", src) AM.pulledby.stop_pulling() //an object can't be pulled by two mobs at once. pulling = AM - AM.pulledby = src + AM.set_pulledby(src) setGrabState(state) if(ismob(AM)) var/mob/M = AM log_combat(src, M, "grabbed", addition="passive grab") if(!supress_message) - visible_message("[src] has grabbed [M] passively!") + M.visible_message("[src] grabs [M] passively.", \ + "[src] grabs you passively.") return TRUE /atom/movable/proc/stop_pulling() if(!pulling) return - pulling.pulledby = null + pulling.set_pulledby(null) var/mob/living/ex_pulled = pulling + setGrabState(GRAB_PASSIVE) pulling = null - setGrabState(0) if(isliving(ex_pulled)) var/mob/living/L = ex_pulled L.update_mobility()// mob gets up if it was lyng down in a chokehold +///Reports the event of the change in value of the pulledby variable. +/atom/movable/proc/set_pulledby(new_pulledby) + if(new_pulledby == pulledby) + return FALSE //null signals there was a change, be sure to return FALSE if none happened here. + . = pulledby + pulledby = new_pulledby + /atom/movable/proc/Move_Pulled(atom/A) if(!pulling) - return + return FALSE if(pulling.anchored || pulling.move_resist > move_force || !pulling.Adjacent(src)) stop_pulling() - return + return FALSE if(isliving(pulling)) var/mob/living/L = pulling if(L.buckled && L.buckled.buckle_prevents_pull) //if they're buckled to something that disallows pulling, prevent it stop_pulling() - return + return FALSE if(A == loc && pulling.density) - return - if(!Process_Spacemove(get_dir(pulling.loc, A))) - return - step(pulling, get_dir(pulling.loc, A)) + return FALSE + var/move_dir = get_dir(pulling.loc, A) + if(!Process_Spacemove(move_dir)) + return FALSE + pulling.Move(get_step(pulling.loc, move_dir), move_dir, glide_size) return TRUE +/** + * Recursively set glide size for atom's pulled things + */ +/atom/movable/proc/recursive_pulled_glidesize_update() + var/list/ran = list() + var/atom/movable/updating = pulling + while(updating) + if(ran[updating]) + return + updating.set_glide_size(glide_size, FALSE) + ran[updating] = TRUE + updating = updating.pulling + /atom/movable/proc/check_pulling() if(pulling) var/atom/movable/pullee = pulling @@ -229,54 +309,57 @@ if(pulledby && moving_diagonally != FIRST_DIAG_STEP && get_dist(src, pulledby) > 1) //separated from our puller and not in the middle of a diagonal move. pulledby.stop_pulling() -/atom/movable/Destroy(force) - QDEL_NULL(proximity_monitor) - QDEL_NULL(language_holder) - QDEL_NULL(em_block) +/atom/movable/proc/set_glide_size(target = 8, recursive = TRUE) +#ifdef SMOOTH_MOVEMENT + // SEND_SIGNAL(src, COMSIG_MOVABLE_UPDATE_GLIDE_SIZE, target) + glide_size = target - unbuckle_all_mobs(force=1) + for(var/m in buckled_mobs) + var/mob/buckled_mob = m + buckled_mob.set_glide_size(target) - . = ..() + if(recursive) + recursive_pulled_glidesize_update() +#else + return +#endif - if(loc) - //Restore air flow if we were blocking it (movables with ATMOS_PASS_PROC will need to do this manually if necessary) - if(((CanAtmosPass == ATMOS_PASS_DENSITY && density) || CanAtmosPass == ATMOS_PASS_NO) && isturf(loc)) - CanAtmosPass = ATMOS_PASS_YES - air_update_turf(TRUE) - loc.handle_atom_del(src) - for(var/atom/movable/AM in contents) - qdel(AM) - moveToNullspace() - invisibility = INVISIBILITY_ABSTRACT - if(pulledby) - pulledby.stop_pulling() - - if(orbiting) - orbiting.end_orbit(src) - orbiting = null +///Sets the anchored var and returns if it was sucessfully changed or not. +/atom/movable/proc/set_anchored(anchorvalue) + SHOULD_CALL_PARENT(TRUE) + if(anchored == anchorvalue) + return + . = anchored + anchored = anchorvalue + // SEND_SIGNAL(src, COMSIG_MOVABLE_SET_ANCHORED, anchorvalue) /atom/movable/proc/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) - set waitfor = 0 + set waitfor = FALSE var/hitpush = TRUE var/impact_signal = SEND_SIGNAL(src, COMSIG_MOVABLE_IMPACT, hit_atom, throwingdatum) if(impact_signal & COMPONENT_MOVABLE_IMPACT_FLIP_HITPUSH) hitpush = FALSE // hacky, tie this to something else or a proper workaround later - if(impact_signal & ~COMPONENT_MOVABLE_IMPACT_NEVERMIND) // in case a signal interceptor broke or deleted the thing before we could process our hit - return hit_atom.hitby(src, throwingdatum = throwingdatum, hitpush = hitpush) + if(!(impact_signal && (impact_signal & COMPONENT_MOVABLE_IMPACT_NEVERMIND))) // in case a signal interceptor broke or deleted the thing before we could process our hit + return hit_atom.hitby(src, throwingdatum=throwingdatum, hitpush=hitpush) /atom/movable/hitby(atom/movable/AM, skipcatch, hitpush = TRUE, blocked, datum/thrownthing/throwingdatum) if(!anchored && hitpush && (!throwingdatum || (throwingdatum.force >= (move_resist * MOVE_FORCE_PUSH_RATIO)))) step(src, AM.dir) ..() -/atom/movable/proc/safe_throw_at(atom/target, range, speed, mob/thrower, spin = TRUE, diagonals_first = FALSE, datum/callback/callback, force = INFINITY, messy_throw = TRUE) +/atom/movable/proc/safe_throw_at(atom/target, range, speed, mob/thrower, spin = TRUE, diagonals_first = FALSE, datum/callback/callback, force = MOVE_FORCE_STRONG, gentle = FALSE) if((force < (move_resist * MOVE_FORCE_THROW_RATIO)) || (move_resist == INFINITY)) return - return throw_at(target, range, speed, thrower, spin, diagonals_first, callback, force, messy_throw) + return throw_at(target, range, speed, thrower, spin, diagonals_first, callback, force, gentle) -/atom/movable/proc/throw_at(atom/target, range, speed, mob/thrower, spin = TRUE, diagonals_first = FALSE, datum/callback/callback, force = INFINITY, messy_throw = TRUE) //If this returns FALSE then callback will not be called. +///If this returns FALSE then callback will not be called. +/atom/movable/proc/throw_at(atom/target, range, speed, mob/thrower, spin = TRUE, diagonals_first = FALSE, datum/callback/callback, force = MOVE_FORCE_STRONG, gentle = FALSE, quickstart = TRUE) . = FALSE + + if(QDELETED(src)) + CRASH("Qdeleted thing being thrown around.") + if (!target || speed <= 0) return @@ -288,7 +371,7 @@ //They are moving! Wouldn't it be cool if we calculated their momentum and added it to the throw? if (thrower && thrower.last_move && thrower.client && thrower.client.move_delay >= world.time + world.tick_lag*2) - var/user_momentum = thrower.movement_delay() + var/user_momentum = thrower.movement_delay() //cached_multiplicative_slowdown if (!user_momentum) //no movement_delay, this means they move once per byond tick, lets calculate from that instead. user_momentum = world.tick_lag @@ -312,19 +395,13 @@ . = TRUE // No failure conditions past this point. - var/datum/thrownthing/TT = new() - TT.thrownthing = src - TT.target = target - TT.target_turf = get_turf(target) - TT.init_dir = get_dir(src, target) - TT.maxrange = range - TT.speed = speed - TT.thrower = thrower - TT.diagonals_first = diagonals_first - TT.force = force - TT.callback = callback - if(!QDELETED(thrower)) - TT.target_zone = thrower.zone_selected + var/target_zone + if(QDELETED(thrower)) + thrower = null //Let's not pass a qdeleting reference if any. + else + target_zone = thrower.zone_selected + + var/datum/thrownthing/TT = new(src, target, get_turf(target), get_dir(src, target), range, speed, thrower, diagonals_first, force, gentle, callback, target_zone) var/dist_x = abs(target.x - src.x) var/dist_y = abs(target.y - src.y) @@ -359,7 +436,8 @@ SSthrowing.processing[src] = TT if (SSthrowing.state == SS_PAUSED && length(SSthrowing.currentrun)) SSthrowing.currentrun[src] = TT - TT.tick() + if (quickstart) + TT.tick() /atom/movable/proc/force_pushed(atom/movable/pusher, force = MOVE_FORCE_DEFAULT, direction) return FALSE @@ -382,13 +460,13 @@ return TRUE return ..() -// called when this atom is removed from a storage item, which is passed on as S. The loc variable is already set to the new destination before this is called. -/atom/movable/proc/on_exit_storage(datum/component/storage/concrete/S) - return +/// called when this atom is removed from a storage item, which is passed on as S. The loc variable is already set to the new destination before this is called. +/atom/movable/proc/on_exit_storage(datum/component/storage/concrete/S) // rename S to master_storage + // SEND_SIGNAL(src, COMSIG_STORAGE_EXITED, master_storage) -// called when this atom is added into a storage item, which is passed on as S. The loc variable is already set to the storage item. +/// called when this atom is added into a storage item, which is passed on as S. The loc variable is already set to the storage item. /atom/movable/proc/on_enter_storage(datum/component/storage/concrete/S) - return + // SEND_SIGNAL(src, COMSIG_STORAGE_ENTERED, master_storage) /atom/movable/proc/get_spacemove_backup() var/atom/movable/dense_object_backup @@ -422,24 +500,26 @@ return //don't do an animation if attacking self var/pixel_x_diff = 0 var/pixel_y_diff = 0 + var/turn_dir = 1 var/direction = get_dir(src, A) if(direction & NORTH) pixel_y_diff = 8 + turn_dir = prob(50) ? -1 : 1 else if(direction & SOUTH) pixel_y_diff = -8 + turn_dir = prob(50) ? -1 : 1 if(direction & EAST) pixel_x_diff = 8 else if(direction & WEST) pixel_x_diff = -8 + turn_dir = -1 - var/matrix/OM = matrix(transform) - var/matrix/M = matrix(transform) - M.Turn(pixel_x_diff ? pixel_x_diff*2 : pick(-16, 16)) - - animate(src, pixel_x = pixel_x + pixel_x_diff, pixel_y = pixel_y + pixel_y_diff, transform = M, time = 2) - animate(src, pixel_x = pixel_x - pixel_x_diff, pixel_y = pixel_y - pixel_y_diff, transform = OM, time = 2) + var/matrix/initial_transform = matrix(transform) + var/matrix/rotated_transform = transform.Turn(15 * turn_dir) + animate(src, pixel_x = pixel_x + pixel_x_diff, pixel_y = pixel_y + pixel_y_diff, transform=rotated_transform, time = 1, easing=BACK_EASING|EASE_IN) + animate(pixel_x = pixel_x - pixel_x_diff, pixel_y = pixel_y - pixel_y_diff, transform=initial_transform, time = 2, easing=SINE_EASING) /atom/movable/proc/do_item_attack_animation(atom/A, visual_effect_icon, obj/item/used_item) var/image/I @@ -450,21 +530,21 @@ I.plane = GAME_PLANE // Scale the icon. - I.transform *= 0.75 + I.transform *= 0.4 // The icon should not rotate. I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA // Set the direction of the icon animation. var/direction = get_dir(src, A) if(direction & NORTH) - I.pixel_y = -16 + I.pixel_y = -12 else if(direction & SOUTH) - I.pixel_y = 16 + I.pixel_y = 12 if(direction & EAST) - I.pixel_x = -16 + I.pixel_x = -14 else if(direction & WEST) - I.pixel_x = 16 + I.pixel_x = 14 if(!direction) // Attacked self?! I.pixel_z = 16 @@ -472,10 +552,12 @@ if(!I) return - flick_overlay(I, GLOB.clients, 5) // 5 ticks/half a second + flick_overlay(I, GLOB.clients, 10) // And animate the attack! - animate(I, alpha = 175, pixel_x = 0, pixel_y = 0, pixel_z = 0, time = 3) + animate(I, alpha = 175, transform = matrix() * 0.75, pixel_x = 0, pixel_y = 0, pixel_z = 0, time = 3) + animate(time = 1) + animate(alpha = 0, time = 3, easing = CIRCULAR_EASING|EASE_OUT) /atom/movable/vv_get_dropdown() . = ..() @@ -492,19 +574,17 @@ return TRUE //TODO: Better floating -/atom/movable/proc/float(on) - if(throwing) +/atom/movable/proc/float(on, throw_override) + if(throwing || !throw_override) return - if(on && (!(movement_type & FLOATING) || floating_need_update)) - animate(src, pixel_y = pixel_y + 2, time = 10, loop = -1) - sleep(10) - animate(src, pixel_y = pixel_y - 2, time = 10, loop = -1) - if(!(movement_type & FLOATING)) - setMovetype(movement_type | FLOATING) - else if (!on && movement_type & FLOATING) + if(on && !(movement_type & FLOATING)) + animate(src, pixel_y = 2, time = 10, loop = -1, flags = ANIMATION_RELATIVE) + animate(pixel_y = -2, time = 10, loop = -1, flags = ANIMATION_RELATIVE) + setMovetype(movement_type | FLOATING) + else if (!on && (movement_type & FLOATING)) animate(src, pixel_y = initial(pixel_y), time = 10) setMovetype(movement_type & ~FLOATING) - floating_need_update = FALSE + floating_need_update = FALSE // assume it's done /* Language procs * Unless you are doing something very specific, these are the ones you want to use. @@ -611,10 +691,32 @@ return FALSE return TRUE -/// Updates the grab state of the movable -/// This exists to act as a hook for behaviour +/** + * Updates the grab state of the movable + * + * This exists to act as a hook for behaviour + */ /atom/movable/proc/setGrabState(newstate) + if(newstate == grab_state) + return + // SEND_SIGNAL(src, COMSIG_MOVABLE_SET_GRAB_STATE, newstate) + . = grab_state grab_state = newstate + // switch(grab_state) // Current state. + // if(GRAB_PASSIVE) + // REMOVE_TRAIT(pulling, TRAIT_IMMOBILIZED, CHOKEHOLD_TRAIT) + // REMOVE_TRAIT(pulling, TRAIT_HANDS_BLOCKED, CHOKEHOLD_TRAIT) + // if(. >= GRAB_NECK) // Previous state was a a neck-grab or higher. + // REMOVE_TRAIT(pulling, TRAIT_FLOORED, CHOKEHOLD_TRAIT) + // if(GRAB_AGGRESSIVE) + // if(. >= GRAB_NECK) // Grab got downgraded. + // REMOVE_TRAIT(pulling, TRAIT_FLOORED, CHOKEHOLD_TRAIT) + // else // Grab got upgraded from a passive one. + // ADD_TRAIT(pulling, TRAIT_IMMOBILIZED, CHOKEHOLD_TRAIT) + // ADD_TRAIT(pulling, TRAIT_HANDS_BLOCKED, CHOKEHOLD_TRAIT) + // if(GRAB_NECK, GRAB_KILL) + // if(. <= GRAB_AGGRESSIVE) + // ADD_TRAIT(pulling, TRAIT_FLOORED, CHOKEHOLD_TRAIT) /obj/item/proc/do_pickup_animation(atom/target) set waitfor = FALSE @@ -626,31 +728,24 @@ I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA var/turf/T = get_turf(src) var/direction - var/to_x = 0 - var/to_y = 0 + var/to_x = initial(target.pixel_x) + var/to_y = initial(target.pixel_y) if(!QDELETED(T) && !QDELETED(target)) direction = get_dir(T, target) if(direction & NORTH) - to_y = 32 + to_y += 32 else if(direction & SOUTH) - to_y = -32 + to_y -= 32 if(direction & EAST) - to_x = 32 + to_x += 32 else if(direction & WEST) - to_x = -32 + to_x -= 32 if(!direction) - to_y = 16 + to_y += 16 flick_overlay(I, GLOB.clients, 6) var/matrix/M = new M.Turn(pick(-30, 30)) animate(I, alpha = 175, pixel_x = to_x, pixel_y = to_y, time = 3, transform = M, easing = CUBIC_EASING) sleep(1) animate(I, alpha = 0, transform = matrix(), time = 1) - -/atom/movable/proc/set_anchored(anchorvalue) //literally only for plumbing ran - SHOULD_CALL_PARENT(TRUE) - if(anchored == anchorvalue) - return - . = anchored - anchored = anchorvalue diff --git a/code/game/atoms_movement.dm b/code/game/atoms_movement.dm index db9424d983..4f07ff6f95 100644 --- a/code/game/atoms_movement.dm +++ b/code/game/atoms_movement.dm @@ -5,8 +5,7 @@ // Here's where we rewrite how byond handles movement except slightly different // To be removed on step_ conversion // All this work to prevent a second bump -/atom/movable/Move(atom/newloc, direct=0) - set waitfor = FALSE //n o +/atom/movable/Move(atom/newloc, direct=0, glide_size_override = 0) . = FALSE if(!newloc || newloc == loc) return @@ -52,8 +51,7 @@ // //////////////////////////////////////// -/atom/movable/Move(atom/newloc, direct) - set waitfor = FALSE //n o +/atom/movable/Move(atom/newloc, direct, glide_size_override = 0) var/atom/movable/pullee = pulling var/turf/T = loc if(!moving_from_pull) @@ -61,6 +59,9 @@ if(!loc || !newloc) return FALSE var/atom/oldloc = loc + //Early override for some cases like diagonal movement + if(glide_size_override) + set_glide_size(glide_size_override, FALSE) if(loc != newloc) if (!(direct & (direct - 1))) //Cardinal move @@ -120,32 +121,38 @@ return if(!loc || (loc == oldloc && oldloc != newloc)) - last_move = NONE + last_move = 0 return + setDir(direct) if(.) - last_move = direct - setDir(direct) - - if(has_buckled_mobs() && !handle_buckled_mob_movement(loc,direct)) //movement failed due to buckled mob(s) - return FALSE - - if(pulling && pulling == pullee && pulling != moving_from_pull) //we were pulling a thing and didn't lose it during our move. - if(pulling.anchored) - stop_pulling() - else - var/pull_dir = get_dir(src, pulling) - //puller and pullee more than one tile away or in diagonal position - if(get_dist(src, pulling) > 1 || (moving_diagonally != SECOND_DIAG_STEP && ((pull_dir - 1) & pull_dir))) - pulling.moving_from_pull = src - pulling.Move(T, get_dir(pulling, T)) //the pullee tries to reach our previous position - pulling.moving_from_pull = null Moved(oldloc, direct) + if(. && pulling && pulling == pullee && pulling != moving_from_pull) //we were pulling a thing and didn't lose it during our move. + if(pulling.anchored) + stop_pulling() + else + var/pull_dir = get_dir(src, pulling) + //puller and pullee more than one tile away or in diagonal position + if(get_dist(src, pulling) > 1 || (moving_diagonally != SECOND_DIAG_STEP && ((pull_dir - 1) & pull_dir))) + pulling.moving_from_pull = src + pulling.Move(T, get_dir(pulling, T), glide_size) //the pullee tries to reach our previous position + pulling.moving_from_pull = null + check_pulling() -/atom/movable/proc/handle_buckled_mob_movement(newloc,direct) + + //glide_size strangely enough can change mid movement animation and update correctly while the animation is playing + //This means that if you don't override it late like this, it will just be set back by the movement update that's called when you move turfs. + if(glide_size_override) + set_glide_size(glide_size_override, FALSE) + + last_move = direct + if(. && has_buckled_mobs() && !handle_buckled_mob_movement(loc, direct, glide_size_override)) //movement failed due to buckled mob(s) + return FALSE + +/atom/movable/proc/handle_buckled_mob_movement(newloc, direct, glide_size_override) for(var/m in buckled_mobs) var/mob/living/buckled_mob = m - if(!buckled_mob.Move(newloc, direct)) + if(!buckled_mob.Move(newloc, direct, glide_size_override)) forceMove(buckled_mob.loc) last_move = buckled_mob.last_move inertia_dir = last_move @@ -155,6 +162,7 @@ //Called after a successful Move(). By this point, we've already moved /atom/movable/proc/Moved(atom/OldLoc, Dir, Forced = FALSE) + SHOULD_CALL_PARENT(TRUE) SEND_SIGNAL(src, COMSIG_MOVABLE_MOVED, OldLoc, Dir, Forced) if (!inertia_moving) inertia_next_move = world.time + inertia_move_delay @@ -174,6 +182,8 @@ //oldloc = old location on atom, inserted when forceMove is called and ONLY when forceMove is called! /atom/movable/Crossed(atom/movable/AM, oldloc) + // SHOULD_CALL_PARENT(TRUE) + . = ..() SEND_SIGNAL(src, COMSIG_MOVABLE_CROSSED, AM) /atom/movable/Uncross(atom/movable/AM, atom/newloc) @@ -204,7 +214,11 @@ var/atom/movable/AM = item AM.onTransitZ(old_z,new_z) +///Proc to modify the movement_type and hook behavior associated with it changing. /atom/movable/proc/setMovetype(newval) + if(movement_type == newval) + return + . = movement_type movement_type = newval ///////////// FORCED MOVEMENT ///////////// @@ -268,37 +282,44 @@ old_area.Exited(src, null) loc = null -//Called whenever an object moves and by mobs when they attempt to move themselves through space -//And when an object or action applies a force on src, see newtonian_move() below -//Return 0 to have src start/keep drifting in a no-grav area and 1 to stop/not start drifting -//Mobs should return 1 if they should be able to move of their own volition, see client/Move() in mob_movement.dm -//movement_dir == 0 when stopping or any dir when trying to move +/** + * Called whenever an object moves and by mobs when they attempt to move themselves through space + * And when an object or action applies a force on src, see [newtonian_move][/atom/movable/proc/newtonian_move] + * + * Return 0 to have src start/keep drifting in a no-grav area and 1 to stop/not start drifting + * + * Mobs should return 1 if they should be able to move of their own volition, see [/client/proc/Move] + * + * Arguments: + * * movement_dir - 0 when stopping or any dir when trying to move + */ /atom/movable/proc/Process_Spacemove(movement_dir = 0) if(has_gravity(src)) - return 1 + return TRUE - if(pulledby) - return 1 + if(pulledby && (pulledby.pulledby != src || moving_from_pull)) + return TRUE if(throwing) - return 1 + return TRUE if(!isturf(loc)) - return 1 + return TRUE if(locate(/obj/structure/lattice) in range(1, get_turf(src))) //Not realistic but makes pushing things in space easier - return 1 + return TRUE - return 0 + return FALSE -/atom/movable/proc/newtonian_move(direction) //Only moves the object if it's under no gravity - if(!loc || Process_Spacemove(0)) +/// Only moves the object if it's under no gravity +/atom/movable/proc/newtonian_move(direction) + if(!isturf(loc) || Process_Spacemove(0)) inertia_dir = 0 - return 0 + return FALSE inertia_dir = direction if(!direction) - return 1 + return TRUE inertia_last_loc = loc SSspacedrift.processing[src] = src - return 1 + return TRUE diff --git a/code/game/gamemodes/gangs/gang_items.dm b/code/game/gamemodes/gangs/gang_items.dm index 7d6ecd00f6..d1cf006600 100644 --- a/code/game/gamemodes/gangs/gang_items.dm +++ b/code/game/gamemodes/gangs/gang_items.dm @@ -133,7 +133,7 @@ icon_state = "knuckles" w_class = 3 -datum/gang_item/clothing/shades //Addition: Why not have cool shades on a gang member anyways? +/datum/gang_item/clothing/shades //Addition: Why not have cool shades on a gang member anyways? name = "Cool Sunglasses" id = "glasses" cost = 5 @@ -313,13 +313,13 @@ datum/gang_item/clothing/shades //Addition: Why not have cool shades on a gang m permeability_coefficient = 0.01 clothing_flags = NOSLIP -datum/gang_item/equipment/shield +/datum/gang_item/equipment/shield name = "Riot Shield" id = "riot_shield" cost = 25 item_path = /obj/item/shield/riot -datum/gang_item/equipment/gangsheild +/datum/gang_item/equipment/gangsheild name = "Tower Shield" id = "metal" cost = 45 //High block of melee and even higher for bullets diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index d8617e0b48..0ee07951a9 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -455,7 +455,7 @@ If not set, defaults to check_completion instead. Set it. It's used by cryo. var/target_real_name // Has to be stored because the target's real_name can change over the course of the round var/target_missing_id -/datum/objective/escape/escape_with_identity/find_target() +/datum/objective/escape/escape_with_identity/find_target(dupe_search_range, blacklist) target = ..() update_explanation_text() @@ -553,7 +553,7 @@ GLOBAL_LIST_EMPTY(possible_items) for(var/I in subtypesof(/datum/objective_item/steal)) new I -/datum/objective/steal/find_target() +/datum/objective/steal/find_target(dupe_search_range, blacklist) var/list/datum/mind/owners = get_owners() var/approved_targets = list() check_items: @@ -631,7 +631,7 @@ GLOBAL_LIST_EMPTY(possible_items_special) for(var/I in subtypesof(/datum/objective_item/special) + subtypesof(/datum/objective_item/stack)) new I -/datum/objective/steal/special/find_target() +/datum/objective/steal/special/find_target(dupe_search_range, blacklist) return set_target(pick(GLOB.possible_items_special)) /datum/objective/steal/exchange @@ -844,7 +844,7 @@ GLOBAL_LIST_EMPTY(possible_items_special) name = "destroy AI" martyr_compatible = 1 -/datum/objective/destroy/find_target() +/datum/objective/destroy/find_target(dupe_search_range, blacklist) var/list/possible_targets = active_ais(1) var/mob/living/silicon/ai/target_ai = pick(possible_targets) target = target_ai.mind @@ -1124,7 +1124,7 @@ GLOBAL_LIST_EMPTY(possible_items_special) /datum/objective/hoard/heirloom name = "steal heirloom" -/datum/objective/hoard/heirloom/find_target() +/datum/objective/hoard/heirloom/find_target(dupe_search_range, blacklist) set_target(pick(GLOB.family_heirlooms)) GLOBAL_LIST_EMPTY(traitor_contraband) @@ -1141,7 +1141,7 @@ GLOBAL_LIST_EMPTY(cult_contraband) if(!GLOB.cult_contraband.len) GLOB.cult_contraband = list(/obj/item/clockwork/slab,/obj/item/clockwork/component/belligerent_eye,/obj/item/clockwork/component/belligerent_eye/lens_gem,/obj/item/shuttle_curse,/obj/item/cult_shift) -/datum/objective/hoard/collector/find_target() +/datum/objective/hoard/collector/find_target(dupe_search_range, blacklist) var/obj/item/I var/I_type if(prob(50)) @@ -1172,7 +1172,7 @@ GLOBAL_LIST_EMPTY(possible_sabotages) for(var/I in subtypesof(/datum/sabotage_objective)) new I -/datum/objective/sabotage/find_target() +/datum/objective/sabotage/find_target(dupe_search_range, blacklist) var/list/datum/mind/owners = get_owners() var/approved_targets = list() check_sabotages: diff --git a/code/game/machinery/camera/motion.dm b/code/game/machinery/camera/motion.dm index e515f56196..af5093d6ca 100644 --- a/code/game/machinery/camera/motion.dm +++ b/code/game/machinery/camera/motion.dm @@ -109,4 +109,4 @@ else if (world.time > detectTime) detectTime = 0 for(var/obj/machinery/computer/security/telescreen/entertainment/TV in GLOB.machines) - TV.notify(FALSE) \ No newline at end of file + TV.notify(FALSE) diff --git a/code/game/machinery/colormate.dm b/code/game/machinery/colormate.dm index b4306d49a4..1f1c16248c 100644 --- a/code/game/machinery/colormate.dm +++ b/code/game/machinery/colormate.dm @@ -6,10 +6,12 @@ density = TRUE anchored = TRUE circuit = /obj/item/circuitboard/machine/colormate - var/obj/item/inserted + var/atom/movable/inserted var/activecolor = "#FFFFFF" var/list/color_matrix_last var/matrix_mode = FALSE + /// Allow holder'd mobs + var/allow_mobs = TRUE /// Minimum lightness for normal mode var/minimum_normal_lightness = 50 /// Minimum lightness for matrix mode, tested using 4 test colors of full red, green, blue, white. @@ -57,11 +59,22 @@ return if(user.a_intent == INTENT_HARM) return ..() + if(allow_mobs && istype(I, /obj/item/clothing/head/mob_holder)) + var/obj/item/clothing/head/mob_holder/H = I + var/mob/victim = H.held_mob + if(!user.transferItemToLoc(I, src)) + to_chat(user, "[I] is stuck to your hand!") + return + if(!QDELETED(H)) + H.release() + insert_mob(victim, user) if(is_type_in_list(I, allowed_types) && is_operational()) if(!user.transferItemToLoc(I, src)) to_chat(user, "[I] is stuck to your hand!") return + if(QDELETED(I)) + return user.visible_message("[user] inserts [I] into [src]'s receptable.") inserted = I @@ -69,9 +82,22 @@ else return ..() +/obj/machinery/gear_painter/proc/insert_mob(mob/victim, mob/user) + if(inserted) + return + if(user) + visible_message("[user] stuffs [victim] into [src]!") + inserted = victim + inserted.forceMove(src) + /obj/machinery/gear_painter/AllowDrop() return FALSE +/obj/machinery/gear_painter/handle_atom_del(atom/movable/AM) + if(AM == inserted) + inserted = null + return ..() + /obj/machinery/gear_painter/AltClick(mob/user) . = ..() if(!user.CanReach(src)) diff --git a/code/game/machinery/computer/arcade/battle.dm b/code/game/machinery/computer/arcade/battle.dm index 5a0f0e9acf..96f224f4cf 100644 --- a/code/game/machinery/computer/arcade/battle.dm +++ b/code/game/machinery/computer/arcade/battle.dm @@ -60,7 +60,7 @@ blocked = TRUE var/attackamt = rand(2,6) temp = "You attack for [attackamt] damage!" - playsound(loc, 'sound/arcade/hit.ogg', 50, 1, extrarange = -3, falloff = 10) + playsound(loc, 'sound/arcade/hit.ogg', 50, TRUE, extrarange = -3) updateUsrDialog() if(turtle > 0) turtle-- @@ -74,7 +74,7 @@ var/pointamt = rand(1,3) var/healamt = rand(6,8) temp = "You use [pointamt] magic to heal for [healamt] damage!" - playsound(loc, 'sound/arcade/heal.ogg', 50, 1, extrarange = -3, falloff = 10) + playsound(loc, 'sound/arcade/heal.ogg', 50, TRUE, extrarange = -3) updateUsrDialog() turtle++ @@ -89,7 +89,7 @@ blocked = TRUE var/chargeamt = rand(4,7) temp = "You regain [chargeamt] points" - playsound(loc, 'sound/arcade/mana.ogg', 50, 1, extrarange = -3, falloff = 10) + playsound(loc, 'sound/arcade/mana.ogg', 50, TRUE, extrarange = -3) player_mp += chargeamt if(turtle > 0) turtle-- @@ -124,7 +124,7 @@ if(!gameover) gameover = TRUE temp = "[enemy_name] has fallen! Rejoice!" - playsound(loc, 'sound/arcade/win.ogg', 50, 1, extrarange = -3, falloff = 10) + playsound(loc, 'sound/arcade/win.ogg', 50, TRUE, extrarange = -3) if(obj_flags & EMAGGED) new /obj/effect/spawner/newbomb/timer/syndicate(loc) @@ -141,13 +141,13 @@ else if ((obj_flags & EMAGGED) && (turtle >= 4)) var/boomamt = rand(5,10) temp = "[enemy_name] throws a bomb, exploding you for [boomamt] damage!" - playsound(loc, 'sound/arcade/boom.ogg', 50, 1, extrarange = -3, falloff = 10) + playsound(loc, 'sound/arcade/boom.ogg', 50, TRUE, extrarange = -3) player_hp -= boomamt else if ((enemy_mp <= 5) && (prob(70))) var/stealamt = rand(2,3) temp = "[enemy_name] steals [stealamt] of your power!" - playsound(loc, 'sound/arcade/steal.ogg', 50, 1, extrarange = -3, falloff = 10) + playsound(loc, 'sound/arcade/steal.ogg', 50, TRUE, extrarange = -3) player_mp -= stealamt updateUsrDialog() @@ -155,27 +155,27 @@ gameover = TRUE sleep(turn_speed) temp = "You have been drained! GAME OVER" - playsound(loc, 'sound/arcade/lose.ogg', 50, 1, extrarange = -3, falloff = 10) + playsound(loc, 'sound/arcade/lose.ogg', 50, TRUE, extrarange = -3) if(obj_flags & EMAGGED) usr.gib() SSblackbox.record_feedback("nested tally", "arcade_results", 1, list("loss", "mana", (obj_flags & EMAGGED ? "emagged":"normal"))) else if ((enemy_hp <= 10) && (enemy_mp > 4)) temp = "[enemy_name] heals for 4 health!" - playsound(loc, 'sound/arcade/heal.ogg', 50, 1, extrarange = -3, falloff = 10) + playsound(loc, 'sound/arcade/heal.ogg', 50, TRUE, extrarange = -3) enemy_hp += 4 enemy_mp -= 4 else var/attackamt = rand(3,6) temp = "[enemy_name] attacks for [attackamt] damage!" - playsound(loc, 'sound/arcade/hit.ogg', 50, 1, extrarange = -3, falloff = 10) + playsound(loc, 'sound/arcade/hit.ogg', 50, TRUE, extrarange = -3) player_hp -= attackamt if ((player_mp <= 0) || (player_hp <= 0)) gameover = TRUE temp = "You have been crushed! GAME OVER" - playsound(loc, 'sound/arcade/lose.ogg', 50, 1, extrarange = -3, falloff = 10) + playsound(loc, 'sound/arcade/lose.ogg', 50, TRUE, extrarange = -3) if(obj_flags & EMAGGED) usr.gib() SSblackbox.record_feedback("nested tally", "arcade_results", 1, list("loss", "hp", (obj_flags & EMAGGED ? "emagged":"normal"))) diff --git a/code/game/machinery/computer/arcade/minesweeper.dm b/code/game/machinery/computer/arcade/minesweeper.dm index a9c9b5dfd9..3f7ef778b0 100644 --- a/code/game/machinery/computer/arcade/minesweeper.dm +++ b/code/game/machinery/computer/arcade/minesweeper.dm @@ -78,7 +78,7 @@ columns = 0 mine_placed = 0 if(href_list["Easy"]) - playsound(loc, startup_sound, 50, 0, extrarange = -3, falloff = 10) + playsound(loc, startup_sound, 50, FALSE, extrarange = -3) flag_text = "OFF" game_status = MINESWEEPER_GAME_PLAYING reset_board = TRUE @@ -87,7 +87,7 @@ columns = 10 mine_limit = 10 if(href_list["Intermediate"]) - playsound(loc, startup_sound, 50, 0, extrarange = -3, falloff = 10) + playsound(loc, startup_sound, 50, FALSE, extrarange = -3) flag_text = "OFF" game_status = MINESWEEPER_GAME_PLAYING reset_board = TRUE @@ -96,7 +96,7 @@ columns = 17 mine_limit = 40 if(href_list["Hard"]) - playsound(loc, startup_sound, 50, 0, extrarange = -3, falloff = 10) + playsound(loc, startup_sound, 50, FALSE, extrarange = -3) flag_text = "OFF" game_status = MINESWEEPER_GAME_PLAYING reset_board = TRUE @@ -110,9 +110,9 @@ game_status = MINESWEEPER_GAME_PLAYING reset_board = TRUE difficulty = "Custom" - playsound(loc, startup_sound, 50, 0, extrarange = -3, falloff = 10) + playsound(loc, startup_sound, 50, FALSE, extrarange = -3) if(href_list["Flag"]) - playsound(loc, 'sound/arcade/minesweeper_boardpress.ogg', 50, 0, extrarange = -3, falloff = 10) + playsound(loc, 'sound/arcade/minesweeper_boardpress.ogg', 50, FALSE, extrarange = -3) if(!flagging) flagging = TRUE flag_text = "ON" @@ -122,10 +122,10 @@ if(game_status == MINESWEEPER_GAME_MAIN_MENU) if(CHECK_BITFIELD(obj_flags, EMAGGED)) - playsound(loc, 'sound/arcade/minesweeper_emag2.ogg', 50, 0, extrarange = -3, falloff = 10) + playsound(loc, 'sound/arcade/minesweeper_emag2.ogg', 50, FALSE, extrarange = -3) web += "Explode in the game, explode in real life!
What difficulty do you want to play?



Easy (9x9 board, 10 mines)
Intermediate (16x16 board, 40 mines)
Hard (16x30 board, 99 mines)
Custom" else - playsound(loc, 'sound/arcade/minesweeper_startup.ogg', 50, 0, extrarange = -3, falloff = 10) + playsound(loc, 'sound/arcade/minesweeper_startup.ogg', 50, FALSE, extrarange = -3) web += web_difficulty_menu if(game_status == MINESWEEPER_GAME_PLAYING) @@ -152,7 +152,7 @@ if(table[y1][x1] < 10 && table[y1][x1] >= 0) //Check that it's not already revealed, and stop flag removal if we're out of flag mode table[y1][x1] += 10 if(table[y1][x1] != 10) - playsound(loc, 'sound/arcade/minesweeper_boardpress.ogg', 50, 0, extrarange = -3, falloff = 10) + playsound(loc, 'sound/arcade/minesweeper_boardpress.ogg', 50, FALSE, extrarange = -3) else if(game_status != MINESWEEPER_GAME_LOST && game_status != MINESWEEPER_GAME_WON) game_status = MINESWEEPER_GAME_LOST @@ -164,14 +164,14 @@ if(mine_sound) switch(rand(1,3)) //Play every time a mine is hit if(1) - playsound(loc, 'sound/arcade/minesweeper_explosion1.ogg', 50, 0, extrarange = -3, falloff = 10) + playsound(loc, 'sound/arcade/minesweeper_explosion1.ogg', 50, FALSE, extrarange = -3) if(2) - playsound(loc, 'sound/arcade/minesweeper_explosion2.ogg', 50, 0, extrarange = -3, falloff = 10) + playsound(loc, 'sound/arcade/minesweeper_explosion2.ogg', 50, FALSE, extrarange = -3) if(3) - playsound(loc, 'sound/arcade/minesweeper_explosion3.ogg', 50, 0, extrarange = -3, falloff = 10) + playsound(loc, 'sound/arcade/minesweeper_explosion3.ogg', 50, FALSE, extrarange = -3) mine_sound = FALSE else - playsound(loc, 'sound/arcade/minesweeper_boardpress.ogg', 50, 0, extrarange = -3, falloff = 10) + playsound(loc, 'sound/arcade/minesweeper_boardpress.ogg', 50, FALSE, extrarange = -3) if(table[y1][x1] >= 0) //Check that it's not already flagged table[y1][x1] -= 10 else if(table[y1][x1] < 0) //If flagged, remove the flag @@ -182,7 +182,7 @@ game_status = MINESWEEPER_GAME_PLAYING if(table[y1][x1] >= 10) //If revealed, become unrevealed! if(mine_sound) - playsound(loc, 'sound/arcade/minesweeper_menuselect.ogg', 50, 0, extrarange = -3, falloff = 10) + playsound(loc, 'sound/arcade/minesweeper_menuselect.ogg', 50, FALSE, extrarange = -3) mine_sound = FALSE table[y1][x1] -= 10 if(table[y1][x1] > 10 && !reset_board) @@ -243,10 +243,10 @@ if(safe_squares_revealed >= win_condition && game_status == MINESWEEPER_GAME_PLAYING) game_status = MINESWEEPER_GAME_WON if(rows < 10 || columns < 10) //If less than easy difficulty - playsound(loc, 'sound/arcade/minesweeper_winfail.ogg', 50, 0, extrarange = -3, falloff = 10) + playsound(loc, 'sound/arcade/minesweeper_winfail.ogg', 50, FALSE, extrarange = -3) say("You cleared the board of all mines, but you picked too small of a board! Try again with at least a 9x9 board!") else - playsound(loc, 'sound/arcade/minesweeper_win.ogg', 50, 0, extrarange = -3, falloff = 10) + playsound(loc, 'sound/arcade/minesweeper_win.ogg', 50, FALSE, extrarange = -3) say("You cleared the board of all mines! Congratulations!") if(CHECK_BITFIELD(obj_flags, EMAGGED)) var/itemname @@ -299,32 +299,32 @@ ENABLE_BITFIELD(obj_flags, EMAGGED) if(game_status == MINESWEEPER_GAME_MAIN_MENU) to_chat(user, "An ominous tune plays from the arcade's speakers!") - playsound(user, 'sound/arcade/minesweeper_emag1.ogg', 100, 0, extrarange = 3, falloff = 10) + playsound(user, 'sound/arcade/minesweeper_emag1.ogg', 100, FALSE, extrarange = 3) else //Can't let you do that, star fox! to_chat(user, "The machine buzzes and sparks... the game has been reset!") - playsound(user, 'sound/machines/buzz-sigh.ogg', 100, 0, extrarange = 3, falloff = 10) //Loud buzz + playsound(user, 'sound/machines/buzz-sigh.ogg', 100, FALSE, extrarange = 3) //Loud buzz game_status = MINESWEEPER_GAME_MAIN_MENU return TRUE /obj/machinery/computer/arcade/minesweeper/proc/custom_generation(mob/user) - playsound(loc, 'sound/arcade/minesweeper_menuselect.ogg', 50, 0, extrarange = -3, falloff = 10) //Entered into the menu so ping sound + playsound(loc, 'sound/arcade/minesweeper_menuselect.ogg', 50, FALSE, extrarange = -3) //Entered into the menu so ping sound var/new_rows = input(user, "How many rows do you want? (Minimum: 4, Maximum: 30)", "Minesweeper Rows") as null|num if(!new_rows || !user.canUseTopic(src, !hasSiliconAccessInArea(user))) return FALSE new_rows = clamp(new_rows + 1, 4, 30) - playsound(loc, 'sound/arcade/minesweeper_menuselect.ogg', 50, 0, extrarange = -3, falloff = 10) + playsound(loc, 'sound/arcade/minesweeper_menuselect.ogg', 50, FALSE, extrarange = -3) var/new_columns = input(user, "How many columns do you want? (Minimum: 4, Maximum: 50)", "Minesweeper Squares") as null|num if(!new_columns || !user.canUseTopic(src, !hasSiliconAccessInArea(user))) return FALSE new_columns = clamp(new_columns + 1, 4, 50) - playsound(loc, 'sound/arcade/minesweeper_menuselect.ogg', 50, 0, extrarange = -3, falloff = 10) + playsound(loc, 'sound/arcade/minesweeper_menuselect.ogg', 50, FALSE, extrarange = -3) var/grid_area = (new_rows - 1) * (new_columns - 1) var/lower_limit = round(grid_area*0.156) var/upper_limit = round(grid_area*0.85) var/new_mine_limit = input(user, "How many mines do you want? (Minimum: [lower_limit], Maximum: [upper_limit])", "Minesweeper Mines") as null|num if(!new_mine_limit || !user.canUseTopic(src, !hasSiliconAccessInArea(user))) return FALSE - playsound(loc, 'sound/arcade/minesweeper_menuselect.ogg', 50, 0, extrarange = -3, falloff = 10) + playsound(loc, 'sound/arcade/minesweeper_menuselect.ogg', 50, FALSE, extrarange = -3) rows = new_rows columns = new_columns mine_limit = clamp(new_mine_limit, lower_limit, upper_limit) diff --git a/code/game/machinery/computer/arcade/misc_arcade.dm b/code/game/machinery/computer/arcade/misc_arcade.dm index 24516740f9..50633192ce 100644 --- a/code/game/machinery/computer/arcade/misc_arcade.dm +++ b/code/game/machinery/computer/arcade/misc_arcade.dm @@ -17,14 +17,14 @@ to_chat(c_user, "You move your hand towards the machine, and begin to hesitate as a bloodied guillotine emerges from inside of it...") if(do_after(c_user, 50, target = src)) to_chat(c_user, "The guillotine drops on your arm, and the machine sucks it in!") - playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1) + playsound(loc, 'sound/weapons/slice.ogg', 25, TRUE, -1) var/which_hand = BODY_ZONE_L_ARM if(!(c_user.active_hand_index % 2)) which_hand = BODY_ZONE_R_ARM var/obj/item/bodypart/chopchop = c_user.get_bodypart(which_hand) chopchop.dismember() qdel(chopchop) - playsound(loc, 'sound/arcade/win.ogg', 50, 1, extrarange = -3, falloff = 10) + playsound(loc, 'sound/arcade/win.ogg', 50, TRUE, extrarange = -3) for(var/i=1; i<=rand(3,5); i++) prizevend(user) else diff --git a/code/game/machinery/doors/alarmlock.dm b/code/game/machinery/doors/alarmlock.dm index a563200575..fa516f4b6b 100644 --- a/code/game/machinery/doors/alarmlock.dm +++ b/code/game/machinery/doors/alarmlock.dm @@ -23,7 +23,7 @@ . = ..() SSradio.remove_object(src, air_frequency) air_connection = SSradio.add_object(src, air_frequency, RADIO_TO_AIRALARM) - open() + INVOKE_ASYNC(src, .proc/open) /obj/machinery/door/airlock/alarmlock/receive_signal(datum/signal/signal) ..() diff --git a/code/game/machinery/quantum_pad.dm b/code/game/machinery/quantum_pad.dm index f9fda50daf..4f706954a6 100644 --- a/code/game/machinery/quantum_pad.dm +++ b/code/game/machinery/quantum_pad.dm @@ -130,7 +130,7 @@ /obj/machinery/quantumpad/proc/doteleport(mob/user, obj/machinery/quantumpad/target_pad = linked_pad) if(target_pad) - playsound(get_turf(src), 'sound/weapons/flash.ogg', 25, 1) + playsound(get_turf(src), 'sound/weapons/flash.ogg', 25, TRUE) teleporting = TRUE spawn(teleport_speed) @@ -155,9 +155,9 @@ target_pad.sparks() flick("qpad-beam", src) - playsound(get_turf(src), 'sound/weapons/emitter2.ogg', 25, 1, extrarange = 3, falloff = 5) + playsound(get_turf(src), 'sound/weapons/emitter2.ogg', 25, TRUE) flick("qpad-beam", target_pad) - playsound(get_turf(target_pad), 'sound/weapons/emitter2.ogg', 25, 1, extrarange = 3, falloff = 5) + playsound(get_turf(target_pad), 'sound/weapons/emitter2.ogg', 25, TRUE) for(var/atom/movable/ROI in get_turf(src)) if(QDELETED(ROI)) continue //sleeps in CHECK_TICK diff --git a/code/game/machinery/recycler.dm b/code/game/machinery/recycler.dm index 706d2bb9bf..2ffd556dc1 100644 --- a/code/game/machinery/recycler.dm +++ b/code/game/machinery/recycler.dm @@ -100,51 +100,54 @@ eat(AM) . = ..() -/obj/machinery/recycler/proc/eat(atom/AM0) - if(stat & (BROKEN|NOPOWER) || safety_mode) +/obj/machinery/recycler/proc/eat(atom/movable/AM0, sound=TRUE) + if(stat & (BROKEN|NOPOWER)) return + if(safety_mode) + return + if(!isturf(AM0.loc)) + return //I don't know how you called Crossed() but stop it. - var/list/to_eat + var/list/to_eat = AM0.GetAllContents() - to_eat = list(AM0) + var/living_detected = FALSE //technically includes silicons as well but eh + var/list/nom = list() + var/list/crunchy_nom = list() //Mobs have to be handled differently so they get a different list instead of checking them multiple times. - var/items_recycled = 0 - var/buzz = FALSE for(var/i in to_eat) var/atom/movable/AM = i - if(QDELETED(AM)) - continue - var/obj/item/bodypart/head/as_head = AM - var/obj/item/mmi/as_mmi = AM - var/brain_holder = istype(AM, /obj/item/organ/brain) || (istype(as_head) && as_head.brain) || (istype(as_mmi) && as_mmi.brain) || istype(AM, /obj/item/dullahan_relay) - if(brain_holder) - if(obj_flags & EMAGGED) - continue - else - emergency_stop(AM) - return + if(istype(AM, /obj/item)) + var/obj/item/bodypart/head/as_head = AM + var/obj/item/mmi/as_mmi = AM + if(istype(AM, /obj/item/organ/brain) || (istype(as_head) && as_head.brain) || (istype(as_mmi) && as_mmi.brain) || istype(AM, /obj/item/dullahan_relay)) + living_detected = TRUE + nom += AM else if(isliving(AM)) - if((obj_flags & EMAGGED)||((!allowed(AM))&&(!ishuman(AM)))) - to_eat += crush_living(AM) - else - emergency_stop(AM) - return - else if(isitem(AM)) - var/obj/O = AM - if(O.resistance_flags & INDESTRUCTIBLE) - buzz = TRUE - O.forceMove(loc) - else - to_eat += recycle_item(AM) - items_recycled++ - else - buzz = TRUE - AM.forceMove(loc) - - if(items_recycled) - playsound(src, item_recycle_sound, 50, 1) - if(buzz) - playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 0) + living_detected = TRUE + crunchy_nom += AM + var/not_eaten = to_eat.len - nom.len - crunchy_nom.len + if(living_detected) // First, check if we have any living beings detected. + if(obj_flags & EMAGGED) + for(var/CRUNCH in crunchy_nom) // Eat them and keep going because we don't care about safety. + if(isliving(CRUNCH)) // MMIs and brains will get eaten like normal items + crush_living(CRUNCH) + else // Stop processing right now without eating anything. + emergency_stop() + return + for(var/nommed in nom) + recycle_item(nommed) + if(nom.len && sound) + playsound(src, item_recycle_sound, (50 + nom.len*5), TRUE, nom.len, ignore_walls = (nom.len - 10)) // As a substitute for playing 50 sounds at once. + if(not_eaten) + playsound(src, 'sound/machines/buzz-sigh.ogg', (50 + not_eaten*5), FALSE, not_eaten, ignore_walls = (not_eaten - 10)) // Ditto. + if(!ismob(AM0)) + AM0.moveToNullspace() + qdel(AM0) + else // Lets not move a mob to nullspace and qdel it, yes? + for(var/i in AM0.contents) + var/atom/movable/content = i + content.moveToNullspace() + qdel(content) /obj/machinery/recycler/proc/recycle_item(obj/item/I) diff --git a/code/game/machinery/slotmachine.dm b/code/game/machinery/slotmachine.dm index 6282d74346..1fadad168e 100644 --- a/code/game/machinery/slotmachine.dm +++ b/code/game/machinery/slotmachine.dm @@ -11,6 +11,8 @@ #define SPIN_TIME 65 //As always, deciseconds. #define REEL_DEACTIVATE_DELAY 7 #define SEVEN "7" +#define HOLOCHIP 1 +#define COIN 2 /obj/machinery/computer/slot_machine name = "slot machine" @@ -21,40 +23,48 @@ use_power = IDLE_POWER_USE idle_power_usage = 50 circuit = /obj/item/circuitboard/computer/slot_machine + light_color = LIGHT_COLOR_BROWN var/money = 3000 //How much money it has CONSUMED var/plays = 0 - var/working = 0 + var/working = FALSE var/balance = 0 //How much money is in the machine, ready to be CONSUMED. var/jackpots = 0 + var/paymode = HOLOCHIP //toggles between HOLOCHIP/COIN, defined above + var/cointype = /obj/item/coin/iron //default cointype + var/list/coinvalues = list() var/list/reels = list(list("", "", "") = 0, list("", "", "") = 0, list("", "", "") = 0, list("", "", "") = 0, list("", "", "") = 0) var/list/symbols = list(SEVEN = 1, "&" = 2, "@" = 2, "$" = 2, "?" = 2, "#" = 2, "!" = 2, "%" = 2) //if people are winning too much, multiply every number in this list by 2 and see if they are still winning too much. - light_color = LIGHT_COLOR_BROWN /obj/machinery/computer/slot_machine/Initialize() . = ..() jackpots = rand(1, 4) //false hope plays = rand(75, 200) - toggle_reel_spin(1) //The reels won't spin unless we activate them + INVOKE_ASYNC(src, .proc/toggle_reel_spin, TRUE)//The reels won't spin unless we activate them var/list/reel = reels[1] for(var/i = 0, i < reel.len, i++) //Populate the reels. randomize_reels() - toggle_reel_spin(0) + INVOKE_ASYNC(src, .proc/toggle_reel_spin, FALSE) + + for(cointype in typesof(/obj/item/coin)) + var/obj/item/coin/C = new cointype + coinvalues["[cointype]"] = C.get_item_credit_value() + qdel(C) //Sigh /obj/machinery/computer/slot_machine/Destroy() if(balance) - give_coins(balance) + give_payout(balance) return ..() -/obj/machinery/computer/slot_machine/process() +/obj/machinery/computer/slot_machine/process(delta_time) . = ..() //Sanity checks. if(!.) return . - money++ //SPESSH MAJICKS + money += round(delta_time / 2) //SPESSH MAJICKS /obj/machinery/computer/slot_machine/update_icon_state() if(stat & NOPOWER) @@ -69,27 +79,46 @@ else icon_state = "slots1" -/obj/machinery/computer/slot_machine/power_change() - ..() - update_icon() - /obj/machinery/computer/slot_machine/attackby(obj/item/I, mob/living/user, params) if(istype(I, /obj/item/coin)) var/obj/item/coin/C = I - if(prob(2)) - if(!user.transferItemToLoc(C, drop_location())) - return - C.throw_at(user, 3, 10) - if(prob(10)) - balance = max(balance - SPIN_PRICE, 0) - to_chat(user, "[src] spits your coin back out!") + if(paymode == COIN) + if(prob(2)) + if(!user.transferItemToLoc(C, drop_location())) + return + C.throw_at(user, 3, 10) + if(prob(10)) + balance = max(balance - SPIN_PRICE, 0) + to_chat(user, "[src] spits your coin back out!") + else + if(!user.temporarilyRemoveItemFromInventory(C)) + return + to_chat(user, "You insert [C] into [src]'s slot!") + balance += C.value + qdel(C) else - if(!user.temporarilyRemoveItemFromInventory(C)) + to_chat(user, "This machine is only accepting holochips!") + else if(istype(I, /obj/item/holochip)) + if(paymode == HOLOCHIP) + var/obj/item/holochip/H = I + if(!user.temporarilyRemoveItemFromInventory(H)) return - to_chat(user, "You insert [C] into [src]'s slot!") - balance += C.value - qdel(C) + to_chat(user, "You insert [H.credits] holocredits into [src]'s slot!") + balance += H.credits + qdel(H) + else + to_chat(user, "This machine is only accepting coins!") + else if(I.tool_behaviour == TOOL_MULTITOOL) + if(balance > 0) + visible_message("[src] says, 'ERROR! Please empty the machine balance before altering paymode'") //Prevents converting coins into holocredits and vice versa + else + if(paymode == HOLOCHIP) + paymode = COIN + visible_message("[src] says, 'This machine now works with COINS!'") + else + paymode = HOLOCHIP + visible_message("[src] says, 'This machine now works with HOLOCHIPS!'") else return ..() @@ -101,8 +130,7 @@ var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread() spark_system.set_up(4, 0, src.loc) spark_system.start() - playsound(src, "sparks", 50, 1) - return TRUE + playsound(src, "sparks", 50, TRUE) /obj/machinery/computer/slot_machine/ui_interact(mob/living/user) . = ..() @@ -127,8 +155,9 @@ Play!

[reeltext] -
- Refund balance
"} +
"} + if(balance > 0) + dat+="Refund balance
" var/datum/browser/popup = new(user, "slotmachine", "Slot Machine") popup.set_content(dat) @@ -143,21 +172,22 @@ spin(usr) else if(href_list["refund"]) - give_coins(balance) - balance = 0 + if(balance > 0) + give_payout(balance) + balance = 0 /obj/machinery/computer/slot_machine/emp_act(severity) . = ..() if(stat & (NOPOWER|BROKEN) || . & EMP_PROTECT_SELF) return - if(prob(1500 / severity)) + if(prob(15 * severity)) return - if(prob(1 * severity/100)) // :^) + if(prob(1)) // :^) obj_flags |= EMAGGED var/severity_ascending = 4 - severity money = max(rand(money - (200 * severity_ascending), money + (200 * severity_ascending)), 0) balance = max(rand(balance - (50 * severity_ascending), balance + (50 * severity_ascending)), 0) - money -= max(0, give_coins(min(rand(-50, 100 * severity_ascending)), money)) //This starts at -50 because it shouldn't always dispense coins yo + money -= max(0, give_payout(min(rand(-50, 100 * severity_ascending)), money)) //This starts at -50 because it shouldn't always dispense coins yo spin() /obj/machinery/computer/slot_machine/proc/spin(mob/user) @@ -174,37 +204,43 @@ balance -= SPIN_PRICE money += SPIN_PRICE plays += 1 - working = 1 + working = TRUE toggle_reel_spin(1) update_icon() updateDialog() - spawn(0) - while(working) - randomize_reels() - updateDialog() - sleep(2) + var/spin_loop = addtimer(CALLBACK(src, .proc/do_spin), 2, TIMER_LOOP|TIMER_STOPPABLE) - spawn(SPIN_TIME - (REEL_DEACTIVATE_DELAY * reels.len)) //WARNING: no sanity checking for user since it's not needed and would complicate things (machine should still spin even if user is gone), be wary of this if you're changing this code. - toggle_reel_spin(0, REEL_DEACTIVATE_DELAY) - working = 0 - give_prizes(the_name, user) - update_icon() - updateDialog() + addtimer(CALLBACK(src, .proc/finish_spinning, spin_loop, user, the_name), SPIN_TIME - (REEL_DEACTIVATE_DELAY * reels.len)) + //WARNING: no sanity checking for user since it's not needed and would complicate things (machine should still spin even if user is gone), be wary of this if you're changing this code. + +/obj/machinery/computer/slot_machine/proc/do_spin() + randomize_reels() + updateDialog() + +/obj/machinery/computer/slot_machine/proc/finish_spinning(spin_loop, mob/user, the_name) + toggle_reel_spin(0, REEL_DEACTIVATE_DELAY) + working = FALSE + deltimer(spin_loop) + give_prizes(the_name, user) + update_icon() + updateDialog() /obj/machinery/computer/slot_machine/proc/can_spin(mob/user) if(stat & NOPOWER) to_chat(user, "The slot machine has no power!") + return FALSE if(stat & BROKEN) to_chat(user, "The slot machine is broken!") + return FALSE if(working) to_chat(user, "You need to wait until the machine stops spinning before you can play again!") - return 0 + return FALSE if(balance < SPIN_PRICE) to_chat(user, "Insufficient money to play!") - return 0 - return 1 + return FALSE + return TRUE /obj/machinery/computer/slot_machine/proc/toggle_reel_spin(value, delay = 0) //value is 1 or 0 aka on or off for(var/list/reel in reels) @@ -223,23 +259,25 @@ var/linelength = get_lines() if(reels[1][2] + reels[2][2] + reels[3][2] + reels[4][2] + reels[5][2] == "[SEVEN][SEVEN][SEVEN][SEVEN][SEVEN]") - visible_message("[src] says, 'JACKPOT! You win [money] credits worth of coins!'") + visible_message("[src] says, 'JACKPOT! You win [money] credits!'") priority_announce("Congratulations to [user ? user.real_name : usrname] for winning the jackpot at the slot machine in [get_area(src)]!") jackpots += 1 - balance += money - give_coins(JACKPOT) + balance += money - give_payout(JACKPOT) money = 0 - - for(var/i = 0, i < 5, i++) - var/cointype = pick(subtypesof(/obj/item/coin)) - var/obj/item/coin/C = new cointype(loc) - random_step(C, 2, 50) + if(paymode == HOLOCHIP) + new /obj/item/holochip(loc,JACKPOT) + else + for(var/i = 0, i < 5, i++) + cointype = pick(subtypesof(/obj/item/coin)) + var/obj/item/coin/C = new cointype(loc) + random_step(C, 2, 50) else if(linelength == 5) - visible_message("[src] says, 'Big Winner! You win a thousand credits worth of coins!'") + visible_message("[src] says, 'Big Winner! You win a thousand credits!'") give_money(BIG_PRIZE) else if(linelength == 4) - visible_message("[src] says, 'Winner! You win four hundred credits worth of coins!'") + visible_message("[src] says, 'Winner! You win four hundred credits!'") give_money(SMALL_PRIZE) else if(linelength == 3) @@ -271,12 +309,15 @@ /obj/machinery/computer/slot_machine/proc/give_money(amount) var/amount_to_give = money >= amount ? amount : money - var/surplus = amount_to_give - give_coins(amount_to_give) + var/surplus = amount_to_give - give_payout(amount_to_give) money = max(0, money - amount) balance += surplus -/obj/machinery/computer/slot_machine/proc/give_coins(amount) - var/cointype = obj_flags & EMAGGED ? /obj/item/coin/iron : /obj/item/coin/silver +/obj/machinery/computer/slot_machine/proc/give_payout(amount) + if(paymode == HOLOCHIP) + cointype = /obj/item/holochip + else + cointype = obj_flags & EMAGGED ? /obj/item/coin/iron : /obj/item/coin/silver if(!(obj_flags & EMAGGED)) amount = dispense(amount, cointype, null, 0) @@ -288,22 +329,25 @@ return amount -/obj/machinery/computer/slot_machine/proc/dispense(amount = 0, cointype = /obj/item/coin/silver, mob/living/target, throwit = FALSE) - var/value = GLOB.coin_values[cointype] || GLOB.coin_values[/obj/item/coin/iron] - INVOKE_ASYNC(src, .proc/become_rich, amount, value, cointype, target, throwit) - return amount % value +/obj/machinery/computer/slot_machine/proc/dispense(amount = 0, cointype = /obj/item/coin/silver, mob/living/target, throwit = 0) + if(paymode == HOLOCHIP) + var/obj/item/holochip/H = new /obj/item/holochip(loc,amount) -/obj/machinery/computer/slot_machine/proc/become_rich(amount, value, cointype = /obj/item/coin/silver, mob/living/target, throwit = FALSE) - if(value <= 0) - return - while(amount >= value && !QDELETED(src)) - var/obj/item/coin/C = new cointype(loc) //DOUBLE THE PAIN - amount -= value if(throwit && target) - C.throw_at(target, 3, 10) - else - random_step(C, 2, 40) - CHECK_TICK + H.throw_at(target, 3, 10) + else + var/value = coinvalues["[cointype]"] + if(value <= 0) + CRASH("Coin value of zero, refusing to payout in dispenser") + while(amount >= value) + var/obj/item/coin/C = new cointype(loc) //DOUBLE THE PAIN + amount -= value + if(throwit && target) + C.throw_at(target, 3, 10) + else + random_step(C, 2, 40) + + return amount #undef SEVEN #undef SPIN_TIME @@ -311,3 +355,5 @@ #undef BIG_PRIZE #undef SMALL_PRIZE #undef SPIN_PRICE +#undef HOLOCHIP +#undef COIN diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index 88a5c3f20f..036aa6ed79 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -578,6 +578,7 @@ /obj/mecha/proc/mechstep(direction) var/current_dir = dir + set_glide_size(DELAY_TO_GLIDE_SIZE(step_in)) var/result = step(src,direction) if(strafe) setDir(current_dir) diff --git a/code/game/objects/buckling.dm b/code/game/objects/buckling.dm index 5142ba69ac..27b0aa4e66 100644 --- a/code/game/objects/buckling.dm +++ b/code/game/objects/buckling.dm @@ -87,16 +87,22 @@ M.IgniteMob() /atom/movable/proc/unbuckle_mob(mob/living/buckled_mob, force=FALSE) - if(istype(buckled_mob) && buckled_mob.buckled == src && (buckled_mob.can_unbuckle() || force)) - . = buckled_mob - buckled_mob.buckled = null - buckled_mob.anchored = initial(buckled_mob.anchored) - buckled_mob.update_mobility() - buckled_mob.clear_alert("buckled") - buckled_mobs -= buckled_mob - SEND_SIGNAL(src, COMSIG_MOVABLE_UNBUCKLE, buckled_mob, force) + if(!isliving(buckled_mob)) + CRASH("Non-living [buckled_mob] thing called unbuckle_mob() for source.") + if(buckled_mob.buckled != src) + CRASH("[buckled_mob] called unbuckle_mob() for source while having buckled as [buckled_mob.buckled].") + if(!force && !buckled_mob.can_unbuckle()) + return + . = buckled_mob + buckled_mob.buckled = null + buckled_mob.anchored = initial(buckled_mob.anchored) + buckled_mob.update_mobility() + buckled_mob.clear_alert("buckled") + buckled_mob.set_glide_size(DELAY_TO_GLIDE_SIZE(buckled_mob.total_multiplicative_slowdown())) + buckled_mobs -= buckled_mob + SEND_SIGNAL(src, COMSIG_MOVABLE_UNBUCKLE, buckled_mob, force) - post_unbuckle_mob(.) + post_unbuckle_mob(.) /atom/movable/proc/unbuckle_all_mobs(force=FALSE) if(!has_buckled_mobs()) diff --git a/code/game/objects/effects/alien_acid.dm b/code/game/objects/effects/alien_acid.dm index 5276062121..6496b392c3 100644 --- a/code/game/objects/effects/alien_acid.dm +++ b/code/game/objects/effects/alien_acid.dm @@ -53,6 +53,7 @@ return 0 /obj/effect/acid/Crossed(AM as mob|obj) + . = ..() if(isliving(AM)) var/mob/living/L = AM if(L.movement_type & FLYING) diff --git a/code/game/objects/effects/anomalies.dm b/code/game/objects/effects/anomalies.dm index 9d6d034364..8f8b83bfde 100644 --- a/code/game/objects/effects/anomalies.dm +++ b/code/game/objects/effects/anomalies.dm @@ -138,7 +138,7 @@ /obj/effect/anomaly/grav/high/Initialize(mapload, new_lifespan) . = ..() - setup_grav_field() + INVOKE_ASYNC(src, .proc/setup_grav_field) /obj/effect/anomaly/grav/high/proc/setup_grav_field() grav_field = make_field(/datum/proximity_monitor/advanced/gravity, list("current_range" = 7, "host" = src, "gravity_value" = rand(0,3))) diff --git a/code/game/objects/effects/decals/cleanable/robots.dm b/code/game/objects/effects/decals/cleanable/robots.dm index 8f8f27c3c6..9dd3c2a852 100644 --- a/code/game/objects/effects/decals/cleanable/robots.dm +++ b/code/game/objects/effects/decals/cleanable/robots.dm @@ -69,4 +69,5 @@ persistent = FALSE /obj/effect/decal/cleanable/oil/slippery/Initialize() + . = ..() AddComponent(/datum/component/slippery, 80, (NO_SLIP_WHEN_WALKING | SLIDE)) diff --git a/code/game/objects/effects/overlays.dm b/code/game/objects/effects/overlays.dm index b310119827..6be0a50a5e 100644 --- a/code/game/objects/effects/overlays.dm +++ b/code/game/objects/effects/overlays.dm @@ -49,6 +49,42 @@ /obj/effect/overlay/vis mouse_opacity = MOUSE_OPACITY_TRANSPARENT anchored = TRUE - vis_flags = NONE - var/unused = 0 //When detected to be unused it gets set to world.time, after a while it gets removed - var/cache_expiration = 2 MINUTES // overlays which go unused for 2 minutes get cleaned up + vis_flags = VIS_INHERIT_DIR + ///When detected to be unused it gets set to world.time, after a while it gets removed + var/unused = 0 + ///overlays which go unused for this amount of time get cleaned up + var/cache_expiration = 2 MINUTES + +// /obj/effect/overlay/atmos_excited +// name = "excited group" +// icon = null +// icon_state = null +// anchored = TRUE // should only appear in vis_contents, but to be safe +// appearance_flags = RESET_TRANSFORM | TILE_BOUND +// invisibility = INVISIBILITY_ABSTRACT +// mouse_opacity = MOUSE_OPACITY_TRANSPARENT + +// layer = ATMOS_GROUP_LAYER +// plane = ATMOS_GROUP_PLANE + +// /obj/effect/overlay/light_visible +// name = "" +// icon = 'icons/effects/light_overlays/light_32.dmi' +// icon_state = "light" +// layer = O_LIGHTING_VISUAL_LAYER +// plane = O_LIGHTING_VISUAL_PLANE +// appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM +// mouse_opacity = MOUSE_OPACITY_TRANSPARENT +// alpha = 0 +// vis_flags = NONE + +// /obj/effect/overlay/light_cone +// name = "" +// icon = 'icons/effects/light_overlays/light_cone.dmi' +// icon_state = "light" +// layer = O_LIGHTING_VISUAL_LAYER +// plane = O_LIGHTING_VISUAL_PLANE +// appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM +// mouse_opacity = MOUSE_OPACITY_TRANSPARENT +// vis_flags = NONE +// alpha = 110 diff --git a/code/game/objects/effects/proximity.dm b/code/game/objects/effects/proximity.dm index ab35d213ea..5c477501f4 100644 --- a/code/game/objects/effects/proximity.dm +++ b/code/game/objects/effects/proximity.dm @@ -5,6 +5,7 @@ var/list/checkers //list of /obj/effect/abstract/proximity_checkers var/current_range var/ignore_if_not_on_turf //don't check turfs in range if the host's loc isn't a turf + var/wire = FALSE /datum/proximity_monitor/New(atom/_host, range, _ignore_if_not_on_turf = TRUE) checkers = list() @@ -35,6 +36,8 @@ return ..() /datum/proximity_monitor/proc/HandleMove() + SIGNAL_HANDLER + var/atom/_host = host var/atom/new_host_loc = _host.loc if(last_host_loc != new_host_loc) @@ -58,6 +61,8 @@ var/atom/_host = host var/atom/loc_to_use = ignore_if_not_on_turf ? _host.loc : get_turf(_host) + if(wire && !isturf(loc_to_use)) //it makes assemblies attached on wires work + loc_to_use = get_turf(loc_to_use) if(!isturf(loc_to_use)) //only check the host's loc if(range) var/obj/effect/abstract/proximity_checker/pc @@ -109,4 +114,5 @@ /obj/effect/abstract/proximity_checker/Crossed(atom/movable/AM) set waitfor = FALSE - monitor?.hasprox_receiver.HasProximity(AM) + . = ..() + monitor?.hasprox_receiver?.HasProximity(AM) diff --git a/code/game/objects/effects/spawners/bundle.dm b/code/game/objects/effects/spawners/bundle.dm index 4304fc3c9c..58cd0f4fa9 100644 --- a/code/game/objects/effects/spawners/bundle.dm +++ b/code/game/objects/effects/spawners/bundle.dm @@ -170,6 +170,7 @@ /obj/item/clothing/under/rank/civilian/mime/sexy) /obj/effect/spawner/bundle/crate/Initialize(mapload) + SHOULD_CALL_PARENT(FALSE) if(items && items.len) var/turf/T = get_turf(src) var/obj/structure/closet/LC = locate(/obj/structure/closet) in T diff --git a/code/game/objects/effects/spawners/xeno_egg_delivery.dm b/code/game/objects/effects/spawners/xeno_egg_delivery.dm index 9be52dab52..dd4a6ea479 100644 --- a/code/game/objects/effects/spawners/xeno_egg_delivery.dm +++ b/code/game/objects/effects/spawners/xeno_egg_delivery.dm @@ -15,5 +15,5 @@ message_admins("An alien egg has been delivered to [ADMIN_VERBOSEJMP(T)].") log_game("An alien egg has been delivered to [AREACOORD(T)]") var/message = "Attention [station_name()], we have entrusted you with a research specimen in [get_area_name(T, TRUE)]. Remember to follow all safety precautions when dealing with the specimen." - SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, /proc/addtimer, CALLBACK(GLOBAL_PROC, /proc/print_command_report, message), announcement_time)) + SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, /proc/_addtimer, CALLBACK(GLOBAL_PROC, /proc/print_command_report, message), announcement_time)) return INITIALIZE_HINT_QDEL diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 1c75f1e533..608768a0c7 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -11,7 +11,7 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb name = "item" icon = 'icons/obj/items_and_weapons.dmi' blocks_emissive = EMISSIVE_BLOCK_GENERIC - + attack_hand_speed = 0 attack_hand_is_action = FALSE attack_hand_unwieldlyness = 0 @@ -428,18 +428,19 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb /obj/item/proc/talk_into(mob/M, input, channel, spans, datum/language/language) return ITALICS | REDUCE_RANGE -/obj/item/proc/dropped(mob/user) +/// Called when a mob drops an item. +/obj/item/proc/dropped(mob/user, silent = FALSE) SHOULD_CALL_PARENT(TRUE) - current_equipped_slot = null for(var/X in actions) var/datum/action/A = X A.Remove(user) if(item_flags & DROPDEL) qdel(src) item_flags &= ~IN_INVENTORY - if(SEND_SIGNAL(src, COMSIG_ITEM_DROPPED,user) & COMPONENT_DROPPED_RELOCATION) - . = ITEM_RELOCATED_BY_DROPPED - user.update_equipment_speed_mods() + SEND_SIGNAL(src, COMSIG_ITEM_DROPPED,user) + // if(!silent) + // playsound(src, drop_sound, DROP_SOUND_VOLUME, ignore_walls = FALSE) + user?.update_equipment_speed_mods() // called just as an item is picked up (loc is not yet changed) /obj/item/proc/pickup(mob/user) @@ -467,29 +468,43 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb melee_attack_chain(usr, over) usr.FlushCurrentAction() return TRUE //returning TRUE as a "is this overridden?" flag + if(isrevenant(usr)) + if(RevenantThrow(over, usr, src)) + return + if(!Adjacent(usr) || !over.Adjacent(usr)) return // should stop you from dragging through windows over.MouseDrop_T(src,usr) return -// called after an item is placed in an equipment slot -// user is mob that equipped it -// slot uses the slot_X defines found in setup.dm -// for items that can be placed in multiple slots -// note this isn't called during the initial dressing of a player -/obj/item/proc/equipped(mob/user, slot) +/** + * Called after an item is placed in an equipment slot. + * + * Note that hands count as slots. + * + * Arguments: + * * user is mob that equipped it + * * slot uses the slot_X defines found in setup.dm for items that can be placed in multiple slots + * * Initial is used to indicate whether or not this is the initial equipment (job datums etc) or just a player doing it + */ +/obj/item/proc/equipped(mob/user, slot, initial = FALSE) SHOULD_CALL_PARENT(TRUE) - . = SEND_SIGNAL(src, COMSIG_ITEM_EQUIPPED, user, slot) + SEND_SIGNAL(src, COMSIG_ITEM_EQUIPPED, user, slot) current_equipped_slot = slot - if(!(. & COMPONENT_NO_GRANT_ACTIONS)) - for(var/X in actions) - var/datum/action/A = X - if(item_action_slot_check(slot, user, A)) //some items only give their actions buttons when in a specific slot. - A.Grant(user) + for(var/X in actions) + var/datum/action/A = X + if(item_action_slot_check(slot, user, A)) //some items only give their actions buttons when in a specific slot. + A.Grant(user) item_flags |= IN_INVENTORY + // if(!initial) + // if(equip_sound && (slot_flags & slot)) + // playsound(src, equip_sound, EQUIP_SOUND_VOLUME, TRUE, ignore_walls = FALSE) + // else if(slot == ITEM_SLOT_HANDS) + // playsound(src, pickup_sound, PICKUP_SOUND_VOLUME, ignore_walls = FALSE) user.update_equipment_speed_mods() + //Overlays for the worn overlay so you can overlay while you overlay //eg: ammo counters, primed grenade flashing, etc. //"icon_file" is used automatically for inhands etc. to make sure it gets the right inhand file @@ -656,6 +671,8 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb else playsound(hit_atom, 'sound/weapons/throwtap.ogg', 1, volume, -1) + // else + // playsound(src, drop_sound, YEET_SOUND_VOLUME, ignore_walls = FALSE) return hit_atom.hitby(src, 0, itempush, throwingdatum=throwingdatum) /obj/item/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force, messy_throw = TRUE) @@ -926,6 +943,10 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb /obj/item/proc/get_part_rating() return 0 +//Can this item be given to people? +/obj/item/proc/can_give() + return TRUE + /obj/item/doMove(atom/destination) if (ismob(loc)) var/mob/M = loc diff --git a/code/game/objects/items/RCL.dm b/code/game/objects/items/RCL.dm index 6e305c30ee..e0ac4b43c6 100644 --- a/code/game/objects/items/RCL.dm +++ b/code/game/objects/items/RCL.dm @@ -166,7 +166,7 @@ last = C break -obj/item/rcl/proc/getMobhook(mob/to_hook) +/obj/item/rcl/proc/getMobhook(mob/to_hook) if(listeningTo == to_hook) return if(listeningTo) diff --git a/code/game/objects/items/candle.dm b/code/game/objects/items/candle.dm index a3366e714e..960e3ce499 100644 --- a/code/game/objects/items/candle.dm +++ b/code/game/objects/items/candle.dm @@ -82,4 +82,8 @@ /obj/item/candle/infinite/hugbox heats_space = FALSE +/obj/item/candle/DoRevenantThrowEffects(atom/target) + if(!infinite) + put_out_candle() + #undef CANDLE_LUMINOSITY diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm index 5b1b86b9e4..7d2b0ed832 100644 --- a/code/game/objects/items/cards_ids.dm +++ b/code/game/objects/items/cards_ids.dm @@ -779,16 +779,40 @@ /obj/item/card/id/departmental_budget/update_label() return +/obj/item/card/id/departmental_budget/civ + department_ID = ACCOUNT_CIV + department_name = ACCOUNT_CIV_NAME + +/obj/item/card/id/departmental_budget/eng + department_ID = ACCOUNT_ENG + department_name = ACCOUNT_ENG_NAME + +/obj/item/card/id/departmental_budget/sci + department_ID = ACCOUNT_SCI + department_name = ACCOUNT_SCI_NAME + +/obj/item/card/id/departmental_budget/med + department_ID = ACCOUNT_MED + department_name = ACCOUNT_MED_NAME + +/obj/item/card/id/departmental_budget/srv + department_ID = ACCOUNT_SRV + department_name = ACCOUNT_SRV_NAME + /obj/item/card/id/departmental_budget/car department_ID = ACCOUNT_CAR department_name = ACCOUNT_CAR_NAME +/obj/item/card/id/departmental_budget/sec + department_ID = ACCOUNT_SEC + department_name = ACCOUNT_SEC_NAME + //Polychromatic Knight Badge /obj/item/card/id/knight name = "knight badge" icon_state = "knight" - desc = "A badge denoting the owner as a knight! It has a strip for swiping like an ID" + desc = "A badge denoting the owner as a knight! It has a strip for swiping like an ID." var/id_color = "#00FF00" //defaults to green var/mutable_appearance/id_overlay diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm index de32375642..4280e7105f 100644 --- a/code/game/objects/items/cigs_lighters.dm +++ b/code/game/objects/items/cigs_lighters.dm @@ -136,6 +136,12 @@ CIGARETTE PACKETS ARE IN FANCY.DM STOP_PROCESSING(SSobj, src) . = ..() +/obj/item/clothing/mask/cigarette/DoRevenantThrowEffects(atom/target) + if(lit) + attackby() + else + light() + /obj/item/clothing/mask/cigarette/attackby(obj/item/W, mob/user, params) if(!lit && smoketime > 0) var/lighting_text = W.ignition_effect(src, user) @@ -517,6 +523,9 @@ CIGARETTE PACKETS ARE IN FANCY.DM overlay_state = pick(overlay_list) update_icon() +/obj/item/lighter/DoRevenantThrowEffects(atom/target) + set_lit() + /obj/item/lighter/suicide_act(mob/living/carbon/user) if (lit) user.visible_message("[user] begins holding \the [src]'s flame up to [user.p_their()] face! It looks like [user.p_theyre()] trying to commit suicide!") diff --git a/code/game/objects/items/circuitboards/machine_circuitboards.dm b/code/game/objects/items/circuitboards/machine_circuitboards.dm index 4873962587..89d566f714 100644 --- a/code/game/objects/items/circuitboards/machine_circuitboards.dm +++ b/code/game/objects/items/circuitboards/machine_circuitboards.dm @@ -263,6 +263,7 @@ /obj/machinery/vending/cola = "Robust Softdrinks", /obj/machinery/vending/cigarette = "ShadyCigs Deluxe", /obj/machinery/vending/games = "\improper Good Clean Fun", + /obj/machinery/vending/kink = "KinkMate", /obj/machinery/vending/autodrobe = "AutoDrobe", /obj/machinery/vending/assist = "\improper Vendomat", /obj/machinery/vending/engivend = "\improper Engi-Vend", diff --git a/code/game/objects/items/devices/dogborg_sleeper.dm b/code/game/objects/items/devices/dogborg_sleeper.dm index 1f91196b24..4d57d05be4 100644 --- a/code/game/objects/items/devices/dogborg_sleeper.dm +++ b/code/game/objects/items/devices/dogborg_sleeper.dm @@ -347,9 +347,9 @@ last_hearcheck = world.time for(var/mob/H in hearing_mobs) if(!istype(H.loc, /obj/item/dogborg/sleeper)) - H.playsound_local(source, null, 45, falloff = 0, S = pred_death) + H.playsound_local(source, null, 45, S = pred_death) else if(H in contents) - H.playsound_local(source, null, 65, falloff = 0, S = prey_death) + H.playsound_local(source, null, 65, S = prey_death) for(var/belly in T.vore_organs) var/obj/belly/B = belly for(var/atom/movable/thing in B) @@ -391,9 +391,9 @@ last_hearcheck = world.time for(var/mob/H in hearing_mobs) if(!istype(H.loc, /obj/item/dogborg/sleeper)) - H.playsound_local(source, null, 45, falloff = 0, S = pred_digest) + H.playsound_local(source, null, 45, S = pred_digest) else if(H in contents) - H.playsound_local(source, null, 65, falloff = 0, S = prey_digest) + H.playsound_local(source, null, 65, S = prey_digest) update_gut(hound) diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm index a2459bce9f..e29519406a 100644 --- a/code/game/objects/items/devices/flashlight.dm +++ b/code/game/objects/items/devices/flashlight.dm @@ -37,11 +37,14 @@ /obj/item/flashlight/attack_self(mob/user) on = !on update_brightness(user) - playsound(user, on ? 'sound/weapons/magin.ogg' : 'sound/weapons/magout.ogg', 40, 1) + playsound(src, on ? 'sound/weapons/magin.ogg' : 'sound/weapons/magout.ogg', 40, TRUE) for(var/X in actions) var/datum/action/A = X A.UpdateButtonIcon() - return 1 + return TRUE + +/obj/item/flashlight/DoRevenantThrowEffects(atom/target) + attack_self() /obj/item/flashlight/suicide_act(mob/living/carbon/human/user) if (user.eye_blind) diff --git a/code/game/objects/items/devices/gps.dm b/code/game/objects/items/devices/gps.dm index bb46577702..a0b695e29f 100644 --- a/code/game/objects/items/devices/gps.dm +++ b/code/game/objects/items/devices/gps.dm @@ -8,10 +8,11 @@ slot_flags = ITEM_SLOT_BELT obj_flags = UNIQUE_RENAME var/gpstag = "COM0" + var/starton = TRUE /obj/item/gps/Initialize() . = ..() - AddComponent(/datum/component/gps/item, gpstag) + AddComponent(/datum/component/gps/item, gpstag, starton) /obj/item/gps/science icon_state = "gps-s" @@ -26,6 +27,9 @@ gpstag = "MINE0" desc = "A positioning system helpful for rescuing trapped or injured miners, keeping one on you at all times while mining might just save your life." +/obj/item/gps/mining/off + starton = FALSE + /obj/item/gps/cyborg icon_state = "gps-b" gpstag = "BORG0" diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm index 6ac2d310a1..939d77a1f0 100644 --- a/code/game/objects/items/devices/radio/headset.dm +++ b/code/game/objects/items/devices/radio/headset.dm @@ -283,14 +283,12 @@ GLOBAL_LIST_INIT(channel_tokens, list( SSradio.remove_object(src, GLOB.radiochannels[ch_name]) secure_radio_connections[ch_name] = null - var/turf/T = user.drop_location() - if(T) - if(keyslot) - keyslot.forceMove(T) - keyslot = null - if(keyslot2) - keyslot2.forceMove(T) - keyslot2 = null + if(keyslot) + user.put_in_hands(keyslot) + keyslot = null + if(keyslot2) + user.put_in_hands(keyslot2) + keyslot2 = null recalculateChannels() to_chat(user, "You pop out the encryption keys in the headset.") diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index d9bfa4b00e..cfe0ba705d 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -306,18 +306,6 @@ GENETICS SCANNER if(T.name == "fluffy tongue") temp_message += " Subject is suffering from a fluffified tongue. Suggested cure: Yamerol or a tongue transplant." - //HECK - else if(istype(O, /obj/item/organ/genital/penis)) - var/obj/item/organ/genital/penis/P = O - if(P.length>20) - temp_message += " Subject has a sizeable gentleman's organ at [P.length] inches." - - else if(istype(O, /obj/item/organ/genital/breasts)) - var/obj/item/organ/genital/breasts/Br = O - if(Br.cached_size>5) - temp_message += " Subject has a sizeable bosom with a [Br.size] cup." - - //GENERAL HANDLER if(!damage_message) diff --git a/code/game/objects/items/eightball.dm b/code/game/objects/items/eightball.dm index 0d5c9a22aa..39c8143ee9 100644 --- a/code/game/objects/items/eightball.dm +++ b/code/game/objects/items/eightball.dm @@ -46,6 +46,9 @@ if(.) new /obj/item/toy/eightball/haunted(loc) +/obj/item/toy/eightball/DoRevenantThrowEffects(atom/target) + MakeHaunted() + /obj/item/toy/eightball/attack_self(mob/user) if(shaking) return diff --git a/code/game/objects/items/extinguisher.dm b/code/game/objects/items/extinguisher.dm index b1f51f608d..c1579dfe15 100644 --- a/code/game/objects/items/extinguisher.dm +++ b/code/game/objects/items/extinguisher.dm @@ -235,16 +235,23 @@ return EmptyExtinguisher(user) -/obj/item/extinguisher/proc/EmptyExtinguisher(var/mob/user) - if(loc == user && reagents.total_volume) +/obj/item/extinguisher/DoRevenantThrowEffects(atom/target) + EmptyExtinguisher() + +/obj/item/extinguisher/proc/EmptyExtinguisher(mob/user) + if(!reagents.total_volume) + return + if(loc == user || !user) reagents.clear_reagents() var/turf/T = get_turf(loc) if(isopenturf(T)) var/turf/open/theturf = T theturf.MakeSlippery(TURF_WET_WATER, min_wet_time = 10 SECONDS, wet_time_to_add = 5 SECONDS) - - user.visible_message("[user] empties out \the [src] onto the floor using the release valve.", "You quietly empty out \the [src] by using its release valve.") + if(user) + user.visible_message("[user] empties out \the [src] onto the floor using the release valve.", "You quietly empty out \the [src] by using its release valve.") + else + user.visible_message("The release valve of \the [src] suddenly opens and sprays it's contents on the floor!") //firebot assembly /obj/item/extinguisher/attackby(obj/O, mob/user, params) diff --git a/code/game/objects/items/grenades/plastic.dm b/code/game/objects/items/grenades/plastic.dm index 69f89d0150..ee259c4050 100644 --- a/code/game/objects/items/grenades/plastic.dm +++ b/code/game/objects/items/grenades/plastic.dm @@ -85,6 +85,7 @@ /obj/item/grenade/plastic/Crossed(atom/movable/AM) if(nadeassembly) nadeassembly.Crossed(AM) + . = ..() /obj/item/grenade/plastic/on_found(mob/finder) if(nadeassembly) diff --git a/code/game/objects/items/pinpointer.dm b/code/game/objects/items/pinpointer.dm index abd9cec950..e47b2bb0d8 100644 --- a/code/game/objects/items/pinpointer.dm +++ b/code/game/objects/items/pinpointer.dm @@ -19,6 +19,8 @@ var/minimum_range = 0 //at what range the pinpointer declares you to be at your destination var/ignore_suit_sensor_level = FALSE // Do we find people even if their suit sensors are turned off var/alert = FALSE // TRUE to display things more seriously + /// resets target on toggle + var/resets_target = TRUE /obj/item/pinpointer/Initialize() . = ..() @@ -27,17 +29,22 @@ /obj/item/pinpointer/Destroy() STOP_PROCESSING(SSfastprocess, src) GLOB.pinpointer_list -= src - target = null + unset_target() return ..() +/obj/item/pinpointer/DoRevenantThrowEffects(atom/target) + attack_self() + /obj/item/pinpointer/attack_self(mob/living/user) active = !active - user.visible_message("[user] [active ? "" : "de"]activates [user.p_their()] pinpointer.", "You [active ? "" : "de"]activate your pinpointer.") + if(user) + user.visible_message("[user] [active ? "" : "de"]activates [user.p_their()] pinpointer.", "You [active ? "" : "de"]activate your pinpointer.") playsound(src, 'sound/items/screwdriver2.ogg', 50, 1) if(active) START_PROCESSING(SSfastprocess, src) else - target = null + if(resets_target) + unset_target() STOP_PROCESSING(SSfastprocess, src) update_icon() @@ -50,6 +57,18 @@ /obj/item/pinpointer/proc/scan_for_target() return +/obj/item/pinpointer/proc/set_target(atom/movable/newtarget) + if(target) + unset_target() + target = newtarget + RegisterSignal(target, COMSIG_PARENT_QDELETING, .proc/unset_target) + +/obj/item/pinpointer/proc/unset_target() + if(!target) + return + UnregisterSignal(target, COMSIG_PARENT_QDELETING) + target = null + /obj/item/pinpointer/update_overlays() . = ..() if(!active) @@ -101,7 +120,8 @@ active = FALSE user.visible_message("[user] deactivates [user.p_their()] pinpointer.", "You deactivate your pinpointer.") playsound(src, 'sound/items/screwdriver2.ogg', 50, 1) - target = null //Restarting the pinpointer forces a target reset + if(resets_target) + unset_target() //Restarting the pinpointer forces a target reset STOP_PROCESSING(SSfastprocess, src) update_icon() return @@ -137,7 +157,7 @@ if(!A || QDELETED(src) || !user || !user.is_holding(src) || user.incapacitated()) return - target = names[A] + set_target(names[A]) active = TRUE user.visible_message("[user] activates [user.p_their()] pinpointer.", "You activate your pinpointer.") playsound(src, 'sound/items/screwdriver2.ogg', 50, 1) @@ -149,7 +169,7 @@ if(ishuman(target)) var/mob/living/carbon/human/H = target if(!trackable(H)) - target = null + unset_target() if(!target) //target can be set to null from above code, or elsewhere active = FALSE @@ -163,7 +183,7 @@ . = ..() /obj/item/pinpointer/pair/scan_for_target() - target = other_pair + set_target(other_pair) /obj/item/pinpointer/pair/examine(mob/user) . = ..() @@ -195,7 +215,7 @@ shuttleport = SSshuttle.getShuttle("huntership") /obj/item/pinpointer/shuttle/scan_for_target() - target = shuttleport + set_target(shuttleport) /obj/item/pinpointer/shuttle/Destroy() shuttleport = null @@ -207,4 +227,8 @@ icon_state = "pinpointer_ian" /obj/item/pinpointer/ian/scan_for_target() - target = locate(/mob/living/simple_animal/pet/dog/corgi/Ian) in GLOB.mob_living_list + set_target(locate(/mob/living/simple_animal/pet/dog/corgi/Ian) in GLOB.mob_living_list) + +/obj/item/pinpointer/custom + resets_target = FALSE + diff --git a/code/game/objects/items/plushes.dm b/code/game/objects/items/plushes.dm index d1174cded7..c213fa34df 100644 --- a/code/game/objects/items/plushes.dm +++ b/code/game/objects/items/plushes.dm @@ -45,6 +45,10 @@ return set_snowflake_from_config(id) +/obj/item/toy/plush/DoRevenantThrowEffects(atom/target) + var/datum/component/squeak/squeaker = GetComponent(/datum/component/squeak) + squeaker.do_play_squeak(TRUE) + /obj/item/toy/plush/Initialize(mapload, set_snowflake_id) . = ..() AddComponent(/datum/component/squeak, squeak_override) @@ -462,6 +466,7 @@ GLOBAL_LIST_INIT(valid_plushie_paths, valid_plushie_paths()) can_random_spawn = FALSE /obj/item/toy/plush/random/Initialize() + SHOULD_CALL_PARENT(FALSE) var/newtype var/list/snowflake_list = CONFIG_GET(keyed_list/snowflake_plushies) diff --git a/code/game/objects/items/pneumaticCannon.dm b/code/game/objects/items/pneumaticCannon.dm index 23be8cbb9a..1db5cdd526 100644 --- a/code/game/objects/items/pneumaticCannon.dm +++ b/code/game/objects/items/pneumaticCannon.dm @@ -43,6 +43,13 @@ /obj/item/pneumatic_cannon/proc/init_charge() //wrapper so it can be vv'd easier START_PROCESSING(SSobj, src) +/obj/item/pneumatic_cannon/DoRevenantThrowEffects(atom/target) + var/picked_target + var/list/possible_targets = range(3,src) + picked_target = pick(possible_targets) + if(target) + Fire(null, picked_target) + /obj/item/pneumatic_cannon/process() if(++charge_tick >= charge_ticks && charge_type) fill_with_type(charge_type, charge_amount) @@ -134,21 +141,29 @@ Fire(user, target) /obj/item/pneumatic_cannon/proc/Fire(mob/living/user, var/atom/target) - if(!istype(user) && !target) + if(!target) return + if(user) + if(!isliving(user)) + return var/discharge = 0 - if(!can_trigger_gun(user)) + if(user && !can_trigger_gun(user)) return if(!loadedItems || !loadedWeightClass) - to_chat(user, "\The [src] has nothing loaded.") + if(user) + to_chat(user, "\The [src] has nothing loaded.") return if(!tank && checktank) - to_chat(user, "\The [src] can't fire without a source of gas.") + if(user) + to_chat(user, "\The [src] can't fire without a source of gas.") return if(tank && !tank.air_contents.remove(gasPerThrow * pressureSetting)) - to_chat(user, "\The [src] lets out a weak hiss and doesn't react!") + if(user) + to_chat(user, "\The [src] lets out a weak hiss and doesn't react!") + else + visible_message(src, "\The [src] lets out a weak hiss and doesn't react!") return - if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(75) && clumsyCheck && iscarbon(user)) + if(user && HAS_TRAIT(user, TRAIT_CLUMSY) && prob(75) && clumsyCheck && iscarbon(user)) var/mob/living/carbon/C = user C.visible_message("[C] loses [C.p_their()] grip on [src], causing it to go off!", "[src] slips out of your hands and goes off!") C.dropItemToGround(src, TRUE) @@ -157,15 +172,18 @@ else var/list/possible_targets = range(3,src) target = pick(possible_targets) - discharge = 1 - if(!discharge) + discharge = TRUE + if(!discharge && user) user.visible_message("[user] fires \the [src]!", \ "You fire \the [src]!") - log_combat(user, target, "fired at", src) var/turf/T = get_target(target, get_turf(src)) - playsound(src, 'sound/weapons/sonic_jackhammer.ogg', 50, 1) - fire_items(T, user) - if(pressureSetting >= 3 && iscarbon(user)) + playsound(src, 'sound/weapons/sonic_jackhammer.ogg', 50, TRUE) + if(user) + log_combat(user, target, "fired at", src) + fire_items(T, user) + else + fire_items(T) + if(user && pressureSetting >= 3 && iscarbon(user)) var/mob/living/carbon/C = user C.visible_message("[C] is thrown down by the force of the cannon!", "[src] slams into your shoulder, knocking you down!") C.DefaultCombatKnockdown(60) diff --git a/code/game/objects/items/puzzle_pieces.dm b/code/game/objects/items/puzzle_pieces.dm index d0fd4dc3f6..345f3185da 100644 --- a/code/game/objects/items/puzzle_pieces.dm +++ b/code/game/objects/items/puzzle_pieces.dm @@ -134,7 +134,7 @@ /obj/item/pressure_plate/hologrid/Crossed(atom/movable/AM) . = ..() if(trigger_item && istype(AM, specific_item) && !claimed) - AM.anchored = TRUE + AM.set_anchored(TRUE) flick("laserbox_burn", AM) trigger() QDEL_IN(src, 15) diff --git a/code/game/objects/items/shields.dm b/code/game/objects/items/shields.dm index d1d57fe375..5c3e4fd612 100644 --- a/code/game/objects/items/shields.dm +++ b/code/game/objects/items/shields.dm @@ -258,7 +258,7 @@ shield_flags = SHIELD_FLAGS_DEFAULT max_integrity = 300 -obj/item/shield/riot/bullet_proof +/obj/item/shield/riot/bullet_proof name = "bullet resistant shield" desc = "A far more frail shield made of resistant plastics and kevlar meant to block ballistics." armor = list("melee" = 30, "bullet" = 80, "laser" = 0, "energy" = 0, "bomb" = -40, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 50) diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index 3e2bb675fa..520a400630 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -65,7 +65,7 @@ if(merge) for(var/obj/item/stack/S in loc) if(S.merge_type == merge_type) - merge(S) + INVOKE_ASYNC(src, .proc/merge, S) var/list/temp_recipes = get_main_recipes() recipes = temp_recipes.Copy() if(material_type) diff --git a/code/game/objects/items/storage/backpack.dm b/code/game/objects/items/storage/backpack.dm index f15588a7f1..f10167890a 100644 --- a/code/game/objects/items/storage/backpack.dm +++ b/code/game/objects/items/storage/backpack.dm @@ -639,7 +639,7 @@ new /obj/item/bikehorn(src) new /obj/item/implanter/sad_trombone(src) -obj/item/storage/backpack/duffelbag/syndie/shredderbundle +/obj/item/storage/backpack/duffelbag/syndie/shredderbundle desc = "A large duffel bag containing two CX Shredders, some magazines, an elite hardsuit, and a chest rig." /obj/item/storage/backpack/duffelbag/syndie/shredderbundle/PopulateContents() diff --git a/code/game/objects/items/storage/belt.dm b/code/game/objects/items/storage/belt.dm index 80818b5fff..9c3d776b56 100755 --- a/code/game/objects/items/storage/belt.dm +++ b/code/game/objects/items/storage/belt.dm @@ -857,7 +857,7 @@ icon_state = "2sheath" item_state = "katana" //this'll do. w_class = WEIGHT_CLASS_BULKY - fitting_swords = list(/obj/item/melee/smith/wakizashi, /obj/item/melee/smith/twohand/katana, /obj/item/melee/bokken) + fitting_swords = list(/obj/item/melee/smith/wakizashi, /obj/item/melee/smith/twohand/katana, /obj/item/melee/bokken, /obj/item/katana) starting_sword = null /obj/item/storage/belt/sabre/twin/ComponentInitialize() diff --git a/code/game/objects/items/storage/boxes.dm b/code/game/objects/items/storage/boxes.dm index 975621ead1..3f9c3a019e 100644 --- a/code/game/objects/items/storage/boxes.dm +++ b/code/game/objects/items/storage/boxes.dm @@ -275,7 +275,7 @@ for(var/i in 1 to 7) new /obj/item/grenade/flashbang(src) -obj/item/storage/box/stingbangs +/obj/item/storage/box/stingbangs name = "box of stingbangs (WARNING)" desc = "WARNING: These devices are extremely dangerous and can cause severe injuries or death in repeated use." icon_state = "secbox" diff --git a/code/game/objects/items/stunbaton.dm b/code/game/objects/items/stunbaton.dm index 26051e65fd..1de77bd8b9 100644 --- a/code/game/objects/items/stunbaton.dm +++ b/code/game/objects/items/stunbaton.dm @@ -47,6 +47,9 @@ cell = new preload_cell_type(src) update_icon() +/obj/item/melee/baton/DoRevenantThrowEffects(atom/target) + switch_status() + /obj/item/melee/baton/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) ..() //Only mob/living types have stun handling @@ -236,6 +239,12 @@ if(!iscyborg(loc)) deductcharge(severity*10, TRUE, FALSE) +/obj/item/melee/baton/can_give() + if(turned_on) + return FALSE + else + ..() + /obj/item/melee/baton/stunsword name = "stunsword" desc = "Not actually sharp, this sword is functionally identical to its baton counterpart." @@ -269,21 +278,22 @@ icon_state = "refill_donksoft" var/product = /obj/item/melee/baton/stunsword //what it makes var/list/fromitem = list(/obj/item/melee/baton, /obj/item/melee/baton/loaded) //what it needs - afterattack(obj/O, mob/user as mob) - if(istype(O, product)) - to_chat(user,"[O] is already modified!") - else if(O.type in fromitem) //makes sure O is the right thing - var/obj/item/melee/baton/B = O - if(!B.cell) //checks for a powercell in the baton. If there isn't one, continue. If there is, warn the user to take it out - new product(usr.loc) //spawns the product - user.visible_message("[user] modifies [O]!","You modify the [O]!") - qdel(O) //Gets rid of the baton - qdel(src) //gets rid of the kit - else - to_chat(user,"Remove the powercell first!") //We make this check because the stunsword starts without a battery. +/obj/item/ssword_kit/afterattack(obj/O, mob/user as mob) + if(istype(O, product)) + to_chat(user,"[O] is already modified!") + return + if(O.type in fromitem) //makes sure O is the right thing + var/obj/item/melee/baton/B = O + if(!B.cell) //checks for a powercell in the baton. If there isn't one, continue. If there is, warn the user to take it out + new product(usr.loc) //spawns the product + user.visible_message("[user] modifies [O]!","You modify the [O]!") + qdel(O) //Gets rid of the baton + qdel(src) //gets rid of the kit else - to_chat(user, " You can't modify [O] with this kit!") + to_chat(user,"Remove the powercell first!") //We make this check because the stunsword starts without a battery. + else + to_chat(user, " You can't modify [O] with this kit!") //Makeshift stun baton. Replacement for stun gloves. /obj/item/melee/baton/cattleprod diff --git a/code/game/objects/items/tanks/tanks.dm b/code/game/objects/items/tanks/tanks.dm index 08b91332ef..d57f0cc51f 100644 --- a/code/game/objects/items/tanks/tanks.dm +++ b/code/game/objects/items/tanks/tanks.dm @@ -73,6 +73,15 @@ /obj/item/tank/proc/populate_gas() return +/obj/item/tank/DoRevenantThrowEffects(atom/target) + if(air_contents) + var/turf/open/location = get_turf(src) + if(istype(location)) + location.assume_air(air_contents) + air_contents.clear() + SSair.add_to_active(location) + visible_message("[src] can't be turned on while unsecured!") + if(user) + to_chat(user, "[src] can't be turned on while unsecured!") return welding = !welding if(welding) if(get_fuel() >= 1) - to_chat(user, "You switch [src] on.") + if(user) + to_chat(user, "You switch [src] on.") playsound(loc, acti_sound, 50, 1) force = 15 damtype = "fire" diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index 4e82df2452..97fced4eb7 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -531,6 +531,7 @@ pop_burst() /obj/item/toy/snappop/Crossed(H as mob|obj) + . = ..() if(ishuman(H) || issilicon(H)) //i guess carp and shit shouldn't set them off var/mob/living/carbon/M = H if(issilicon(H) || M.m_intent == MOVE_INTENT_RUN) diff --git a/code/game/objects/structures/plasticflaps.dm b/code/game/objects/structures/plasticflaps.dm index a07e9a26d5..ff8287d77b 100644 --- a/code/game/objects/structures/plasticflaps.dm +++ b/code/game/objects/structures/plasticflaps.dm @@ -62,7 +62,7 @@ return 1 var/mob/living/M = caller - if(!M.ventcrawler && M.mob_size != MOB_SIZE_TINY) + if(!(SEND_SIGNAL(M, COMSIG_CHECK_VENTCRAWL)) && M.mob_size != MOB_SIZE_TINY) return 0 var/atom/movable/M = caller if(M && M.pulling) @@ -91,7 +91,7 @@ return 1 if(M.buckled && istype(M.buckled, /mob/living/simple_animal/bot/mulebot)) // mulebot passenger gets a free pass. return 1 - if(!M.lying && !M.ventcrawler && M.mob_size != MOB_SIZE_TINY) //If your not laying down, or a ventcrawler or a small creature, no pass. + if(!M.lying && !(SEND_SIGNAL(M, COMSIG_CHECK_VENTCRAWL)) && M.mob_size != MOB_SIZE_TINY) //If your not laying down, or a ventcrawler or a small creature, no pass. return 0 return ..() diff --git a/code/game/objects/structures/signs/signs_maps.dm b/code/game/objects/structures/signs/signs_maps.dm index ee29ef7443..bcd7c02c66 100644 --- a/code/game/objects/structures/signs/signs_maps.dm +++ b/code/game/objects/structures/signs/signs_maps.dm @@ -56,17 +56,17 @@ desc = "A direction sign, pointing out which way the Cafe is." icon_state = "direction_cafe" -obj/structure/sign/directions/rooms +/obj/structure/sign/directions/rooms name = "room" desc = "Room numbers, helps others find you!" icon_state = "roomnum" -obj/structure/sign/directions/dorms +/obj/structure/sign/directions/dorms name = "dorm" desc = "Dorm numbers, help others find you, or you find others." icon_state = "dormnum" -obj/structure/sign/directions/cells +/obj/structure/sign/directions/cells name = "room" desc = "So the less fortunate amongst us know where they'll be staying." icon_state = "cellnum" diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 31f11a199c..1ef0726e63 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -269,13 +269,13 @@ UnregisterSignal(source, COMSIG_MOVABLE_MOVED) /obj/structure/table/rolling/Moved(atom/OldLoc, Dir) + . = ..() for(var/mob/M in OldLoc.contents)//Kidnap everyone on top M.forceMove(loc) for(var/x in attached_items) var/atom/movable/AM = x if(!AM.Move(loc)) RemoveItemFromTable(AM, AM.loc) - return TRUE /* * Glass tables diff --git a/code/game/objects/structures/transit_tubes/transit_tube_pod.dm b/code/game/objects/structures/transit_tubes/transit_tube_pod.dm index cf68341b2c..21709edf73 100644 --- a/code/game/objects/structures/transit_tubes/transit_tube_pod.dm +++ b/code/game/objects/structures/transit_tubes/transit_tube_pod.dm @@ -126,12 +126,13 @@ if(current_tube == null) setDir(next_dir) - Move(get_step(loc, dir), dir) // Allow collisions when leaving the tubes. + Move(get_step(loc, dir), dir, DELAY_TO_GLIDE_SIZE(exit_delay)) // Allow collisions when leaving the tubes. break last_delay = current_tube.enter_delay(src, next_dir) sleep(last_delay) setDir(next_dir) + set_glide_size(DELAY_TO_GLIDE_SIZE(last_delay + exit_delay)) forceMove(next_loc) // When moving from one tube to another, skip collision and such. density = current_tube.density diff --git a/code/game/objects/structures/traps.dm b/code/game/objects/structures/traps.dm index 4c8379d14f..e6a76f36ca 100644 --- a/code/game/objects/structures/traps.dm +++ b/code/game/objects/structures/traps.dm @@ -56,6 +56,7 @@ animate(src, alpha = initial(alpha), time = time_between_triggers) /obj/structure/trap/Crossed(atom/movable/AM) + . = ..() if(last_trigger + time_between_triggers > world.time) return // Don't want the traps triggered by sparks, ghosts or projectiles. @@ -67,6 +68,7 @@ return if(M.anti_magic_check()) flare() + return if(charges <= 0) return flare() diff --git a/code/game/say.dm b/code/game/say.dm index 3bc14ed245..b7bfe540d0 100644 --- a/code/game/say.dm +++ b/code/game/say.dm @@ -59,7 +59,7 @@ GLOBAL_LIST_INIT(freqtospan, list( var/endspanpart = "" //Message - var/messagepart = " [say_emphasis(lang_treat(speaker, message_language, raw_message, spans, message_mode))]" + var/messagepart = " [lang_treat(speaker, message_language, raw_message, spans, message_mode)]" var/languageicon = "" var/datum/language/D = GLOB.language_datum_instances[message_language] @@ -116,6 +116,7 @@ GLOBAL_LIST_INIT(freqtospan, list( /atom/movable/proc/lang_treat(atom/movable/speaker, datum/language/language, raw_message, list/spans, message_mode, no_quote = FALSE) if(has_language(language)) var/atom/movable/AM = speaker.GetSource() + raw_message = say_emphasis(raw_message) if(AM) //Basically means "if the speaker is virtual" return no_quote ? AM.quoteless_say_quote(raw_message, spans, message_mode) : AM.say_quote(raw_message, spans, message_mode) else diff --git a/code/game/sound.dm b/code/game/sound.dm index b012ba4e2a..1816336bd1 100644 --- a/code/game/sound.dm +++ b/code/game/sound.dm @@ -1,4 +1,49 @@ -/proc/playsound(atom/source, soundin, vol as num, vary, extrarange as num, falloff, frequency = null, channel = 0, pressure_affected = TRUE, ignore_walls = TRUE, soundenvwet = -10000, soundenvdry = 0) +// /tg/ reverb disabled +/* +///Default override for echo +/sound + echo = list( + 0, // Direct + 0, // DirectHF + -10000, // Room, -10000 means no low frequency sound reverb + -10000, // RoomHF, -10000 means no high frequency sound reverb + 0, // Obstruction + 0, // ObstructionLFRatio + 0, // Occlusion + 0.25, // OcclusionLFRatio + 1.5, // OcclusionRoomRatio + 1.0, // OcclusionDirectRatio + 0, // Exclusion + 1.0, // ExclusionLFRatio + 0, // OutsideVolumeHF + 0, // DopplerFactor + 0, // RolloffFactor + 0, // RoomRolloffFactor + 1.0, // AirAbsorptionFactor + 0, // Flags (1 = Auto Direct, 2 = Auto Room, 4 = Auto RoomHF) + ) + environment = SOUND_ENVIRONMENT_NONE //Default to none so sounds without overrides dont get reverb +*/ + +/*! playsound + +playsound is a proc used to play a 3D sound in a specific range. This uses SOUND_RANGE + extra_range to determine that. + +source - Origin of sound +soundin - Either a file, or a string that can be used to get an SFX +vol - The volume of the sound, excluding falloff and pressure affection. +vary - bool that determines if the sound changes pitch every time it plays +extrarange - modifier for sound range. This gets added on top of SOUND_RANGE +falloff_exponent - Rate of falloff for the audio. Higher means quicker drop to low volume. Should generally be over 1 to indicate a quick dive to 0 rather than a slow dive. +frequency - playback speed of audio +channel - The channel the sound is played at +pressure_affected - Whether or not difference in pressure affects the sound (E.g. if you can hear in space) +ignore_walls - Whether or not the sound can pass through walls. +falloff_distance - Distance at which falloff begins. Sound is at peak volume (in regards to falloff) aslong as it is in this range. + +*/ + +/proc/playsound(atom/source, soundin, vol as num, vary, extrarange as num, falloff_exponent = SOUND_FALLOFF_EXPONENT, frequency = null, channel = 0, pressure_affected = TRUE, ignore_walls = TRUE, falloff_distance = SOUND_DEFAULT_FALLOFF_DISTANCE, envwet = -10000, envdry = 0) if(isarea(source)) CRASH("playsound(): source is an area") @@ -10,26 +55,60 @@ //allocate a channel if necessary now so its the same for everyone channel = channel || SSsounds.random_available_channel() - // Looping through the player list has the added bonus of working for mobs inside containers + // Looping through the player list has the added bonus of working for mobs inside containers var/sound/S = sound(get_sfx(soundin)) - var/maxdistance = (world.view + extrarange) - var/z = turf_source.z - var/list/listeners = SSmobs.clients_by_zlevel[z] + var/maxdistance = SOUND_RANGE + extrarange + var/source_z = turf_source.z + var/list/listeners = SSmobs.clients_by_zlevel[source_z].Copy() + + var/turf/above_turf = SSmapping.get_turf_above(turf_source) + var/turf/below_turf = SSmapping.get_turf_below(turf_source) + if(!ignore_walls) //these sounds don't carry through walls listeners = listeners & hearers(maxdistance,turf_source) + + if(above_turf && istransparentturf(above_turf)) + listeners += hearers(maxdistance,above_turf) + + if(below_turf && istransparentturf(turf_source)) + listeners += hearers(maxdistance,below_turf) + + else + if(above_turf && istransparentturf(above_turf)) + listeners += SSmobs.clients_by_zlevel[above_turf.z] + + if(below_turf && istransparentturf(turf_source)) + listeners += SSmobs.clients_by_zlevel[below_turf.z] + for(var/P in listeners) var/mob/M = P if(get_dist(M, turf_source) <= maxdistance) - M.playsound_local(turf_source, soundin, vol, vary, frequency, falloff, channel, pressure_affected, S, soundenvwet, soundenvdry) - for(var/P in SSmobs.dead_players_by_zlevel[z]) + M.playsound_local(turf_source, soundin, vol, vary, frequency, falloff_exponent, channel, pressure_affected, S, maxdistance, falloff_distance, null, envwet, envdry) + for(var/P in SSmobs.dead_players_by_zlevel[source_z]) var/mob/M = P if(get_dist(M, turf_source) <= maxdistance) - M.playsound_local(turf_source, soundin, vol, vary, frequency, falloff, channel, pressure_affected, S, soundenvwet, soundenvdry) + M.playsound_local(turf_source, soundin, vol, vary, frequency, falloff_exponent, channel, pressure_affected, S, maxdistance, falloff_distance, null, envwet, envdry) -/mob/proc/playsound_local(turf/turf_source, soundin, vol as num, vary, frequency, falloff, channel = 0, pressure_affected = TRUE, sound/S, envwet = -10000, envdry = 0, manual_x, manual_y, distance_multiplier = 1) - if(audiovisual_redirect) - var/turf/T = get_turf(src) - audiovisual_redirect.playsound_local(turf_source, soundin, vol, vary, frequency, falloff, channel, pressure_affected, S, 0, -1000, turf_source.x - T.x, turf_source.y - T.y, distance_multiplier) +/*! playsound + +playsound_local is a proc used to play a sound directly on a mob from a specific turf. +This is called by playsound to send sounds to players, in which case it also gets the max_distance of that sound. + +turf_source - Origin of sound +soundin - Either a file, or a string that can be used to get an SFX +vol - The volume of the sound, excluding falloff +vary - bool that determines if the sound changes pitch every time it plays +frequency - playback speed of audio +falloff_exponent - Rate of falloff for the audio. Higher means quicker drop to low volume. Should generally be over 1 to indicate a quick dive to 0 rather than a slow dive. +channel - The channel the sound is played at +pressure_affected - Whether or not difference in pressure affects the sound (E.g. if you can hear in space) +max_distance - The peak distance of the sound, if this is a 3D sound +falloff_distance - Distance at which falloff begins, if this is a 3D sound +distance_multiplier - Can be used to multiply the distance at which the sound is heard + +*/ + +/mob/proc/playsound_local(turf/turf_source, soundin, vol as num, vary, frequency, falloff_exponent = SOUND_FALLOFF_EXPONENT, channel = 0, pressure_affected = TRUE, sound/S, max_distance, falloff_distance = SOUND_DEFAULT_FALLOFF_DISTANCE, distance_multiplier = 1, envwet = -10000, envdry = 0) if(!client || !can_hear()) return @@ -39,7 +118,9 @@ S.wait = 0 //No queue S.channel = channel || SSsounds.random_available_channel() S.volume = vol + // CITADEL EDIT - Force citadel reverb S.environment = 7 + // End if(vary) if(frequency) @@ -51,13 +132,13 @@ var/turf/T = get_turf(src) //sound volume falloff with distance - var/distance = 0 - if(!manual_x && !manual_y) - distance = get_dist(T, turf_source) + var/distance = get_dist(T, turf_source) distance *= distance_multiplier - S.volume -= max(distance - world.view, 0) * 2 //multiplicative falloff to add on top of natural audio falloff. + if(max_distance) //If theres no max_distance we're not a 3D sound, so no falloff. + S.volume -= (max(distance - falloff_distance, 0) ** (1 / falloff_exponent)) / ((max(max_distance, distance) - falloff_distance) ** (1 / falloff_exponent)) * S.volume + //https://www.desmos.com/calculator/sqdfl8ipgf if(pressure_affected) //Atmosphere affects sound @@ -72,42 +153,57 @@ else //space pressure_factor = 0 - S.echo = list(envdry, null, envwet, null, null, null, null, null, null, null, null, null, null, 1, 1, 1, null, null) - if(distance <= 1) pressure_factor = max(pressure_factor, 0.15) //touching the source of the sound S.volume *= pressure_factor //End Atmosphere affecting sound + /// Citadel edit - Citadel reverb + S.echo = list(envdry, null, envwet, null, null, null, null, null, null, null, null, null, null, 1, 1, 1, null, null) + /// End + if(S.volume <= 0) return //No sound - var/dx = 0 // Hearing from the right/left - if(!manual_x) - dx = turf_source.x - T.x - else - dx = manual_x + var/dx = turf_source.x - T.x // Hearing from the right/left S.x = dx * distance_multiplier - var/dz = 0 // Hearing from infront/behind - if(!manual_x) - dz = turf_source.y - T.y - else - dz = manual_y + var/dz = turf_source.y - T.y // Hearing from infront/behind S.z = dz * distance_multiplier - // The y value is for above your head, but there is no ceiling in 2d spessmens. - S.y = 1 - S.falloff = (falloff ? falloff : FALLOFF_SOUNDS) + var/dy = (turf_source.z - T.z) * 5 * distance_multiplier // Hearing from above / below, multiplied by 5 because we assume height is further along coords. + S.y = dy + + S.falloff = isnull(max_distance)? FALLOFF_SOUNDS : max_distance //use max_distance, else just use 1 as we are a direct sound so falloff isnt relevant. + + /* + /// Tg reverb removed + if(S.environment == SOUND_ENVIRONMENT_NONE) + if(sound_environment_override != SOUND_ENVIRONMENT_NONE) + S.environment = sound_environment_override + else + var/area/A = get_area(src) + if(A.sound_environment != SOUND_ENVIRONMENT_NONE) + S.environment = A.sound_environment + + if(use_reverb) + if(S.environment == SOUND_ENVIRONMENT_NONE) //We have reverb, reset our echo setting + S.environment = SOUND_ENVIRONMENT_CONCERT_HALL + S.echo = list(0, null, -10000, null, null, null, null, null, null, null, null, null, null, 1, 1, 1, null, null) + else + S.echo[3] = 0 //Room setting, 0 means normal reverb + S.echo[4] = 0 //RoomHF setting, 0 means normal reverb. + */ + /// SEND_SOUND(src, S) -/proc/sound_to_playing_players(soundin, volume = 100, vary = FALSE, frequency = 0, falloff = FALSE, channel = 0, pressure_affected = FALSE, sound/S) +/proc/sound_to_playing_players(soundin, volume = 100, vary = FALSE, frequency = 0, channel = 0, pressure_affected = FALSE, sound/S) if(!S) S = sound(get_sfx(soundin)) for(var/m in GLOB.player_list) if(ismob(m) && !isnewplayer(m)) var/mob/M = m - M.playsound_local(M, null, volume, vary, frequency, falloff, channel, pressure_affected, S) + M.playsound_local(M, null, volume, vary, frequency, null, channel, pressure_affected, S) /mob/proc/stop_sound_channel(chan) SEND_SOUND(src, sound(null, repeat = 0, wait = 0, channel = chan)) @@ -130,14 +226,14 @@ /proc/get_sfx(soundin) if(istext(soundin)) switch(soundin) - if ("explosion_creaking") // from skyrat-ss13/skyrat13/pull/3295 - soundin = pick('sound/effects/explosioncreak1.ogg', 'sound/effects/explosioncreak2.ogg') - if ("hull_creaking") // from skyrat-ss13/skyrat13/pull/3295 - soundin = pick('sound/effects/creak1.ogg', 'sound/effects/creak2.ogg', 'sound/effects/creak3.ogg') if ("shatter") soundin = pick('sound/effects/glassbr1.ogg','sound/effects/glassbr2.ogg','sound/effects/glassbr3.ogg') if ("explosion") soundin = pick('sound/effects/explosion1.ogg','sound/effects/explosion2.ogg') + if ("explosion_creaking") + soundin = pick('sound/effects/explosioncreak1.ogg', 'sound/effects/explosioncreak2.ogg') + if ("hull_creaking") + soundin = pick('sound/effects/creak1.ogg', 'sound/effects/creak2.ogg', 'sound/effects/creak3.ogg') if ("sparks") soundin = pick('sound/effects/sparks1.ogg','sound/effects/sparks2.ogg','sound/effects/sparks3.ogg','sound/effects/sparks4.ogg') if ("rustle") diff --git a/code/game/turfs/open.dm b/code/game/turfs/open.dm index 7e00b1cf63..876c170923 100644 --- a/code/game/turfs/open.dm +++ b/code/game/turfs/open.dm @@ -1,12 +1,5 @@ /turf/open plane = FLOOR_PLANE - /// Does dirt buildup happen on us? - var/dirt_buildup_allowed = FALSE - /// Dirt level. - var/dirtyness = 0 - /// Dirt level to spawn dirt. Null to use config. - var/dirt_spawn_threshold - /// Slowdown applied to mobs on us. var/slowdown = 0 //negative for faster, positive for slower var/postdig_icon_change = FALSE @@ -18,6 +11,15 @@ var/clawfootstep = null var/heavyfootstep = null + /// Dirtyness system, cit specific. + + /// Does dirt buildup happen on us? + var/dirt_buildup_allowed = FALSE + /// Dirt level. + var/dirtyness = 0 + /// Dirt level to spawn dirt. Null to use config. + var/dirt_spawn_threshold + /turf/open/ComponentInitialize() . = ..() if(wet) diff --git a/code/game/turfs/openspace/openspace.dm b/code/game/turfs/openspace/openspace.dm index 0607f19dd3..69bdcf06cf 100644 --- a/code/game/turfs/openspace/openspace.dm +++ b/code/game/turfs/openspace/openspace.dm @@ -10,6 +10,8 @@ GLOBAL_DATUM_INIT(openspace_backdrop_one_for_all, /atom/movable/openspace_backdr plane = OPENSPACE_BACKDROP_PLANE mouse_opacity = MOUSE_OPACITY_TRANSPARENT layer = SPLASHSCREEN_LAYER + //I don't know why the others are aligned but I shall do the same. + vis_flags = VIS_INHERIT_ID /turf/open/transparent/openspace name = "open space" @@ -17,6 +19,7 @@ GLOBAL_DATUM_INIT(openspace_backdrop_one_for_all, /atom/movable/openspace_backdr icon_state = "transparent" baseturfs = /turf/open/transparent/openspace CanAtmosPassVertical = ATMOS_PASS_YES + intact = FALSE //this means wires go on top //mouse_opacity = MOUSE_OPACITY_TRANSPARENT var/can_cover_up = TRUE var/can_build_on = TRUE @@ -32,10 +35,14 @@ GLOBAL_DATUM_INIT(openspace_backdrop_one_for_all, /atom/movable/openspace_backdr /turf/open/transparent/openspace/show_bottom_level() return FALSE -/turf/open/transparent/openspace/Initialize() // handle plane and layer here so that they don't cover other obs/turfs in Dream Maker +/turf/open/openspace/Initialize() // handle plane and layer here so that they don't cover other obs/turfs in Dream Maker . = ..() - vis_contents += GLOB.openspace_backdrop_one_for_all //Special grey square for projecting backdrop darkness filter on it. + return INITIALIZE_HINT_LATELOAD + +/turf/open/openspace/LateInitialize() + . = ..() + // AddElement(/datum/element/turf_z_transparency, FALSE) /turf/open/transparent/openspace/can_have_cabling() if(locate(/obj/structure/lattice/catwalk, src)) @@ -95,6 +102,7 @@ GLOBAL_DATUM_INIT(openspace_backdrop_one_for_all, /atom/movable/openspace_backdr return if(L) if(R.use(1)) + qdel(L) to_chat(user, "You construct a catwalk.") playsound(src, 'sound/weapons/genhit.ogg', 50, TRUE) new/obj/structure/lattice/catwalk(src) @@ -148,9 +156,22 @@ GLOBAL_DATUM_INIT(openspace_backdrop_one_for_all, /atom/movable/openspace_backdr /turf/open/transparent/openspace/icemoon name = "ice chasm" baseturfs = /turf/open/transparent/openspace/icemoon - can_cover_up = TRUE - can_build_on = TRUE initial_gas_mix = ICEMOON_DEFAULT_ATMOS + planetary_atmos = TRUE + var/replacement_turf = /turf/open/floor/plating/asteroid/snow/icemoon + +/turf/open/transparent/openspace/icemoon/Initialize() + . = ..() + var/turf/T = below() + // if(T.flags_1 & NO_RUINS_1) + // ChangeTurf(replacement_turf, null, CHANGETURF_IGNORE_AIR) + // return + // if(!ismineralturf(T)) + // return + var/turf/closed/mineral/M = T + M.mineralAmt = 0 + M.gets_drilled() + baseturfs = /turf/open/transparent/openspace/icemoon //This is to ensure that IF random turf generation produces a openturf, there won't be other turfs assigned other than openspace. /turf/open/transparent/openspace/icemoon/can_zFall(atom/movable/A, levels = 1, turf/target) return TRUE diff --git a/code/game/turfs/openspace/transparent.dm b/code/game/turfs/openspace/transparent.dm index 8efc60a15b..fa5bc17638 100644 --- a/code/game/turfs/openspace/transparent.dm +++ b/code/game/turfs/openspace/transparent.dm @@ -66,7 +66,12 @@ /turf/open/transparent/glass/Initialize() icon_state = "" //Prevent the normal icon from appearing behind the smooth overlays - return ..() + ..() + return INITIALIZE_HINT_LATELOAD + +/turf/open/floor/glass/LateInitialize() + . = ..() + // AddElement(/datum/element/turf_z_transparency, TRUE) /turf/open/transparent/glass/wrench_act(mob/living/user, obj/item/I) to_chat(user, "You begin removing glass...") diff --git a/code/game/turfs/space/space.dm b/code/game/turfs/space/space.dm index 9c9639e57c..0905fb2e9c 100644 --- a/code/game/turfs/space/space.dm +++ b/code/game/turfs/space/space.dm @@ -20,12 +20,19 @@ dynamic_lighting = DYNAMIC_LIGHTING_DISABLED bullet_bounce_sound = null + vis_flags = VIS_INHERIT_ID //when this be added to vis_contents of something it be associated with something on clicking, important for visualisation of turf in openspace and interraction with openspace that show you turf. /turf/open/space/basic/New() //Do not convert to Initialize //This is used to optimize the map loader return +/** + * Space Initialize + * + * Doesn't call parent, see [/atom/proc/Initialize] + */ /turf/open/space/Initialize() + SHOULD_CALL_PARENT(FALSE) icon_state = SPACE_ICON_STATE air = space_gas update_air_ref() @@ -36,6 +43,15 @@ stack_trace("Warning: [src]([type]) initialized multiple times!") flags_1 |= INITIALIZED_1 + // if (length(smoothing_groups)) + // sortTim(smoothing_groups) //In case it's not properly ordered, let's avoid duplicate entries with the same values. + // SET_BITFLAG_LIST(smoothing_groups) + // if (length(canSmoothWith)) + // sortTim(canSmoothWith) + // if(canSmoothWith[length(canSmoothWith)] > MAX_S_TURF) //If the last element is higher than the maximum turf-only value, then it must scan turf contents for smoothing targets. + // smoothing_flags |= SMOOTH_OBJ + // SET_BITFLAG_LIST(canSmoothWith) + var/area/A = loc if(!IS_DYNAMIC_LIGHTING(src) && IS_DYNAMIC_LIGHTING(A)) add_overlay(/obj/effect/fullbright) @@ -49,6 +65,13 @@ if (opacity) has_opaque_atom = TRUE + var/turf/T = SSmapping.get_turf_above(src) + if(T) + T.multiz_turf_new(src, DOWN) + T = SSmapping.get_turf_below(src) + if(T) + T.multiz_turf_new(src, UP) + ComponentInitialize() return INITIALIZE_HINT_NORMAL @@ -74,6 +97,10 @@ /turf/open/space/Assimilate_Air() return +//IT SHOULD RETURN NULL YOU MONKEY, WHY IN TARNATION WHAT THE FUCKING FUCK +/turf/open/space/remove_air(amount) + return null + /turf/open/space/proc/update_starlight() if(CONFIG_GET(flag/starlight)) for(var/t in RANGE_TURFS(1,src)) //RANGE_TURFS is in code\__HELPERS\game.dm @@ -90,9 +117,8 @@ /turf/open/space/proc/CanBuildHere() return TRUE -/turf/open/space/handle_slip(mob/living/carbon/C, knockdown_amount, obj/O, lube) - if(lube & FLYING_DOESNT_HELP) - return ..() +/turf/open/space/handle_slip() + return // no lube bullshit, this is space /turf/open/space/attackby(obj/item/C, mob/user, params) ..() @@ -107,15 +133,16 @@ return if(L) if(R.use(1)) + qdel(L) to_chat(user, "You construct a catwalk.") - playsound(src, 'sound/weapons/genhit.ogg', 50, 1) + playsound(src, 'sound/weapons/genhit.ogg', 50, TRUE) new/obj/structure/lattice/catwalk(src) else to_chat(user, "You need two rods to build a catwalk!") return if(R.use(1)) to_chat(user, "You construct a lattice.") - playsound(src, 'sound/weapons/genhit.ogg', 50, 1) + playsound(src, 'sound/weapons/genhit.ogg', 50, TRUE) ReplaceWithLattice() else to_chat(user, "You need one rod to build a lattice.") @@ -126,7 +153,7 @@ var/obj/item/stack/tile/plasteel/S = C if(S.use(1)) qdel(L) - playsound(src, 'sound/weapons/genhit.ogg', 50, 1) + playsound(src, 'sound/weapons/genhit.ogg', 50, TRUE) to_chat(user, "You build a floor.") PlaceOnTop(/turf/open/floor/plating, flags = CHANGETURF_INHERIT_AIR) else diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 55d945535d..c2fee908fb 100755 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -1,8 +1,11 @@ +GLOBAL_LIST_EMPTY(station_turfs) + +/// Any floor or wall. What makes up the station and the rest of the map. /turf icon = 'icons/turf/floors.dmi' - level = 1 - vis_flags = VIS_INHERIT_PLANE|VIS_INHERIT_ID //when this be added to vis_contents of something it inherit something.plane and be associatet with something on clicking, - //important for visualisation of turf in openspace and interraction with openspace that show you turf. + flags_1 = CAN_BE_DIRTY_1 + vis_flags = VIS_INHERIT_ID|VIS_INHERIT_PLANE // Important for interaction with and visualization of openspace. + luminosity = 1 var/intact = 1 @@ -19,8 +22,6 @@ var/blocks_air = FALSE - flags_1 = CAN_BE_DIRTY_1 - var/list/image/blueprint_data //for the station blueprints, images of objects eg: pipes var/explosion_level = 0 //for preventing explosion dodging @@ -41,7 +42,13 @@ return FALSE . = ..() +/** + * Turf Initialize + * + * Doesn't call parent, see [/atom/proc/Initialize] + */ /turf/Initialize(mapload) + SHOULD_CALL_PARENT(FALSE) if(flags_1 & INITIALIZED_1) stack_trace("Warning: [src]([type]) initialized multiple times!") flags_1 |= INITIALIZED_1 @@ -49,7 +56,7 @@ // by default, vis_contents is inherited from the turf that was here before vis_contents.Cut() - if(color) + if(color) // is this being used? This is here because parent isn't being called add_atom_colour(color, FIXED_COLOUR_PRIORITY) assemble_baseturfs() @@ -57,6 +64,7 @@ levelupdate() if(smooth) queue_smooth(src) + visibilityChanged() for(var/atom/movable/AM in src) @@ -76,11 +84,10 @@ var/turf/T = SSmapping.get_turf_above(src) if(T) T.multiz_turf_new(src, DOWN) - SEND_SIGNAL(T, COMSIG_TURF_MULTIZ_NEW, src, DOWN) T = SSmapping.get_turf_below(src) if(T) T.multiz_turf_new(src, UP) - SEND_SIGNAL(T, COMSIG_TURF_MULTIZ_NEW, src, UP) + if (opacity) has_opaque_atom = TRUE @@ -112,8 +119,6 @@ var/turf/B = new world.turf(src) for(var/A in B.contents) qdel(A) - for(var/I in B.vars) - B.vars[I] = null return SSair.remove_from_active(src) visibilityChanged() @@ -122,12 +127,14 @@ requires_activation = FALSE ..() -/turf/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) +/turf/on_attack_hand(mob/user) user.Move_Pulled(src) /turf/proc/multiz_turf_del(turf/T, dir) + // SEND_SIGNAL(src, COMSIG_TURF_MULTIZ_DEL, T, dir) /turf/proc/multiz_turf_new(turf/T, dir) + SEND_SIGNAL(src, COMSIG_TURF_MULTIZ_NEW, T, dir) //zPassIn doesn't necessarily pass an atom! //direction is direction of travel of air @@ -158,13 +165,14 @@ prev_turf.visible_message("[mov_name] falls through [prev_turf]!") if(flags & FALL_INTERCEPTED) return - if(zFall(A, ++levels)) + if(zFall(A, levels + 1)) return FALSE A.visible_message("[A] crashes into [src]!") A.onZImpact(src, levels) return TRUE /turf/proc/can_zFall(atom/movable/A, levels = 1, turf/target) + SHOULD_BE_PURE(TRUE) return zPassOut(A, DOWN, target) && target.zPassIn(A, DOWN, src) /turf/proc/zFall(atom/movable/A, levels = 1, force = FALSE) @@ -217,49 +225,54 @@ stack_trace("Non movable passed to turf CanPass : [mover]") return FALSE +//There's a lot of QDELETED() calls here if someone can figure out how to optimize this but not runtime when something gets deleted by a Bump/CanPass/Cross call, lemme know or go ahead and fix this mess - kevinz000 /turf/Enter(atom/movable/mover, atom/oldloc) // Do not call ..() // Byond's default turf/Enter() doesn't have the behaviour we want with Bump() // By default byond will call Bump() on the first dense object in contents // Here's hoping it doesn't stay like this for years before we finish conversion to step_ var/atom/firstbump - if(!CanPass(mover, src)) - firstbump = src - else + var/canPassSelf = CanPass(mover, src) + if(canPassSelf || (mover.movement_type & UNSTOPPABLE)) for(var/i in contents) + if(QDELETED(mover)) + return FALSE //We were deleted, do not attempt to proceed with movement. if(i == mover || i == mover.loc) // Multi tile objects and moving out of other objects continue - if(QDELETED(mover)) - break var/atom/movable/thing = i if(!thing.Cross(mover)) - if(CHECK_BITFIELD(mover.movement_type, UNSTOPPABLE)) + if(QDELETED(mover)) //Mover deleted from Cross/CanPass, do not proceed. + return FALSE + if((mover.movement_type & UNSTOPPABLE)) mover.Bump(thing) continue else if(!firstbump || ((thing.layer > firstbump.layer || thing.flags_1 & ON_BORDER_1) && !(firstbump.flags_1 & ON_BORDER_1))) firstbump = thing + if(QDELETED(mover)) //Mover deleted from Cross/CanPass/Bump, do not proceed. + return FALSE + if(!canPassSelf) //Even if mover is unstoppable they need to bump us. + firstbump = src if(firstbump) - if(!QDELETED(mover)) - mover.Bump(firstbump) - return CHECK_BITFIELD(mover.movement_type, UNSTOPPABLE) + mover.Bump(firstbump) + return (mover.movement_type & UNSTOPPABLE) return TRUE /turf/Exit(atom/movable/mover, atom/newloc) . = ..() - if(!.) + if(!. || QDELETED(mover)) return FALSE for(var/i in contents) - if(QDELETED(mover)) - break if(i == mover) continue var/atom/movable/thing = i if(!thing.Uncross(mover, newloc)) if(thing.flags_1 & ON_BORDER_1) mover.Bump(thing) - if(!CHECK_BITFIELD(mover.movement_type, UNSTOPPABLE)) + if(!(mover.movement_type & UNSTOPPABLE)) return FALSE + if(QDELETED(mover)) + return FALSE //We were deleted. /turf/Entered(atom/movable/AM) ..() @@ -271,6 +284,7 @@ has_opaque_atom = TRUE // Make sure to do this before reconsider_lights(), incase we're on instant updates. Guaranteed to be on in this case. reconsider_lights() + /turf/open/Entered(atom/movable/AM) ..() //melting @@ -278,7 +292,6 @@ var/obj/O = AM if(O.obj_flags & FROZEN) O.make_unfrozen() - if(!AM.zfalling) zFall(AM) @@ -336,14 +349,13 @@ /turf/proc/levelupdate() for(var/obj/O in src) - if(O.level == 1 && (O.flags_1 & INITIALIZED_1)) - O.hide(src.intact) + if(O.flags_1 & INITIALIZED_1) + // SEND_SIGNAL(O, COMSIG_OBJ_HIDE, intact) + O.hide(intact) // override for space turfs, since they should never hide anything /turf/open/space/levelupdate() - for(var/obj/O in src) - if(O.level == 1 && (O.flags_1 & INITIALIZED_1)) - O.hide(0) + return // Removes all signs of lattice on the pos of the turf -Donkieyo /turf/proc/RemoveLattice() @@ -368,13 +380,13 @@ if(.) return if(length(src_object.contents())) - to_chat(user, "You start dumping out the contents...") - if(!do_after(user,20,target=src_object.parent)) + to_chat(usr, "You start dumping out the contents...") + if(!do_after(usr,20,target=src_object.parent)) return FALSE var/list/things = src_object.contents() var/datum/progressbar/progress = new(user, things.len, src) - while (do_after(user, 10, TRUE, src, FALSE, CALLBACK(src_object, /datum/component/storage.proc/mass_remove_from_storage, src, things, progress))) + while (do_after(usr, 1 SECONDS, TRUE, src, FALSE, CALLBACK(src_object, /datum/component/storage.proc/mass_remove_from_storage, src, things, progress))) stoplag(1) qdel(progress) @@ -494,10 +506,8 @@ I.loc = src I.setDir(AM.dir) I.alpha = 128 - LAZYADD(blueprint_data, I) - /turf/proc/add_blueprints_preround(atom/movable/AM) if(!SSticker.HasRoundStarted()) add_blueprints(AM) @@ -531,7 +541,7 @@ if(!forced) return if(has_gravity(src)) - playsound(src, "bodyfall", 50, 1) + playsound(src, "bodyfall", 50, TRUE) faller.drop_all_held_items() /turf/proc/photograph(limit=20) diff --git a/code/game/world.dm b/code/game/world.dm index 42c90d8be1..4369ca6668 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -1,21 +1,46 @@ #define RESTART_COUNTER_PATH "data/round_counter.txt" GLOBAL_VAR(restart_counter) + GLOBAL_VAR_INIT(tgs_initialized, FALSE) GLOBAL_VAR(topic_status_lastcache) GLOBAL_LIST(topic_status_cache) -//This happens after the Master subsystem new(s) (it's a global datum) -//So subsystems globals exist, but are not initialised +/** + * World creation + * + * Here is where a round itself is actually begun and setup. + * * db connection setup + * * config loaded from files + * * loads admins + * * Sets up the dynamic menu system + * * and most importantly, calls initialize on the master subsystem, starting the game loop that causes the rest of the game to begin processing and setting up + * + * + * Nothing happens until something moves. ~Albert Einstein + * + * For clarity, this proc gets triggered later in the initialization pipeline, it is not the first thing to happen, as it might seem. + * + * Initialization Pipeline: + * Global vars are new()'ed, (including config, glob, and the master controller will also new and preinit all subsystems when it gets new()ed) + * Compiled in maps are loaded (mainly centcom). all areas/turfs/objs/mobs(ATOMs) in these maps will be new()ed + * world/New() (You are here) + * Once world/New() returns, client's can connect. + * 1 second sleep + * Master Controller initialization. + * Subsystem initialization. + * Non-compiled-in maps are maploaded, all atoms are new()ed + * All atoms in both compiled and uncompiled maps are initialized() + */ /world/New() if (fexists(EXTOOLS)) call(EXTOOLS, "maptick_initialize")() - #ifdef EXTOOLS_LOGGING +#ifdef EXTOOLS_LOGGING call(EXTOOLS, "init_logging")() else CRASH("[EXTOOLS] does not exist!") - #endif +#endif enable_debugger() #ifdef REFERENCE_TRACKING enable_reference_tracking() @@ -23,12 +48,11 @@ GLOBAL_LIST(topic_status_cache) world.Profile(PROFILE_START) - log_world("World loaded at [TIME_STAMP("hh:mm:ss", FALSE)]!") - GLOB.config_error_log = GLOB.world_manifest_log = GLOB.world_pda_log = GLOB.world_job_debug_log = GLOB.sql_error_log = GLOB.world_href_log = GLOB.world_runtime_log = GLOB.world_attack_log = GLOB.world_game_log = "data/logs/config_error.[GUID()].log" //temporary file used to record errors with loading config, moved to log directory once logging is set bl - make_datum_references_lists() //initialises global lists for referencing frequently used datums (so that we only ever do it once) + log_world("World loaded at [TIME_STAMP("hh:mm:ss", FALSE)]!") + make_datum_references_lists() //initialises global lists for referencing frequently used datums (so that we only ever do it once) GLOB.revdata = new @@ -36,6 +60,9 @@ GLOBAL_LIST(topic_status_cache) config.Load(params[OVERRIDE_CONFIG_DIRECTORY_PARAMETER]) + load_admins() + load_mentors() + //SetupLogs depends on the RoundID, so lets check //DB schema and set RoundID if we can SSdbcore.CheckSchemaVersion() @@ -49,14 +76,9 @@ GLOBAL_LIST(topic_status_cache) world.log = file("[GLOB.log_directory]/dd.log") //not all runtimes trigger world/Error, so this is the only way to ensure we can see all of them. #endif - load_admins() - load_mentors() LoadVerbs(/datum/verbs/menu) if(CONFIG_GET(flag/usewhitelist)) load_whitelist() - LoadBans() - initialize_global_loadout_items() - reload_custom_roundstart_items_list()//Cit change - loads donator items. Remind me to remove when I port over bay's loadout system GLOB.timezoneOffset = text2num(time2text(0,"hh")) * 36000 @@ -67,10 +89,15 @@ GLOBAL_LIST(topic_status_cache) if(NO_INIT_PARAMETER in params) return + LoadBans() + initialize_global_loadout_items() + reload_custom_roundstart_items_list()//Cit change - loads donator items. Remind me to remove when I port over bay's loadout system + Master.Initialize(10, FALSE, TRUE) - if(TEST_RUN_PARAMETER in params) - HandleTestRun() + #ifdef UNIT_TESTS + HandleTestRun() + #endif /world/proc/InitTgs() TgsNew(new /datum/tgs_event_handler/impl, TGS_SECURITY_TRUSTED) @@ -88,7 +115,7 @@ GLOBAL_LIST(topic_status_cache) #else cb = VARSET_CALLBACK(SSticker, force_ending, TRUE) #endif - SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, /proc/addtimer, cb, 10 SECONDS)) + SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, /proc/_addtimer, cb, 10 SECONDS)) /world/proc/SetupLogs() var/override_dir = params[OVERRIDE_LOG_DIRECTORY_PARAMETER] @@ -136,7 +163,7 @@ GLOBAL_LIST(topic_status_cache) #ifdef UNIT_TESTS - GLOB.test_log = file("[GLOB.log_directory]/tests.log") + GLOB.test_log = "[GLOB.log_directory]/tests.log" start_log(GLOB.test_log) #endif start_log(GLOB.world_game_log) @@ -172,7 +199,7 @@ GLOBAL_LIST(topic_status_cache) if(!SSfail2topic) return "Server not initialized." - else if(SSfail2topic.IsRateLimited(addr)) + if(SSfail2topic.IsRateLimited(addr)) return "Rate limited." if(length(T) > CONFIG_GET(number/topic_max_size)) @@ -243,9 +270,10 @@ GLOBAL_LIST(topic_status_cache) TgsReboot() - if(TEST_RUN_PARAMETER in params) - FinishTestRun() - return + #ifdef UNIT_TESTS + FinishTestRun() + return + #endif if(TgsAvailable()) var/do_hard_reboot @@ -280,11 +308,11 @@ GLOBAL_LIST(topic_status_cache) var/list/features = list() - /*if(GLOB.master_mode) CIT CHANGE - hides the gamemode from the hub entry, removes some useless info from the hub entry - features += GLOB.master_mode + // if(GLOB.master_mode) + // features += GLOB.master_mode - if (!GLOB.enter_allowed) - features += "closed"*/ + // if (!GLOB.enter_allowed) + // features += "closed" var/s = "" var/hostedby @@ -292,25 +320,22 @@ GLOBAL_LIST(topic_status_cache) var/server_name = CONFIG_GET(string/servername) if (server_name) s += "[server_name] — " - /*features += "[CONFIG_GET(flag/norespawn) ? "no " : ""]respawn" CIT CHANGE - removes some useless info from the hub entry - if(CONFIG_GET(flag/allow_vote_mode)) - features += "vote" - if(CONFIG_GET(flag/allow_ai)) - features += "AI allowed"*/ + // features += "[CONFIG_GET(flag/norespawn) ? "no " : ""]respawn" + // if(CONFIG_GET(flag/allow_vote_mode)) + // features += "vote" + // if(CONFIG_GET(flag/allow_ai)) + // features += "AI allowed" hostedby = CONFIG_GET(string/hostedby) s += "[station_name()]"; s += " (" - s += "" //Change this to wherever you want the hub to link to. CIT CHANGE - links to cit's website on the hub - s += "Citadel" //Replace this with something else. Or ever better, delete it and uncomment the game version. CIT CHANGE - modifies the hub entry link + s += "" //Change this to wherever you want the hub to link to. + s += "Citadel" //Replace this with something else. Or ever better, delete it and uncomment the game version. s += "" s += ")\]" //CIT CHANGE - encloses the server title in brackets to make the hub entry fancier s += "
[CONFIG_GET(string/servertagline)]
" //CIT CHANGE - adds a tagline! - var/n = 0 - for (var/mob/M in GLOB.player_list) - if (M.client) - n++ + var/players = GLOB.clients.len if(SSmapping.config) // this just stops the runtime, honk. features += "[SSmapping.config.map_name]" //CIT CHANGE - makes the hub entry display the current map @@ -318,16 +343,23 @@ GLOBAL_LIST(topic_status_cache) if(NUM2SECLEVEL(GLOB.security_level))//CIT CHANGE - makes the hub entry show the security level features += "[NUM2SECLEVEL(GLOB.security_level)] alert" - if (n > 1) - features += "~[n] players" - else if (n > 0) - features += "~[n] player" + var/popcaptext = "" + var/popcap = max(CONFIG_GET(number/extreme_popcap), CONFIG_GET(number/hard_popcap), CONFIG_GET(number/soft_popcap)) + if (popcap) + popcaptext = "/[popcap]" + + if (players > 1) + features += "[players][popcaptext] players" + else if (players > 0) + features += "[players][popcaptext] player" + + game_state = (CONFIG_GET(number/extreme_popcap) && players >= CONFIG_GET(number/extreme_popcap)) //tells the hub if we are full if (!host && hostedby) features += "hosted by [hostedby]" if (features) - s += "\[[jointext(features, ", ")]" //CIT CHANGE - replaces the colon here with a left bracket + s += "\[[jointext(features, ", ")]" status = s @@ -346,4 +378,28 @@ GLOBAL_LIST(topic_status_cache) SSidlenpcpool.MaxZChanged() world.refresh_atmos_grid() +/// Extools atmos /world/proc/refresh_atmos_grid() + +/world/proc/change_fps(new_value = 20) + if(new_value <= 0) + CRASH("change_fps() called with [new_value] new_value.") + if(fps == new_value) + return //No change required. + + fps = new_value + on_tickrate_change() + + +/world/proc/change_tick_lag(new_value = 0.5) + if(new_value <= 0) + CRASH("change_tick_lag() called with [new_value] new_value.") + if(tick_lag == new_value) + return //No change required. + + tick_lag = new_value + on_tickrate_change() + + +/world/proc/on_tickrate_change() + SStimer?.reset_buckets() diff --git a/code/modules/actionspeed/_actionspeed_modifier.dm b/code/modules/actionspeed/_actionspeed_modifier.dm index fe244e6653..a2870be6f4 100644 --- a/code/modules/actionspeed/_actionspeed_modifier.dm +++ b/code/modules/actionspeed/_actionspeed_modifier.dm @@ -69,7 +69,7 @@ GLOBAL_LIST_EMPTY(actionspeed_modification_cache) return TRUE remove_actionspeed_modifier(existing, FALSE) if(length(actionspeed_modification)) - BINARY_INSERT(type_or_datum.id, actionspeed_modification, datum/actionspeed_modifier, type_or_datum, priority, COMPARE_VALUE) + BINARY_INSERT(type_or_datum.id, actionspeed_modification, /datum/actionspeed_modifier, type_or_datum, priority, COMPARE_VALUE) LAZYSET(actionspeed_modification, type_or_datum.id, type_or_datum) if(update) update_actionspeed() diff --git a/code/modules/admin/IsBanned.dm b/code/modules/admin/IsBanned.dm index 4ddb92ab19..63facade2e 100644 --- a/code/modules/admin/IsBanned.dm +++ b/code/modules/admin/IsBanned.dm @@ -226,6 +226,14 @@ key_cache[key] = 0 return . +/proc/restore_stickybans() + for (var/banned_ckey in GLOB.stickybanadmintexts) + world.SetConfig("ban", banned_ckey, GLOB.stickybanadmintexts[banned_ckey]) + GLOB.stickybanadminexemptions = list() + GLOB.stickybanadmintexts = list() + if (GLOB.stickbanadminexemptiontimerid) + deltimer(GLOB.stickbanadminexemptiontimerid) + GLOB.stickbanadminexemptiontimerid = null #undef STICKYBAN_MAX_MATCHES #undef STICKYBAN_MAX_EXISTING_USER_MATCHES diff --git a/code/modules/admin/sound_emitter.dm b/code/modules/admin/sound_emitter.dm index 56c778dc85..ad9c995aa1 100644 --- a/code/modules/admin/sound_emitter.dm +++ b/code/modules/admin/sound_emitter.dm @@ -52,11 +52,9 @@ edit_emitter(user) /obj/effect/sound_emitter/AltClick(mob/user) - . = ..() if(check_rights_for(user.client, R_SOUNDS)) activate(user) - to_chat(user, "Sound emitter activated.") - return TRUE + to_chat(user, "Sound emitter activated.", confidential = TRUE) /obj/effect/sound_emitter/proc/edit_emitter(mob/user) var/dat = "" @@ -84,20 +82,20 @@ if(!new_label) return maptext = new_label - to_chat(user, "Label set to [maptext].") + to_chat(user, "Label set to [maptext].", confidential = TRUE) if(href_list["edit_sound_file"]) var/new_file = input(user, "Choose a sound file.", "Sound Emitter") as null|sound if(!new_file) return sound_file = new_file - to_chat(user, "New sound file set to [sound_file].") + to_chat(user, "New sound file set to [sound_file].", confidential = TRUE) if(href_list["edit_volume"]) var/new_volume = input(user, "Choose a volume.", "Sound Emitter", sound_volume) as null|num if(isnull(new_volume)) return new_volume = clamp(new_volume, 0, 100) sound_volume = new_volume - to_chat(user, "Volume set to [sound_volume]%.") + to_chat(user, "Volume set to [sound_volume]%.", confidential = TRUE) if(href_list["edit_mode"]) var/new_mode var/mode_list = list("Local (normal sound)" = SOUND_EMITTER_LOCAL, "Direct (not affected by environment/location)" = SOUND_EMITTER_DIRECT) @@ -105,7 +103,7 @@ if(!new_mode) return motus_operandi = mode_list[new_mode] - to_chat(user, "Mode set to [motus_operandi].") + to_chat(user, "Mode set to [motus_operandi].", confidential = TRUE) if(href_list["edit_range"]) var/new_range var/range_list = list("Radius (all mobs within a radius)" = SOUND_EMITTER_RADIUS, "Z-Level (all mobs on the same z)" = SOUND_EMITTER_ZLEVEL, "Global (all players)" = SOUND_EMITTER_GLOBAL) @@ -113,14 +111,14 @@ if(!new_range) return emitter_range = range_list[new_range] - to_chat(user, "Range set to [emitter_range].") + to_chat(user, "Range set to [emitter_range].", confidential = TRUE) if(href_list["edit_radius"]) var/new_radius = input(user, "Choose a radius.", "Sound Emitter", sound_volume) as null|num if(isnull(new_radius)) return new_radius = clamp(new_radius, 0, 127) play_radius = new_radius - to_chat(user, "Audible radius set to [play_radius].") + to_chat(user, "Audible radius set to [play_radius].", confidential = TRUE) if(href_list["play"]) activate(user) edit_emitter(user) //Refresh the UI to see our changes diff --git a/code/modules/admin/stickyban.dm b/code/modules/admin/stickyban.dm index df6a9b89ad..ef0bfe8e70 100644 --- a/code/modules/admin/stickyban.dm +++ b/code/modules/admin/stickyban.dm @@ -7,7 +7,7 @@ if ("add") var/list/ban = list() var/ckey - ban["admin"] = usr.key + ban["admin"] = usr.ckey ban["type"] = list("sticky") ban["reason"] = "(InGameBan)([usr.key])" //this will be displayed in dd only @@ -21,7 +21,8 @@ ban["ckey"] = ckey if (get_stickyban_from_ckey(ckey)) - to_chat(usr, "Error: Can not add a stickyban: User already has a current sticky ban") + to_chat(usr, "Error: Can not add a stickyban: User already has a current sticky ban", confidential = TRUE) + return if (data["reason"]) ban["message"] = data["reason"] @@ -31,7 +32,26 @@ return ban["message"] = "[reason]" + if(SSdbcore.Connect()) // todo: second wave + // var/datum/db_query/query_create_stickyban = SSdbcore.NewQuery({" + // INSERT INTO [format_table_name("stickyban")] (ckey, reason, banning_admin) + // VALUES (:ckey, :message, :banning_admin) + // "}, list("ckey" = ckey, "message" = ban["message"], "banning_admin" = usr.ckey)) + var/datum/DBQuery/query_create_stickyban = SSdbcore.NewQuery({" + INSERT INTO [format_table_name("stickyban")] (ckey, reason, banning_admin) + VALUES ([ckey], [ban["message"]], [usr.ckey]) + "}) + if (query_create_stickyban.warn_execute()) + ban["fromdb"] = TRUE + qdel(query_create_stickyban) + world.SetConfig("ban",ckey,list2stickyban(ban)) + ban = stickyban2list(list2stickyban(ban)) + ban["matches_this_round"] = list() + ban["existing_user_matches_this_round"] = list() + ban["admin_matches_this_round"] = list() + ban["pending_matches_this_round"] = list() + SSstickyban.cache[ckey] = ban log_admin_private("[key_name(usr)] has stickybanned [ckey].\nReason: [ban["message"]]") message_admins("[key_name_admin(usr)] has stickybanned [ckey].\nReason: [ban["message"]]") @@ -43,14 +63,29 @@ var/ban = get_stickyban_from_ckey(ckey) if (!ban) - to_chat(usr, "Error: No sticky ban for [ckey] found!") + to_chat(usr, "Error: No sticky ban for [ckey] found!", confidential = TRUE) return if (alert("Are you sure you want to remove the sticky ban on [ckey]?","Are you sure","Yes","No") == "No") return if (!get_stickyban_from_ckey(ckey)) - to_chat(usr, "Error: The ban disappeared.") + to_chat(usr, "Error: The ban disappeared.", confidential = TRUE) return world.SetConfig("ban",ckey, null) + SSstickyban.cache -= ckey + + if (SSdbcore.Connect()) + // SSdbcore.QuerySelect(list( + // SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban")] WHERE ckey = :ckey", list("ckey" = ckey)), + // SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_ckey")] WHERE stickyban = :ckey", list("ckey" = ckey)), + // SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_cid")] WHERE stickyban = :ckey", list("ckey" = ckey)), + // SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_ip")] WHERE stickyban = :ckey", list("ckey" = ckey)) + // ), warn = TRUE, qdel = TRUE) + SSdbcore.QuerySelect(list( + SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban")] WHERE ckey = [ckey]"), + SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_ckey")] WHERE stickyban = [ckey]"), + SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_cid")] WHERE stickyban = [ckey]"), + SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_ip")] WHERE stickyban = [ckey]") + ), warn = TRUE, qdel = TRUE) log_admin_private("[key_name(usr)] removed [ckey]'s stickyban") message_admins("[key_name_admin(usr)] removed [ckey]'s stickyban") @@ -64,42 +99,45 @@ var/alt = ckey(data["alt"]) var/ban = get_stickyban_from_ckey(ckey) if (!ban) - to_chat(usr, "Error: No sticky ban for [ckey] found!") + to_chat(usr, "Error: No sticky ban for [ckey] found!", confidential = TRUE) return - var/found = 0 - //we have to do it this way because byond keeps the case in its sticky ban matches WHY!!! - for (var/key in ban["keys"]) - if (ckey(key) == alt) - found = 1 - break - - if (!found) - to_chat(usr, "Error: [alt] is not linked to [ckey]'s sticky ban!") + var/key = LAZYACCESS(ban["keys"], alt) + if (!key) + to_chat(usr, "Error: [alt] is not linked to [ckey]'s sticky ban!", confidential = TRUE) return - if (alert("Are you sure you want to disassociate [alt] from [ckey]'s sticky ban? \nNote: Nothing stops byond from re-linking them","Are you sure","Yes","No") == "No") + if (alert("Are you sure you want to disassociate [alt] from [ckey]'s sticky ban? \nNote: Nothing stops byond from re-linking them, Use \[E] to exempt them","Are you sure","Yes","No") == "No") return //we have to do this again incase something changes ban = get_stickyban_from_ckey(ckey) if (!ban) - to_chat(usr, "Error: The ban disappeared.") + to_chat(usr, "Error: The ban disappeared.", confidential = TRUE) return - found = 0 - for (var/key in ban["keys"]) - if (ckey(key) == alt) - ban["keys"] -= key - found = 1 - break + key = LAZYACCESS(ban["keys"], alt) - if (!found) - to_chat(usr, "Error: [alt] link to [ckey]'s sticky ban disappeared.") + if (!key) + to_chat(usr, "Error: [alt] link to [ckey]'s sticky ban disappeared.", confidential = TRUE) return + LAZYREMOVE(ban["keys"], alt) world.SetConfig("ban",ckey,list2stickyban(ban)) + SSstickyban.cache[ckey] = ban + + if (SSdbcore.Connect()) + // var/datum/db_query/query_remove_stickyban_alt = SSdbcore.NewQuery( + // "DELETE FROM [format_table_name("stickyban_matched_ckey")] WHERE stickyban = :ckey AND matched_ckey = :alt", + // list("ckey" = ckey, "alt" = alt) + // ) + var/datum/DBQuery/query_remove_stickyban_alt = SSdbcore.NewQuery( + "DELETE FROM [format_table_name("stickyban_matched_ckey")] WHERE stickyban = [ckey] AND matched_ckey = [alt]" + ) + query_remove_stickyban_alt.warn_execute() + qdel(query_remove_stickyban_alt) + log_admin_private("[key_name(usr)] has disassociated [alt] from [ckey]'s sticky ban") message_admins("[key_name_admin(usr)] has disassociated [alt] from [ckey]'s sticky ban") @@ -109,7 +147,7 @@ var/ckey = data["ckey"] var/ban = get_stickyban_from_ckey(ckey) if (!ban) - to_chat(usr, "Error: No sticky ban for [ckey] found!") + to_chat(usr, "Error: No sticky ban for [ckey] found!", confidential = TRUE) return var/oldreason = ban["message"] var/reason = input(usr,"Reason","Reason","[ban["message"]]") as text|null @@ -118,28 +156,203 @@ //we have to do this again incase something changed while we waited for input ban = get_stickyban_from_ckey(ckey) if (!ban) - to_chat(usr, "Error: The ban disappeared.") + to_chat(usr, "Error: The ban disappeared.", confidential = TRUE) return ban["message"] = "[reason]" world.SetConfig("ban",ckey,list2stickyban(ban)) + SSstickyban.cache[ckey] = ban + + if (SSdbcore.Connect()) + // var/datum/db_query/query_edit_stickyban = SSdbcore.NewQuery( + // "UPDATE [format_table_name("stickyban")] SET reason = :reason WHERE ckey = :ckey", + // list("reason" = reason, "ckey" = ckey) + // ) + var/datum/DBQuery/query_edit_stickyban = SSdbcore.NewQuery( + "UPDATE [format_table_name("stickyban")] SET reason = [reason] WHERE ckey = [ckey]" + ) + query_edit_stickyban.warn_execute() + qdel(query_edit_stickyban) + log_admin_private("[key_name(usr)] has edited [ckey]'s sticky ban reason from [oldreason] to [reason]") message_admins("[key_name_admin(usr)] has edited [ckey]'s sticky ban reason from [oldreason] to [reason]") + if ("exempt") + if (!data["ckey"]) + return + var/ckey = data["ckey"] + if (!data["alt"]) + return + var/alt = ckey(data["alt"]) + var/ban = get_stickyban_from_ckey(ckey) + if (!ban) + to_chat(usr, "Error: No sticky ban for [ckey] found!", confidential = TRUE) + return + + var/key = LAZYACCESS(ban["keys"], alt) + if (!key) + to_chat(usr, "Error: [alt] is not linked to [ckey]'s sticky ban!", confidential = TRUE) + return + + if (alert("Are you sure you want to exempt [alt] from [ckey]'s sticky ban?","Are you sure","Yes","No") == "No") + return + + //we have to do this again incase something changes + ban = get_stickyban_from_ckey(ckey) + if (!ban) + to_chat(usr, "Error: The ban disappeared.", confidential = TRUE) + return + + key = LAZYACCESS(ban["keys"], alt) + + if (!key) + to_chat(usr, "Error: [alt]'s link to [ckey]'s sticky ban disappeared.", confidential = TRUE) + return + LAZYREMOVE(ban["keys"], alt) + key["exempt"] = TRUE + LAZYSET(ban["whitelist"], alt, key) + + world.SetConfig("ban",ckey,list2stickyban(ban)) + + SSstickyban.cache[ckey] = ban + + if (SSdbcore.Connect()) + // var/datum/db_query/query_exempt_stickyban_alt = SSdbcore.NewQuery( + // "UPDATE [format_table_name("stickyban_matched_ckey")] SET exempt = 1 WHERE stickyban = :ckey AND matched_ckey = :alt", + // list("ckey" = ckey, "alt" = alt) + // ) + var/datum/DBQuery/query_exempt_stickyban_alt = SSdbcore.NewQuery( + "UPDATE [format_table_name("stickyban_matched_ckey")] SET exempt = 1 WHERE stickyban = [ckey] AND matched_ckey = [alt]" + ) + query_exempt_stickyban_alt.warn_execute() + qdel(query_exempt_stickyban_alt) + + log_admin_private("[key_name(usr)] has exempted [alt] from [ckey]'s sticky ban") + message_admins("[key_name_admin(usr)] has exempted [alt] from [ckey]'s sticky ban") + + if ("unexempt") + if (!data["ckey"]) + return + var/ckey = data["ckey"] + if (!data["alt"]) + return + var/alt = ckey(data["alt"]) + var/ban = get_stickyban_from_ckey(ckey) + if (!ban) + to_chat(usr, "Error: No sticky ban for [ckey] found!", confidential = TRUE) + return + + var/key = LAZYACCESS(ban["whitelist"], alt) + if (!key) + to_chat(usr, "Error: [alt] is not exempt from [ckey]'s sticky ban!", confidential = TRUE) + return + + if (alert("Are you sure you want to unexempt [alt] from [ckey]'s sticky ban?","Are you sure","Yes","No") == "No") + return + + //we have to do this again incase something changes + ban = get_stickyban_from_ckey(ckey) + if (!ban) + to_chat(usr, "Error: The ban disappeared.", confidential = TRUE) + return + + key = LAZYACCESS(ban["whitelist"], alt) + if (!key) + to_chat(usr, "Error: [alt]'s exemption from [ckey]'s sticky ban disappeared.", confidential = TRUE) + return + + LAZYREMOVE(ban["whitelist"], alt) + key["exempt"] = FALSE + LAZYSET(ban["keys"], alt, key) + + world.SetConfig("ban",ckey,list2stickyban(ban)) + + SSstickyban.cache[ckey] = ban + + if (SSdbcore.Connect()) + // var/datum/db_query/query_unexempt_stickyban_alt = SSdbcore.NewQuery( + // "UPDATE [format_table_name("stickyban_matched_ckey")] SET exempt = 0 WHERE stickyban = :ckey AND matched_ckey = :alt", + // list("ckey" = ckey, "alt" = alt) + // ) + var/datum/DBQuery/query_unexempt_stickyban_alt = SSdbcore.NewQuery( + "UPDATE [format_table_name("stickyban_matched_ckey")] SET exempt = 0 WHERE stickyban = [ckey] AND matched_ckey = [alt]" + ) + query_unexempt_stickyban_alt.warn_execute() + qdel(query_unexempt_stickyban_alt) + + log_admin_private("[key_name(usr)] has unexempted [alt] from [ckey]'s sticky ban") + message_admins("[key_name_admin(usr)] has unexempted [alt] from [ckey]'s sticky ban") + + if ("timeout") + if (!data["ckey"]) + return + if (!SSdbcore.Connect()) + to_chat(usr, "No database connection!", confidential = TRUE) + return + + var/ckey = data["ckey"] + + if (alert("Are you sure you want to put [ckey]'s stickyban on timeout until next round (or removed)?","Are you sure","Yes","No") == "No") + return + var/ban = get_stickyban_from_ckey(ckey) + if (!ban) + to_chat(usr, "Error: No sticky ban for [ckey] found!", confidential = TRUE) + return + + ban["timeout"] = TRUE + + world.SetConfig("ban", ckey, null) + + var/cachedban = SSstickyban.cache[ckey] + if (cachedban) + cachedban["timeout"] = TRUE + + log_admin_private("[key_name(usr)] has put [ckey]'s sticky ban on timeout.") + message_admins("[key_name_admin(usr)] has put [ckey]'s sticky ban on timeout.") + + if ("untimeout") + if (!data["ckey"]) + return + if (!SSdbcore.Connect()) + to_chat(usr, "No database connection!", confidential = TRUE) + return + var/ckey = data["ckey"] + + if (alert("Are you sure you want to lift the timeout on [ckey]'s stickyban?","Are you sure","Yes","No") == "No") + return + + var/ban = get_stickyban_from_ckey(ckey) + var/cachedban = SSstickyban.cache[ckey] + if (cachedban) + cachedban["timeout"] = FALSE + if (!ban) + if (!cachedban) + to_chat(usr, "Error: No sticky ban for [ckey] found!", confidential = TRUE) + return + ban = cachedban + + ban["timeout"] = FALSE + + world.SetConfig("ban",ckey,list2stickyban(ban)) + + log_admin_private("[key_name(usr)] has taken [ckey]'s sticky ban off of timeout.") + message_admins("[key_name_admin(usr)] has taken [ckey]'s sticky ban off of timeout.") + + if ("revert") if (!data["ckey"]) return var/ckey = data["ckey"] - if (alert("Are you sure you want to revert the sticky ban on [ckey] to its state at round start?","Are you sure","Yes","No") == "No") + if (alert("Are you sure you want to revert the sticky ban on [ckey] to its state at round start (or last edit)?","Are you sure","Yes","No") == "No") return var/ban = get_stickyban_from_ckey(ckey) if (!ban) - to_chat(usr, "Error: No sticky ban for [ckey] found!") + to_chat(usr, "Error: No sticky ban for [ckey] found!", confidential = TRUE) return var/cached_ban = SSstickyban.cache[ckey] if (!cached_ban) - to_chat(usr, "Error: No cached sticky ban for [ckey] found!") + to_chat(usr, "Error: No cached sticky ban for [ckey] found!", confidential = TRUE) world.SetConfig("ban",ckey,null) log_admin_private("[key_name(usr)] has reverted [ckey]'s sticky ban to its state at round start.") @@ -150,14 +363,22 @@ world.SetConfig("ban",ckey,list2stickyban(cached_ban)) -/datum/admins/proc/stickyban_gethtml(ckey, ban) - . = {" +/datum/admins/proc/stickyban_gethtml(ckey) + var/ban = get_stickyban_from_ckey(ckey) + if (!ban) + return + var/timeout + if (SSdbcore.Connect()) + timeout = "\[[(ban["timeout"] ? "untimeout" : "timeout" )]\]" + else + timeout = "\[revert\]" + . = list({" \[-\] - \[revert\] + [timeout] [ckey]
" [ban["message"]] \[Edit\]
- "} + "}) if (ban["admin"]) . += "[ban["admin"]]
" else @@ -166,19 +387,24 @@ for (var/key in ban["keys"]) if (ckey(key) == ckey) continue - . += "
  • \[-\][key]
  • " + . += "
  • \[-\][key]\[E\]
  • " + + for (var/key in ban["whitelist"]) + if (ckey(key) == ckey) + continue + . += "
  • \[-\][key]\[UE\]
  • " + . += "\n" /datum/admins/proc/stickyban_show() if(!check_rights(R_BAN)) return - var/list/bans = sortList(world.GetConfig("ban")) - var/banhtml = "" + var/list/bans = sticky_banned_ckeys() + var/list/banhtml = list() for(var/key in bans) var/ckey = ckey(key) - var/ban = stickyban2list(world.GetConfig("ban",key)) banhtml += "

    \n" - banhtml += stickyban_gethtml(ckey,ban) + banhtml += stickyban_gethtml(ckey) var/html = {" @@ -186,22 +412,49 @@

    All Sticky Bans:

    \[+\]
    - [banhtml] + [banhtml.Join("")] "} usr << browse(html,"window=stickybans;size=700x400") -/proc/get_stickyban_from_ckey(var/ckey) +/proc/sticky_banned_ckeys() + if (SSdbcore.Connect() || length(SSstickyban.dbcache)) + if (SSstickyban.dbcacheexpire < world.time) + SSstickyban.Populatedbcache() + if (SSstickyban.dbcacheexpire) + return SSstickyban.dbcache.Copy() + + return sortList(world.GetConfig("ban")) + + +/proc/get_stickyban_from_ckey(ckey) + . = list() if (!ckey) return null - ckey = ckey(ckey) - . = null - for (var/key in world.GetConfig("ban")) - if (ckey(key) == ckey) - . = stickyban2list(world.GetConfig("ban",key)) - break + if (SSdbcore.Connect() || length(SSstickyban.dbcache)) + if (SSstickyban.dbcacheexpire < world.time) + SSstickyban.Populatedbcache() + if (SSstickyban.dbcacheexpire) + . = SSstickyban.dbcache[ckey] + //reset the cache incase its a newer ban (but only if we didn't update the cache recently) + if (!. && SSstickyban.dbcacheexpire != world.time+STICKYBAN_DB_CACHE_TIME) + SSstickyban.dbcacheexpire = 1 + SSstickyban.Populatedbcache() + . = SSstickyban.dbcache[ckey] + if (.) + var/list/cachedban = SSstickyban.cache["[ckey]"] + if (cachedban) + .["timeout"] = cachedban["timeout"] -/proc/stickyban2list(var/ban) + .["fromdb"] = TRUE + return + + . = stickyban2list(world.GetConfig("ban", ckey)) || stickyban2list(world.GetConfig("ban", ckey(ckey))) || list() + + if (!length(.)) + return null + +/proc/stickyban2list(ban, strictdb = TRUE) if (!ban) return null . = params2list(ban) @@ -212,30 +465,40 @@ var/ckey = ckey(key) ckeys[ckey] = ckey //to make searching faster. .["keys"] = ckeys + if (.["whitelist"]) + var/keys = splittext(.["whitelist"], ",") + var/ckeys = list() + for (var/key in keys) + var/ckey = ckey(key) + ckeys[ckey] = ckey //to make searching faster. + .["whitelist"] = ckeys .["type"] = splittext(.["type"], ",") .["IP"] = splittext(.["IP"], ",") .["computer_id"] = splittext(.["computer_id"], ",") + . -= "fromdb" -/proc/list2stickyban(var/list/ban) +/proc/list2stickyban(list/ban) if (!ban || !islist(ban)) return null . = ban.Copy() if (.["keys"]) .["keys"] = jointext(.["keys"], ",") + if (.["IP"]) + .["IP"] = jointext(.["IP"], ",") + if (.["computer_id"]) + .["computer_id"] = jointext(.["computer_id"], ",") + if (.["whitelist"]) + .["whitelist"] = jointext(.["whitelist"], ",") if (.["type"]) .["type"] = jointext(.["type"], ",") - //internal tracking only, shouldn't be stored + . -= "reverting" + . -= "matches_this_round" . -= "existing_user_matches_this_round" . -= "admin_matches_this_round" - . -= "matches_this_round" - . -= "reverting" + . -= "pending_matches_this_round" - //storing these can sometimes cause sticky bans to start matching everybody - // and isn't even needed for sticky ban matching, as the hub tracks these separately - . -= "IP" - . -= "computer_id" . = list2params(.) diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2.dm b/code/modules/admin/verbs/SDQL2/SDQL_2.dm index 97d912cb9e..f2c10ecc1c 100644 --- a/code/modules/admin/verbs/SDQL2/SDQL_2.dm +++ b/code/modules/admin/verbs/SDQL2/SDQL_2.dm @@ -782,7 +782,7 @@ GLOBAL_DATUM_INIT(sdql2_vv_statobj, /obj/effect/statclick/SDQL2_VV_all, new(null if(temp.vars.Find(v)) temp.vars[v] = SDQL_expression(d, set_list[sets]) else - temp.vv_edit_var(v, SDQL_expression(d, set_list[sets])) + temp.vv_edit_var(v, SDQL_expression(d, set_list[sets]), TRUE) break if(temp.vars.Find(v) && (istype(temp.vars[v], /datum) || istype(temp.vars[v], /client))) temp = temp.vars[v] diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm index 4348ae7661..45d05c70b9 100644 --- a/code/modules/admin/verbs/adminhelp.dm +++ b/code/modules/admin/verbs/adminhelp.dm @@ -174,7 +174,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) //is_bwoink is TRUE if this ticket was started by an admin PM /datum/admin_help/New(msg, client/C, is_bwoink) //clean the input msg - msg = sanitize(copytext_char(msg,1,MAX_MESSAGE_LEN)) + msg = copytext_char(msg,1,MAX_MESSAGE_LEN) if(!msg || !C || !C.mob) qdel(src) return @@ -263,7 +263,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) //message from the initiator without a target, all admins will see this //won't bug irc /datum/admin_help/proc/MessageNoRecipient(msg) - msg = sanitize(copytext_char(msg, 1, MAX_MESSAGE_LEN)) + msg = copytext_char(msg, 1, MAX_MESSAGE_LEN) var/ref_src = "[REF(src)]" //Message to be sent to all admins var/admin_msg = "Ticket [TicketHref("#[id]", ref_src)]: [LinkedReplyName(ref_src)] [FullMonty(ref_src)]: [keywords_lookup(msg)]" @@ -523,7 +523,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) if(handle_spam_prevention(msg,MUTE_ADMINHELP)) return - msg = trim(msg) + msg = sanitize(trim(msg)) if(!msg) return diff --git a/code/modules/admin/verbs/adminjump.dm b/code/modules/admin/verbs/adminjump.dm index ef56b4cd2a..2f89dc82eb 100644 --- a/code/modules/admin/verbs/adminjump.dm +++ b/code/modules/admin/verbs/adminjump.dm @@ -158,3 +158,19 @@ else to_chat(src, "Failed to move mob to a valid location.", confidential = TRUE) SSblackbox.record_feedback("tally", "admin_verb", 1, "Send Mob") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/// Proc to hook user-enacted teleporting behavior and keep logging of the event. +/atom/movable/proc/admin_teleport(atom/new_location, message = TRUE) + if(isnull(new_location)) + log_admin("[key_name(usr)] teleported [key_name(src)] to nullspace") + moveToNullspace() + else + log_admin("[key_name(usr)] teleported [key_name(src)] to [AREACOORD(loc)]") + forceMove(new_location) + +/mob/admin_teleport(atom/new_location, message = TRUE) + var/msg = "[key_name_admin(usr)] teleported [ADMIN_LOOKUPFLW(src)] to [isnull(new_location) ? "nullspace" : ADMIN_VERBOSEJMP(loc)]" + if(message) + message_admins(msg) + admin_ticket_log(src, msg) + return ..() diff --git a/code/modules/admin/verbs/adminpm.dm b/code/modules/admin/verbs/adminpm.dm index 2931c52a5c..ab0b0d933a 100644 --- a/code/modules/admin/verbs/adminpm.dm +++ b/code/modules/admin/verbs/adminpm.dm @@ -113,7 +113,6 @@ to_chat(src, "Error: Use the admin IRC/Discord channel, nerd.", confidential = TRUE) return - else //get message text, limit it's length.and clean/escape html if(!msg) @@ -128,11 +127,16 @@ else if(holder) to_chat(src, "Error: Admin-PM: Client not found.", confidential = TRUE) - to_chat(src, "Message not sent:
    [msg]", confidential = TRUE) + to_chat(src, "Message not sent:
    [sanitize(msg)]", confidential = TRUE) if(recipient_ticket) recipient_ticket.AddInteraction("No client found, message not sent:
    [msg]") return else + //clean the message if it's not sent by a high-rank admin + if(!check_rights(R_SERVER|R_DEBUG,0)||external)//no sending html to the poor bots + msg = sanitize(copytext_char(msg, 1, MAX_MESSAGE_LEN)) + if(!msg) + return current_ticket.MessageNoRecipient(msg) return @@ -141,7 +145,7 @@ to_chat(src, "Error: Admin-PM: You are unable to use admin PM-s (muted).", confidential = TRUE) return - if (src.handle_spam_prevention(msg,MUTE_ADMINHELP)) + if(src.handle_spam_prevention(msg,MUTE_ADMINHELP)) return //clean the message if it's not sent by a high-rank admin diff --git a/code/modules/admin/verbs/playsound.dm b/code/modules/admin/verbs/playsound.dm index 6e188a6c7a..c9a5cafd9b 100644 --- a/code/modules/admin/verbs/playsound.dm +++ b/code/modules/admin/verbs/playsound.dm @@ -4,12 +4,10 @@ if(!check_rights(R_SOUNDS)) return + var/freq = 1 var/vol = input(usr, "What volume would you like the sound to play at?",, 100) as null|num if(!vol) return - var/freq = input(usr, "What frequency would you like the sound to play at?",, 1) as null|num - if(!freq) - freq = 1 vol = clamp(vol, 1, 100) var/sound/admin_sound = new() @@ -18,14 +16,14 @@ admin_sound.channel = CHANNEL_ADMIN admin_sound.frequency = freq admin_sound.wait = 1 - admin_sound.repeat = 0 + admin_sound.repeat = FALSE admin_sound.status = SOUND_STREAM admin_sound.volume = vol var/res = alert(usr, "Show the title of this song to the players?",, "Yes","No", "Cancel") switch(res) if("Yes") - to_chat(world, "An admin played: [S]") + to_chat(world, "An admin played: [S]", confidential = TRUE) if("Cancel") return @@ -49,7 +47,7 @@ log_admin("[key_name(src)] played a local sound [S]") message_admins("[key_name_admin(src)] played a local sound [S]") - playsound(get_turf(src.mob), S, 50, 0, 0) + playsound(get_turf(src.mob), S, 50, FALSE, FALSE) SSblackbox.record_feedback("tally", "admin_verb", 1, "Play Local Sound") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/play_web_sound() diff --git a/code/modules/admin/view_variables/mass_edit_variables.dm b/code/modules/admin/view_variables/mass_edit_variables.dm index a498868436..c45513e812 100644 --- a/code/modules/admin/view_variables/mass_edit_variables.dm +++ b/code/modules/admin/view_variables/mass_edit_variables.dm @@ -104,7 +104,7 @@ if (!thing) continue var/datum/D = thing - if (D.vv_edit_var(variable, initial(D.vars[variable])) != FALSE) + if (D.vv_edit_var(variable, initial(D.vars[variable]), TRUE) != FALSE) accepted++ else rejected++ @@ -135,7 +135,7 @@ for(var/V in varsvars) new_value = replacetext(new_value,"\[[V]]","[D.vars[V]]") - if (D.vv_edit_var(variable, new_value) != FALSE) + if (D.vv_edit_var(variable, new_value, TRUE) != FALSE) accepted++ else rejected++ @@ -161,7 +161,7 @@ if(many && !new_value) new_value = new type() - if (D.vv_edit_var(variable, new_value) != FALSE) + if (D.vv_edit_var(variable, new_value, TRUE) != FALSE) accepted++ else rejected++ @@ -176,7 +176,7 @@ if (!thing) continue var/datum/D = thing - if (D.vv_edit_var(variable, new_value) != FALSE) + if (D.vv_edit_var(variable, new_value, TRUE) != FALSE) accepted++ else rejected++ diff --git a/code/modules/admin/view_variables/reference_tracking.dm b/code/modules/admin/view_variables/reference_tracking.dm index 70aac2f107..c293500298 100644 --- a/code/modules/admin/view_variables/reference_tracking.dm +++ b/code/modules/admin/view_variables/reference_tracking.dm @@ -109,7 +109,7 @@ GLOBAL_LIST_EMPTY(deletion_failures) set name = "Find References" set src in world - find_references(FALSE) + find_references_legacy(FALSE) /datum/proc/find_references_legacy(skip_alert) @@ -164,7 +164,7 @@ GLOBAL_LIST_EMPTY(deletion_failures) qdel(src, TRUE) //force a qdel if(!running_find_references) - find_references(TRUE) + find_references_legacy(TRUE) /datum/verb/qdel_then_if_fail_find_references() diff --git a/code/modules/antagonists/abductor/equipment/glands/ventcrawl.dm b/code/modules/antagonists/abductor/equipment/glands/ventcrawl.dm index 8ac083f68b..c35016cf2e 100644 --- a/code/modules/antagonists/abductor/equipment/glands/ventcrawl.dm +++ b/code/modules/antagonists/abductor/equipment/glands/ventcrawl.dm @@ -9,4 +9,4 @@ /obj/item/organ/heart/gland/ventcrawling/activate() to_chat(owner, "You feel very stretchy.") - owner.ventcrawler = VENTCRAWLER_ALWAYS + owner.AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) diff --git a/code/modules/antagonists/blob/blob/overmind.dm b/code/modules/antagonists/blob/blob/overmind.dm index 02be432045..18f6817ec9 100644 --- a/code/modules/antagonists/blob/blob/overmind.dm +++ b/code/modules/antagonists/blob/blob/overmind.dm @@ -277,3 +277,7 @@ GLOBAL_LIST_EMPTY(blob_nodes) var/datum/antagonist/blob/B = mind.has_antag_datum(/datum/antagonist/blob) if(!B) mind.add_antag_datum(/datum/antagonist/blob) + +//the same but it's forced to be allowed by default as cameras usually don't allow emoting +/mob/camera/blob/emote(act, m_type=1, message = null, intentional = FALSE, forced = TRUE) + . = ..() diff --git a/code/modules/antagonists/bloodsucker/bloodsucker_sunlight.dm b/code/modules/antagonists/bloodsucker/bloodsucker_sunlight.dm index 43163f6a70..2cb50c6b3b 100644 --- a/code/modules/antagonists/bloodsucker/bloodsucker_sunlight.dm +++ b/code/modules/antagonists/bloodsucker/bloodsucker_sunlight.dm @@ -13,8 +13,9 @@ var/nightime_duration = 900 //15 Minutes /obj/effect/sunlight/Initialize() - countdown() - hud_tick() + . = ..() + INVOKE_ASYNC(src, .proc/countdown) + INVOKE_ASYNC(src, .proc/hud_tick) /obj/effect/sunlight/proc/countdown() set waitfor = FALSE diff --git a/code/modules/antagonists/bloodsucker/datum_vassal.dm b/code/modules/antagonists/bloodsucker/datum_vassal.dm index c065d5fe7c..91e89e71e6 100644 --- a/code/modules/antagonists/bloodsucker/datum_vassal.dm +++ b/code/modules/antagonists/bloodsucker/datum_vassal.dm @@ -90,7 +90,7 @@ /datum/antagonist/vassal/greet() to_chat(owner, "You are now the mortal servant of [master.owner.current], a bloodsucking vampire!") to_chat(owner, "The power of [master.owner.current.p_their()] immortal blood compells you to obey [master.owner.current.p_them()] in all things, even offering your own life to prolong theirs.
    \ - You are not required to obey any other Bloodsucker, for only [master.owner.current] is your master. The laws of Nanotransen do not apply to you now; only your vampiric master's word must be obeyed.") + You are not required to obey any other Bloodsucker, for only [master.owner.current] is your master. The laws of Nanotrasen do not apply to you now; only your vampiric master's word must be obeyed.") // Effects... owner.current.playsound_local(null, 'sound/magic/mutate.ogg', 100, FALSE, pressure_affected = FALSE) //owner.store_memory("You became the mortal servant of [master.owner.current], a bloodsucking vampire!") diff --git a/code/modules/antagonists/changeling/changeling.dm b/code/modules/antagonists/changeling/changeling.dm index dacd568993..7a34af4d13 100644 --- a/code/modules/antagonists/changeling/changeling.dm +++ b/code/modules/antagonists/changeling/changeling.dm @@ -213,7 +213,7 @@ if(canrespec) to_chat(owner.current, "We have removed our evolutions from this form, and are now ready to readapt.") reset_powers() - playsound(get_turf(owner.current), 'sound/effects/lingreadapt.ogg', 75, TRUE, 5, soundenvwet = 0) + playsound(get_turf(owner.current), 'sound/effects/lingreadapt.ogg', 75, TRUE, 5) canrespec = 0 SSblackbox.record_feedback("tally", "changeling_power_purchase", 1, "Readapt") return 1 diff --git a/code/modules/antagonists/changeling/powers/shriek.dm b/code/modules/antagonists/changeling/powers/shriek.dm index 0e2515fdae..dae1da9f8f 100644 --- a/code/modules/antagonists/changeling/powers/shriek.dm +++ b/code/modules/antagonists/changeling/powers/shriek.dm @@ -29,7 +29,7 @@ for(var/obj/machinery/light/L in range(4, user)) L.on = 1 L.break_light_tube() - playsound(get_turf(user), 'sound/effects/lingscreech.ogg', 75, TRUE, 5, soundenvwet = 0) + playsound(get_turf(user), 'sound/effects/lingscreech.ogg', 75, TRUE, 5) return TRUE /obj/effect/proc_holder/changeling/dissonant_shriek @@ -49,5 +49,5 @@ L.on = 1 L.break_light_tube() empulse_using_range(get_turf(user), 8, TRUE) - playsound(get_turf(user), 'sound/effects/lingempscreech.ogg', 75, TRUE, 5, soundenvwet = 0) + playsound(get_turf(user), 'sound/effects/lingempscreech.ogg', 75, TRUE, 5) return TRUE diff --git a/code/modules/antagonists/clockcult/clock_effects/city_of_cogs_rift.dm b/code/modules/antagonists/clockcult/clock_effects/city_of_cogs_rift.dm index 3ea4668df8..1da49efe3c 100644 --- a/code/modules/antagonists/clockcult/clock_effects/city_of_cogs_rift.dm +++ b/code/modules/antagonists/clockcult/clock_effects/city_of_cogs_rift.dm @@ -22,7 +22,7 @@ for(var/mob/M in GLOB.player_list) if(M.z == z) if(get_dist(src, M) >= 7) - M.playsound_local(src, 'sound/magic/blink.ogg', 10, FALSE, falloff = 10) + M.playsound_local(src, 'sound/magic/blink.ogg', 10, FALSE) else M.playsound_local(src, 'sound/magic/blink.ogg', 50, FALSE) diff --git a/code/modules/antagonists/clockcult/clock_helpers/clock_rites.dm b/code/modules/antagonists/clockcult/clock_helpers/clock_rites.dm index 59a86ffa34..58ee73ef5b 100644 --- a/code/modules/antagonists/clockcult/clock_helpers/clock_rites.dm +++ b/code/modules/antagonists/clockcult/clock_helpers/clock_rites.dm @@ -165,14 +165,16 @@ /datum/clockwork_rite/treat_wounds/cast(var/mob/living/invoker, var/turf/T, var/mob/living/carbon/human/target) if(!target) return FALSE - if(!target.all_wounds.len) + if(!target.all_wounds || !target.all_wounds.len) to_chat(invoker, "This one does not require mending.") return FALSE .= ..() if(!.) return FALSE target.adjustToxLoss(10 * target.all_wounds.len) - QDEL_LIST(target.all_wounds) + for(var/i in target.all_wounds) + var/datum/wound/mended = i + mended.remove_wound() to_chat(target, "You feel your wounds heal, but are overcome with deep nausea.") new /obj/effect/temp_visual/ratvar/sigil/vitality(T) diff --git a/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_shield.dm b/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_shield.dm index a681e9b38b..fb7b4f8a94 100644 --- a/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_shield.dm +++ b/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_shield.dm @@ -22,7 +22,7 @@ . = ..() desc = initial(desc) -obj/item/shield/riot/ratvarian/proc/calc_bash_mult() +/obj/item/shield/riot/ratvarian/proc/calc_bash_mult() var/bash_mult = 0 if(!dam_absorbed) return 1 diff --git a/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm b/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm index 571a817024..ff6dc12ce1 100644 --- a/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm +++ b/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm @@ -203,10 +203,10 @@ to_chat(user, "You need to hold the slab in your active hand to recite scripture!") return FALSE var/initial_tier = initial(scripture.tier) - if(initial_tier == SCRIPTURE_PERIPHERAL) + if(initial_tier == SCRIPTURE_PERIPHERAL && !issilicon(user)) //Silicons use peripheral scripture & cannot open the slab. to_chat(user, "Nice try using href exploits") return - if(!GLOB.ratvar_awakens && !no_cost && !SSticker.scripture_states[initial_tier]) + if(!GLOB.ratvar_awakens && !no_cost && !SSticker.scripture_states[initial_tier] &&!issilicon(user)) //silicons can't choose their spells, so lets allow them to always cast their assigned ones. to_chat(user, "That scripture is not unlocked, and cannot be recited!") return FALSE var/datum/clockwork_scripture/scripture_to_recite = new scripture diff --git a/code/modules/antagonists/clockcult/clock_structures/ark_of_the_clockwork_justicar.dm b/code/modules/antagonists/clockcult/clock_structures/ark_of_the_clockwork_justicar.dm index 7478d45b08..3b507fb57c 100644 --- a/code/modules/antagonists/clockcult/clock_structures/ark_of_the_clockwork_justicar.dm +++ b/code/modules/antagonists/clockcult/clock_structures/ark_of_the_clockwork_justicar.dm @@ -149,7 +149,7 @@ transform = matrix() * 2 animate(src, transform = matrix() * 0.5, time = 30, flags = ANIMATION_END_NOW) -obj/structure/destructible/clockwork/massive/celestial_gateway/Destroy() +/obj/structure/destructible/clockwork/massive/celestial_gateway/Destroy() STOP_PROCESSING(SSprocessing, src) if(!purpose_fulfilled) var/area/gate_area = get_area(src) diff --git a/code/modules/antagonists/clockcult/clock_structures/trap_triggers/pressure_sensor.dm b/code/modules/antagonists/clockcult/clock_structures/trap_triggers/pressure_sensor.dm index af29bc9b31..c5d1bc2ded 100644 --- a/code/modules/antagonists/clockcult/clock_structures/trap_triggers/pressure_sensor.dm +++ b/code/modules/antagonists/clockcult/clock_structures/trap_triggers/pressure_sensor.dm @@ -15,3 +15,5 @@ audible_message("*click*") playsound(src, 'sound/items/screwdriver2.ogg', 50, TRUE) activate() + + . = ..() diff --git a/code/modules/antagonists/clockcult/clock_structures/trap_triggers/pressure_sensor_mech.dm b/code/modules/antagonists/clockcult/clock_structures/trap_triggers/pressure_sensor_mech.dm index 10a5b7787f..21735ad6d7 100644 --- a/code/modules/antagonists/clockcult/clock_structures/trap_triggers/pressure_sensor_mech.dm +++ b/code/modules/antagonists/clockcult/clock_structures/trap_triggers/pressure_sensor_mech.dm @@ -8,7 +8,7 @@ alpha = 75 /obj/structure/destructible/clockwork/trap/trigger/pressure_sensor/mech/Crossed(atom/movable/AM) - + . = ..() if(!istype(AM,/obj/mecha/)) return diff --git a/code/modules/antagonists/clockcult/clock_structures/traps/steam_vent.dm b/code/modules/antagonists/clockcult/clock_structures/traps/steam_vent.dm index 6aede1592e..7d6eea1c79 100644 --- a/code/modules/antagonists/clockcult/clock_structures/traps/steam_vent.dm +++ b/code/modules/antagonists/clockcult/clock_structures/traps/steam_vent.dm @@ -21,3 +21,5 @@ if(isliving(AM) && opacity) var/mob/living/L = AM L.adjust_fire_stacks(-1) //It's wet! + return + . = ..() diff --git a/code/modules/antagonists/devil/true_devil/_true_devil.dm b/code/modules/antagonists/devil/true_devil/_true_devil.dm index 293b1de3dc..069080170e 100644 --- a/code/modules/antagonists/devil/true_devil/_true_devil.dm +++ b/code/modules/antagonists/devil/true_devil/_true_devil.dm @@ -11,7 +11,6 @@ gender = NEUTER health = 350 maxHealth = 350 - ventcrawler = VENTCRAWLER_NONE density = TRUE pass_flags = 0 sight = (SEE_TURFS | SEE_OBJS) diff --git a/code/modules/antagonists/eldritch_cult/eldritch_antag.dm b/code/modules/antagonists/eldritch_cult/eldritch_antag.dm index ea226a3cb6..1e43754477 100644 --- a/code/modules/antagonists/eldritch_cult/eldritch_antag.dm +++ b/code/modules/antagonists/eldritch_cult/eldritch_antag.dm @@ -10,6 +10,8 @@ var/give_equipment = TRUE var/list/researched_knowledge = list() var/total_sacrifices = 0 + var/list/sac_targetted = list() //Which targets did living hearts give them, but they did not sac? + var/list/actually_sacced = list() //Which targets did they actually sac? var/ascended = FALSE /datum/antagonist/heretic/admin_add(datum/mind/new_owner,mob/admin) @@ -175,6 +177,17 @@ knowledge_message += "[EK.name]" parts += knowledge_message.Join(", ") + parts += "Targets assigned by living hearts, but not sacrificed:" + if(!sac_targetted.len) + parts += "None." + else + parts += sac_targetted.Join(",") + parts += "Sacrifices performed:" + if(!actually_sacced.len) + parts += "None!" + else + parts += actually_sacced.Join(",") + return parts.Join("
    ") //////////////// // Knowledge // @@ -213,6 +226,23 @@ if(ascended) . += 20 +/datum/antagonist/heretic/antag_panel() + var/list/parts = list() + parts += ..() + parts += "Targets currently assigned by living hearts (Can give a false negative if they stole someone elses living heart):" + if(!sac_targetted.len) + parts += "None." + else + parts += sac_targetted.Join(",") + parts += "Targets actually sacrificed:" + if(!actually_sacced.len) + parts += "None." + else + parts += actually_sacced.Join(",") + + return (parts.Join("
    ") + "
    ") + + //////////////// // Objectives // //////////////// diff --git a/code/modules/antagonists/eldritch_cult/eldritch_items.dm b/code/modules/antagonists/eldritch_cult/eldritch_items.dm index da2c61ad16..fbf0740e50 100644 --- a/code/modules/antagonists/eldritch_cult/eldritch_items.dm +++ b/code/modules/antagonists/eldritch_cult/eldritch_items.dm @@ -6,6 +6,17 @@ w_class = WEIGHT_CLASS_SMALL ///Target var/mob/living/carbon/human/target + var/datum/antagonist/heretic/sac_targetter //The heretic who used this to acquire the current target - gets cleared when target gets sacrificed. + +/obj/item/living_heart/Initialize() + . = ..() + GLOB.living_heart_cache.Add(src) //Add is better than +=. + +/obj/item/living_heart/Destroy() + GLOB.living_heart_cache.Remove(src) + if(sac_targetter && target) + sac_targetter.sac_targetted.Remove(target.real_name) + return ..() /obj/item/living_heart/attack_self(mob/user) . = ..() diff --git a/code/modules/antagonists/eldritch_cult/eldritch_knowledge.dm b/code/modules/antagonists/eldritch_cult/eldritch_knowledge.dm index e0189944e5..481ac08ea5 100644 --- a/code/modules/antagonists/eldritch_cult/eldritch_knowledge.dm +++ b/code/modules/antagonists/eldritch_cult/eldritch_knowledge.dm @@ -1,6 +1,6 @@ /** - * #Eldritch Knwoledge + * #Eldritch Knowledge * * Datum that makes eldritch cultist interesting. * @@ -252,6 +252,10 @@ LH.target = null var/datum/antagonist/heretic/EC = carbon_user.mind.has_antag_datum(/datum/antagonist/heretic) + EC.actually_sacced.Add(H.real_name) + if(LH.sac_targetter) + LH.sac_targetter.sac_targetted.Remove(H.real_name) + LH.sac_targetter = null EC.total_sacrifices++ for(var/X in carbon_user.get_all_gear()) if(!istype(X,/obj/item/forbidden_book)) @@ -265,8 +269,14 @@ var/datum/objective/A = new A.owner = user.mind var/list/targets = list() + var/list/target_blacklist = list() + for(var/obj/item/living_heart/CLH in GLOB.living_heart_cache) + if(!CLH || !CLH.target || !CLH.target.mind) + continue + target_blacklist.Add(CLH.target.mind) + for(var/i in 0 to 3) - var/datum/mind/targeted = A.find_target()//easy way, i dont feel like copy pasting that entire block of code + var/datum/mind/targeted = A.find_target(blacklist = target_blacklist)//easy way, i dont feel like copy pasting that entire block of code if(!targeted) break targets[targeted.current.real_name] = targeted.current @@ -274,9 +284,24 @@ if(!LH.target && targets.len) LH.target = pick(targets) //Tsk tsk, you can and will get another target if you want it or not. + + if(LH.target) + target_blacklist = list() + for(var/obj/item/living_heart/CLH in (GLOB.living_heart_cache - LH)) //Recreate blacklist, excluding ourselves. + if(!CLH || !CLH.target || !CLH.target.mind) + continue + target_blacklist.Add(CLH.target.mind) + if(LH.target.mind in target_blacklist) //Someone was faster, or you tried to cheese the system. + to_chat(user, "It seems you were too slow, and your target of choice has already been selected by another living heart!") + LH.target = null + qdel(A) if(LH.target) to_chat(user,"Your new target has been selected, go and sacrifice [LH.target.real_name]!") + var/datum/antagonist/heretic/EC = carbon_user.mind.has_antag_datum(/datum/antagonist/heretic) + LH.sac_targetter = EC + EC.sac_targetted.Add(LH.target.real_name) + else to_chat(user,"target could not be found for living heart.") diff --git a/code/modules/antagonists/morph/morph.dm b/code/modules/antagonists/morph/morph.dm index 5844aad02b..077c380ef0 100644 --- a/code/modules/antagonists/morph/morph.dm +++ b/code/modules/antagonists/morph/morph.dm @@ -15,7 +15,6 @@ stop_automated_movement = 1 status_flags = CANPUSH pass_flags = PASSTABLE - ventcrawler = VENTCRAWLER_ALWAYS atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) minbodytemp = 0 maxHealth = 150 @@ -53,6 +52,10 @@ You can attack any item or dead creature to consume it - creatures will fully restore your health. \ Finally, you can restore yourself to your original form while morphed by shift-clicking yourself.
    " +/mob/living/simple_animal/hostile/morph/Initialize() + . = ..() + src.AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) + /mob/living/simple_animal/hostile/morph/examine(mob/user) if(morphed) . = form.examine(user) diff --git a/code/modules/antagonists/revenant/revenant.dm b/code/modules/antagonists/revenant/revenant.dm index f5ebcffe35..ef58e5af39 100644 --- a/code/modules/antagonists/revenant/revenant.dm +++ b/code/modules/antagonists/revenant/revenant.dm @@ -72,6 +72,7 @@ var/list/drained_mobs = list() //Cannot harvest the same mob twice var/perfectsouls = 0 //How many perfect, regen-cap increasing souls the revenant has. //TODO, add objective for getting a perfect soul(s?) var/generated_objectives_and_spells = FALSE + var/telekinesis_cooldown /mob/living/simple_animal/revenant/Initialize(mapload) . = ..() @@ -93,13 +94,16 @@ /mob/living/simple_animal/revenant/Login() ..() - to_chat(src, "You are a revenant.") - to_chat(src, "Your formerly mundane spirit has been infused with alien energies and empowered into a revenant.") - to_chat(src, "You are not dead, not alive, but somewhere in between. You are capable of limited interaction with both worlds.") - to_chat(src, "You are invincible and invisible to everyone but other ghosts. Most abilities will reveal you, rendering you vulnerable.") - to_chat(src, "To function, you are to drain the life essence from humans. This essence is a resource, as well as your health, and will power all of your abilities.") - to_chat(src, "You do not remember anything of your past lives, nor will you remember anything about this one after your death.") - to_chat(src, "Be sure to read the wiki page to learn more.") + var/revenant_greet + revenant_greet += "You are a revenant." + revenant_greet += "Your formerly mundane spirit has been infused with alien energies and empowered into a revenant." + revenant_greet += "You are not dead, not alive, but somewhere in between. You are capable of limited interaction with both worlds." + revenant_greet += "You are invincible and invisible to everyone but other ghosts. Most abilities will reveal you, rendering you vulnerable." + revenant_greet += "To function, you are to drain the life essence from humans. This essence is a resource, as well as your health, and will power all of your abilities." + revenant_greet += "You do not remember anything of your past lives, nor will you remember anything about this one after your death." + revenant_greet += "Be sure to read the wiki page to learn more." + revenant_greet += "You are also able to telekinetically throw objects by clickdragging them." + to_chat(src, revenant_greet) if(!generated_objectives_and_spells) generated_objectives_and_spells = TRUE mind.assigned_role = ROLE_REVENANT @@ -317,6 +321,12 @@ to_chat(src, "Lost [essence_amt]E[source ? " from [source]":""].") return 1 +/mob/living/simple_animal/revenant/proc/telekinesis_cooldown_end() + if(!telekinesis_cooldown) + CRASH("telekinesis_cooldown_end ran when telekinesis_cooldown on [src] was false") + else + telekinesis_cooldown = FALSE + /mob/living/simple_animal/revenant/proc/death_reset() revealed = FALSE unreveal_time = 0 @@ -431,6 +441,38 @@ qdel(revenant) ..() +/proc/RevenantThrow(over, mob/user, obj/item/throwable) + var/mob/living/simple_animal/revenant/spooker = user + if(!istype(throwable)) + return + if(!throwable.anchored && !spooker.telekinesis_cooldown && spooker.essence > 20) + if(7 < get_dist(throwable, spooker)) + return + if(3 >= get_dist(throwable, spooker)) + spooker.stun(10) + spooker.reveal(25) + else + spooker.stun(20) + spooker.reveal(50) + spooker.change_essence_amount(-20, FALSE, "telekinesis") + spooker.telekinesis_cooldown = TRUE + throwable.float(TRUE, TRUE) + sleep(20) + throwable.DoRevenantThrowEffects(over) + throwable.throw_at(over, 10, 2) + ADD_TRAIT(throwable, TRAIT_SPOOKY_THROW, "revenant") + log_combat(throwable, over, "spooky telekinesised at", throwable) + var/obj/effect/temp_visual/telekinesis/T = new(get_turf(throwable)) + T.color = "#8715b4" + addtimer(CALLBACK(spooker, /mob/living/simple_animal/revenant.proc/telekinesis_cooldown_end), 50) + sleep(5) + throwable.float(FALSE, TRUE) + + +//Use this for effects you want to happen when a revenant throws stuff, check the TRAIT_SPOOKY_THROW if you want to know if its still being thrown +/obj/item/proc/DoRevenantThrowEffects(atom/target) + return TRUE + //objectives /datum/objective/revenant var/targetAmount = 100 diff --git a/code/modules/antagonists/swarmer/swarmer.dm b/code/modules/antagonists/swarmer/swarmer.dm index 7444905b89..d1bdac7e05 100644 --- a/code/modules/antagonists/swarmer/swarmer.dm +++ b/code/modules/antagonists/swarmer/swarmer.dm @@ -93,7 +93,6 @@ AIStatus = AI_OFF pass_flags = PASSTABLE mob_size = MOB_SIZE_TINY - ventcrawler = VENTCRAWLER_ALWAYS ranged = 1 projectiletype = /obj/item/projectile/beam/disabler ranged_cooldown_time = 20 @@ -112,6 +111,7 @@ remove_verb(src, /mob/living/verb/pulled) for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds) diag_hud.add_to_hud(src) + AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) /mob/living/simple_animal/hostile/swarmer/med_hud_set_health() var/image/holder = hud_list[DIAG_HUD] diff --git a/code/modules/antagonists/traitor/equipment/contractor.dm b/code/modules/antagonists/traitor/equipment/contractor.dm index 28298f4983..525f40d1f7 100644 --- a/code/modules/antagonists/traitor/equipment/contractor.dm +++ b/code/modules/antagonists/traitor/equipment/contractor.dm @@ -43,7 +43,7 @@ var/list/to_generate = list( CONTRACT_PAYOUT_LARGE, CONTRACT_PAYOUT_MEDIUM, - CONTRACT_PAYOUT_SMALL, + CONTRACT_PAYOUT_MEDIUM, CONTRACT_PAYOUT_SMALL, CONTRACT_PAYOUT_SMALL, CONTRACT_PAYOUT_SMALL diff --git a/code/modules/arousal/toys/dildos.dm b/code/modules/arousal/toys/dildos.dm index 0cfa57e5fc..2482b93300 100644 --- a/code/modules/arousal/toys/dildos.dm +++ b/code/modules/arousal/toys/dildos.dm @@ -103,29 +103,29 @@ name = "knotted dildo" attack_verb = list("penetrated", "knotted", "slapped", "inseminated") -obj/item/dildo/human +/obj/item/dildo/human dildo_shape = "human" name = "human dildo" attack_verb = list("penetrated", "slapped", "inseminated") -obj/item/dildo/plain +/obj/item/dildo/plain dildo_shape = "plain" name = "plain dildo" attack_verb = list("penetrated", "slapped", "inseminated") -obj/item/dildo/flared +/obj/item/dildo/flared dildo_shape = "flared" name = "flared dildo" attack_verb = list("penetrated", "slapped", "neighed", "gaped", "prolapsed", "inseminated") -obj/item/dildo/flared/huge +/obj/item/dildo/flared/huge name = "literal horse cock" desc = "THIS THING IS HUGE!" dildo_size = 4 force = 10 hitsound = 'sound/weapons/klonk.ogg' -obj/item/dildo/custom +/obj/item/dildo/custom name = "customizable dildo" desc = "Thanks to significant advances in synthetic nanomaterials, this dildo is capable of taking on many different forms to fit the user's preferences! Pricy!" can_customize = TRUE @@ -136,9 +136,9 @@ obj/item/dildo/custom // Suicide acts, by request /obj/item/dildo/proc/manual_suicide(mob/living/user) - user.visible_message("[user] finally finishes deepthroating the [src], and their life.") - user.adjustOxyLoss(200) - user.death(0) + user.visible_message("[user] finally finishes deepthroating the [src], and their life.") + user.adjustOxyLoss(200) + user.death(0) /obj/item/dildo/suicide_act(mob/living/user) // is_knotted = ((src.dildo_shape == "knotted")?"They swallowed the knot":"Their face is turning blue") diff --git a/code/modules/assembly/flash.dm b/code/modules/assembly/flash.dm index 8a0645f311..07a9f499f8 100644 --- a/code/modules/assembly/flash.dm +++ b/code/modules/assembly/flash.dm @@ -30,6 +30,9 @@ attack(user,user) return FIRELOSS +/obj/item/assembly/flash/DoRevenantThrowEffects(atom/target) + AOE_flash() + /obj/item/assembly/flash/update_icon(flash = FALSE) cut_overlays() attached_overlays = list() diff --git a/code/modules/assembly/holder.dm b/code/modules/assembly/holder.dm index bf56449a0c..84e70bbbb3 100644 --- a/code/modules/assembly/holder.dm +++ b/code/modules/assembly/holder.dm @@ -62,6 +62,7 @@ master.update_icon() /obj/item/assembly_holder/Crossed(atom/movable/AM as mob|obj) + . = ..() if(a_left) a_left.Crossed(AM) if(a_right) diff --git a/code/modules/asset_cache/asset_cache_client.dm b/code/modules/asset_cache/asset_cache_client.dm index f462fe386b..3cff8cb41f 100644 --- a/code/modules/asset_cache/asset_cache_client.dm +++ b/code/modules/asset_cache/asset_cache_client.dm @@ -1,5 +1,5 @@ -/// Process asset cache client topic calls for "asset_cache_confirm_arrival=[INT]" +/// Process asset cache client topic calls for `"asset_cache_confirm_arrival=[INT]"` /client/proc/asset_cache_confirm_arrival(job_id) var/asset_cache_job = round(text2num(job_id)) //because we skip the limiter, we have to make sure this is a valid arrival and not somebody tricking us into letting them append to a list without limit. @@ -10,7 +10,7 @@ return asset_cache_job || TRUE -/// Process asset cache client topic calls for "asset_cache_preload_data=[HTML+JSON_STRING] +/// Process asset cache client topic calls for `"asset_cache_preload_data=[HTML+JSON_STRING]"` /client/proc/asset_cache_preload_data(data) var/json = data var/list/preloaded_assets = json_decode(json) diff --git a/code/modules/asset_cache/asset_list_items.dm b/code/modules/asset_cache/asset_list_items.dm index 3b6a30a02a..22fb266033 100644 --- a/code/modules/asset_cache/asset_list_items.dm +++ b/code/modules/asset_cache/asset_list_items.dm @@ -47,8 +47,9 @@ "smmon_3.gif" = 'icons/program_icons/smmon_3.gif', "smmon_4.gif" = 'icons/program_icons/smmon_4.gif', "smmon_5.gif" = 'icons/program_icons/smmon_5.gif', - "smmon_6.gif" = 'icons/program_icons/smmon_6.gif', - "borg_mon.gif" = 'icons/program_icons/borg_mon.gif' + "smmon_6.gif" = 'icons/program_icons/smmon_6.gif' + // "borg_mon.gif" = 'icons/program_icons/borg_mon.gif', + // "robotact.gif" = 'icons/program_icons/robotact.gif' ) /datum/asset/simple/radar_assets @@ -156,7 +157,6 @@ ) /datum/asset/simple/namespaced/fontawesome - legacy = TRUE assets = list( "fa-regular-400.eot" = 'html/font-awesome/webfonts/fa-regular-400.eot', "fa-regular-400.woff" = 'html/font-awesome/webfonts/fa-regular-400.woff', @@ -248,6 +248,10 @@ "rule8" = 'icons/UI_Icons/Achievements/Misc/rule8.png', "snail" = 'icons/UI_Icons/Achievements/Misc/snail.png', "ascension" = 'icons/UI_Icons/Achievements/Misc/ascension.png', + "ashascend" = 'icons/UI_Icons/Achievements/Misc/ashascend.png', + "fleshascend" = 'icons/UI_Icons/Achievements/Misc/fleshascend.png', + "rustascend" = 'icons/UI_Icons/Achievements/Misc/rustascend.png', + "voidascend" = 'icons/UI_Icons/Achievements/Misc/voidascend.png', "mining" = 'icons/UI_Icons/Achievements/Skills/mining.png', "assistant" = 'icons/UI_Icons/Achievements/Mafia/assistant.png', "changeling" = 'icons/UI_Icons/Achievements/Mafia/changeling.png', @@ -288,7 +292,7 @@ ) /datum/asset/spritesheet/simple/pills - name ="pills" + name = "pills" assets = list( "pill1" = 'icons/UI_Icons/Pills/pill1.png', "pill2" = 'icons/UI_Icons/Pills/pill2.png', @@ -313,7 +317,28 @@ "pill21" = 'icons/UI_Icons/Pills/pill21.png', "pill22" = 'icons/UI_Icons/Pills/pill22.png', ) - +/* +/datum/asset/spritesheet/simple/condiments + name = "condiments" + assets = list( + CONDIMASTER_STYLE_FALLBACK = 'icons/UI_Icons/Condiments/emptycondiment.png', + "enzyme" = 'icons/UI_Icons/Condiments/enzyme.png', + "flour" = 'icons/UI_Icons/Condiments/flour.png', + "mayonnaise" = 'icons/UI_Icons/Condiments/mayonnaise.png', + "milk" = 'icons/UI_Icons/Condiments/milk.png', + "blackpepper" = 'icons/UI_Icons/Condiments/peppermillsmall.png', + "rice" = 'icons/UI_Icons/Condiments/rice.png', + "sodiumchloride" = 'icons/UI_Icons/Condiments/saltshakersmall.png', + "soymilk" = 'icons/UI_Icons/Condiments/soymilk.png', + "soysauce" = 'icons/UI_Icons/Condiments/soysauce.png', + "sugar" = 'icons/UI_Icons/Condiments/sugar.png', + "ketchup" = 'icons/UI_Icons/Condiments/ketchup.png', + "capsaicin" = 'icons/UI_Icons/Condiments/hotsauce.png', + "frostoil" = 'icons/UI_Icons/Condiments/coldsauce.png', + "bbqsauce" = 'icons/UI_Icons/Condiments/bbqsauce.png', + "cornoil" = 'icons/UI_Icons/Condiments/oliveoil.png', + ) +*/ //this exists purely to avoid meta by pre-loading all language icons. /datum/asset/language/register() for(var/path in typesof(/datum/language)) @@ -484,3 +509,31 @@ /datum/asset/spritesheet/mafia/register() InsertAll("", 'icons/obj/mafia.dmi') ..() + +/datum/asset/simple/portraits + var/tab = "use subtypes of this please" + assets = list() + +/datum/asset/simple/portraits/New() + if(!SSpersistence.paintings || !SSpersistence.paintings[tab] || !length(SSpersistence.paintings[tab])) + return + for(var/p in SSpersistence.paintings[tab]) + var/list/portrait = p + var/png = "data/paintings/[tab]/[portrait["md5"]].png" + if(fexists(png)) + assets[portrait["title"]] = png + ..() //this is where it registers all these assets we added to the list + +/datum/asset/simple/portraits/library + tab = "library" + +/datum/asset/simple/portraits/library_secure + tab = "library_secure" + +/datum/asset/simple/portraits/library_private + tab = "library_private" + +/datum/asset/simple/safe + assets = list( + "safe_dial.png" = 'html/safe_dial.png' + ) diff --git a/code/modules/asset_cache/readme.md b/code/modules/asset_cache/readme.md index 82e6bea896..c8c9d78b71 100644 --- a/code/modules/asset_cache/readme.md +++ b/code/modules/asset_cache/readme.md @@ -24,7 +24,7 @@ Call .get_url_mappings() to get an associated list with the urls your assets can See the documentation for `/datum/asset_transport` for the backend api the asset datums utilize. -The global variable `SSassets.transport` contains the currently configured transport. +The global variable `SSassets.transport` contains the currently configured transport. @@ -32,6 +32,6 @@ The global variable `SSassets.transport` contains the currently configured trans Because byond browse() calls use non-blocking queues, if your code uses output() (which bypasses all of these queues) to invoke javascript functions you will need to first have the javascript announce to the server it has loaded before trying to invoke js functions. -To make your code work with any CDNs configured by the server, you must make sure assets are referenced from the url returned by `get_url_mappings()` or by asset_transport's `get_asset_url()`. (TGUI also has helpers for this.) If this can not be easily done, you can bypass the cdn using legacy assets, see the simple asset datum for details. +To make your code work with any CDNs configured by the server, you must make sure assets are referenced from the url returned by `get_url_mappings()` or by asset_transport's `get_asset_url()`. (TGUI also has helpers for this.) If this can not be easily done, you can bypass the cdn using legacy assets, see the simple asset datum for details. CSS files that use url() can be made to use the CDN without needing to rewrite all url() calls in code by using the namespaced helper datum. See the documentation for `/datum/asset/simple/namespaced` for details. diff --git a/code/modules/atmospherics/environmental/LINDA_turf_tile.dm b/code/modules/atmospherics/environmental/LINDA_turf_tile.dm index eee8859485..244b51bd2b 100644 --- a/code/modules/atmospherics/environmental/LINDA_turf_tile.dm +++ b/code/modules/atmospherics/environmental/LINDA_turf_tile.dm @@ -49,6 +49,7 @@ SSair.add_to_active(T) return ..() +/// Function for Extools Atmos /turf/proc/update_air_ref() /////////////////GAS MIXTURE PROCS/////////////////// diff --git a/code/modules/atmospherics/machinery/atmosmachinery.dm b/code/modules/atmospherics/machinery/atmosmachinery.dm index 25e4084524..7f4a8cd794 100644 --- a/code/modules/atmospherics/machinery/atmosmachinery.dm +++ b/code/modules/atmospherics/machinery/atmosmachinery.dm @@ -44,7 +44,7 @@ . = ..() if(is_type_in_list(src, GLOB.ventcrawl_machinery) && isliving(user)) var/mob/living/L = user - if(L.ventcrawler) + if(SEND_SIGNAL(L, COMSIG_CHECK_VENTCRAWL)) . += "Alt-click to crawl through it." /obj/machinery/atmospherics/New(loc, process = TRUE, setdir) @@ -318,7 +318,7 @@ /obj/machinery/atmospherics/AltClick(mob/living/L) if(is_type_in_typecache(src, GLOB.ventcrawl_machinery)) - return L.handle_ventcrawl(src) + return SEND_SIGNAL(L, COMSIG_HANDLE_VENTCRAWL, src) return ..() diff --git a/code/modules/atmospherics/machinery/portable/canister.dm b/code/modules/atmospherics/machinery/portable/canister.dm index 0eebf22be4..2690ad555b 100644 --- a/code/modules/atmospherics/machinery/portable/canister.dm +++ b/code/modules/atmospherics/machinery/portable/canister.dm @@ -261,7 +261,7 @@ new /obj/item/stack/sheet/metal (loc, 5) qdel(src) -obj/machinery/portable_atmospherics/canister/welder_act(mob/living/user, obj/item/I) +/obj/machinery/portable_atmospherics/canister/welder_act(mob/living/user, obj/item/I) ..() if(user.a_intent == INTENT_HARM) return FALSE diff --git a/code/modules/atmospherics/multiz.dm b/code/modules/atmospherics/multiz.dm index 79a5c2cf14..cb52d03ff6 100644 --- a/code/modules/atmospherics/multiz.dm +++ b/code/modules/atmospherics/multiz.dm @@ -1,4 +1,5 @@ -obj/machinery/atmospherics/pipe/simple/multiz ///This is an atmospherics pipe which can relay air up a deck (Z+1). It currently only supports being on pipe layer 1 +/// This is an atmospherics pipe which can relay air up/down a deck. +/obj/machinery/atmospherics/pipe/simple/multiz name = "multi deck pipe adapter" desc = "An adapter which allows pipes to connect to other pipenets on different decks." icon_state = "multiz_pipe" @@ -24,6 +25,4 @@ obj/machinery/atmospherics/pipe/simple/multiz ///This is an atmospherics pipe wh if(above) nodes += above above.nodes += src //Two way travel :) - return ..() - else - return ..() + return ..() diff --git a/code/modules/awaymissions/capture_the_flag.dm b/code/modules/awaymissions/capture_the_flag.dm index 3426208fae..d32905e007 100644 --- a/code/modules/awaymissions/capture_the_flag.dm +++ b/code/modules/awaymissions/capture_the_flag.dm @@ -7,6 +7,8 @@ #define AMMO_DROP_LIFETIME 300 #define CTF_REQUIRED_PLAYERS 4 + + /obj/item/ctf name = "banner" icon = 'icons/obj/items_and_weapons.dmi' @@ -16,13 +18,13 @@ righthand_file = 'icons/mob/inhands/equipment/banners_righthand.dmi' desc = "A banner with Nanotrasen's logo on it." slowdown = 2 - item_flags = SLOWS_WHILE_IN_HAND throw_speed = 0 throw_range = 1 force = 200 armour_penetration = 1000 resistance_flags = INDESTRUCTIBLE anchored = TRUE + item_flags = SLOWS_WHILE_IN_HAND var/team = WHITE_TEAM var/reset_cooldown = 0 var/anyonecanpickup = TRUE @@ -53,12 +55,13 @@ to_chat(M, "\The [src] has been returned to base!") STOP_PROCESSING(SSobj, src) -/obj/item/ctf/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) +//ATTACK HAND IGNORING PARENT RETURN VALUE +/obj/item/ctf/on_attack_hand(mob/living/user) if(!is_ctf_target(user) && !anyonecanpickup) - to_chat(user, "Non players shouldn't be moving the flag!") + to_chat(user, "Non-players shouldn't be moving the flag!") return if(team in user.faction) - to_chat(user, "You can't move your own flag!") + to_chat(user, "You can't move your own flag!") return if(loc == user) if(!user.dropItemToGround(src)) @@ -68,7 +71,7 @@ if(!user.put_in_active_hand(src)) dropped(user) return - user.anchored = TRUE + user.set_anchored(TRUE) user.status_flags &= ~CANPUSH for(var/mob/M in GLOB.player_list) var/area/mob_area = get_area(M) @@ -79,7 +82,7 @@ /obj/item/ctf/dropped(mob/user) ..() - user.anchored = FALSE + user.set_anchored(FALSE) user.status_flags |= CANPUSH reset_cooldown = world.time + 200 //20 seconds START_PROCESSING(SSobj, src) @@ -172,20 +175,20 @@ GLOB.poi_list.Remove(src) ..() -/obj/machinery/capture_the_flag/process() +/obj/machinery/capture_the_flag/process(delta_time) for(var/i in spawned_mobs) if(!i) spawned_mobs -= i continue // Anyone in crit, automatically reap - var/mob/living/M = i - if(M.InCritical() || M.stat == DEAD) - ctf_dust_old(M) + var/mob/living/living_participant = i + if(living_participant.InCritical() || living_participant.stat == DEAD) + ctf_dust_old(living_participant) else // The changes that you've been hit with no shield but not // instantly critted are low, but have some healing. - M.adjustBruteLoss(-5) - M.adjustFireLoss(-5) + living_participant.adjustBruteLoss(-2.5 * delta_time) + living_participant.adjustFireLoss(-2.5 * delta_time) /obj/machinery/capture_the_flag/red name = "Red CTF Controller" @@ -212,6 +215,10 @@ toggle_all_ctf(user) return + + // if(!(GLOB.ghost_role_flags & GHOSTROLE_MINIGAME)) + // to_chat(user, "CTF has been temporarily disabled by admins.") + // return people_who_want_to_play |= user.ckey var/num = people_who_want_to_play.len var/remaining = CTF_REQUIRED_PLAYERS - num @@ -227,7 +234,7 @@ return if(user.ckey in team_members) if(user.ckey in recently_dead_ckeys) - to_chat(user, "It must be more than [DisplayTimeText(respawn_cooldown)] from your last death to respawn!") + to_chat(user, "It must be more than [DisplayTimeText(respawn_cooldown)] from your last death to respawn!") return var/client/new_team_member = user.client if(user.mind && user.mind.current) @@ -239,10 +246,10 @@ if(CTF == src || CTF.ctf_enabled == FALSE) continue if(user.ckey in CTF.team_members) - to_chat(user, "No switching teams while the round is going!") + to_chat(user, "No switching teams while the round is going!") return if(CTF.team_members.len < src.team_members.len) - to_chat(user, "[src.team] has more team members than [CTF.team]. Try joining [CTF.team] team to even things up.") + to_chat(user, "[src.team] has more team members than [CTF.team]! Try joining [CTF.team] team to even things up.") return team_members |= user.ckey var/client/new_team_member = user.client @@ -258,7 +265,7 @@ addtimer(CALLBACK(src, .proc/clear_cooldown, body.ckey), respawn_cooldown, TIMER_UNIQUE) body.dust() -/obj/machinery/capture_the_flag/proc/clear_cooldown(var/ckey) +/obj/machinery/capture_the_flag/proc/clear_cooldown(ckey) recently_dead_ckeys -= ckey /obj/machinery/capture_the_flag/proc/spawn_team_member(client/new_team_member) @@ -270,7 +277,7 @@ M.equipOutfit(ctf_gear) M.dna.species.punchdamagehigh = 25 M.dna.species.punchdamagelow = 25 - M.AddElement(/datum/element/ghost_role_eligibility) + M.AddElement(/datum/element/ghost_role_eligibility) //?? spawned_mobs += M /obj/machinery/capture_the_flag/Topic(href, href_list) @@ -293,14 +300,15 @@ victory() /obj/machinery/capture_the_flag/proc/victory() - for(var/mob/M in GLOB.mob_list) - var/area/mob_area = get_area(M) + for(var/mob/_competitor in GLOB.mob_living_list) + var/mob/living/competitor = _competitor + var/area/mob_area = get_area(competitor) if(istype(mob_area, /area/ctf)) - to_chat(M, "[team] team wins!") - to_chat(M, "Teams have been cleared. Click on the machines to vote to begin another round.") - for(var/obj/item/ctf/W in M) - M.dropItemToGround(W) - M.dust() + to_chat(competitor, "[team] team wins!") + to_chat(competitor, "Teams have been cleared. Click on the machines to vote to begin another round.") + for(var/obj/item/ctf/W in competitor) + competitor.dropItemToGround(W) + competitor.dust() for(var/obj/machinery/control_point/control in GLOB.machines) control.icon_state = "dominator" control.controlling = null @@ -328,7 +336,7 @@ dead_barricades.Cut() - notify_ghosts("[name] has been activated!", enter_link="(Click to join the [team] team!) or click on the controller directly!", source = src, action=NOTIFY_ATTACK) + notify_ghosts("[name] has been activated!", enter_link="(Click to join the [team] team!) or click on the controller directly!", source = src, action=NOTIFY_ATTACK, header = "CTF has been activated") if(!arena_reset) reset_the_arena() @@ -355,10 +363,10 @@ ctf_enabled = FALSE arena_reset = FALSE var/area/A = get_area(src) - for(var/i in GLOB.mob_list) - var/mob/M = i - if((get_area(A) == A) && (M.ckey in team_members)) - M.dust() + for(var/_competitor in GLOB.mob_living_list) + var/mob/living/competitor = _competitor + if((get_area(A) == A) && (competitor.ckey in team_members)) + competitor.dust() team_members.Cut() spawned_mobs.Cut() recently_dead_ckeys.Cut() @@ -375,18 +383,18 @@ CTF.ctf_gear = initial(ctf_gear) CTF.respawn_cooldown = DEFAULT_RESPAWN -/proc/ctf_floor_vanish(atom/target) - if(isturf(target.loc)) - qdel(target) - /obj/item/gun/ballistic/automatic/pistol/deagle/ctf desc = "This looks like it could really hurt in melee." force = 75 mag_type = /obj/item/ammo_box/magazine/m50/ctf -/obj/item/gun/ballistic/automatic/pistol/deagle/ctf/dropped(mob/user) +/obj/item/gun/ballistic/automatic/pistol/deagle/ctf/dropped() . = ..() - addtimer(CALLBACK(GLOBAL_PROC, /proc/ctf_floor_vanish, src), 1) + addtimer(CALLBACK(src, .proc/floor_vanish), 1) + +/obj/item/gun/ballistic/automatic/pistol/deagle/ctf/proc/floor_vanish() + if(isturf(loc)) + qdel(src) /obj/item/ammo_box/magazine/m50/ctf ammo_type = /obj/item/ammo_casing/a50/ctf @@ -400,6 +408,7 @@ /obj/item/projectile/bullet/ctf/prehit(atom/target) if(is_ctf_target(target)) damage = 60 + return //PROJECTILE_PIERCE_NONE /// hey uhh don't hit anyone behind them . = ..() /obj/item/gun/ballistic/automatic/laser/ctf @@ -407,16 +416,24 @@ desc = "This looks like it could really hurt in melee." force = 50 -/obj/item/gun/ballistic/automatic/laser/ctf/dropped(mob/user) +/obj/item/gun/ballistic/automatic/laser/ctf/dropped() . = ..() - addtimer(CALLBACK(GLOBAL_PROC, /proc/ctf_floor_vanish, src), 1) + addtimer(CALLBACK(src, .proc/floor_vanish), 1) + +/obj/item/gun/ballistic/automatic/laser/ctf/proc/floor_vanish() + if(isturf(loc)) + qdel(src) /obj/item/ammo_box/magazine/recharge/ctf ammo_type = /obj/item/ammo_casing/caseless/laser/ctf -/obj/item/ammo_box/magazine/recharge/ctf/dropped(mob/user) +/obj/item/ammo_box/magazine/recharge/ctf/dropped() . = ..() - addtimer(CALLBACK(GLOBAL_PROC, /proc/ctf_floor_vanish, src), 1) + addtimer(CALLBACK(src, .proc/floor_vanish), 1) + +/obj/item/ammo_box/magazine/recharge/ctf/proc/floor_vanish() + if(isturf(loc)) + qdel(src) /obj/item/ammo_casing/caseless/laser/ctf projectile_type = /obj/item/projectile/beam/ctf @@ -428,15 +445,16 @@ /obj/item/projectile/beam/ctf/prehit(atom/target) if(is_ctf_target(target)) damage = 150 + return //PROJECTILE_PIERCE_NONE /// hey uhhh don't hit anyone behind them . = ..() /proc/is_ctf_target(atom/target) . = FALSE if(istype(target, /obj/structure/barricade/security/ctf)) . = TRUE - if(isliving(target)) - var/mob/living/H = target - if((RED_TEAM in H.faction) || (BLUE_TEAM in H.faction)) + if(ishuman(target)) + var/mob/living/carbon/human/H = target + if(istype(H.wear_suit, /obj/item/clothing/suit/space/hardsuit/shielded/ctf)) . = TRUE // RED TEAM GUNS @@ -482,7 +500,11 @@ /obj/item/claymore/ctf/dropped(mob/user) . = ..() - addtimer(CALLBACK(GLOBAL_PROC, /proc/ctf_floor_vanish, src), 1) + addtimer(CALLBACK(src, .proc/floor_vanish), 1) + +/obj/item/claymore/ctf/proc/floor_vanish() + if(isturf(loc)) + qdel(src) /datum/outfit/ctf name = "CTF" @@ -491,27 +513,28 @@ suit = /obj/item/clothing/suit/space/hardsuit/shielded/ctf toggle_helmet = FALSE // see the whites of their eyes shoes = /obj/item/clothing/shoes/combat - gloves = /obj/item/clothing/gloves/tackler/combat + gloves = /obj/item/clothing/gloves/combat + id = /obj/item/card/id/away belt = /obj/item/gun/ballistic/automatic/pistol/deagle/ctf l_pocket = /obj/item/ammo_box/magazine/recharge/ctf r_pocket = /obj/item/ammo_box/magazine/recharge/ctf r_hand = /obj/item/gun/ballistic/automatic/laser/ctf back = /obj/item/claymore/ctf -/datum/outfit/ctf/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) +/datum/outfit/ctf/post_equip(mob/living/carbon/human/H, visualsOnly=FALSE) if(visualsOnly) return var/list/no_drops = list() var/obj/item/card/id/W = H.wear_id no_drops += W W.registered_name = H.real_name - W.update_label(W.registered_name, W.assignment) + W.update_label() - // The shielded hardsuit is already TRAIT_NODROP - no_drops += H.get_item_by_slot(SLOT_GLOVES) - no_drops += H.get_item_by_slot(SLOT_SHOES) - no_drops += H.get_item_by_slot(SLOT_W_UNIFORM) - no_drops += H.get_item_by_slot(SLOT_EARS) + no_drops += H.get_item_by_slot(ITEM_SLOT_OCLOTHING) + no_drops += H.get_item_by_slot(ITEM_SLOT_GLOVES) + no_drops += H.get_item_by_slot(ITEM_SLOT_FEET) + no_drops += H.get_item_by_slot(ITEM_SLOT_ICLOTHING) + no_drops += H.get_item_by_slot(ITEM_SLOT_EARS) for(var/i in no_drops) var/obj/item/I = i ADD_TRAIT(I, TRAIT_NODROP, CAPTURE_THE_FLAG_TRAIT) @@ -525,6 +548,7 @@ r_hand = /obj/item/gun/ballistic/automatic/laser/ctf/red l_pocket = /obj/item/ammo_box/magazine/recharge/ctf/red r_pocket = /obj/item/ammo_box/magazine/recharge/ctf/red + id = /obj/item/card/id/syndicate_command //it's red /datum/outfit/ctf/red/instagib r_hand = /obj/item/gun/energy/laser/instakill/red @@ -535,12 +559,13 @@ r_hand = /obj/item/gun/ballistic/automatic/laser/ctf/blue l_pocket = /obj/item/ammo_box/magazine/recharge/ctf/blue r_pocket = /obj/item/ammo_box/magazine/recharge/ctf/blue + id = /obj/item/card/id/centcom //it's blue /datum/outfit/ctf/blue/instagib r_hand = /obj/item/gun/energy/laser/instakill/blue shoes = /obj/item/clothing/shoes/jackboots/fast -/datum/outfit/ctf/red/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) +/datum/outfit/ctf/red/post_equip(mob/living/carbon/human/H) ..() var/obj/item/radio/R = H.ears R.set_frequency(FREQ_CTF_RED) @@ -548,7 +573,7 @@ R.independent = TRUE H.dna.species.stunmod = 0 -/datum/outfit/ctf/blue/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) +/datum/outfit/ctf/blue/post_equip(mob/living/carbon/human/H) ..() var/obj/item/radio/R = H.ears R.set_frequency(FREQ_CTF_BLUE) @@ -595,6 +620,10 @@ /obj/structure/barricade/security/ctf/make_debris() new /obj/effect/ctf/dead_barricade(get_turf(src)) +/obj/structure/table/reinforced/ctf + resistance_flags = INDESTRUCTIBLE + flags_1 = NODECONSTRUCT_1 + /obj/effect/ctf density = FALSE anchored = TRUE @@ -617,10 +646,11 @@ QDEL_IN(src, AMMO_DROP_LIFETIME) /obj/effect/ctf/ammo/Crossed(atom/movable/AM) + . = ..() reload(AM) -/obj/effect/ctf/ammo/Bump(atom/movable/AM) - reload(AM) +/obj/effect/ctf/ammo/Bump(atom/A) + reload(A) /obj/effect/ctf/ammo/Bumped(atom/movable/AM) reload(AM) @@ -636,7 +666,7 @@ qdel(G) O.equip(M) to_chat(M, "Ammunition reloaded!") - playsound(get_turf(M), 'sound/weapons/shotgunpump.ogg', 50, 1, -1) + playsound(get_turf(M), 'sound/weapons/shotgunpump.ogg', 50, TRUE, -1) qdel(src) break @@ -667,18 +697,18 @@ resistance_flags = INDESTRUCTIBLE var/obj/machinery/capture_the_flag/controlling var/team = "none" - var/point_rate = 1 + var/point_rate = 0.5 -/obj/machinery/control_point/process() +/obj/machinery/control_point/process(delta_time) if(controlling) - controlling.control_points += point_rate + controlling.control_points += point_rate * delta_time if(controlling.control_points >= controlling.control_points_to_win) controlling.victory() /obj/machinery/control_point/attackby(mob/user, params) capture(user) -/obj/machinery/control_point/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) +/obj/machinery/control_point/on_attack_hand(mob/user) capture(user) /obj/machinery/control_point/proc/capture(mob/user) diff --git a/code/modules/awaymissions/corpse.dm b/code/modules/awaymissions/corpse.dm index e68c45a84c..cd5c2f76f3 100644 --- a/code/modules/awaymissions/corpse.dm +++ b/code/modules/awaymissions/corpse.dm @@ -66,7 +66,7 @@ /obj/effect/mob_spawn/Initialize(mapload) . = ..() if(instant || (roundstart && (mapload || (SSticker && SSticker.current_state > GAME_STATE_SETTING_UP)))) - create() + INVOKE_ASYNC(src, .proc/create) else if(ghost_usable) GLOB.poi_list |= src LAZYADD(GLOB.mob_spawners[job_description ? job_description : name], src) diff --git a/code/modules/awaymissions/mission_code/Academy.dm b/code/modules/awaymissions/mission_code/Academy.dm index 129e6d7a2b..98e7f4c292 100644 --- a/code/modules/awaymissions/mission_code/Academy.dm +++ b/code/modules/awaymissions/mission_code/Academy.dm @@ -196,7 +196,7 @@ /obj/item/dice/d20/fate/proc/effect(var/mob/living/carbon/human/user,roll) if(!reusable) used = 1 - visible_message("The die flare briefly.") + visible_message("The die flares briefly.") switch(roll) if(1) //Dust diff --git a/code/modules/awaymissions/mission_code/wildwest.dm b/code/modules/awaymissions/mission_code/wildwest.dm index f13341faf3..bc7e2cbd08 100644 --- a/code/modules/awaymissions/mission_code/wildwest.dm +++ b/code/modules/awaymissions/mission_code/wildwest.dm @@ -132,6 +132,7 @@ var/triggered = 0 /obj/effect/meatgrinder/Crossed(atom/movable/AM) + . = ..() Bumped(AM) /obj/effect/meatgrinder/Bumped(atom/movable/AM) diff --git a/code/modules/cargo/bounties/reagent.dm b/code/modules/cargo/bounties/reagent.dm index 391b4ff464..57501beab3 100644 --- a/code/modules/cargo/bounties/reagent.dm +++ b/code/modules/cargo/bounties/reagent.dm @@ -35,7 +35,7 @@ name = "Simple Drink" reward = 1500 -datum/bounty/reagent/simple_drink/New() +/datum/bounty/reagent/simple_drink/New() // Don't worry about making this comprehensive. It doesn't matter if some drinks are skipped. var/static/list/possible_reagents = list(\ /datum/reagent/consumable/ethanol/antifreeze,\ @@ -91,7 +91,7 @@ datum/bounty/reagent/simple_drink/New() name = "Complex Drink" reward = 4000 -datum/bounty/reagent/complex_drink/New() +/datum/bounty/reagent/complex_drink/New() // Don't worry about making this comprehensive. It doesn't matter if some drinks are skipped. var/static/list/possible_reagents = list(\ /datum/reagent/consumable/ethanol/atomicbomb,\ @@ -124,7 +124,7 @@ datum/bounty/reagent/complex_drink/New() reward = 2750 required_volume = 30 -datum/bounty/reagent/chemical/New() +/datum/bounty/reagent/chemical/New() // Don't worry about making this comprehensive. It doesn't matter if some chems are skipped. var/static/list/possible_reagents = list(\ /datum/reagent/medicine/leporazine,\ diff --git a/code/modules/cargo/exports/gear.dm b/code/modules/cargo/exports/gear.dm index 678948128f..8e93fc5fc3 100644 --- a/code/modules/cargo/exports/gear.dm +++ b/code/modules/cargo/exports/gear.dm @@ -473,7 +473,7 @@ //Soft Suits //Blanket -datum/export/gear/space/helmet +/datum/export/gear/space/helmet cost = 55 unit_name = "space helmet" export_types = list(/obj/item/clothing/head/helmet/space) @@ -485,7 +485,7 @@ datum/export/gear/space/helmet export_types = list(/obj/item/clothing/suit/space) include_subtypes = TRUE -datum/export/gear/space/helmet/plasma +/datum/export/gear/space/helmet/plasma cost = 100 unit_name = "plasmaman space helmet" export_types = list(/obj/item/clothing/suit/space/eva/plasmaman) @@ -495,7 +495,7 @@ datum/export/gear/space/helmet/plasma unit_name = "plasmaman space suit" export_types = list(/obj/item/clothing/suit/space/eva/plasmaman) -datum/export/gear/space/helmet/synda +/datum/export/gear/space/helmet/synda cost = 150 //Flash proof unit_name = "syndicate space helmet" export_types = list(/obj/item/clothing/head/helmet/space/syndicate) @@ -510,7 +510,7 @@ datum/export/gear/space/helmet/synda //Glasses //Blanket -datum/export/gear/glasses //glasses are not worth selling +/datum/export/gear/glasses //glasses are not worth selling cost = 3 unit_name = "glasses" export_types = list(/obj/item/clothing/glasses) diff --git a/code/modules/chatter/chatter.dm b/code/modules/chatter/chatter.dm index 2dfd0bd77d..3da2b32a67 100644 --- a/code/modules/chatter/chatter.dm +++ b/code/modules/chatter/chatter.dm @@ -38,7 +38,7 @@ var/path = "sound/chatter/[phomeme]_[length].ogg" playsound(loc, path, - vol = 40, vary = 0, extrarange = 3, falloff = FALSE) + vol = 40, vary = 0, extrarange = 3) sleep((length + 1) * chatter_get_sleep_multiplier(phomeme)) diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm index b71521121b..241cd6be93 100644 --- a/code/modules/client/client_defines.dm +++ b/code/modules/client/client_defines.dm @@ -31,6 +31,7 @@ var/datum/preferences/prefs = null var/last_turn = 0 var/move_delay = 0 + var/last_move = 0 var/area = null /// Last time we Click()ed. No clicking twice in one tick! diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index c298d150f8..5f567f1360 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -147,6 +147,8 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( /client/proc/handle_statpanel_click(list/href_list) var/atom/target = locate(href_list["statpanel_item_target"]) + if(!target) + return Click(target, target.loc, null, "[href_list["statpanel_item_shiftclick"]?"shift=1;":null][href_list["statpanel_item_ctrlclick"]?"ctrl=1;":null]&alt=[href_list["statpanel_item_altclick"]?"alt=1;":null]", FALSE, "statpanel") /client/proc/is_content_unlocked() @@ -496,7 +498,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( GLOB.directory -= ckey log_access("Logout: [key_name(src)]") GLOB.ahelp_tickets.ClientLogout(src) - // SSserver_maint.UpdateHubStatus() + SSserver_maint.UpdateHubStatus() if(credits) QDEL_LIST(credits) if(holder) @@ -642,7 +644,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( query_log_connection.Execute() qdel(query_log_connection) - // SSserver_maint.UpdateHubStatus() + SSserver_maint.UpdateHubStatus() if(new_player) player_age = -1 diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 7c6ba30b80..7cc8be800c 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -895,19 +895,23 @@ GLOBAL_LIST_EMPTY(preferences_datums) continue var/class_link = "" var/list/loadout_item = has_loadout_gear(loadout_slot, "[gear.type]") - var/extra_color_data = "" + var/extra_loadout_data = "" if(loadout_item) class_link = "style='white-space:normal;' class='linkOn' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(name)];toggle_gear=0'" if(gear.loadout_flags & LOADOUT_CAN_COLOR_POLYCHROMIC) - extra_color_data += "
    Color" + extra_loadout_data += "
    Color" for(var/loadout_color in loadout_item[LOADOUT_COLOR]) - extra_color_data += "   " + extra_loadout_data += "   " else var/loadout_color_non_poly = "#FFFFFF" if(length(loadout_item[LOADOUT_COLOR])) loadout_color_non_poly = loadout_item[LOADOUT_COLOR][1] - extra_color_data += "
    Color" - extra_color_data += "   " + extra_loadout_data += "
    Color" + extra_loadout_data += "   " + if(gear.loadout_flags & LOADOUT_CAN_NAME) + extra_loadout_data += "
    Name [loadout_item[LOADOUT_CUSTOM_NAME] ? loadout_item[LOADOUT_CUSTOM_NAME] : "N/A"]" + if(gear.loadout_flags & LOADOUT_CAN_DESCRIPTION) + extra_loadout_data += "
    Description" else if((gear_points - gear.cost) < 0) class_link = "style='white-space:normal;' class='linkOff'" else if(donoritem) @@ -916,7 +920,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) class_link = "style='white-space:normal;' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(name)];toggle_gear=1'" else class_link = "style='white-space:normal;background:#eb2e2e;' class='linkOff'" - dat += "[name][extra_color_data]" + dat += "[name][extra_loadout_data]" dat += "[gear.cost]" if(islist(gear.restricted_roles)) if(gear.restricted_roles.len) @@ -929,14 +933,15 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += gear.restricted_roles.Join(";") dat += "
    " if(!istype(gear, /datum/gear/unlockable)) - dat += "[gear.description]" + // the below line essentially means "if the loadout item is picked by the user and has a custom description, give it the custom description, otherwise give it the default description" + dat += "[loadout_item ? (loadout_item[LOADOUT_CUSTOM_DESCRIPTION] ? loadout_item[LOADOUT_CUSTOM_DESCRIPTION] : gear.description) : gear.description]" else //we add the user's progress to the description assuming they have progress var/datum/gear/unlockable/unlockable = gear var/progress_made = unlockable_loadout_data[unlockable.progress_key] if(!progress_made) progress_made = 0 - dat += "[gear.description] Progress: [min(progress_made, unlockable.progress_required)]/[unlockable.progress_required]" + dat += "[loadout_item ? (loadout_item[LOADOUT_CUSTOM_DESCRIPTION] ? loadout_item[LOADOUT_CUSTOM_DESCRIPTION] : gear.description) : gear.description] Progress: [min(progress_made, unlockable.progress_required)]/[unlockable.progress_required]" dat += "" if(4) // Content preferences @@ -2700,7 +2705,9 @@ GLOBAL_LIST_EMPTY(preferences_datums) loadout_data["SAVE_[loadout_slot]"] += list(new_loadout_data) //double packed because it does the union of the CONTENTS of the lists else loadout_data["SAVE_[loadout_slot]"] = list(new_loadout_data) //double packed because you somehow had no save slot in your loadout? - if(href_list["loadout_color"]) + + if(href_list["loadout_color"] || href_list["loadout_color_polychromic"] || href_list["loadout_rename"] || href_list["loadout_redescribe"]) + //if the gear doesn't exist, or they don't have it, ignore the request var/name = html_decode(href_list["loadout_gear_name"]) var/datum/gear/G = GLOB.loadout_items[gear_category][gear_subcategory][name] if(!G) @@ -2708,29 +2715,44 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/user_gear = has_loadout_gear(loadout_slot, "[G.type]") if(!user_gear) return - if(!length(user_gear[LOADOUT_COLOR])) - user_gear[LOADOUT_COLOR] = list("#FFFFFF") - var/current_color = user_gear[LOADOUT_COLOR][1] - var/new_color = input(user, "Polychromic options", "Choose Color", current_color) as color|null - user_gear[LOADOUT_COLOR][1] = sanitize_hexcolor(new_color, 6, TRUE, current_color) - if(href_list["loadout_color_polychromic"]) - var/name = html_decode(href_list["loadout_gear_name"]) - var/datum/gear/G = GLOB.loadout_items[gear_category][gear_subcategory][name] - if(!G) - return - var/user_gear = has_loadout_gear(loadout_slot, "[G.type]") - if(!user_gear) - return - var/list/color_options = list() - for(var/i=1, i<=length(G.loadout_initial_colors), i++) - color_options += "Color [i]" - var/color_to_change = input(user, "Polychromic options", "Recolor [name]") as null|anything in color_options - if(color_to_change) - var/color_index = text2num(copytext(color_to_change, 7)) - var/current_color = user_gear[LOADOUT_COLOR][color_index] - var/new_color = input(user, "Polychromic options", "Choose [color_to_change] Color", current_color) as color|null - if(new_color) - user_gear[LOADOUT_COLOR][color_index] = sanitize_hexcolor(new_color, 6, TRUE, current_color) + + //possible requests: recolor, recolor (polychromic), rename, redescribe + //always make sure the gear allows said request before proceeding + + //non-poly coloring can only be done by non-poly items + if(href_list["loadout_color"] && !(G.loadout_flags & LOADOUT_CAN_COLOR_POLYCHROMIC)) + if(!length(user_gear[LOADOUT_COLOR])) + user_gear[LOADOUT_COLOR] = list("#FFFFFF") + var/current_color = user_gear[LOADOUT_COLOR][1] + var/new_color = input(user, "Polychromic options", "Choose Color", current_color) as color|null + user_gear[LOADOUT_COLOR][1] = sanitize_hexcolor(new_color, 6, TRUE, current_color) + + //poly coloring can only be done by poly items + if(href_list["loadout_color_polychromic"] && (G.loadout_flags & LOADOUT_CAN_COLOR_POLYCHROMIC)) + var/list/color_options = list() + for(var/i=1, i<=length(G.loadout_initial_colors), i++) + color_options += "Color [i]" + var/color_to_change = input(user, "Polychromic options", "Recolor [name]") as null|anything in color_options + if(color_to_change) + var/color_index = text2num(copytext(color_to_change, 7)) + var/current_color = user_gear[LOADOUT_COLOR][color_index] + var/new_color = input(user, "Polychromic options", "Choose [color_to_change] Color", current_color) as color|null + if(new_color) + user_gear[LOADOUT_COLOR][color_index] = sanitize_hexcolor(new_color, 6, TRUE, current_color) + + //both renaming and redescribing strip the input to stop html injection + + //renaming is only allowed if it has the flag for it + if(href_list["loadout_rename"] && (G.loadout_flags & LOADOUT_CAN_NAME)) + var/new_name = stripped_input(user, "Enter new name for item. Maximum [MAX_NAME_LEN] characters.", "Loadout Item Naming", null, MAX_NAME_LEN) + if(new_name) + user_gear[LOADOUT_CUSTOM_NAME] = new_name + + //redescribing is only allowed if it has the flag for it + if(href_list["loadout_redescribe"] && (G.loadout_flags & LOADOUT_CAN_DESCRIPTION)) //redescribe isnt a real word but i can't think of the right term to use + var/new_description = stripped_input(user, "Enter new description for item. Maximum 500 characters.", "Loadout Item Redescribing", null, 500) + if(new_description) + user_gear[LOADOUT_CUSTOM_DESCRIPTION] = new_description ShowChoices(user) return 1 diff --git a/code/modules/clothing/gloves/miscellaneous.dm b/code/modules/clothing/gloves/miscellaneous.dm index af55c6b9d7..c069649848 100644 --- a/code/modules/clothing/gloves/miscellaneous.dm +++ b/code/modules/clothing/gloves/miscellaneous.dm @@ -36,7 +36,7 @@ /obj/item/clothing/gloves/fingerless/pugilist/equipped(mob/user, slot) . = ..() - if(current_equipped_slot == SLOT_GLOVES) + if(slot == SLOT_GLOVES) use_buffs(user, TRUE) wornonce = TRUE diff --git a/code/modules/clothing/masks/gasmask.dm b/code/modules/clothing/masks/gasmask.dm index 15a5345ad1..525db577e0 100644 --- a/code/modules/clothing/masks/gasmask.dm +++ b/code/modules/clothing/masks/gasmask.dm @@ -17,7 +17,7 @@ /obj/item/clothing/mask/gas/examine(mob/user) . = ..() if(flavor_adjust) - . += "Alt-click to toggle identity concealment. it's currently [flags_inv & HIDEFACE ? "on" : "off"]." + . += "Alt-click to toggle identity concealment. It's currently [flags_inv & HIDEFACE ? "on" : "off"]." /obj/item/clothing/mask/gas/AltClick(mob/user) . = ..() @@ -143,14 +143,17 @@ "Blanc" = image(icon = src.icon, icon_state = "mime"), "Excité" = image(icon = src.icon, icon_state = "sexymime"), "Triste" = image(icon = src.icon, icon_state = "sadmime"), - "Effrayé" = image(icon = src.icon, icon_state = "scaredmime") + "Effrayé" = image(icon = src.icon, icon_state = "scaredmime"), + "Timid Woman" = image(icon = src.icon, icon_state = "timidwoman"), + "Timid Man" = image(icon = src.icon, icon_state = "timidman") ) /obj/item/clothing/mask/gas/mime/ui_action_click(mob/user) if(!istype(user) || user.incapacitated()) return - var/static/list/options = list("Blanc" = "mime", "Triste" = "sadmime", "Effrayé" = "scaredmime", "Excité" ="sexymime") + var/static/list/options = list("Blanc" = "mime", "Triste" = "sadmime", "Effrayé" = "scaredmime", "Excité" ="sexymime", + "Timid Woman" = "timidwoman", "Timid Man" = "timidman") var/choice = show_radial_menu(user,src, mimemask_designs, custom_check = FALSE, radius = 36, require_near = TRUE) @@ -170,6 +173,20 @@ item_state = "sexymime" actions_types = list() +/obj/item/clothing/mask/gas/timidcostume + name = "timid woman mask" + desc = "Most people who wear these are not really that timid." + clothing_flags = ALLOWINTERNALS + icon_state = "timidwoman" + item_state = "timidwoman" + flags_cover = MASKCOVERSEYES + resistance_flags = FLAMMABLE + +/obj/item/clothing/mask/gas/timidcostume/man + name = "timid man mask" + icon_state = "timidman" + item_state = "timidman" + /obj/item/clothing/mask/gas/monkeymask name = "monkey mask" desc = "A mask used when acting as a monkey." diff --git a/code/modules/clothing/masks/miscellaneous.dm b/code/modules/clothing/masks/miscellaneous.dm index 5dd35788f1..fc4185f207 100644 --- a/code/modules/clothing/masks/miscellaneous.dm +++ b/code/modules/clothing/masks/miscellaneous.dm @@ -33,6 +33,16 @@ actions_types = list(/datum/action/item_action/adjust) mutantrace_variation = STYLE_MUZZLE +/obj/item/clothing/mask/surgical/aesthetic + name = "aesthetic sterile mask" + desc = "A sterile mask designed to help prevent the spread of diseases. This one doesn't seem like it does a whole lot, somehow." + flags_inv = HIDEFACE + flags_cover = null + visor_flags_inv = null + visor_flags_cover = null + permeability_coefficient = 1 + armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0) + /obj/item/clothing/mask/surgical/attack_self(mob/user) adjustmask(user) diff --git a/code/modules/clothing/neck/_neck.dm b/code/modules/clothing/neck/_neck.dm index 51a526d089..b0af7aa0d5 100644 --- a/code/modules/clothing/neck/_neck.dm +++ b/code/modules/clothing/neck/_neck.dm @@ -237,6 +237,12 @@ icon_state = "choker" poly_colors = list("#222222") +/obj/item/clothing/neck/necklace/cowbell + name = "cowbell collar" + desc = "Who would wear this? Take this off, you aren't a cow, you're just an awful degenerate." + icon = 'icons/obj/clothing/neck.dmi' + icon_state = "cowbell" + /obj/item/key/collar name = "Collar Key" desc = "A key for a tiny lock on a collar or bag." @@ -289,7 +295,7 @@ //VERY SUPER BADASS NECKERCHIEFS// ////////////////////////////////// -obj/item/clothing/neck/neckerchief +/obj/item/clothing/neck/neckerchief icon = 'icons/obj/clothing/masks.dmi' //In order to reuse the bandana sprite w_class = WEIGHT_CLASS_TINY var/sourceBandanaType diff --git a/code/modules/clothing/shoes/miscellaneous.dm b/code/modules/clothing/shoes/miscellaneous.dm index b0d760ebd9..d99d52666b 100644 --- a/code/modules/clothing/shoes/miscellaneous.dm +++ b/code/modules/clothing/shoes/miscellaneous.dm @@ -413,6 +413,22 @@ var/wallcharges = 4 var/newlocobject = null +/obj/item/clothing/shoes/timidcostume + name = "timid woman boots" + desc = "Ready to rock your hips back and forth? These boots have a polychromic finish." + icon_state = "timidwoman" + item_state = "timidwoman" + +/obj/item/clothing/shoes/timidcostume/ComponentInitialize() + . = ..() + AddElement(/datum/element/polychromic, list("#0094FF"), 1) + +/obj/item/clothing/shoes/timidcostume/man + name = "timid man shoes" + desc = "Ready to go kart racing? These shoes have a polychromic finish." + icon_state = "timidman" + item_state = "timidman" + /obj/item/clothing/shoes/wallwalkers/equipped(mob/user,slot) . = ..() if(slot == SLOT_SHOES) diff --git a/code/modules/clothing/suits/miscellaneous.dm b/code/modules/clothing/suits/miscellaneous.dm index 6dfcd72c10..a47d55bfcb 100644 --- a/code/modules/clothing/suits/miscellaneous.dm +++ b/code/modules/clothing/suits/miscellaneous.dm @@ -1088,6 +1088,36 @@ icon_state = "winterhood_poly" item_state = "winterhood_poly" +/obj/item/clothing/suit/hooded/wintercoat/timidcostume + name = "timid woman hoodie" + desc = "A snug, tight yet warm outfit with belts wrapped around it. Looks to be made of polychromic materials." + icon_state = "timidwoman" + item_state = "timidwoman" + hoodtype = /obj/item/clothing/head/hooded/winterhood/timidcostume + +/obj/item/clothing/suit/hooded/wintercoat/timidcostume/ComponentInitialize() + . = ..() + AddElement(/datum/element/polychromic, list("#EB0C07", "#5E2400", "#CEA100"), 3) + +/obj/item/clothing/head/hooded/winterhood/timidcostume + name = "timid woman hood" + desc = "A hood attached to the hoodie." + icon_state = "timidwoman" + item_state = "timidwoman" + +/obj/item/clothing/suit/hooded/wintercoat/timidcostume/man + name = "timid man hoodie" + desc = "A snug, tight yet warm outfit a belt wrapped around it. Looks to be made of polychromic materials." + icon_state = "timidman" + item_state = "timidman" + hoodtype = /obj/item/clothing/head/hooded/winterhood/timidcostume/man + +/obj/item/clothing/head/hooded/winterhood/timidcostume/man + name = "timid man hood" + icon_state = "timidman" + item_state = "timidman" + + /obj/item/clothing/suit/striped_sweater name = "striped sweater" desc = "Reminds you of someone, but you just can't put your finger on it..." diff --git a/code/modules/clothing/suits/toggles.dm b/code/modules/clothing/suits/toggles.dm index f496468371..aa22834670 100644 --- a/code/modules/clothing/suits/toggles.dm +++ b/code/modules/clothing/suits/toggles.dm @@ -58,6 +58,12 @@ RemoveHood() /obj/item/clothing/suit/hooded/proc/ToggleHood() + if(!hood) + to_chat(loc, "[src] seems to be missing its hood..") + return + if(atom_colours) + hood.atom_colours = atom_colours.Copy() + hood.update_atom_colour() if(!suittoggled) if(ishuman(src.loc)) var/mob/living/carbon/human/H = src.loc @@ -191,7 +197,11 @@ if(!helmettype) return if(!helmet) + to_chat(H, "[src] seems to be missing its helmet..") return + if(atom_colours) + helmet.atom_colours = atom_colours.Copy() + helmet.update_atom_colour() if(!suittoggled) if(ishuman(src.loc)) if(H.wear_suit != src) diff --git a/code/modules/clothing/under/accessories.dm b/code/modules/clothing/under/accessories.dm index ee7e4c48e1..ba66bf6e26 100644 --- a/code/modules/clothing/under/accessories.dm +++ b/code/modules/clothing/under/accessories.dm @@ -79,13 +79,175 @@ if(initial(above_suit)) . += "\The [src] can be worn above or below your suit. Alt-click to toggle." +////////////// +//Waistcoats// +////////////// + /obj/item/clothing/accessory/waistcoat - name = "waistcoat" + name = "black waistcoat" desc = "For some classy, murderous fun." icon_state = "waistcoat" item_state = "waistcoat" minimize_when_attached = FALSE +/obj/item/clothing/accessory/waistcoat/red + name = "red waistcoat" + icon_state = "waistcoat_red" + item_state = "waistcoat_red" + +/obj/item/clothing/accessory/waistcoat/grey + name = "grey waistcoat" + icon_state = "waistcoat_grey" + item_state = "waistcoat_grey" + +/obj/item/clothing/accessory/waistcoat/brown + name = "red waistcoat" + icon_state = "waistcoat_brown" + item_state = "waistcoat_brown" + +/obj/item/clothing/accessory/waistcoat/sweatervest + name = "black sweatervest" + icon_state = "sweatervest" + item_state = "sweatervest" + +/obj/item/clothing/accessory/waistcoat/sweatervest/blue + name = "blue sweatervest" + icon_state = "sweatervest_blue" + item_state = "sweatervest_blue" + +/obj/item/clothing/accessory/waistcoat/sweatervest/red + name = "red sweatervest" + icon_state = "sweatervest_red" + item_state = "sweatervest_red" + +//////////// +//Sweaters// +//////////// + +/obj/item/clothing/accessory/sweater + name = "grey sweater" + desc = "Nicely comfy and warm!" + icon_state = "sweater" + item_state = "sweater" + minimize_when_attached = FALSE + +/obj/item/clothing/accessory/sweater/pink + name = "pink sweater" + icon_state = "sweater_pink" + item_state = "sweater_pink" + +/obj/item/clothing/accessory/sweater/heart + name = "heart sweater" + icon_state = "sweater_heart" + item_state = "sweater_heart" + +/obj/item/clothing/accessory/sweater/blue + name = "blue sweater" + icon_state = "sweater_blue" + item_state = "sweater_blue" + +/obj/item/clothing/accessory/sweater/nt + name = "nanotrasen sweater" + icon_state = "sweater_nt" + item_state = "sweater_nt" + +/obj/item/clothing/accessory/sweater/mint + name = "mint sweater" + icon_state = "sweater_mint" + item_state = "sweater_mint" + +/obj/item/clothing/accessory/sweater/shoulderless + name = "shoulderless sweater" + icon_state = "sweater_shoulderless" + item_state = "sweater_shoulderless" + +/obj/item/clothing/accessory/sweater/uglyxmas + name = "ugly xmas sweater" + icon_state = "sweater_uglyxmas" + item_state = "sweater_uglyxmas" + +/obj/item/clothing/accessory/sweater/uglyxmas + name = "ugly xmas sweater" + icon_state = "sweater_uglyxmas" + item_state = "sweater_uglyxmas" + +/obj/item/clothing/accessory/sweater/flower + name = "flower sweater" + icon_state = "sweater_uglyxmas" + item_state = "sweater_uglyxmas" + +//////////////// +//Suit Jackets// +//////////////// + +/obj/item/clothing/accessory/suitjacket + name = "tan suit jacket" + desc = "For those times when you have to attend a fancy business meeting without wearing your pants." + icon_state = "jacket_tan" + item_state = "jacket_tan" + minimize_when_attached = FALSE + +/obj/item/clothing/accessory/suitjacket/charcoal + name = "charcoal suit jacket" + icon_state = "jacket_charcoal" + item_state = "jacket_charcoal" + +/obj/item/clothing/accessory/suitjacket/navy + name = "navy suit jacket" + icon_state = "jacket_navy" + item_state = "jacket_navy" + +/obj/item/clothing/accessory/suitjacket/burgundy + name = "burgundy suit jacket" + icon_state = "jacket_burgundy" + item_state = "jacket_burgundy" + +/obj/item/clothing/accessory/suitjacket/checkered + name = "checkered suit jacket" + icon_state = "jacket_checkered" + item_state = "jacket_checkered" + +/////////////////////// +//Tactical Turtlnecks// +/////////////////////// + +/obj/item/clothing/accessory/turtleneck + name = "black turtleneck" + desc = "Extra cool. Extra fool." + icon_state = "turtleneck" + item_state = "turtleneck" + minimize_when_attached = FALSE + +/obj/item/clothing/accessory/turtleneck/red + name = "red turtleneck" + icon_state = "turtleneck_red" + item_state = "turtleneck_red" + +/obj/item/clothing/accessory/turtleneck/tactifool + name = "black sweaterneck" + desc = "Extra fool. Extra cool." + icon_state = "tactifool" + item_state = "tactifool" + +/obj/item/clothing/accessory/turtleneck/tactifool/green + name = "green sweaterneck" + icon_state = "tactifool_green" + item_state = "tactifool_green" + +/obj/item/clothing/accessory/turtleneck/tactifool/blue + name = "blue sweaterneck" + icon_state = "tactifool_blue" + item_state = "tactifool_blue" + +/obj/item/clothing/accessory/turtleneck/tactifool/syndicate + name = "tactifool sweaterneck" + icon_state = "tactifool_syndicate" + item_state = "tactifool_syndicate" + +///////////////// +//Miscellaneous// +///////////////// + /obj/item/clothing/accessory/maidapron name = "maid apron" desc = "The best part of a maid costume." diff --git a/code/modules/events/_event.dm b/code/modules/events/_event.dm index 40ce543d31..10f8c60386 100644 --- a/code/modules/events/_event.dm +++ b/code/modules/events/_event.dm @@ -92,7 +92,7 @@ log_admin_private("[key_name(usr)] cancelled event [name].") SSblackbox.record_feedback("tally", "event_admin_cancelled", 1, typepath) -/datum/round_event_control/proc/runEvent() +/datum/round_event_control/proc/runEvent(random = FALSE) var/datum/round_event/E = new typepath() E.current_players = get_active_player_count(alive_check = 1, afk_check = 1, human_check = 1) E.control = src diff --git a/code/modules/events/immovable_rod.dm b/code/modules/events/immovable_rod.dm index 06318df4f5..90ebe7f6a1 100644 --- a/code/modules/events/immovable_rod.dm +++ b/code/modules/events/immovable_rod.dm @@ -144,22 +144,23 @@ In my current plan for it, 'solid' will be defined as anything with density == 1 if(L && (L.density || prob(10))) L.ex_act(EXPLODE_HEAVY) -obj/effect/immovablerod/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) - if(ishuman(user)) - var/mob/living/carbon/human/U = user - if(U.job in list("Research Director")) - playsound(src, 'sound/effects/meteorimpact.ogg', 100, 1) - for(var/mob/M in urange(8, src)) - if(!M.stat) - shake_camera(M, 2, 3) - if(wizard) - U.visible_message("[src] transforms into [wizard] as [U] suplexes them!", "As you grab [src], it suddenly turns into [wizard] as you suplex them!") - to_chat(wizard, "You're suddenly jolted out of rod-form as [U] somehow manages to grab you, slamming you into the ground!") - wizard.Stun(60) - wizard.apply_damage(25, BRUTE) - qdel(src) - else - U.visible_message("[U] suplexes [src] into the ground!", "You suplex [src] into the ground!") - new /obj/structure/festivus/anchored(drop_location()) - new /obj/effect/anomaly/flux(drop_location()) - qdel(src) +/obj/effect/immovablerod/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) + if(!ishuman(user)) + return + var/mob/living/carbon/human/U = user + if(U.job in list("Research Director")) + playsound(src, 'sound/effects/meteorimpact.ogg', 100, TRUE) + for(var/mob/M in urange(8, src)) + if(!M.stat) + shake_camera(M, 2, 3) + if(wizard) + U.visible_message("[src] transforms into [wizard] as [U] suplexes them!", "As you grab [src], it suddenly turns into [wizard] as you suplex them!") + to_chat(wizard, "You're suddenly jolted out of rod-form as [U] somehow manages to grab you, slamming you into the ground!") + wizard.Stun(60) + wizard.apply_damage(25, BRUTE) + qdel(src) + else + U.visible_message("[U] suplexes [src] into the ground!", "You suplex [src] into the ground!") + new /obj/structure/festivus/anchored(drop_location()) + new /obj/effect/anomaly/flux(drop_location()) + qdel(src) diff --git a/code/modules/events/spacevine.dm b/code/modules/events/spacevine.dm index 7cf11848e8..edc062f78f 100644 --- a/code/modules/events/spacevine.dm +++ b/code/modules/events/spacevine.dm @@ -340,6 +340,7 @@ playsound(src.loc, 'sound/items/welder.ogg', 100, TRUE) /obj/structure/spacevine/Crossed(atom/movable/AM) + . = ..() if(!isliving(AM)) return for(var/datum/spacevine_mutation/SM in mutations) diff --git a/code/modules/events/travelling_trader.dm b/code/modules/events/travelling_trader.dm index eeb1acdba5..2f7b9dbea5 100644 --- a/code/modules/events/travelling_trader.dm +++ b/code/modules/events/travelling_trader.dm @@ -25,14 +25,14 @@ var/datum/effect_system/smoke_spread/smoke = new smoke.set_up(1, spawn_location) smoke.start() - trader.visible_message("[src] suddenly appears in a puff of smoke!") + trader.visible_message("[trader] suddenly appears in a puff of smoke!") /datum/round_event/travelling_trader/announce(fake) priority_announce("A mysterious figure has been detected on sensors at [get_area(spawn_location)]", "Mysterious Figure") /datum/round_event/travelling_trader/end() - if(trader) - trader.visible_message("The [src] has given up on waiting!") + if(trader) // the /datum/round_event/travelling_trader has given up on waiting! + trader.visible_message("The [trader] has given up on waiting!") qdel(trader) //the actual trader mob @@ -99,7 +99,7 @@ new reward(get_turf(src)) /mob/living/carbon/human/dummy/travelling_trader/Initialize() - ..() + . = ..() // return a hint you fuck add_atom_colour("#570d6b", FIXED_COLOUR_PRIORITY) //make them purple (otherworldly!) set_light(1, -0.7, "#AAD84B") ADD_TRAIT(src,TRAIT_PIERCEIMMUNE, "trader_pierce_immune") //don't let people take their blood @@ -188,18 +188,18 @@ /mob/living/simple_animal/hostile/netherworld/blankbody = 1, /mob/living/simple_animal/hostile/retaliate/goose = 1) -mob/living/carbon/human/dummy/travelling_trader/animal_hunter/Initialize() +/mob/living/carbon/human/dummy/travelling_trader/animal_hunter/Initialize() + . = ..() acceptance_speech = pick(list("This lifeform shall make for a great stew, thank you.", "This lifeform shall be of a true use to our cause, thank you.", "The lifeform is adequate. Goodbye.", "This lifeform shall make a great addition to my collection.")) - ..() -/mob/living/carbon/human/dummy/travelling_trader/animal_hunter/check_item(var/obj/item/supplied_item) //item is likely to be in contents of whats supplied +/mob/living/carbon/human/dummy/travelling_trader/animal_hunter/check_item(obj/item/supplied_item) //item is likely to be in contents of whats supplied for(var/atom/something in supplied_item.contents) if(istype(something, requested_item)) qdel(something) //typically things holding mobs release the mob when the container is deleted, so delete the mob first here return TRUE return FALSE -/mob/living/carbon/human/dummy/travelling_trader/animal_hunter/give_reward(var/mob/giver) //the reward is actually given in a jar, because releasing it onto the station might be a bad idea +/mob/living/carbon/human/dummy/travelling_trader/animal_hunter/give_reward(mob/giver) //the reward is actually given in a jar, because releasing it onto the station might be a bad idea var/obj/item/pet_carrier/bluespace/jar = new(get_turf(src)) var/chosen_animal = pickweight(possible_rewards) var/mob/living/new_animal = new chosen_animal(jar) @@ -223,6 +223,7 @@ mob/living/carbon/human/dummy/travelling_trader/animal_hunter/Initialize() /obj/structure/reagent_dispensers/keg/quintuple_sec = 3) /mob/living/carbon/human/dummy/travelling_trader/bartender/Initialize() //pick a subtype of ethanol that isn't found in the default set of the booze dispensers reagents + . = ..() // RETURN A HINT. requested_item = pick(subtypesof(/datum/reagent/consumable/ethanol) - list(/datum/reagent/consumable/ethanol/beer, /datum/reagent/consumable/ethanol/kahlua, /datum/reagent/consumable/ethanol/whiskey, @@ -242,7 +243,6 @@ mob/living/carbon/human/dummy/travelling_trader/animal_hunter/Initialize() /datum/reagent/consumable/ethanol/triple_sec, /datum/reagent/consumable/ethanol/sake, /datum/reagent/consumable/ethanol/applejack)) - ..() /mob/living/carbon/human/dummy/travelling_trader/bartender/check_item(var/obj/item/supplied_item) //you need to check its reagents if(istype(supplied_item, /obj/item/reagent_containers)) diff --git a/code/modules/fields/fields.dm b/code/modules/fields/fields.dm index 8710282021..cb8d3e8dcf 100644 --- a/code/modules/fields/fields.dm +++ b/code/modules/fields/fields.dm @@ -16,7 +16,7 @@ if(!F.check_variables() && !override_checks) QDEL_NULL(F) if(start_field && (F || override_checks)) - F.Initialize() + F.begin_field() return F /datum/proximity_monitor/advanced @@ -78,11 +78,11 @@ /datum/proximity_monitor/advanced/proc/process_edge_turf(turf/T) -/datum/proximity_monitor/advanced/New() +/datum/proximity_monitor/advanced/New(atom/_host, range, _ignore_if_not_on_turf = TRUE) if(requires_processing) START_PROCESSING(SSfields, src) -/datum/proximity_monitor/advanced/proc/Initialize() +/datum/proximity_monitor/advanced/proc/begin_field() setup_field() post_setup_field() @@ -154,7 +154,7 @@ var/atom/_host = host var/atom/new_host_loc = _host.loc if(last_host_loc != new_host_loc) - recalculate_field() + INVOKE_ASYNC(src, .proc/recalculate_field) /datum/proximity_monitor/advanced/proc/post_setup_field() @@ -302,7 +302,7 @@ /obj/item/multitool/field_debug/attack_self(mob/user) operating = !operating - to_chat(user, "You turn [src] [operating? "on":"off"].") + to_chat(user, "You turn [src] [operating? "on":"off"].") UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED) listeningTo = null if(!istype(current) && operating) @@ -312,13 +312,15 @@ else if(!operating) QDEL_NULL(current) -/obj/item/multitool/field_debug/dropped(mob/user) +/obj/item/multitool/field_debug/dropped() . = ..() if(listeningTo) UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED) listeningTo = null /obj/item/multitool/field_debug/proc/on_mob_move() + SIGNAL_HANDLER + check_turf(get_turf(src)) /obj/item/multitool/field_debug/process() diff --git a/code/modules/fields/timestop.dm b/code/modules/fields/timestop.dm index 56abef8cd6..a96a44a789 100644 --- a/code/modules/fields/timestop.dm +++ b/code/modules/fields/timestop.dm @@ -33,7 +33,7 @@ if(G.summoner && locate(/obj/effect/proc_holder/spell/aoe_turf/timestop) in G.summoner.mind.spell_list) //It would only make sense that a person's stand would also be immune. immune[G] = TRUE if(start) - timestop() + INVOKE_ASYNC(src, .proc/timestop) /obj/effect/timestop/Destroy() qdel(chronofield) @@ -42,7 +42,7 @@ /obj/effect/timestop/proc/timestop() target = get_turf(src) - playsound(src, 'sound/magic/timeparadox2.ogg', 75, 1, -1) + playsound(src, 'sound/magic/timeparadox2.ogg', 75, TRUE, -1) chronofield = make_field(/datum/proximity_monitor/advanced/timestop, list("current_range" = freezerange, "host" = src, "immune" = immune, "check_anti_magic" = check_anti_magic, "check_holy" = check_holy)) QDEL_IN(src, duration) @@ -112,6 +112,8 @@ unfreeze_turf(T) /datum/proximity_monitor/advanced/timestop/proc/unfreeze_atom(atom/movable/A) + SIGNAL_HANDLER + if(A.throwing) unfreeze_throwing(A) if(isliving(A)) @@ -128,12 +130,14 @@ frozen_things -= A global_frozen_atoms -= A + /datum/proximity_monitor/advanced/timestop/proc/freeze_mecha(obj/mecha/M) M.completely_disabled = TRUE /datum/proximity_monitor/advanced/timestop/proc/unfreeze_mecha(obj/mecha/M) M.completely_disabled = FALSE + /datum/proximity_monitor/advanced/timestop/proc/freeze_throwing(atom/movable/AM) var/datum/thrownthing/T = AM.throwing T.paused = TRUE @@ -160,7 +164,7 @@ /datum/proximity_monitor/advanced/timestop/process() for(var/i in frozen_mobs) var/mob/living/m = i - m.Stun(20, 1, 1) + m.Stun(20, ignore_canstun = TRUE) /datum/proximity_monitor/advanced/timestop/setup_field_turf(turf/T) for(var/i in T.contents) @@ -168,6 +172,7 @@ freeze_turf(T) return ..() + /datum/proximity_monitor/advanced/timestop/proc/freeze_projectile(obj/item/projectile/P) P.paused = TRUE @@ -176,18 +181,18 @@ /datum/proximity_monitor/advanced/timestop/proc/freeze_mob(mob/living/L) frozen_mobs += L - L.Stun(20, 1, 1) + L.Stun(20, ignore_canstun = TRUE) ADD_TRAIT(L, TRAIT_MUTE, TIMESTOP_TRAIT) walk(L, 0) //stops them mid pathing even if they're stunimmune if(isanimal(L)) var/mob/living/simple_animal/S = L S.toggle_ai(AI_OFF) - if(ishostile(L)) - var/mob/living/simple_animal/hostile/H = L - H.LoseTarget() + if(ishostile(L)) + var/mob/living/simple_animal/hostile/H = L + H.LoseTarget() /datum/proximity_monitor/advanced/timestop/proc/unfreeze_mob(mob/living/L) - L.AdjustStun(-20, 1, 1) + L.AdjustStun(-20, ignore_canstun = TRUE) REMOVE_TRAIT(L, TRAIT_MUTE, TIMESTOP_TRAIT) frozen_mobs -= L if(isanimal(L)) diff --git a/code/modules/fields/turf_objects.dm b/code/modules/fields/turf_objects.dm index d37036d83c..1af924294a 100644 --- a/code/modules/fields/turf_objects.dm +++ b/code/modules/fields/turf_objects.dm @@ -24,11 +24,12 @@ desc = "Get off my turf!" /obj/effect/abstract/proximity_checker/advanced/field_turf/CanPass(atom/movable/AM, turf/target) + . = ..() if(parent) return parent.field_turf_canpass(AM, src, target) - return TRUE /obj/effect/abstract/proximity_checker/advanced/field_turf/Crossed(atom/movable/AM) + . = ..() if(parent) return parent.field_turf_crossed(AM, src) return TRUE @@ -48,11 +49,12 @@ desc = "Edgy description here." /obj/effect/abstract/proximity_checker/advanced/field_edge/CanPass(atom/movable/AM, turf/target) + . = ..() if(parent) return parent.field_edge_canpass(AM, src, target) - return TRUE /obj/effect/abstract/proximity_checker/advanced/field_edge/Crossed(atom/movable/AM) + . = ..() if(parent) return parent.field_edge_crossed(AM, src) return TRUE diff --git a/code/modules/flufftext/Hallucination.dm b/code/modules/flufftext/Hallucination.dm index 56c96c3559..cc18207a29 100644 --- a/code/modules/flufftext/Hallucination.dm +++ b/code/modules/flufftext/Hallucination.dm @@ -139,10 +139,11 @@ GLOBAL_LIST_INIT(hallucination_list, list( Show() /obj/effect/hallucination/simple/Moved(atom/OldLoc, Dir) + . = ..() Show() /obj/effect/hallucination/simple/Destroy() - if(target && target.client) + if(target?.client) target.client.images.Remove(current_image) active = FALSE return ..() @@ -1093,6 +1094,7 @@ GLOBAL_LIST_INIT(hallucination_list, list( target.client.images += image /obj/effect/hallucination/danger/lava/Crossed(atom/movable/AM) + . = ..() if(AM == target) target.adjustStaminaLoss(20) new /datum/hallucination/fire(target) diff --git a/code/modules/food_and_drinks/drinks/drinks.dm b/code/modules/food_and_drinks/drinks/drinks.dm index 07039139bf..807251111a 100644 --- a/code/modules/food_and_drinks/drinks/drinks.dm +++ b/code/modules/food_and_drinks/drinks/drinks.dm @@ -17,10 +17,7 @@ var/isGlass = TRUE //Whether the 'bottle' is made of glass or not so that milk cartons dont shatter when someone gets hit by it /obj/item/reagent_containers/food/drinks/on_reagent_change(changetype) - if (gulp_size < 5) - gulp_size = 5 - else - gulp_size = max(round(reagents.total_volume / 5), 5) + gulp_size = max(round(reagents.total_volume / 5), 5) /obj/item/reagent_containers/food/drinks/attack(mob/living/M, mob/user, def_zone) if(!reagents || !reagents.total_volume) diff --git a/code/modules/food_and_drinks/drinks/drinks/drinkingglass.dm b/code/modules/food_and_drinks/drinks/drinks/drinkingglass.dm index 8e5069925f..9602c1d24e 100644 --- a/code/modules/food_and_drinks/drinks/drinks/drinkingglass.dm +++ b/code/modules/food_and_drinks/drinks/drinks/drinkingglass.dm @@ -52,10 +52,7 @@ /obj/item/reagent_containers/food/drinks/drinkingglass/shotglass/on_reagent_change(changetype) cut_overlays() - if (gulp_size < 15) - gulp_size = 15 - else - gulp_size = max(round(reagents.total_volume / 15), 15) + gulp_size = max(round(reagents.total_volume / 15), 15) if (reagents.reagent_list.len > 0) var/datum/reagent/largest_reagent = reagents.get_master_reagent() diff --git a/code/modules/food_and_drinks/food/snacks_cake.dm b/code/modules/food_and_drinks/food/snacks_cake.dm index be07826a7f..67ac2ee59b 100644 --- a/code/modules/food_and_drinks/food/snacks_cake.dm +++ b/code/modules/food_and_drinks/food/snacks_cake.dm @@ -308,7 +308,7 @@ tastes = list("cake" = 5, "sweetness" = 1, "clouds" = 1) foodtype = GRAIN | DAIRY | SUGAR -obj/item/reagent_containers/food/snacks/store/cake/pound_cake +/obj/item/reagent_containers/food/snacks/store/cake/pound_cake name = "pound cake" desc = "A condensed cake made for filling people up quickly." icon_state = "pound_cake" diff --git a/code/modules/food_and_drinks/kitchen_machinery/microwave.dm b/code/modules/food_and_drinks/kitchen_machinery/microwave.dm index 6bdf3cff8e..5954788d5c 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/microwave.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/microwave.dm @@ -151,10 +151,13 @@ to_chat(user, "You need more space cleaner!") return TRUE - if(istype(O, /obj/item/soap)) - var/obj/item/soap/P = O + if(istype(O, /obj/item/soap) || istype(O, /obj/item/reagent_containers/rag)) + var/cleanspeed = 50 + if(istype(O, /obj/item/soap)) + var/obj/item/soap/used_soap = O + cleanspeed = used_soap.cleanspeed user.visible_message("[user] starts to clean \the [src].", "You start to clean \the [src]...") - if(do_after(user, P.cleanspeed, target = src)) + if(do_after(user, cleanspeed, target = src)) user.visible_message("[user] has cleaned \the [src].", "You clean \the [src].") dirty = 0 update_icon() diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_donut.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_donut.dm index c376ab4025..3d3b1ac0fd 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_donut.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_donut.dm @@ -21,7 +21,7 @@ ) result = /obj/item/reagent_containers/food/snacks/donut/chaos -datum/crafting_recipe/food/donut/meat +/datum/crafting_recipe/food/donut/meat time = 15 name = "Meat donut" reqs = list( diff --git a/code/modules/holiday/halloween/jacqueen.dm b/code/modules/holiday/halloween/jacqueen.dm index 90016954fc..4212a2e296 100644 --- a/code/modules/holiday/halloween/jacqueen.dm +++ b/code/modules/holiday/halloween/jacqueen.dm @@ -50,16 +50,18 @@ var/cached_z /// I'm busy, don't move. var/busy = FALSE + var/static/blacklisted_items = typecacheof(list( - /obj/effect, - /obj/belly, - /obj/mafia_game_board, - /obj/docking_port, - /obj/shapeshift_holder, - /obj/screen)) + /obj/effect, + /obj/belly, + /obj/mafia_game_board, + /obj/docking_port, + /obj/shapeshift_holder, + /obj/screen + )) /mob/living/simple_animal/jacq/Initialize() - ..() + . = ..() //fuck you jacq, return a hint you shit cached_z = z poof() @@ -158,23 +160,18 @@ return FALSE /mob/living/simple_animal/jacq/proc/gender_check(mob/living/carbon/C) - var/gender = "lamb" - if(C) - if(C.gender == MALE) - gender = "laddie" - if(C.gender == FEMALE) - gender = "lassie" - return gender + . = "lamb" + switch(C) + if(MALE) + . = "laddie" + if(FEMALE) + . = "lassie" //Ye wee bugger, gerrout of it. Ye've nae tae enjoy reading the code fer mae secrets like. /mob/living/simple_animal/jacq/proc/chit_chat(mob/living/carbon/C) //Very important var/gender = gender_check(C) - if(C) - if(C.gender == MALE) - gender = "laddie" - if(C.gender == FEMALE) - gender = "lassie" + // it physicaly cannot fail*. Why is there a fucking dupe if(!progression["[C.real_name]"] || !(progression["[C.real_name]"] & JACQ_HELLO)) visible_message("[src] smiles ominously at [C], \"Well halo there [gender]! Ah'm Jacqueline, tae great Pumpqueen, great tae meet ye.\"") diff --git a/code/modules/hydroponics/grown/cotton.dm b/code/modules/hydroponics/grown/cotton.dm index beff751479..daaf71c626 100644 --- a/code/modules/hydroponics/grown/cotton.dm +++ b/code/modules/hydroponics/grown/cotton.dm @@ -34,16 +34,14 @@ /obj/item/grown/cotton/attack_self(mob/user) user.show_message("You pull some [cotton_name] out of the [name]!", MSG_VISUAL) - var/seed_modifier = 0 - if(seed) - seed_modifier = round(seed.potency / 25) - var/obj/item/stack/cotton = new cotton_type(user.loc, 1 + seed_modifier) - var/old_cotton_amount = cotton.amount - for(var/obj/item/stack/ST in user.loc) - if(ST != cotton && istype(ST, cotton_type) && ST.amount < ST.max_amount) - ST.attackby(cotton, user) - if(cotton.amount > old_cotton_amount) - to_chat(user, "You add the newly-formed [cotton_name] to the stack. It now contains [cotton.amount] [cotton_name].") + var/cottonAmt = 1 + round(seed.potency / 25) // cotton inhand we're holding + for(var/obj/item/grown/cotton/ctn in user.loc) // cotton on the floor + if(ctn.type != type) + continue + cottonAmt += 1 + round(ctn.seed.potency / 25) + qdel(ctn) + new cotton_type(user.drop_location(), cottonAmt) + // above code stolen from grass qdel(src) //reinforced mutated variant diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm index 8467d00124..24f65756c8 100644 --- a/code/modules/hydroponics/hydroponics.dm +++ b/code/modules/hydroponics/hydroponics.dm @@ -92,6 +92,11 @@ return BULLET_ACT_HIT else if(istype(Proj , /obj/item/projectile/energy/florayield)) return myseed.bullet_act(Proj) + else if(istype(Proj , /obj/item/projectile/energy/florarevolution)) + if(myseed) + if(myseed.mutatelist.len > 0) + myseed.instability = (myseed.instability/2) + mutatespecie() else return ..() @@ -384,7 +389,6 @@ /obj/machinery/hydroponics/proc/hardmutate() mutate(4, 10, 2, 4, 50, 4, 10, 3) - /obj/machinery/hydroponics/proc/mutatespecie() // Mutagent produced a new plant! if(!myseed || dead) return @@ -600,7 +604,34 @@ desc = initial(desc) weedlevel = 0 //Has a side effect of cleaning up those nasty weeds update_icon() - + else if(istype(O, /obj/item/gun/energy/floragun)) + var/obj/item/gun/energy/floragun/flowergun = O + if(flowergun.cell.charge < flowergun.cell.maxcharge) + to_chat(user, "[flowergun] must be fully charged to lock in a mutation!") + return + if(!myseed) + to_chat(user, "[src] is empty!") + return + if(myseed.endurance <= 20) + to_chat(user, "[myseed.plantname] isn't hardy enough to sequence its mutation!") + return + if(!myseed.mutatelist) + to_chat(user, "[myseed.plantname] has nothing else to mutate into!") + return + else + var/list/fresh_mut_list = list() + for(var/muties in myseed.mutatelist) + var/obj/item/seeds/another_mut = new muties + fresh_mut_list[another_mut.plantname] = muties + var/locked_mutation = (input(user, "Select a mutation to lock.", "Plant Mutation Locks") as null|anything in sortList(fresh_mut_list)) + if(!user.canUseTopic(src, BE_CLOSE) || !locked_mutation) + return + myseed.mutatelist = list(fresh_mut_list[locked_mutation]) + myseed.endurance = (myseed.endurance/2) + flowergun.cell.use(flowergun.cell.charge) + flowergun.update_icon() + to_chat(user, "[myseed.plantname]'s mutation was set to [locked_mutation], depleting [flowergun]'s cell!") + return else return ..() diff --git a/code/modules/hydroponics/seeds.dm b/code/modules/hydroponics/seeds.dm index 2dc80cd8fc..d8082e667d 100644 --- a/code/modules/hydroponics/seeds.dm +++ b/code/modules/hydroponics/seeds.dm @@ -24,7 +24,7 @@ var/yield = 3 // Amount of growns created per harvest. If is -1, the plant/shroom/weed is never meant to be harvested. var/potency = 10 // The 'power' of a plant. Generally effects the amount of reagent in a plant, also used in other ways. var/growthstages = 6 // Amount of growth sprites the plant has. - var/instability = 5 //Chance that a plant will mutate in each stage of it's life. + var/instability = 5 //Chance that a plant will mutate in each stage of it's life. var/rarity = 0 // How rare the plant is. Used for giving points to cargo when shipping off to CentCom. var/list/mutatelist = list() // The type of plants that this plant can mutate into. var/list/genes = list() // Plant genes are stored here, see plant_genes.dm for more info. @@ -105,7 +105,7 @@ S.reagents_add = reagents_add.Copy() // Faster than grabbing the list from genes. return S -obj/item/seeds/proc/is_gene_forbidden(typepath) +/obj/item/seeds/proc/is_gene_forbidden(typepath) return (typepath in forbiddengenes) diff --git a/code/modules/instruments/songs/play_legacy.dm b/code/modules/instruments/songs/play_legacy.dm index eee9be3cc7..c4d86e2013 100644 --- a/code/modules/instruments/songs/play_legacy.dm +++ b/code/modules/instruments/songs/play_legacy.dm @@ -82,5 +82,5 @@ var/sound/music_played = sound(soundfile) for(var/i in hearing_mobs) var/mob/M = i - M.playsound_local(source, null, volume * using_instrument.volume_multiplier, falloff = 5, S = music_played) + M.playsound_local(source, null, volume * using_instrument.volume_multiplier, S = music_played) // Could do environment and echo later but not for now diff --git a/code/modules/integrated_electronics/core/assemblies.dm b/code/modules/integrated_electronics/core/assemblies.dm index 7c9f811c34..6cb578dfb1 100644 --- a/code/modules/integrated_electronics/core/assemblies.dm +++ b/code/modules/integrated_electronics/core/assemblies.dm @@ -578,6 +578,7 @@ return FALSE /obj/item/electronic_assembly/Moved(oldLoc, dir) + . = ..() for(var/I in assembly_components) var/obj/item/integrated_circuit/IC = I IC.ext_moved(oldLoc, dir) diff --git a/code/modules/integrated_electronics/core/integrated_circuit.dm b/code/modules/integrated_electronics/core/integrated_circuit.dm index f90b584d76..92d2aa270f 100644 --- a/code/modules/integrated_electronics/core/integrated_circuit.dm +++ b/code/modules/integrated_electronics/core/integrated_circuit.dm @@ -378,7 +378,7 @@ a creative player the means to solve many problems. Circuits are held inside an // Checks if the target object is reachable. Useful for various manipulators and manipulator-like objects. -/obj/item/integrated_circuit/proc/check_target(atom/target, exclude_contents = FALSE, exclude_components = FALSE, exclude_self = FALSE) +/obj/item/integrated_circuit/proc/check_target(atom/target, exclude_contents = FALSE, exclude_components = FALSE, exclude_self = FALSE, exclude_outside = FALSE) if(!target) return FALSE @@ -394,7 +394,7 @@ a creative player the means to solve many problems. Circuits are held inside an if(target == assembly.battery) return FALSE - if(target.Adjacent(acting_object) && isturf(target.loc)) + if(!exclude_outside && target.Adjacent(acting_object) && isturf(target.loc)) return TRUE if(!exclude_contents && (target in acting_object.GetAllContents())) diff --git a/code/modules/integrated_electronics/subtypes/atmospherics.dm b/code/modules/integrated_electronics/subtypes/atmospherics.dm index 26ac3080de..d449775bd1 100644 --- a/code/modules/integrated_electronics/subtypes/atmospherics.dm +++ b/code/modules/integrated_electronics/subtypes/atmospherics.dm @@ -292,7 +292,7 @@ activate_pin(2) // Required for making the connector port script work -obj/item/integrated_circuit/atmospherics/connector/portableConnectorReturnAir() +/obj/item/integrated_circuit/atmospherics/connector/portableConnectorReturnAir() return air_contents diff --git a/code/modules/integrated_electronics/subtypes/manipulation.dm b/code/modules/integrated_electronics/subtypes/manipulation.dm index eac16d2950..e32f8daa2d 100644 --- a/code/modules/integrated_electronics/subtypes/manipulation.dm +++ b/code/modules/integrated_electronics/subtypes/manipulation.dm @@ -186,6 +186,8 @@ AM.forceMove(src) /obj/item/integrated_circuit/manipulation/grabber/proc/drop(obj/item/AM, turf/T = drop_location()) + if(!check_target(AM, FALSE, TRUE, TRUE, TRUE)) + return var/atom/A = get_object() A.investigate_log("dropped ([AM]) from [src].", INVESTIGATE_CIRCUIT) AM.forceMove(T) diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm index 64ab4791d3..855e2ccbd7 100644 --- a/code/modules/jobs/job_types/_job.dm +++ b/code/modules/jobs/job_types/_job.dm @@ -187,7 +187,7 @@ /datum/job/proc/announce_head(var/mob/living/carbon/human/H, var/channels) //tells the given channel that the given mob is the new department head. See communications.dm for valid channels. if(H && GLOB.announcement_systems.len) //timer because these should come after the captain announcement - SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/addtimer, CALLBACK(pick(GLOB.announcement_systems), /obj/machinery/announcement_system/proc/announce, "NEWHEAD", H.real_name, H.job, channels), 1)) + SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/_addtimer, CALLBACK(pick(GLOB.announcement_systems), /obj/machinery/announcement_system/proc/announce, "NEWHEAD", H.real_name, H.job, channels), 1)) //If the configuration option is set to require players to be logged as old enough to play certain jobs, then this proc checks that they are, otherwise it just returns 1 /datum/job/proc/player_old_enough(client/C) diff --git a/code/modules/keybindings/keybind/carbon.dm b/code/modules/keybindings/keybind/carbon.dm index 46cb5cd0ac..50ec29ff5e 100644 --- a/code/modules/keybindings/keybind/carbon.dm +++ b/code/modules/keybindings/keybind/carbon.dm @@ -60,3 +60,14 @@ /datum/keybinding/carbon/select_harm_intent/down(client/user) user.mob?.a_intent_change(INTENT_HARM) return TRUE + +/datum/keybinding/carbon/give + hotkey_keys = list("CtrlG") + name = "Give_Item" + full_name = "Give item" + description = "Give the item you're currently holding" + +/datum/keybinding/carbon/give/down(client/user) + var/mob/living/carbon/C = user.mob + C.give() + return TRUE diff --git a/code/modules/mapping/reader.dm b/code/modules/mapping/reader.dm index 11bcc0ffcf..a3e0653678 100644 --- a/code/modules/mapping/reader.dm +++ b/code/modules/mapping/reader.dm @@ -135,7 +135,7 @@ var/curr_z = text2num(dmmRegex.group[5]) if(curr_z < z_lower || curr_z > z_upper) continue - + var/curr_x = text2num(dmmRegex.group[3]) var/curr_y = text2num(dmmRegex.group[4]) @@ -171,7 +171,7 @@ if(width > right_width) for(var/i in 1 to lines) gridLines[i] = copytext(gridLines[i], 1, key_len * right_width) - + // during the actual load we're starting at the top and working our way down gridSet.ycrd += lines - 1 @@ -300,14 +300,14 @@ //we do this after we load everything in. if we don't; we'll have weird atmos bugs regarding atmos adjacent turfs T.AfterChange(CHANGETURF_IGNORE_AIR) + if(did_expand) + world.refresh_atmos_grid() + #ifdef TESTING if(turfsSkipped) testing("Skipped loading [turfsSkipped] default turfs") #endif - if(did_expand) - world.refresh_atmos_grid() - return TRUE /datum/parsed_map/proc/build_cache(no_changeturf, bad_paths=null) diff --git a/code/modules/mining/machine_redemption.dm b/code/modules/mining/machine_redemption.dm index 0268d32a6b..d6c4dfae34 100644 --- a/code/modules/mining/machine_redemption.dm +++ b/code/modules/mining/machine_redemption.dm @@ -250,6 +250,8 @@ if(points) if(I) I.mining_points += points + if(usr.client) + usr.client.increment_progress("miner", points) points = 0 else to_chat(usr, "No ID detected.") diff --git a/code/modules/mining/point_bank.dm b/code/modules/mining/point_bank.dm index f18b62635f..f467b94de5 100644 --- a/code/modules/mining/point_bank.dm +++ b/code/modules/mining/point_bank.dm @@ -20,25 +20,6 @@ data["totalPoints"] = points return data -/obj/machinery/mineral/ore_redemption/ui_act(action, params) - if(..()) - return - switch(action) - if("Claim") - var/mob/M = usr - var/obj/item/card/id/I = M.get_idcard(TRUE) - if(points) - if(I) - I.mining_points += points - if(usr.client) - usr.client.increment_progress("miner", points) - points = 0 - else - to_chat(usr, "No ID detected.") - else - to_chat(usr, "No points to claim.") - return TRUE - /obj/machinery/point_bank/power_change() ..() update_icon() diff --git a/code/modules/mob/dead/dead.dm b/code/modules/mob/dead/dead.dm index 87f9d716bd..223366c7ab 100644 --- a/code/modules/mob/dead/dead.dm +++ b/code/modules/mob/dead/dead.dm @@ -8,6 +8,7 @@ INITIALIZE_IMMEDIATE(/mob/dead) throwforce = 0 /mob/dead/Initialize() + SHOULD_CALL_PARENT(FALSE) if(flags_1 & INITIALIZED_1) stack_trace("Warning: [src]([type]) initialized multiple times!") flags_1 |= INITIALIZED_1 @@ -68,14 +69,15 @@ INITIALIZE_IMMEDIATE(/mob/dead) set desc= "Jump to the other server" if(mob_transforming) return - var/list/csa = CONFIG_GET(keyed_list/cross_server) + var/list/our_id = CONFIG_GET(string/cross_comms_name) + var/list/csa = CONFIG_GET(keyed_list/cross_server) - our_id var/pick switch(csa.len) if(0) remove_verb(src, /mob/dead/proc/server_hop) to_chat(src, "Server Hop has been disabled.") if(1) - pick = csa[0] + pick = csa[1] else pick = input(src, "Pick a server to jump to", "Server Hop") as null|anything in csa @@ -100,7 +102,7 @@ INITIALIZE_IMMEDIATE(/mob/dead) winset(src, null, "command=.options") //other wise the user never knows if byond is downloading resources - C << link("[addr]?server_hop=[key]") + C << link("[addr]") /mob/dead/proc/update_z(new_z) // 1+ to register, null to unregister if (registered_z != new_z) diff --git a/code/modules/mob/dead/new_player/sprite_accessories/body_markings.dm b/code/modules/mob/dead/new_player/sprite_accessories/body_markings.dm index 4e5f010964..bc6c4899dd 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/body_markings.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/body_markings.dm @@ -341,4 +341,4 @@ /datum/sprite_accessory/insect_fluff/witchwing name = "Witch Wing" - icon_state = "witchwing" \ No newline at end of file + icon_state = "witchwing" diff --git a/code/modules/mob/dead/new_player/sprite_accessories/caps.dm b/code/modules/mob/dead/new_player/sprite_accessories/caps.dm index 822fcf960d..d974672490 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/caps.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/caps.dm @@ -1,4 +1,4 @@ -datum/sprite_accessory/caps +/datum/sprite_accessory/caps icon = 'icons/mob/mutant_bodyparts.dmi' color_src = HAIR relevant_layers = list(BODY_ADJ_LAYER) diff --git a/code/modules/mob/dead/new_player/sprite_accessories/hair_head.dm b/code/modules/mob/dead/new_player/sprite_accessories/hair_head.dm index 55ab18c20c..4b23112e5e 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/hair_head.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/hair_head.dm @@ -13,6 +13,10 @@ name = "Bald" icon_state = "bald" +/datum/sprite_accessory/hair/adhara + name = "Adhara" + icon_state = "hair_adhara" + /datum/sprite_accessory/hair/afro name = "Afro" icon_state = "hair_afro" @@ -29,6 +33,14 @@ name = "Ahoge" icon_state = "hair_antenna" +/datum/sprite_accessory/hair/amazon + name = "Amazon" + icon_state = "hair_amazon" + +/datum/sprite_accessory/hair/anita + name = "Anita" + icon_state = "hair_anita" + /datum/sprite_accessory/hair/balding name = "Balding Hair" icon_state = "hair_e" @@ -61,6 +73,10 @@ name = "Beehive 2" icon_state = "hair_beehive2" +/datum/sprite_accessory/hair/belle + name = "Belle" + icon_state = "hair_belle" + /datum/sprite_accessory/hair/bob name = "Bob Hair" icon_state = "hair_bob" @@ -365,6 +381,10 @@ name = "Hitop" icon_state = "hair_hitop" +/datum/sprite_accessory/hair/inkling + name = "Inkling" + icon_state = "hair_inkling" + /datum/sprite_accessory/hair/jade name = "Jade" icon_state = "hair_jade" @@ -373,6 +393,10 @@ name = "Jensen" icon_state = "hair_jensen" +/datum/sprite_accessory/hair/jessica + name = "Jessica" + icon_state = "hair_jessica" + /datum/sprite_accessory/hair/joestar name = "Joestar" icon_state = "hair_joestar" @@ -389,6 +413,10 @@ name = "Kusanagi" icon_state = "hair_kusanagi" +/datum/sprite_accessory/hair/kleeia + name = "Kleeia" + icon_state = "hair_kleeia" + /datum/sprite_accessory/hair/long name = "Long Hair 1" icon_state = "hair_long" @@ -445,6 +473,10 @@ name = "Mohawk" icon_state = "hair_d" +/datum/sprite_accessory/hair/newyou + name = "New You" + icon_state = "hair_newyou" + /datum/sprite_accessory/hair/reversemohawk name = "Mohawk (Reverse)" icon_state = "hair_reversemohawk" @@ -699,6 +731,10 @@ name = "Spiky 3" icon_state = "hair_spiky2" +/datum/sprite_accessory/hair/supernova + name = "Supernova" + icon_state = "hair_supernova" + /datum/sprite_accessory/hair/swept name = "Swept Back Hair" icon_state = "hair_swept" @@ -743,6 +779,10 @@ name = "Trimmed (Flat)" icon_state = "hair_trimflat" +/datum/sprite_accessory/hair/twincurls + name = "Twincurls" + icon_state = "hair_twincurls" + /datum/sprite_accessory/hair/twintails name = "Twintails" icon_state = "hair_twintail" @@ -787,6 +827,10 @@ name = "Very Short Over Eye (Alt)" icon_state = "hair_veryshortovereyealternate" +/datum/sprite_accessory/hair/vivi + name = "Vivi" + icon_state = "hair_vivi" + /datum/sprite_accessory/hair/volaju name = "Volaju" icon_state = "hair_volaju" diff --git a/code/modules/mob/dead/new_player/sprite_accessories/socks.dm b/code/modules/mob/dead/new_player/sprite_accessories/socks.dm index cd55a17e3c..78517b003e 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/socks.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/socks.dm @@ -11,6 +11,11 @@ // please make sure they're sorted alphabetically and categorized +/datum/sprite_accessory/underwear/socks/garter + name = "Garter" + icon_state = "garter" + has_color = TRUE + /datum/sprite_accessory/underwear/socks/socks_knee name = "Knee-high" icon_state = "socks_knee" @@ -83,6 +88,10 @@ name = "Pantyhose" icon_state = "pantyhose" +/datum/sprite_accessory/underwear/socks/pantyhose_ripped + name = "Pantyhose - Ripped" + icon_state = "pantyhose_ripped" + /datum/sprite_accessory/underwear/socks/socks_short name = "Short" icon_state = "socks_short" diff --git a/code/modules/mob/dead/new_player/sprite_accessories/tails.dm b/code/modules/mob/dead/new_player/sprite_accessories/tails.dm index 6135d42569..a964be3f8a 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/tails.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/tails.dm @@ -757,7 +757,7 @@ icon_state = "husky" matrixed_sections = MATRIX_RED_GREEN -datum/sprite_accessory/tails/mam_tails/insect +/datum/sprite_accessory/tails/mam_tails/insect name = "Insect" icon_state = "insect" matrixed_sections = MATRIX_RED diff --git a/code/modules/mob/dead/new_player/sprite_accessories/undershirt.dm b/code/modules/mob/dead/new_player/sprite_accessories/undershirt.dm index 1be02c207e..364485fe8a 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/undershirt.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/undershirt.dm @@ -343,6 +343,20 @@ icon_state = "fishnet_body" gender = FEMALE +/datum/sprite_accessory/underwear/top/shibari + name = "Shibari Ropes" + icon_state = "shibari" + gender = FEMALE + has_color = TRUE + covers_chest = FALSE + +/datum/sprite_accessory/underwear/top/shibari_sleeved + name = "Shibari Ropes - sleeves" + icon_state = "shibari_sleeves" + gender = FEMALE + has_color = TRUE + covers_chest = FALSE + /datum/sprite_accessory/underwear/top/swimsuit name = "Swimsuit Top" icon_state = "bra_swimming" diff --git a/code/modules/mob/death.dm b/code/modules/mob/death.dm index 09336d2fea..476bddded3 100644 --- a/code/modules/mob/death.dm +++ b/code/modules/mob/death.dm @@ -1,6 +1,6 @@ //This is the proc for gibbing a mob. Cannot gib ghosts. //added different sort of gibs and animations. N -/mob/proc/gib() +/mob/proc/gib(no_brain, no_organs, no_bodyparts, datum/explosion/was_explosion) return //This is the proc for turning a mob into ash. Mostly a copy of gib code (above). diff --git a/code/modules/mob/living/carbon/alien/alien.dm b/code/modules/mob/living/carbon/alien/alien.dm index e7ad67d240..7c80d1d426 100644 --- a/code/modules/mob/living/carbon/alien/alien.dm +++ b/code/modules/mob/living/carbon/alien/alien.dm @@ -4,7 +4,6 @@ gender = FEMALE //All xenos are girls!! dna = null faction = list(ROLE_ALIEN) - ventcrawler = VENTCRAWLER_ALWAYS sight = SEE_MOBS see_in_dark = 4 verb_say = "hisses" @@ -19,7 +18,6 @@ /// How much brute damage they do to simple animals var/meleeSlashSAPower = 35 - var/obj/item/card/id/wear_id = null // Fix for station bounced radios -- Skie var/has_fine_manipulation = 0 var/move_delay_add = 0 // movement delay to add @@ -40,6 +38,8 @@ create_internal_organs() + AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) + . = ..() /mob/living/carbon/alien/create_internal_organs() diff --git a/code/modules/mob/living/carbon/alien/humanoid/queen.dm b/code/modules/mob/living/carbon/alien/humanoid/queen.dm index 91a61efea6..42b62e37a0 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/queen.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/queen.dm @@ -2,7 +2,6 @@ //Common stuffs for Praetorian and Queen icon = 'icons/mob/alienqueen.dmi' status_flags = 0 - ventcrawler = VENTCRAWLER_NONE //pull over that ass too fat unique_name = 0 pixel_x = -16 bubble_icon = "alienroyal" diff --git a/code/modules/mob/living/carbon/alien/special/facehugger.dm b/code/modules/mob/living/carbon/alien/special/facehugger.dm index 5392e7b2d5..ca2946fd8a 100644 --- a/code/modules/mob/living/carbon/alien/special/facehugger.dm +++ b/code/modules/mob/living/carbon/alien/special/facehugger.dm @@ -91,8 +91,8 @@ Attach(M) /obj/item/clothing/mask/facehugger/Crossed(atom/target) + . = ..() HasProximity(target) - return /obj/item/clothing/mask/facehugger/on_found(mob/finder) if(stat == CONSCIOUS) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 45a0d82d2c..979baeb065 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -1229,3 +1229,25 @@ */ /mob/living/carbon/proc/get_biological_state() return BIO_FLESH_BONE + +/mob/living/carbon/altattackby(obj/item/W, mob/living/carbon/user, params) + if(user.incapacitated() || !user.Adjacent(src)) + return FALSE + if(W && user.a_intent == INTENT_HELP && W.can_give()) + user.give() + return TRUE + +/mob/living/carbon/verb/give_verb() + set src in oview(1) + set category = "IC" + set name = "Give" + + if(usr.incapacitated() || !usr.Adjacent(src)) + return + + if(!usr.get_active_held_item()) // Let me know if this has any problems -Yota + return + var/obj/item/I = usr.get_active_held_item() + var/mob/living/carbon/C = usr + if(I.can_give()) + C.give() diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index 7a16d5c352..b2c14c30fe 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -304,10 +304,16 @@ emote("wag") else if(check_zone(M.zone_selected) == BODY_ZONE_R_ARM || check_zone(M.zone_selected) == BODY_ZONE_L_ARM) - M.visible_message( \ - "[M] shakes [src]'s hand.", \ - "You shake [src]'s hand.", target = src, - target_message = "[M] shakes your hand.") + if((pulling == M) && (grab_state == GRAB_PASSIVE)) + M.visible_message( \ + "[M] squeezes [src]'s hand.", \ + "You squeeze [src]'s hand.", target = src, + target_message = "[M] squeezes your hand.") + else + M.visible_message( \ + "[M] shakes [src]'s hand.", \ + "You shake [src]'s hand.", target = src, + target_message = "[M] shakes your hand.") else M.visible_message("[M] hugs [src] to make [p_them()] feel better!", \ diff --git a/code/modules/mob/living/carbon/death.dm b/code/modules/mob/living/carbon/death.dm index ee2f945b65..528848fb14 100644 --- a/code/modules/mob/living/carbon/death.dm +++ b/code/modules/mob/living/carbon/death.dm @@ -17,7 +17,7 @@ if(SSticker.mode) SSticker.mode.check_win() //Calls the rounds wincheck, mainly for wizard, malf, and changeling now -/mob/living/carbon/gib(no_brain, no_organs, no_bodyparts) +/mob/living/carbon/gib(no_brain, no_organs, no_bodyparts, datum/explosion/was_explosion) var/atom/Tsec = drop_location() for(var/mob/M in src) if(M in stomach_contents) @@ -27,7 +27,7 @@ "You burst out of [src]!") ..() -/mob/living/carbon/spill_organs(no_brain, no_organs, no_bodyparts) +/mob/living/carbon/spill_organs(no_brain, no_organs, no_bodyparts, datum/explosion/was_explosion) var/atom/Tsec = drop_location() if(!no_bodyparts) if(no_organs)//so the organs don't get transfered inside the bodyparts we'll drop. @@ -41,6 +41,8 @@ qdel(O) //so the brain isn't transfered to the head when the head drops. continue if(!(O.organ_flags & ORGAN_NO_DISMEMBERMENT) && check_zone(O.zone) == BODY_ZONE_CHEST) + if(was_explosion) + LAZYADD(O.acted_explosions, was_explosion.explosion_id) O.Remove() O.forceMove(Tsec) O.throw_at(get_edge_target_turf(src,pick(GLOB.alldirs)),rand(1,3),5) @@ -50,13 +52,16 @@ if(I.organ_flags & ORGAN_NO_DISMEMBERMENT || (no_brain && istype(I, /obj/item/organ/brain)) || (no_organs && !istype(I, /obj/item/organ/brain))) qdel(I) continue + if(was_explosion) + LAZYADD(I.acted_explosions, was_explosion.explosion_id) I.Remove() I.forceMove(Tsec) I.throw_at(get_edge_target_turf(src,pick(GLOB.alldirs)),rand(1,3),5) - -/mob/living/carbon/spread_bodyparts() +/mob/living/carbon/spread_bodyparts(no_brain, no_organs, datum/explosion/was_explosion) for(var/X in bodyparts) var/obj/item/bodypart/BP = X + if(was_explosion) + LAZYADD(BP.acted_explosions, was_explosion.explosion_id) BP.drop_limb() BP.throw_at(get_edge_target_turf(src,pick(GLOB.alldirs)),rand(1,3),5) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 03816555b3..df7ed66169 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -3,7 +3,7 @@ real_name = "Unknown" icon = 'icons/mob/human.dmi' icon_state = "caucasian_m" - appearance_flags = KEEP_TOGETHER|TILE_BOUND|PIXEL_SCALE + SET_APPEARANCE_FLAGS(KEEP_TOGETHER|TILE_BOUND|PIXEL_SCALE) /mob/living/carbon/human/Initialize() add_verb(src, /mob/living/proc/mob_sleep) @@ -1028,7 +1028,7 @@ return stop_pulling() - riding_datum.handle_vehicle_layer() + riding_datum.handle_vehicle_layer(dir) riding_datum.fireman_carrying = fireman . = ..(target, force, check_loc) diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm index 440400f889..1619d0f6de 100644 --- a/code/modules/mob/living/carbon/human/human_movement.dm +++ b/code/modules/mob/living/carbon/human/human_movement.dm @@ -9,11 +9,6 @@ return return considering -/mob/living/carbon/human/movement_delay() - . = ..() - if (m_intent == MOVE_INTENT_WALK && HAS_TRAIT(src, TRAIT_SPEEDY_STEP)) - . -= 1.5 - /mob/living/carbon/human/slip(knockdown_amount, obj/O, lube) if(HAS_TRAIT(src, TRAIT_NOSLIPALL)) return 0 diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 94d7e84c6b..8d473639b4 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -1796,12 +1796,10 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) "[M] attempted to touch you!", target = M, \ target_message = "You attempted to touch [H]!") return TRUE + if(M == H) + althelp(M, H, attacker_style) + return TRUE switch(M.a_intent) - if(INTENT_HELP) - if(M == H) - althelp(M, H, attacker_style) - return TRUE - return FALSE if(INTENT_DISARM) altdisarm(M, H, attacker_style) return TRUE @@ -1987,6 +1985,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) H.show_message("The radiation beam dissipates harmlessly through your body.") if(/obj/item/projectile/energy/florayield) H.show_message("The radiation beam dissipates harmlessly through your body.") + if(/obj/item/projectile/energy/florarevolution) + H.show_message("The radiation beam dissipates harmlessly through your body.") /datum/species/proc/bullet_act(obj/item/projectile/P, mob/living/carbon/human/H) // called before a projectile hit 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 ff0287d7b9..75aff774ce 100644 --- a/code/modules/mob/living/carbon/human/species_types/golems.dm +++ b/code/modules/mob/living/carbon/human/species_types/golems.dm @@ -801,11 +801,11 @@ /datum/species/golem/plastic/on_species_gain(mob/living/carbon/C, datum/species/old_species) . = ..() - C.ventcrawler = VENTCRAWLER_NUDE + C.AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) /datum/species/golem/plastic/on_species_loss(mob/living/carbon/C) . = ..() - C.ventcrawler = initial(C.ventcrawler) + C.RemoveElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) /datum/species/golem/bronze name = "Bronze Golem" 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 c25c5efb6c..697c3db35e 100644 --- a/code/modules/mob/living/carbon/human/species_types/podpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/podpeople.dm @@ -64,6 +64,11 @@ H.show_message("The radiation beam singes you!") if(/obj/item/projectile/energy/florayield) H.adjust_nutrition(30, NUTRITION_LEVEL_FULL) + if(/obj/item/projectile/energy/florarevolution) + H.show_message("The radiation beam leaves you feeling disoriented!") + H.Dizzy(15) + H.emote("flip") + H.emote("spin") /datum/species/pod/pseudo_weak name = "Anthromorphic Plant" 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 558fdc6594..5e07150ce6 100644 --- a/code/modules/mob/living/carbon/human/species_types/vampire.dm +++ b/code/modules/mob/living/carbon/human/species_types/vampire.dm @@ -169,7 +169,7 @@ if(istype(H, /mob/living/simple_animal)) var/mob/living/simple_animal/SA = H if((human_caster.blood_volume <= (BLOOD_VOLUME_BAD*human_caster.blood_ratio)) || (ventcrawl_nude_only && length(human_caster.get_equipped_items(include_pockets = TRUE)))) - SA.ventcrawler = FALSE + SA.RemoveElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) if(transfer_name) H.name = human_caster.name diff --git a/code/modules/mob/living/carbon/inventory.dm b/code/modules/mob/living/carbon/inventory.dm index 96dab9e95d..e5ba022277 100644 --- a/code/modules/mob/living/carbon/inventory.dm +++ b/code/modules/mob/living/carbon/inventory.dm @@ -159,3 +159,57 @@ /mob/living/carbon/proc/get_holding_bodypart_of_item(obj/item/I) var/index = get_held_index_of_item(I) return index && hand_bodyparts[index] + +/** + * Proc called when giving an item to another player + * + * This handles creating an alert and adding an overlay to it + */ +/mob/living/carbon/proc/give(target) + var/obj/item/receiving = get_active_held_item() + if(!receiving) + to_chat(src, "You're not holding anything to give!") + return + visible_message("[src] is offering [receiving]", \ + "You offer [receiving]", null, 2) + var/mob/living/carbon/targets = list() + if(!target) + for(var/mob/living/carbon/C in orange(1, src)) + if(!CanReach(C)) + return + targets += C + else + targets += target + if(!targets) + return + for(var/mob/living/carbon/C in targets) + var/obj/screen/alert/give/G = C.throw_alert("[src]", /obj/screen/alert/give) + if(!G) + return + G.setup(C, src, receiving) + +/** + * Proc called when the player clicks the give alert + * + * Handles checking if the player taking the item has open slots and is in range of the giver + * Also deals with the actual transferring of the item to the players hands + * Arguments: + * * giver - The person giving the original item + * * I - The item being given by the giver + */ +/mob/living/carbon/proc/take(mob/living/carbon/giver, obj/item/I) + clear_alert("[giver]") + if(get_dist(src, giver) > 1) + to_chat(src, "[giver] is out of range! ") + return + if(!I || giver.get_active_held_item() != I) + to_chat(src, "[giver] is no longer holding the item they were offering! ") + return + if(!get_empty_held_indexes()) + to_chat(src, "You have no empty hands!") + return + if(!giver.temporarilyRemoveItemFromInventory(I)) + visible_message("[src] tries to hand over [I] but it's stuck to them....", \ + " You make a fool of yourself trying to give away an item stuck to your hands") + return + put_in_hands(I) diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index e0fab331a6..9885efd7c7 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -594,10 +594,18 @@ GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put drunkenness = max(drunkenness - (drunkenness * 0.04), 0) if(drunkenness >= 6) SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "drunk", /datum/mood_event/drunk) + if(prob(25)) + slurring += 2 jitteriness = max(jitteriness - 3, 0) + // throw_alert("drunk", /atom/movable/screen/alert/drunk) if(HAS_TRAIT(src, TRAIT_DRUNK_HEALING)) adjustBruteLoss(-0.12, FALSE) adjustFireLoss(-0.06, FALSE) + sound_environment_override = SOUND_ENVIRONMENT_PSYCHOTIC + else + SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "drunk") + clear_alert("drunk") + sound_environment_override = SOUND_ENVIRONMENT_NONE if(mind && (mind.assigned_role == "Scientist" || mind.assigned_role == "Research Director")) if(SSresearch.science_tech) diff --git a/code/modules/mob/living/carbon/monkey/monkey.dm b/code/modules/mob/living/carbon/monkey/monkey.dm index 1f3e0a1b81..d49059f839 100644 --- a/code/modules/mob/living/carbon/monkey/monkey.dm +++ b/code/modules/mob/living/carbon/monkey/monkey.dm @@ -6,7 +6,6 @@ icon_state = "" gender = NEUTER pass_flags = PASSTABLE - ventcrawler = VENTCRAWLER_NUDE mob_biotypes = MOB_ORGANIC|MOB_HUMANOID butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/monkey = 5, /obj/item/stack/sheet/animalhide/monkey = 1) type_of_meat = /obj/item/reagent_containers/food/snacks/meat/slab/monkey @@ -29,6 +28,8 @@ create_bodyparts() create_internal_organs() + AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_NUDE) + . = ..() if (cubespawned) diff --git a/code/modules/mob/living/carbon/status_procs.dm b/code/modules/mob/living/carbon/status_procs.dm index a47bb7fb4a..d602c25331 100644 --- a/code/modules/mob/living/carbon/status_procs.dm +++ b/code/modules/mob/living/carbon/status_procs.dm @@ -8,10 +8,12 @@ overlay_fullscreen("high", /obj/screen/fullscreen/high) throw_alert("high", /obj/screen/alert/high) SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "high", /datum/mood_event/high) + sound_environment_override = SOUND_ENVIRONMENT_DRUGGED else clear_fullscreen("high") clear_alert("high") SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "high") + sound_environment_override = SOUND_ENVIRONMENT_NONE /mob/living/carbon/set_drugginess(amount) druggy = max(amount, 0) diff --git a/code/modules/mob/living/death.dm b/code/modules/mob/living/death.dm index 688b0cf63e..be9cd0aabb 100644 --- a/code/modules/mob/living/death.dm +++ b/code/modules/mob/living/death.dm @@ -1,4 +1,4 @@ -/mob/living/gib(no_brain, no_organs, no_bodyparts) +/mob/living/gib(no_brain, no_organs, no_bodyparts, datum/explosion/was_explosion) var/prev_lying = lying if(stat != DEAD) death(1) @@ -6,22 +6,22 @@ if(!prev_lying) gib_animation() - spill_organs(no_brain, no_organs, no_bodyparts) + spill_organs(no_brain, no_organs, no_bodyparts, was_explosion) if(!no_bodyparts) - spread_bodyparts(no_brain, no_organs) + spread_bodyparts(no_brain, no_organs, was_explosion) for(var/X in implants) var/obj/item/implant/I = X qdel(I) - spawn_gibs(no_bodyparts) + spawn_gibs(no_bodyparts, null, was_explosion) qdel(src) /mob/living/proc/gib_animation() return -/mob/living/proc/spawn_gibs(with_bodyparts, atom/loc_override) +/mob/living/proc/spawn_gibs(with_bodyparts, atom/loc_override, datum/explosion/was_explosion) var/location = loc_override ? loc_override.drop_location() : drop_location() if(mob_biotypes & MOB_ROBOTIC) new /obj/effect/gibspawner/robot(location, src, get_static_viruses()) @@ -31,7 +31,7 @@ /mob/living/proc/spill_organs() return -/mob/living/proc/spread_bodyparts() +/mob/living/proc/spread_bodyparts(no_brain, no_organs, datum/explosion/was_explosion) return /mob/living/dust(just_ash, drop_items, force) diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm index 742d4d8624..386f1174e1 100644 --- a/code/modules/mob/living/living_defines.dm +++ b/code/modules/mob/living/living_defines.dm @@ -81,7 +81,6 @@ var/bloodcrawl = 0 //0 No blood crawling, BLOODCRAWL for bloodcrawling, BLOODCRAWL_EAT for crawling+mob devour var/holder = null //The holder for blood crawling - var/ventcrawler = 0 //0 No vent crawling, 1 vent crawling in the nude, 2 vent crawling always var/limb_destroyer = 0 //1 Sets AI behavior that allows mobs to target and dismember limbs with their basic attack. var/mob_size = MOB_SIZE_HUMAN diff --git a/code/modules/mob/living/living_movement.dm b/code/modules/mob/living/living_movement.dm index 9e093d391e..bafa38ec5e 100644 --- a/code/modules/mob/living/living_movement.dm +++ b/code/modules/mob/living/living_movement.dm @@ -101,6 +101,7 @@ if(lying && !buckled && prob(getBruteLoss()*200/maxHealth)) makeTrail(newloc, T, old_direction) + if(causes_dirt_buildup_on_floor && (movement_type & GROUND)) dirt_buildup() diff --git a/code/modules/mob/living/login.dm b/code/modules/mob/living/login.dm index 931f87eb7c..2b1c2de17a 100644 --- a/code/modules/mob/living/login.dm +++ b/code/modules/mob/living/login.dm @@ -17,10 +17,6 @@ if (isturf(T)) update_z(T.z) - //Vents - if(ventcrawler) - to_chat(src, "You can ventcrawl! Use alt+click on vents to quickly travel about the station.") - if(ranged_ability) ranged_ability.add_ranged_ability(src, "You currently have [ranged_ability] active!") if((vore_flags & VORE_INIT) && !(vore_flags & VOREPREF_INIT)) //Vore's been initialized, voreprefs haven't. If this triggers then that means that voreprefs failed to load due to the client being missing. diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index fbf2d27c31..e0e1d91ba9 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -911,10 +911,10 @@ if(!istype(apc) || QDELETED(apc) || apc.stat & BROKEN) to_chat(src, "Hack aborted. The designated APC no longer exists on the power network.") - playsound(get_turf(src), 'sound/machines/buzz-two.ogg', 50, 1) + playsound(get_turf(src), 'sound/machines/buzz-two.ogg', 50, TRUE, ignore_walls = FALSE) else if(apc.aidisabled) to_chat(src, "Hack aborted. \The [apc] is no longer responding to our systems.") - playsound(get_turf(src), 'sound/machines/buzz-sigh.ogg', 50, 1) + playsound(get_turf(src), 'sound/machines/buzz-sigh.ogg', 50, TRUE, ignore_walls = FALSE) else malf_picker.processing_time += 10 @@ -923,7 +923,7 @@ apc.locked = TRUE apc.coverlocked = TRUE - playsound(get_turf(src), 'sound/machines/ding.ogg', 50, 1) + playsound(get_turf(src), 'sound/machines/ding.ogg', 50, TRUE, ignore_walls = FALSE) to_chat(src, "Hack complete. \The [apc] is now under your exclusive control.") apc.update_icon() @@ -1039,3 +1039,6 @@ if(current && eyeobj) return eyeobj.emote(act, m_type, message, intentional, forced = TRUE) return ..() + +/mob/living/silicon/ai/zMove(dir, feedback = FALSE) + . = eyeobj.zMove(dir, feedback) diff --git a/code/modules/mob/living/silicon/ai/freelook/eye.dm b/code/modules/mob/living/silicon/ai/freelook/eye.dm index 17de811cdd..dcaa28b39c 100644 --- a/code/modules/mob/living/silicon/ai/freelook/eye.dm +++ b/code/modules/mob/living/silicon/ai/freelook/eye.dm @@ -94,6 +94,25 @@ if(ai.master_multicam) ai.master_multicam.refresh_view() +//it uses setLoc not forceMove, talks to the sillycone and not the camera mob +/mob/camera/aiEye/zMove(dir, feedback = FALSE) + if(dir != UP && dir != DOWN) + return FALSE + var/turf/target = get_step_multiz(src, dir) + if(!target) + if(feedback) + to_chat(ai, "There's nowhere to go in that direction!") + return FALSE + if(!canZMove(dir, target)) + if(feedback) + to_chat(ai, "You couldn't move there!") + return FALSE + setLoc(target, TRUE) + return TRUE + +/mob/camera/aiEye/canZMove(direction, turf/target) //cameras do not respect these FLOORS you speak so much of + return TRUE + /mob/camera/aiEye/Move() return 0 diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index 786c121ad6..2ab74664a3 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -426,6 +426,10 @@ //Misc .["Cyborg - Misc (dog - blade)"] = process_holoform_icon_filter(icon('modular_citadel/icons/mob/widerobot.dmi', "blade"), HOLOFORM_FILTER_PAI, FALSE) + // Gorillas + .["Gorilla (standing)"] = process_holoform_icon_filter(icon('icons/mob/gorilla.dmi', "standing"), HOLOFORM_FILTER_PAI, FALSE) + .["Gorilla (crawling)"] = process_holoform_icon_filter(icon('icons/mob/gorilla.dmi', "crawling"), HOLOFORM_FILTER_PAI, FALSE) + /mob/living/silicon/pai/proc/default_chassis_pixel_offsets_x() . = list() //Engi diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index 7c4125fbc6..4c83841809 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -923,7 +923,8 @@ /obj/item/cyborg_clamp, /obj/item/stack/marker_beacon, /obj/item/destTagger, - /obj/item/stack/packageWrap) + /obj/item/stack/packageWrap, + /obj/item/card/id/miningborg) emag_modules = list(/obj/item/borg/stun) ratvar_modules = list( /obj/item/clockwork/slab/cyborg/miner, diff --git a/code/modules/mob/living/simple_animal/bot/floorbot.dm b/code/modules/mob/living/simple_animal/bot/floorbot.dm index 0ba4023864..ff6941ec70 100644 --- a/code/modules/mob/living/simple_animal/bot/floorbot.dm +++ b/code/modules/mob/living/simple_animal/bot/floorbot.dm @@ -335,6 +335,11 @@ /mob/living/simple_animal/bot/floorbot/proc/repair(turf/target_turf) + if(check_bot_working(target_turf)) + add_to_ignore(target_turf) + target = null + playsound(src, 'sound/effects/whistlereset.ogg', 50, TRUE) + return if(isspaceturf(target_turf)) //Must be a hull breach or in line mode to continue. if(!is_hull_breach(target_turf) && !targetdirection) @@ -418,3 +423,14 @@ repair(A) else ..() + +/** + * Checks a given turf to see if another floorbot is there, working as well. + */ +/mob/living/simple_animal/bot/floorbot/proc/check_bot_working(turf/active_turf) + if(isturf(active_turf)) + for(var/mob/living/simple_animal/bot/floorbot/robot in active_turf) + if(robot.mode == BOT_REPAIRING) + return TRUE + return FALSE + diff --git a/code/modules/mob/living/simple_animal/friendly/bumbles.dm b/code/modules/mob/living/simple_animal/friendly/bumbles.dm index 0debb7b98c..6ed6d03b68 100644 --- a/code/modules/mob/living/simple_animal/friendly/bumbles.dm +++ b/code/modules/mob/living/simple_animal/friendly/bumbles.dm @@ -20,7 +20,6 @@ density = FALSE movement_type = FLYING pass_flags = PASSTABLE | PASSGRILLE | PASSMOB - ventcrawler = VENTCRAWLER_ALWAYS mob_size = MOB_SIZE_TINY mob_biotypes = MOB_ORGANIC|MOB_BEAST gold_core_spawnable = FRIENDLY_SPAWN @@ -35,6 +34,7 @@ /mob/living/simple_animal/pet/bumbles/Initialize() . = ..() add_verb(src, /mob/living/proc/lay_down) + AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) /mob/living/simple_animal/pet/bumbles/ComponentInitialize() . = ..() diff --git a/code/modules/mob/living/simple_animal/friendly/butterfly.dm b/code/modules/mob/living/simple_animal/friendly/butterfly.dm index bf4f45e283..1e6afd6044 100644 --- a/code/modules/mob/living/simple_animal/friendly/butterfly.dm +++ b/code/modules/mob/living/simple_animal/friendly/butterfly.dm @@ -20,7 +20,6 @@ density = FALSE movement_type = FLYING pass_flags = PASSTABLE | PASSGRILLE | PASSMOB - ventcrawler = VENTCRAWLER_ALWAYS mob_size = MOB_SIZE_TINY mob_biotypes = MOB_ORGANIC|MOB_BUG gold_core_spawnable = FRIENDLY_SPAWN @@ -33,6 +32,7 @@ . = ..() var/newcolor = rgb(rand(0, 255), rand(0, 255), rand(0, 255)) add_atom_colour(newcolor, FIXED_COLOUR_PRIORITY) + AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) /mob/living/simple_animal/butterfly/bee_friendly() return TRUE //treaty signed at the Beeneeva convention diff --git a/code/modules/mob/living/simple_animal/friendly/cat.dm b/code/modules/mob/living/simple_animal/friendly/cat.dm index 71ae3b4c03..4594d27ecd 100644 --- a/code/modules/mob/living/simple_animal/friendly/cat.dm +++ b/code/modules/mob/living/simple_animal/friendly/cat.dm @@ -14,7 +14,6 @@ speak_chance = 1 turns_per_move = 5 see_in_dark = 6 - ventcrawler = VENTCRAWLER_ALWAYS pass_flags = PASSTABLE mob_size = MOB_SIZE_SMALL mob_biotypes = MOB_ORGANIC|MOB_BEAST @@ -40,6 +39,7 @@ /mob/living/simple_animal/pet/cat/Initialize() . = ..() add_verb(src, /mob/living/proc/lay_down) + AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) /mob/living/simple_animal/pet/cat/ComponentInitialize() . = ..() diff --git a/code/modules/mob/living/simple_animal/friendly/cockroach.dm b/code/modules/mob/living/simple_animal/friendly/cockroach.dm index 384fa8146f..f65b2bab9b 100644 --- a/code/modules/mob/living/simple_animal/friendly/cockroach.dm +++ b/code/modules/mob/living/simple_animal/friendly/cockroach.dm @@ -22,7 +22,6 @@ response_harm_simple = "splat" speak_emote = list("chitters") density = FALSE - ventcrawler = VENTCRAWLER_ALWAYS mob_size = MOB_SIZE_TINY gold_core_spawnable = FRIENDLY_SPAWN verb_say = "chitters" @@ -32,28 +31,34 @@ var/squish_chance = 50 del_on_death = 1 +/mob/living/simple_animal/cockroach/Initialize() + . = ..() + AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) + /mob/living/simple_animal/cockroach/death(gibbed) if(SSticker.mode && SSticker.mode.station_was_nuked) //If the nuke is going off, then cockroaches are invincible. Keeps the nuke from killing them, cause cockroaches are immune to nukes. return ..() -/mob/living/simple_animal/cockroach/Crossed(var/atom/movable/AM) - if(ismob(AM)) - if(isliving(AM)) - var/mob/living/A = AM - if(A.mob_size > MOB_SIZE_SMALL && !(A.movement_type & FLYING)) - if(prob(squish_chance)) - A.visible_message("[A] squashed [src].", "You squashed [src].") - adjustBruteLoss(1) //kills a normal cockroach - else - visible_message("[src] avoids getting crushed.") - else - if(isstructure(AM)) +/mob/living/simple_animal/cockroach/Crossed(atom/movable/AM) + . = ..() + if(isliving(AM)) + var/mob/living/A = AM + if(A.mob_size > MOB_SIZE_SMALL && !(A.movement_type & FLYING)) + if(HAS_TRAIT(A, TRAIT_PACIFISM)) + A.visible_message("[A] carefully steps over [src].", "You carefully step over [src] to avoid hurting it.") + return if(prob(squish_chance)) - AM.visible_message("[src] was crushed under [AM].") - adjustBruteLoss(1) + A.visible_message("[A] squashed [src].", "You squashed [src].") + adjustBruteLoss(1) //kills a normal cockroach else visible_message("[src] avoids getting crushed.") + else if(isstructure(AM)) + if(prob(squish_chance)) + AM.visible_message("[src] is crushed under [AM].") + adjustBruteLoss(1) + else + visible_message("[src] avoids getting crushed.") /mob/living/simple_animal/cockroach/ex_act() //Explosions are a terrible way to handle a cockroach. return diff --git a/code/modules/mob/living/simple_animal/friendly/crab.dm b/code/modules/mob/living/simple_animal/friendly/crab.dm index 7f3693f622..addbd493a5 100644 --- a/code/modules/mob/living/simple_animal/friendly/crab.dm +++ b/code/modules/mob/living/simple_animal/friendly/crab.dm @@ -21,12 +21,15 @@ stop_automated_movement = 1 friendly_verb_continuous = "pinches" friendly_verb_simple = "pinch" - ventcrawler = VENTCRAWLER_ALWAYS mob_size = MOB_SIZE_TINY var/obj/item/inventory_head var/obj/item/inventory_mask gold_core_spawnable = FRIENDLY_SPAWN +/mob/living/simple_animal/crab/Initialize() + . = ..() + AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) + /mob/living/simple_animal/crab/BiologicalLife(seconds, times_fired) if(!(. = ..())) return diff --git a/code/modules/mob/living/simple_animal/friendly/dog.dm b/code/modules/mob/living/simple_animal/friendly/dog.dm index 0584995583..49581b91a7 100644 --- a/code/modules/mob/living/simple_animal/friendly/dog.dm +++ b/code/modules/mob/living/simple_animal/friendly/dog.dm @@ -263,7 +263,7 @@ /mob/living/simple_animal/pet/dog/corgi/proc/place_on_head(obj/item/item_to_add, mob/user) if(istype(item_to_add, /obj/item/grenade/plastic)) // last thing he ever wears, I guess - item_to_add.afterattack(src,user,1) + INVOKE_ASYNC(item_to_add, /obj/item.proc/afterattack, src, user, 1) return if(inventory_head) @@ -271,13 +271,15 @@ to_chat(user, "You can't put more than one hat on [src]!") return if(!item_to_add) - user.visible_message("[user] pets [src].","You rest your hand on [src]'s head for a moment.") + user.visible_message("[user] pets [src].", "You rest your hand on [src]'s head for a moment.") + if(flags_1 & HOLOGRAM_1) + return SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, src, /datum/mood_event/pet_animal, src) return if(user && !user.temporarilyRemoveItemFromInventory(item_to_add)) to_chat(user, "\The [item_to_add] is stuck to your hand, you cannot put it on [src]'s head!") - return 0 + return var/valid = FALSE if(ispath(item_to_add.dog_fashion, /datum/dog_fashion/head)) @@ -287,11 +289,11 @@ if(valid) if(health <= 0) - to_chat(user, "There is merely a dull, lifeless look in [real_name]'s eyes as you put the [item_to_add] on [p_them()].") + to_chat(user, "There is merely a dull, lifeless look in [real_name]'s eyes as you put the [item_to_add] on [p_them()].") else if(user) - user.visible_message("[user] puts [item_to_add] on [real_name]'s head. [src] looks at [user] and barks once.", - "You put [item_to_add] on [real_name]'s head. [src] gives you a peculiar look, then wags [p_their()] tail once and barks.", - "You hear a friendly-sounding bark.") + user.visible_message("[user] puts [item_to_add] on [real_name]'s head. [src] looks at [user] and barks once.", + "You put [item_to_add] on [real_name]'s head. [src] gives you a peculiar look, then wags [p_their()] tail once and barks.", + "You hear a friendly-sounding bark.") item_to_add.forceMove(src) src.inventory_head = item_to_add update_corgi_fluff() @@ -361,7 +363,7 @@ icon_state = "old_corgi" icon_living = "old_corgi" icon_dead = "old_corgi_dead" - desc = "At a ripe old age of [record_age] Ian's not as spry as he used to be, but he'll always be the HoP's beloved corgi." //RIP + desc = "At a ripe old age of [record_age], Ian's not as spry as he used to be, but he'll always be the HoP's beloved corgi." //RIP turns_per_move = 20 RemoveElement(/datum/element/mob_holder, held_icon) AddElement(/datum/element/mob_holder, "old_corgi") diff --git a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm index a8c0e7d207..e11facb4ba 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm @@ -28,7 +28,6 @@ unsuitable_atmos_damage = 0 wander = 0 speed = 0 - ventcrawler = VENTCRAWLER_ALWAYS healable = 0 density = FALSE pass_flags = PASSTABLE | PASSMOB @@ -101,6 +100,8 @@ for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds) diag_hud.add_to_hud(src) + AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) + /mob/living/simple_animal/drone/ComponentInitialize() . = ..() if(can_be_held) diff --git a/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm b/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm index 55339a02fd..22dbdd3db7 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm @@ -114,7 +114,6 @@ harm_intent_damage = 5 density = TRUE speed = 1 - ventcrawler = VENTCRAWLER_NONE faction = list("neutral", "ratvar") speak_emote = list("clanks", "clinks", "clunks", "clangs") verb_ask = "requests" diff --git a/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm b/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm index 54184310a8..11d7884999 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm @@ -110,7 +110,7 @@ to_chat(src, "Your onboard antivirus has initiated lockdown. Motor servos are impaired, ventilation access is denied, and your display reports that you are hacked to all nearby.") hacked = TRUE mind.special_role = "hacked drone" - ventcrawler = VENTCRAWLER_NONE //Again, balance + RemoveElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) // balance speed = 1 //gotta go slow message_admins("[src] ([src.key]) became a hacked drone hellbent on [clockwork ? "serving Ratvar" : "destroying the station"]!") else @@ -125,7 +125,7 @@ to_chat(src, "Having been restored, your onboard antivirus reports the all-clear and you are able to perform all actions again.") hacked = FALSE mind.special_role = null - ventcrawler = initial(ventcrawler) + AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) speed = initial(speed) if(is_servant_of_ratvar(src)) remove_servant_of_ratvar(src, TRUE) diff --git a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm index 51e7ee6c03..81925d922f 100644 --- a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm +++ b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm @@ -241,7 +241,6 @@ attack_verb_simple = "kick" health = 3 maxHealth = 3 - ventcrawler = VENTCRAWLER_ALWAYS var/amount_grown = 0 pass_flags = PASSTABLE | PASSGRILLE | PASSMOB mob_size = MOB_SIZE_TINY @@ -253,6 +252,7 @@ . = ..() pixel_x = rand(-6, 6) pixel_y = rand(0, 10) + AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) /mob/living/simple_animal/chick/BiologicalLife(seconds, times_fired) if(!(. = ..())) @@ -296,7 +296,6 @@ attack_verb_simple = "kick" health = 15 maxHealth = 15 - ventcrawler = VENTCRAWLER_ALWAYS var/eggsleft = 0 var/eggsFertile = TRUE var/body_color @@ -322,6 +321,8 @@ pixel_y = rand(0, 10) ++chicken_count + AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) + /mob/living/simple_animal/chicken/Destroy() --chicken_count return ..() @@ -392,7 +393,6 @@ attack_verb_simple = "kick" health = 25 maxHealth = 25 - ventcrawler = VENTCRAWLER_ALWAYS var/eggsleft = 0 var/eggsFertile = TRUE pass_flags = PASSTABLE | PASSMOB @@ -412,6 +412,8 @@ . = ..() ++kiwi_count + AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) + /mob/living/simple_animal/kiwi/BiologicalLife(seconds, times_fired) if(!(. = ..())) return @@ -473,7 +475,6 @@ attack_verb_simple = "kick" health = 10 maxHealth = 10 - ventcrawler = VENTCRAWLER_ALWAYS var/amount_grown = 0 pass_flags = PASSTABLE | PASSGRILLE | PASSMOB mob_size = MOB_SIZE_TINY @@ -486,6 +487,8 @@ pixel_x = rand(-6, 6) pixel_y = rand(0, 10) + AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) + /mob/living/simple_animal/babyKiwi/BiologicalLife(seconds, times_fired) if(!(. = ..())) return diff --git a/code/modules/mob/living/simple_animal/friendly/lizard.dm b/code/modules/mob/living/simple_animal/friendly/lizard.dm index b9ff99b677..fd0095bf87 100644 --- a/code/modules/mob/living/simple_animal/friendly/lizard.dm +++ b/code/modules/mob/living/simple_animal/friendly/lizard.dm @@ -18,7 +18,6 @@ response_disarm_simple = "shoo" response_harm_continuous = "stomps on" response_harm_simple = "stomp on" - ventcrawler = VENTCRAWLER_ALWAYS density = FALSE pass_flags = PASSTABLE | PASSMOB mob_size = MOB_SIZE_SMALL @@ -31,6 +30,7 @@ /mob/living/simple_animal/hostile/lizard/ComponentInitialize() . = ..() AddElement(/datum/element/mob_holder, worn_state = "lizard", inv_slots = ITEM_SLOT_HEAD) //you can hold lizards now. + AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) /mob/living/simple_animal/hostile/lizard/CanAttack(atom/the_target)//Can we actually attack a possible target? if(see_invisible < the_target.invisibility)//Target's invisible to us, forget it diff --git a/code/modules/mob/living/simple_animal/friendly/mouse.dm b/code/modules/mob/living/simple_animal/friendly/mouse.dm index 51c903ee16..8348af43fa 100644 --- a/code/modules/mob/living/simple_animal/friendly/mouse.dm +++ b/code/modules/mob/living/simple_animal/friendly/mouse.dm @@ -22,7 +22,6 @@ response_harm_continuous = "splats" response_harm_simple = "splat" density = FALSE - ventcrawler = VENTCRAWLER_ALWAYS pass_flags = PASSTABLE | PASSGRILLE | PASSMOB mob_size = MOB_SIZE_TINY mob_biotypes = MOB_ORGANIC|MOB_BEAST @@ -40,6 +39,7 @@ icon_state = "mouse_[body_color]" icon_living = "mouse_[body_color]" icon_dead = "mouse_[body_color]_dead" + AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) /mob/living/simple_animal/mouse/proc/splat() src.health = 0 diff --git a/code/modules/mob/living/simple_animal/friendly/possum.dm b/code/modules/mob/living/simple_animal/friendly/possum.dm index 71fdbd1465..5e7ed572e2 100644 --- a/code/modules/mob/living/simple_animal/friendly/possum.dm +++ b/code/modules/mob/living/simple_animal/friendly/possum.dm @@ -22,12 +22,15 @@ response_harm_continuous = "stamps on" response_harm_simple = "stamp" density = FALSE - ventcrawler = VENTCRAWLER_ALWAYS pass_flags = PASSTABLE | PASSMOB mob_size = MOB_SIZE_TINY mob_biotypes = MOB_ORGANIC|MOB_BEAST gold_core_spawnable = FRIENDLY_SPAWN +/mob/living/simple_animal/opossum/Initialize() + . = ..() + AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) + /mob/living/simple_animal/opossum/poppy name = "Poppy the Safety Possum" desc = "Safety first!" diff --git a/code/modules/mob/living/simple_animal/friendly/snake.dm b/code/modules/mob/living/simple_animal/friendly/snake.dm index 4d20b927a6..61c735c7c1 100644 --- a/code/modules/mob/living/simple_animal/friendly/snake.dm +++ b/code/modules/mob/living/simple_animal/friendly/snake.dm @@ -30,7 +30,6 @@ response_harm_continuous = "steps on" response_harm_simple = "step on" faction = list("hostile") - ventcrawler = VENTCRAWLER_ALWAYS density = FALSE pass_flags = PASSTABLE | PASSMOB mob_size = MOB_SIZE_SMALL @@ -39,6 +38,9 @@ obj_damage = 0 environment_smash = ENVIRONMENT_SMASH_NONE +/mob/living/simple_animal/hostile/retaliate/poison/snake/Initialize() + . = ..() + AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) /mob/living/simple_animal/hostile/retaliate/poison/snake/ListTargets(atom/the_target) . = oview(vision_range, targets_from) //get list of things in vision range diff --git a/code/modules/mob/living/simple_animal/guardian/types/ranged.dm b/code/modules/mob/living/simple_animal/guardian/types/ranged.dm index e7c4e2f352..e2bcdd5684 100644 --- a/code/modules/mob/living/simple_animal/guardian/types/ranged.dm +++ b/code/modules/mob/living/simple_animal/guardian/types/ranged.dm @@ -110,6 +110,7 @@ /obj/effect/snare/Crossed(AM as mob|obj) + . = ..() if(isliving(AM) && spawner && spawner.summoner && AM != spawner && !spawner.hasmatchingsummoner(AM)) to_chat(spawner.summoner, "[AM] has crossed surveillance snare, [name].") var/list/guardians = spawner.summoner.hasparasites() diff --git a/code/modules/mob/living/simple_animal/hostile/banana_spider.dm b/code/modules/mob/living/simple_animal/hostile/banana_spider.dm index 259c0bc721..a88593ed74 100644 --- a/code/modules/mob/living/simple_animal/hostile/banana_spider.dm +++ b/code/modules/mob/living/simple_animal/hostile/banana_spider.dm @@ -22,7 +22,6 @@ speak_emote = list("chitters") mouse_opacity = 2 density = TRUE - ventcrawler = VENTCRAWLER_ALWAYS verb_say = "chitters" verb_ask = "chitters inquisitively" verb_exclaim = "chitters loudly" @@ -37,6 +36,8 @@ if(A) notify_ghosts("A banana spider has been created in \the [A.name].", source = src, action=NOTIFY_ATTACK, flashwindow = FALSE, ignore_dnr_observers = TRUE) + AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) + /mob/living/simple_animal/banana_spider/attack_ghost(mob/user) if(key) //please stop using src. without a good reason. return diff --git a/code/modules/mob/living/simple_animal/hostile/bear.dm b/code/modules/mob/living/simple_animal/hostile/bear.dm index 1be90a07f8..c7772f780d 100644 --- a/code/modules/mob/living/simple_animal/hostile/bear.dm +++ b/code/modules/mob/living/simple_animal/hostile/bear.dm @@ -109,7 +109,7 @@ to_chat(user, "You strap the armor plating to [A] and sharpen [A.p_their()] claws with the nail filer. This was a great idea.") qdel(src) -mob/living/simple_animal/hostile/bear/butter //The mighty companion to Cak. Several functions used from it. +/mob/living/simple_animal/hostile/bear/butter //The mighty companion to Cak. Several functions used from it. name = "Terrygold" icon_state = "butterbear" icon_living = "butterbear" @@ -155,7 +155,7 @@ mob/living/simple_animal/hostile/bear/butter //The mighty companion to Cak. Seve to_chat(src, "Your name is now \"new_name\"!") name = new_name -mob/living/simple_animal/hostile/bear/butter/AttackingTarget() //Makes some attacks by the butter bear slip those who dare cross its path. +/mob/living/simple_animal/hostile/bear/butter/AttackingTarget() //Makes some attacks by the butter bear slip those who dare cross its path. if(isliving(target)) var/mob/living/L = target if((L.mobility_flags & MOBILITY_STAND)) diff --git a/code/modules/mob/living/simple_animal/hostile/bread.dm b/code/modules/mob/living/simple_animal/hostile/bread.dm index 317827028d..70c8b0c540 100644 --- a/code/modules/mob/living/simple_animal/hostile/bread.dm +++ b/code/modules/mob/living/simple_animal/hostile/bread.dm @@ -26,7 +26,6 @@ speak_emote = list("growls") mouse_opacity = 2 density = TRUE - ventcrawler = VENTCRAWLER_ALWAYS verb_say = "growls" verb_ask = "growls inquisitively" verb_exclaim = "growls loudly" @@ -38,6 +37,7 @@ var/area/A = get_area(src) if(A) notify_ghosts("A tumor bread has been created in \the [A.name].", source = src, action=NOTIFY_ATTACK, flashwindow = FALSE, ignore_dnr_observers = TRUE) + AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) /mob/living/simple_animal/hostile/bread/attack_ghost(mob/user) if(key) //please stop using src. without a good reason. diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm index bde5a19518..2349685a4e 100644 --- a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm +++ b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm @@ -44,7 +44,6 @@ var/busy = SPIDER_IDLE pass_flags = PASSTABLE move_to_delay = 6 - ventcrawler = VENTCRAWLER_ALWAYS attack_verb_continuous = "bites" attack_verb_simple = "bite" attack_sound = 'sound/weapons/bite.ogg' @@ -63,6 +62,8 @@ lay_web = new lay_web.Grant(src) + AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) + /mob/living/simple_animal/hostile/poison/giant_spider/Destroy() QDEL_NULL(lay_web) return ..() @@ -389,7 +390,6 @@ name = "Wrap" panel = "Spider" active = FALSE - datum/action/spell_action/action = null desc = "Wrap something or someone in a cocoon. If it's a living being, you'll also consume them, allowing you to lay eggs." ranged_mousepointer = 'icons/effects/wrap_target.dmi' action_icon = 'icons/mob/actions/actions_animal.dmi' diff --git a/code/modules/mob/living/simple_animal/hostile/headcrab.dm b/code/modules/mob/living/simple_animal/hostile/headcrab.dm index 850beeb099..5e34d17bb2 100644 --- a/code/modules/mob/living/simple_animal/hostile/headcrab.dm +++ b/code/modules/mob/living/simple_animal/hostile/headcrab.dm @@ -20,11 +20,14 @@ obj_damage = 0 environment_smash = ENVIRONMENT_SMASH_NONE speak_emote = list("squeaks") - ventcrawler = VENTCRAWLER_ALWAYS var/datum/mind/origin var/egg_lain = 0 gold_core_spawnable = NO_SPAWN //are you sure about this?? // CITADEL CHANGE, Yes. +/mob/living/simple_animal/hostile/headcrab/Initialize() + . = ..() + AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) + /mob/living/simple_animal/hostile/headcrab/proc/Infect(mob/living/carbon/victim) var/obj/item/organ/body_egg/changeling_egg/egg = new(victim) egg.Insert(victim) diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm index 37eb9b7f67..95f8f2acc1 100644 --- a/code/modules/mob/living/simple_animal/hostile/hostile.dm +++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm @@ -511,7 +511,7 @@ DestroyObjectsInDirection(direction) -mob/living/simple_animal/hostile/proc/DestroySurroundings() // for use with megafauna destroying everything around them +/mob/living/simple_animal/hostile/proc/DestroySurroundings() // for use with megafauna destroying everything around them if(environment_smash) EscapeConfinement() for(var/dir in GLOB.cardinals) diff --git a/code/modules/mob/living/simple_animal/hostile/killertomato.dm b/code/modules/mob/living/simple_animal/hostile/killertomato.dm index b86d5d87fc..d3d3dadd1e 100644 --- a/code/modules/mob/living/simple_animal/hostile/killertomato.dm +++ b/code/modules/mob/living/simple_animal/hostile/killertomato.dm @@ -22,10 +22,13 @@ attack_verb_continuous = "slams" attack_verb_simple = "slam" attack_sound = 'sound/weapons/punch1.ogg' - ventcrawler = VENTCRAWLER_ALWAYS faction = list("plants") atmos_requirements = list("min_oxy" = 5, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) minbodytemp = 150 maxbodytemp = 500 gold_core_spawnable = HOSTILE_SPAWN + +/mob/living/simple_animal/hostile/killertomato/Initialize() + . = ..() + AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm index fa3a59a6b9..a584d34995 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm @@ -620,7 +620,6 @@ Difficulty: Very Hard density = FALSE movement_type = FLYING pass_flags = PASSTABLE | PASSGRILLE | PASSMOB - ventcrawler = VENTCRAWLER_ALWAYS mob_size = MOB_SIZE_TINY gold_core_spawnable = HOSTILE_SPAWN verb_say = "warps" @@ -648,6 +647,7 @@ Difficulty: Very Hard remove_verb(src, /mob/verb/me_verb) var/datum/atom_hud/medsensor = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED] medsensor.add_hud_to(src) + AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) /mob/living/simple_animal/hostile/lightgeist/AttackingTarget() . = ..() diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm index 4e8f4f6160..ef51dc572f 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm @@ -219,6 +219,9 @@ /obj/effect/temp_visual/goliath_tentacle/broodmother/patch/Initialize(mapload, new_spawner) . = ..() + INVOKE_ASYNC(src, .proc/createpatch) + +/obj/effect/temp_visual/goliath_tentacle/broodmother/patch/proc/createpatch() var/tentacle_locs = spiral_range_turfs(1, get_turf(src)) for(var/T in tentacle_locs) new /obj/effect/temp_visual/goliath_tentacle/broodmother(T, spawner) diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/gutlunch.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/gutlunch.dm index 0ccc4525c7..e35220a920 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/gutlunch.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/gutlunch.dm @@ -27,7 +27,6 @@ friendly_verb_continuous = "pinches" friendly_verb_simple = "pinch" a_intent = INTENT_HELP - ventcrawler = VENTCRAWLER_ALWAYS gold_core_spawnable = FRIENDLY_SPAWN stat_attack = UNCONSCIOUS gender = NEUTER @@ -50,6 +49,7 @@ /mob/living/simple_animal/hostile/asteroid/gutlunch/Initialize() udder = new() . = ..() + AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) /mob/living/simple_animal/hostile/asteroid/gutlunch/CanAttack(atom/the_target) // Gutlunch-specific version of CanAttack to handle stupid stat_exclusive = true crap so we don't have to do it for literally every single simple_animal/hostile except the two that spawn in lavaland if(isturf(the_target) || !the_target || the_target.type == /atom/movable/lighting_object) // bail out on invalids diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm index 11ce4f9214..ae0f5ea3ca 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm @@ -398,7 +398,6 @@ uniform = /obj/item/clothing/under/color/grey belt = /obj/item/tank/internals/emergency_oxygen mask = /obj/item/clothing/mask/gas - ears = /obj/item/radio/headset gloves = /obj/item/clothing/gloves/color/fyellow id = /obj/item/card/id/silver/reaper //looks cool and has a fancy name but only a 1% chance if(prob(99)) @@ -412,7 +411,7 @@ back = /obj/item/spear else if(prob(80)) //Now they dont always have a backpack back = /obj/item/storage/backpack - backpack_contents = list(/obj/item/stack/cable_coil = 1, /obj/item/assembly/flash = 1, /obj/item/storage/fancy/donut_box = 1, /obj/item/storage/fancy/cigarettes/cigpack_shadyjims = 1, /obj/item/lighter = 1) + backpack_contents = list(/obj/item/stack/cable_coil = 1, /obj/item/storage/fancy/donut_box = 1, /obj/item/storage/fancy/cigarettes/cigpack_shadyjims = 1, /obj/item/lighter = 1) if(prob(90)) r_pocket = /obj/item/kitchen/knife if(prob(60)) @@ -423,7 +422,6 @@ suit = /obj/item/clothing/suit/hooded/bee_costume shoes = /obj/item/clothing/shoes/sneakers/yellow gloves = /obj/item/clothing/gloves/color/yellow - ears = /obj/item/radio/headset belt = /obj/item/storage/belt/fannypack/yellow id_job = "Assisant" id = /obj/item/card/id diff --git a/code/modules/mob/living/simple_animal/hostile/mushroom.dm b/code/modules/mob/living/simple_animal/hostile/mushroom.dm index 9101430ccc..f41746ea69 100644 --- a/code/modules/mob/living/simple_animal/hostile/mushroom.dm +++ b/code/modules/mob/living/simple_animal/hostile/mushroom.dm @@ -28,7 +28,6 @@ stat_attack = DEAD mouse_opacity = MOUSE_OPACITY_ICON speed = 1 - ventcrawler = VENTCRAWLER_ALWAYS robust_searching = 1 unique_name = 1 speak_emote = list("squeaks") @@ -41,6 +40,10 @@ var/static/mutable_appearance/cap_living //Where we store our cap icons so we dont generate them constantly to update our icon var/static/mutable_appearance/cap_dead +/mob/living/simple_animal/hostile/mushroom/Initialize() + . = ..() + AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) + /mob/living/simple_animal/hostile/mushroom/examine(mob/user) . = ..() if(health >= maxHealth) diff --git a/code/modules/mob/living/simple_animal/hostile/regalrat.dm b/code/modules/mob/living/simple_animal/hostile/regalrat.dm index 77b2d4268a..77731f0ea4 100644 --- a/code/modules/mob/living/simple_animal/hostile/regalrat.dm +++ b/code/modules/mob/living/simple_animal/hostile/regalrat.dm @@ -23,7 +23,6 @@ attack_verb_continuous = "slashes" attack_verb_simple = "slash" attack_sound = 'sound/weapons/punch1.ogg' - ventcrawler = VENTCRAWLER_ALWAYS unique_name = TRUE faction = list("rat") var/datum/action/cooldown/coffer @@ -42,6 +41,8 @@ key = C.key notify_ghosts("All rise for the rat king, ascendant to the throne in \the [get_area(src)].", source = src, action = NOTIFY_ORBIT, flashwindow = FALSE) + AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) + /mob/living/simple_animal/hostile/regalrat/handle_automated_action() if(prob(20)) riot.Trigger() @@ -175,7 +176,6 @@ health = 15 butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 1) density = FALSE - ventcrawler = VENTCRAWLER_ALWAYS pass_flags = PASSTABLE | PASSGRILLE | PASSMOB mob_size = MOB_SIZE_TINY mob_biotypes = MOB_ORGANIC|MOB_BEAST @@ -185,6 +185,7 @@ . = ..() SSmobs.cheeserats += src AddComponent(/datum/component/swarming) + AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) /mob/living/simple_animal/hostile/rat/Destroy() SSmobs.cheeserats -= src diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/bat.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/bat.dm index 9045ccef51..cb1ee6c6f6 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/bat.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/bat.dm @@ -30,7 +30,6 @@ attack_sound = 'sound/weapons/bite.ogg' obj_damage = 0 environment_smash = ENVIRONMENT_SMASH_NONE - ventcrawler = VENTCRAWLER_ALWAYS mob_size = MOB_SIZE_TINY movement_type = FLYING speak_emote = list("squeaks") @@ -38,11 +37,14 @@ var/min_oxy = 0 var/max_tox = 0 - //Space bats need no air to fly in. atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) minbodytemp = 0 +/mob/living/simple_animal/hostile/retaliate/bat/Initialize() + . = ..() + AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) + /mob/living/simple_animal/hostile/retaliate/bat/secbat name = "Security Bat" icon_state = "secbat" diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm index dec2159dc0..96418686d3 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm @@ -137,7 +137,6 @@ emote_see = list("honks", "sweats", "jiggles", "contemplates its existence") speak_chance = 5 dextrous = TRUE - ventcrawler = VENTCRAWLER_ALWAYS maxHealth = 140 health = 140 speed = -5 @@ -147,6 +146,10 @@ obj_damage = 5 loot = list(/obj/item/clothing/suit/hooded/bloated_human, /obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/human, /obj/item/soap) +/mob/living/simple_animal/hostile/retaliate/clown/fleshclown/Initialize() + . = ..() + AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) + /mob/living/simple_animal/hostile/retaliate/clown/longface name = "Longface" desc = "Often found walking into the bar." diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/frog.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/frog.dm index 8424a0a576..2433b45cc0 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/frog.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/frog.dm @@ -22,7 +22,6 @@ response_harm_continuous = "splats" response_harm_simple = "splat" density = FALSE - ventcrawler = VENTCRAWLER_ALWAYS faction = list("hostile") attack_sound = 'sound/effects/reee.ogg' butcher_results = list(/obj/item/reagent_containers/food/snacks/nugget = 1) @@ -40,9 +39,11 @@ icon_living = "rare_frog" icon_dead = "rare_frog_dead" butcher_results = list(/obj/item/reagent_containers/food/snacks/nugget = 5) + AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) /mob/living/simple_animal/hostile/retaliate/frog/Crossed(AM as mob|obj) + . = ..() if(!stat && isliving(AM)) var/mob/living/L = AM if(L.mob_size > MOB_SIZE_TINY) - playsound(src, stepped_sound, 50, 1) + playsound(src, stepped_sound, 50, TRUE) diff --git a/code/modules/mob/living/simple_animal/hostile/venus_human_trap.dm b/code/modules/mob/living/simple_animal/hostile/venus_human_trap.dm index fdb088934c..cc5b0b8a75 100644 --- a/code/modules/mob/living/simple_animal/hostile/venus_human_trap.dm +++ b/code/modules/mob/living/simple_animal/hostile/venus_human_trap.dm @@ -190,5 +190,5 @@ * Arguments: * * datum/beam/vine - The vine to be removed from the list. */ -mob/living/simple_animal/hostile/venus_human_trap/proc/remove_vine(datum/beam/vine, force) +/mob/living/simple_animal/hostile/venus_human_trap/proc/remove_vine(datum/beam/vine, force) vines -= vine diff --git a/code/modules/mob/living/simple_animal/parrot.dm b/code/modules/mob/living/simple_animal/parrot.dm index 6e02944885..d146bb855f 100644 --- a/code/modules/mob/living/simple_animal/parrot.dm +++ b/code/modules/mob/living/simple_animal/parrot.dm @@ -83,6 +83,8 @@ //Headset for Poly to yell at engineers :) var/obj/item/radio/headset/ears = null + /// spawns with headset + var/spawns_with_headset = FALSE //The thing the parrot is currently interested in. This gets used for items the parrot wants to pick up, mobs it wants to steal from, //mobs it wants to attack or mobs that have attacked it @@ -105,13 +107,14 @@ /mob/living/simple_animal/parrot/Initialize() . = ..() - if(!ears) - var/headset = pick(/obj/item/radio/headset/headset_sec, \ - /obj/item/radio/headset/headset_eng, \ - /obj/item/radio/headset/headset_med, \ - /obj/item/radio/headset/headset_sci, \ - /obj/item/radio/headset/headset_cargo) - ears = new headset(src) + if(spawns_with_headset) + if(!ears) + var/headset = pick(/obj/item/radio/headset/headset_sec, \ + /obj/item/radio/headset/headset_eng, \ + /obj/item/radio/headset/headset_med, \ + /obj/item/radio/headset/headset_sci, \ + /obj/item/radio/headset/headset_cargo) + ears = new headset(src) parrot_sleep_dur = parrot_sleep_max //In case someone decides to change the max without changing the duration var @@ -881,6 +884,7 @@ speak = list("Poly wanna cracker!", ":e Check the crystal, you chucklefucks!",":e Wire the solars, you lazy bums!",":e WHO TOOK THE DAMN HARDSUITS?",":e OH GOD ITS ABOUT TO DELAMINATE CALL THE SHUTTLE") gold_core_spawnable = NO_SPAWN speak_chance = 3 + spawns_with_headset = TRUE var/memory_saved = FALSE var/rounds_survived = 0 var/longest_survival = 0 @@ -1189,4 +1193,4 @@ icon_state = "mtoo-flap" icon_living = "mtoo-flap" icon_dead = "mtoo-dead" - icon_sit = "mtoo_sit" \ No newline at end of file + icon_sit = "mtoo_sit" diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm index ab59441572..06649ac7d6 100644 --- a/code/modules/mob/living/simple_animal/slime/slime.dm +++ b/code/modules/mob/living/simple_animal/slime/slime.dm @@ -4,7 +4,6 @@ icon_state = "grey baby slime" pass_flags = PASSTABLE mob_size = MOB_SIZE_SMALL - ventcrawler = VENTCRAWLER_ALWAYS gender = NEUTER var/is_adult = 0 var/docile = 0 @@ -108,6 +107,8 @@ AddComponent(/datum/component/footstep, FOOTSTEP_MOB_SLIME, 7.5) set_nutrition(rand(650, 800)) + AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS) + /mob/living/simple_animal/slime/Destroy() for (var/A in actions) var/datum/action/AC = A diff --git a/code/modules/mob/living/ventcrawling.dm b/code/modules/mob/living/ventcrawling.dm index 4c00fd0033..9ade9f097f 100644 --- a/code/modules/mob/living/ventcrawling.dm +++ b/code/modules/mob/living/ventcrawling.dm @@ -5,7 +5,7 @@ GLOBAL_LIST_INIT(ventcrawl_machinery, typecacheof(list( //VENTCRAWLING -/mob/living/proc/handle_ventcrawl(atom/A) +/mob/living/proc/handle_ventcrawl(atom/A, ventcrawler) if(!ventcrawler || !Adjacent(A)) return . = TRUE //return value to stop the client from being shown the turf contents stat tab on alt-click. @@ -59,7 +59,7 @@ GLOBAL_LIST_INIT(ventcrawl_machinery, typecacheof(list( if(!client) return - if(iscarbon(src) && ventcrawler == VENTCRAWLER_NUDE) + if(iscarbon(src) && ventcrawler==VENTCRAWLER_NUDE) if(length(get_equipped_items(include_pockets = TRUE)) || get_num_held_items()) to_chat(src, "You can't crawl around in the ventilation ducts with items!") return diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index dc81b3cfbf..ba2399b831 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -177,3 +177,6 @@ var/list/ability_actions /// ability = list(data). see __DEFINES/mobs/innate_abilities.dm var/list/ability_properties + + ///Override for sound_environments. If this is set the user will always hear a specific type of reverb (Instead of the area defined reverb) + var/sound_environment_override = SOUND_ENVIRONMENT_NONE diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index e977c397c9..c467605f37 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -73,6 +73,7 @@ return FALSE //We are now going to move var/add_delay = mob.movement_delay() + mob.set_glide_size(DELAY_TO_GLIDE_SIZE(add_delay * ( (NSCOMPONENT(direction) && EWCOMPONENT(direction)) ? 2 : 1 ) ), FALSE) // set it now in case of pulled objects if(old_move_delay + (add_delay*MOVEMENT_DELAY_BUFFER_DELTA) + MOVEMENT_DELAY_BUFFER > world.time) move_delay = old_move_delay else @@ -95,6 +96,7 @@ if((direction & (direction - 1)) && mob.loc == n) //moved diagonally successfully add_delay *= 2 + mob.set_glide_size(DELAY_TO_GLIDE_SIZE(add_delay), FALSE) move_delay += add_delay if(.) // If mob is null here, we deserve the runtime if(mob.throwing) @@ -104,6 +106,8 @@ if(AM && AM.density && !SEND_SIGNAL(L, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_ACTIVE) && !ismob(AM)) L.setDir(turn(L.dir, 180)) + last_move = world.time + SEND_SIGNAL(mob, COMSIG_MOB_CLIENT_MOVE, src, direction, n, oldloc, add_delay) /// Process_Grab(): checks for grab, attempts to break if so. Return TRUE to prevent movement. diff --git a/code/modules/mob/say_vr.dm b/code/modules/mob/say_vr.dm index c5c53dc876..94bf45c1b0 100644 --- a/code/modules/mob/say_vr.dm +++ b/code/modules/mob/say_vr.dm @@ -3,14 +3,14 @@ ////////////////////////////////////////////////////// /mob/proc/get_top_level_mob() - if(istype(src.loc,/mob)&&src.loc!=src) - var/mob/M=src.loc + if(ismob(src.loc) && src.loc != src) + var/mob/M = src.loc return M.get_top_level_mob() return src -proc/get_top_level_mob(var/mob/S) - if(istype(S.loc,/mob)&&S.loc!=S) - var/mob/M=S.loc +/proc/get_top_level_mob(mob/S) + if(ismob(S.loc) && S.loc != S) + var/mob/M = S.loc return M.get_top_level_mob() return S diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index 3a7e270567..e49bd5162b 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -175,6 +175,7 @@ icon = null cut_overlays() invisibility = INVISIBILITY_MAXIMUM + new /obj/effect/temp_visual/monkeyify/humanify(loc) transformation_timer = addtimer(CALLBACK(src, .proc/finish_humanize, tr_flags), TRANSFORMATION_DURATION, TIMER_UNIQUE) @@ -202,6 +203,8 @@ var/mob/living/carbon/human/O = new( loc ) for(var/obj/item/C in O.loc) + if(C.anchored) + continue O.equip_to_appropriate_slot(C) dna.transfer_identity(O) diff --git a/code/modules/modular_computers/file_system/programs/arcade.dm b/code/modules/modular_computers/file_system/programs/arcade.dm index 4c7b51a7fd..002cf20801 100644 --- a/code/modules/modular_computers/file_system/programs/arcade.dm +++ b/code/modules/modular_computers/file_system/programs/arcade.dm @@ -27,7 +27,7 @@ // user?.mind?.adjust_experience(/datum/skill/gaming, 1) if(boss_hp <= 0) heads_up = "You have crushed [boss_name]! Rejoice!" - playsound(computer.loc, 'sound/arcade/win.ogg', 50, TRUE, extrarange = -3, falloff = 10) + playsound(computer.loc, 'sound/arcade/win.ogg', 50, TRUE, extrarange = -3) game_active = FALSE program_icon_state = "arcade_off" if(istype(computer)) @@ -37,7 +37,7 @@ sleep(10) else if(player_hp <= 0 || player_mp <= 0) heads_up = "You have been defeated... how will the station survive?" - playsound(computer.loc, 'sound/arcade/lose.ogg', 50, TRUE, extrarange = -3, falloff = 10) + playsound(computer.loc, 'sound/arcade/lose.ogg', 50, TRUE, extrarange = -3) game_active = FALSE program_icon_state = "arcade_off" if(istype(computer)) @@ -57,17 +57,17 @@ return if (boss_mp <= 5) heads_up = "[boss_mpamt] magic power has been stolen from you!" - playsound(computer.loc, 'sound/arcade/steal.ogg', 50, TRUE, extrarange = -3, falloff = 10) + playsound(computer.loc, 'sound/arcade/steal.ogg', 50, TRUE, extrarange = -3) player_mp -= boss_mpamt boss_mp += boss_mpamt else if(boss_mp > 5 && boss_hp <12) heads_up = "[boss_name] heals for [bossheal] health!" - playsound(computer.loc, 'sound/arcade/heal.ogg', 50, TRUE, extrarange = -3, falloff = 10) + playsound(computer.loc, 'sound/arcade/heal.ogg', 50, TRUE, extrarange = -3) boss_hp += bossheal boss_mp -= boss_mpamt else heads_up = "[boss_name] attacks you for [boss_attackamt] damage!" - playsound(computer.loc, 'sound/arcade/hit.ogg', 50, TRUE, extrarange = -3, falloff = 10) + playsound(computer.loc, 'sound/arcade/hit.ogg', 50, TRUE, extrarange = -3) player_hp -= boss_attackamt pause_state = FALSE @@ -106,7 +106,7 @@ attackamt = rand(2,6)// + rand(0, gamerSkill) pause_state = TRUE heads_up = "You attack for [attackamt] damage." - playsound(computer.loc, 'sound/arcade/hit.ogg', 50, TRUE, extrarange = -3, falloff = 10) + playsound(computer.loc, 'sound/arcade/hit.ogg', 50, TRUE, extrarange = -3) boss_hp -= attackamt sleep(10) game_check() @@ -123,7 +123,7 @@ healcost = rand(1, maxPointCost) pause_state = TRUE heads_up = "You heal for [healamt] damage." - playsound(computer.loc, 'sound/arcade/heal.ogg', 50, TRUE, extrarange = -3, falloff = 10) + playsound(computer.loc, 'sound/arcade/heal.ogg', 50, TRUE, extrarange = -3) player_hp += healamt player_mp -= healcost sleep(10) @@ -136,7 +136,7 @@ rechargeamt = rand(4,7)// + rand(0, gamerSkill) pause_state = TRUE heads_up = "You regain [rechargeamt] magic power." - playsound(computer.loc, 'sound/arcade/mana.ogg', 50, TRUE, extrarange = -3, falloff = 10) + playsound(computer.loc, 'sound/arcade/mana.ogg', 50, TRUE, extrarange = -3) player_mp += rechargeamt sleep(10) game_check() diff --git a/code/modules/movespeed/_movespeed_modifier.dm b/code/modules/movespeed/_movespeed_modifier.dm index 9c8036bd55..46d10afe7f 100644 --- a/code/modules/movespeed/_movespeed_modifier.dm +++ b/code/modules/movespeed/_movespeed_modifier.dm @@ -96,7 +96,7 @@ GLOBAL_LIST_EMPTY(movespeed_modification_cache) return TRUE remove_movespeed_modifier(existing, FALSE) if(length(movespeed_modification)) - BINARY_INSERT(type_or_datum.id, movespeed_modification, datum/movespeed_modifier, type_or_datum, priority, COMPARE_VALUE) + BINARY_INSERT(type_or_datum.id, movespeed_modification, /datum/movespeed_modifier, type_or_datum, priority, COMPARE_VALUE) LAZYSET(movespeed_modification, type_or_datum.id, type_or_datum) if(update) update_movespeed() @@ -217,13 +217,25 @@ GLOBAL_LIST_EMPTY(movespeed_modification_cache) else continue . = 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 = . - var/diff = old - cached_multiplicative_slowdown - if((diff > 0) && client) + if(!client) + return + var/diff = (client.last_move - client.move_delay) - cached_multiplicative_slowdown + if(diff > 0) if(client.move_delay > world.time + 1.5) client.move_delay -= diff + var/timeleft = world.time - client.move_delay + var/elapsed = world.time - client.last_move + var/glide_size_current = glide_size + if((timeleft <= 0) || (elapsed > 20)) + set_glide_size(16, TRUE) + return + var/pixels_moved = glide_size_current * elapsed * (1 / world.tick_lag) + // calculate glidesize needed to move to the next tile within timeleft deciseconds + var/ticks_allowed = timeleft / world.tick_lag + var/pixels_per_tick = pixels_moved / ticks_allowed + set_glide_size(pixels_per_tick * GLOB.glide_size_multiplier, TRUE) /// Get the move speed modifiers list of the mob /mob/proc/get_movespeed_modifiers() diff --git a/code/modules/movespeed/modifiers/mobs.dm b/code/modules/movespeed/modifiers/mobs.dm index d453124b71..cdfb275418 100644 --- a/code/modules/movespeed/modifiers/mobs.dm +++ b/code/modules/movespeed/modifiers/mobs.dm @@ -62,6 +62,11 @@ var/mod = CONFIG_GET(number/movedelay/walk_delay) multiplicative_slowdown = isnum(mod)? mod : initial(multiplicative_slowdown) +/datum/movespeed_modifier/config_wak_run/walk/apply_multiplicative(existing, mob/target) + . = ..() + if(HAS_TRAIT(target, TRAIT_SPEEDY_STEP)) + . -= 1.25 + /datum/movespeed_modifier/config_walk_run/run/sync() var/mod = CONFIG_GET(number/movedelay/run_delay) multiplicative_slowdown = isnum(mod)? mod : initial(multiplicative_slowdown) diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm index 20ec678e45..a00145f9dc 100644 --- a/code/modules/paperwork/paper.dm +++ b/code/modules/paperwork/paper.dm @@ -193,6 +193,13 @@ user.visible_message(ignition_message) add_fingerprint(user) fire_act(I.get_temperature()) +//I would have it become a paper plane before the throw, but that would risk runtimes +/obj/item/paper/DoRevenantThrowEffects(atom/target) + sleep(10) + if(HAS_TRAIT(src, TRAIT_SPOOKY_THROW)) + return + new /obj/item/paperplane(get_turf(src)) + qdel(src) /obj/item/paper/attackby(obj/item/P, mob/living/user, params) if(burn_paper_product_attackby_check(P, user)) diff --git a/code/modules/pool/pool_main.dm b/code/modules/pool/pool_main.dm index 98189cc8a4..088c991ca0 100644 --- a/code/modules/pool/pool_main.dm +++ b/code/modules/pool/pool_main.dm @@ -150,7 +150,8 @@ H.DefaultCombatKnockdown(40) playsound(src, 'sound/effects/woodhit.ogg', 60, TRUE, 1) else if(filled) - victim.adjustStaminaLoss(1) + if(iscarbon(victim)) + victim.adjustStaminaLoss(1) playsound(src, "water_wade", 20, TRUE) return ..() diff --git a/code/modules/power/singularity/containment_field.dm b/code/modules/power/singularity/containment_field.dm index dfb51df9cf..2ca9b7513c 100644 --- a/code/modules/power/singularity/containment_field.dm +++ b/code/modules/power/singularity/containment_field.dm @@ -56,12 +56,14 @@ else ..() -/obj/machinery/field/containment/Crossed(mob/mover) - if(isliving(mover)) - shock(mover) +/obj/machinery/field/containment/Crossed(atom/movable/AM) + . = ..() + if(isliving(AM)) + shock(AM) + + if(ismachinery(AM) || isstructure(AM) || ismecha(AM)) + bump_field(AM) - if(ismachinery(mover) || isstructure(mover) || ismecha(mover)) - bump_field(mover) /obj/machinery/field/containment/proc/set_master(master1,master2) if(!master1 || !master2) diff --git a/code/modules/power/singularity/particle_accelerator/particle.dm b/code/modules/power/singularity/particle_accelerator/particle.dm index 9e098446d1..7ecde364ae 100644 --- a/code/modules/power/singularity/particle_accelerator/particle.dm +++ b/code/modules/power/singularity/particle_accelerator/particle.dm @@ -44,6 +44,7 @@ movement_range = 0 /obj/effect/accelerated_particle/Crossed(atom/A) + . = ..() if(isliving(A)) toxmob(A) diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm index f385b640aa..1e82a601ea 100644 --- a/code/modules/power/supermatter/supermatter.dm +++ b/code/modules/power/supermatter/supermatter.dm @@ -348,11 +348,11 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) /obj/machinery/power/supermatter_crystal/proc/alarm() switch(get_status()) if(SUPERMATTER_DELAMINATING) - playsound(src, 'sound/misc/bloblarm.ogg', 100) + playsound(src, 'sound/misc/bloblarm.ogg', 100, FALSE, 40, 30, falloff_distance = 10) if(SUPERMATTER_EMERGENCY) - playsound(src, 'sound/machines/engine_alert1.ogg', 100) + playsound(src, 'sound/machines/engine_alert1.ogg', 100, FALSE, 30, 30, falloff_distance = 10) if(SUPERMATTER_DANGER) - playsound(src, 'sound/machines/engine_alert2.ogg', 100) + playsound(src, 'sound/machines/engine_alert2.ogg', 100, FALSE, 30, 30, falloff_distance = 10) if(SUPERMATTER_WARNING) playsound(src, 'sound/machines/terminal_alert.ogg', 75) diff --git a/code/modules/projectiles/ammunition/ballistic/shotgun.dm b/code/modules/projectiles/ammunition/ballistic/shotgun.dm index 68c1c1036d..2a41b41d1d 100644 --- a/code/modules/projectiles/ammunition/ballistic/shotgun.dm +++ b/code/modules/projectiles/ammunition/ballistic/shotgun.dm @@ -8,7 +8,7 @@ projectile_type = /obj/item/projectile/bullet/shotgun_slug custom_materials = list(/datum/material/iron=4000) -obj/item/ammo_casing/shotgun/executioner +/obj/item/ammo_casing/shotgun/executioner name = "executioner slug" desc = "A 12 gauge lead slug purpose built to annihilate flesh on impact." icon_state = "stunshell" diff --git a/code/modules/projectiles/ammunition/energy/special.dm b/code/modules/projectiles/ammunition/energy/special.dm index fc4207d084..2bf7c06ec6 100644 --- a/code/modules/projectiles/ammunition/energy/special.dm +++ b/code/modules/projectiles/ammunition/energy/special.dm @@ -24,6 +24,11 @@ projectile_type = /obj/item/projectile/energy/floramut select_name = "mutation" +/obj/item/ammo_casing/energy/flora/revolution + projectile_type = /obj/item/projectile/energy/florarevolution + select_name = "revolution" + e_cost = 250 + /obj/item/ammo_casing/energy/temp projectile_type = /obj/item/projectile/temp select_name = "freeze" diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 1c3a0d230f..e3a2da68da 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -18,6 +18,8 @@ item_flags = NEEDS_PERMIT attack_verb = list("struck", "hit", "bashed") attack_speed = CLICK_CD_RANGE + var/ranged_attack_speed = CLICK_CD_RANGE + var/melee_attack_speed = CLICK_CD_MELEE var/fire_sound = "gunshot" var/suppressed = null //whether or not a message is displayed when fired @@ -158,7 +160,7 @@ user.UseStaminaBuffer(safe_cost) if(suppressed) - playsound(user, fire_sound, 10, 1) + playsound(user, fire_sound, 10, TRUE, ignore_walls = FALSE, extrarange = SILENCED_SOUND_EXTRARANGE, falloff_distance = 0) else playsound(user, fire_sound, 50, 1) if(message) @@ -173,12 +175,25 @@ for(var/obj/O in contents) O.emp_act(severity) +/obj/item/gun/attack(mob/living/M, mob/user) + . = ..() + if(!(. & DISCARD_LAST_ACTION)) + user.DelayNextAction(melee_attack_speed) + +/obj/item/gun/attack_obj(obj/O, mob/user) + . = ..() + if(!(. & DISCARD_LAST_ACTION)) + user.DelayNextAction(melee_attack_speed) + /obj/item/gun/afterattack(atom/target, mob/living/user, flag, params) . = ..() - if(!CheckAttackCooldown(user, target)) + if(!CheckAttackCooldown(user, target, TRUE)) return process_afterattack(target, user, flag, params) +/obj/item/gun/CheckAttackCooldown(mob/user, atom/target, shooting = FALSE) + return user.CheckActionCooldown(shooting? ranged_attack_speed : attack_speed, clickdelay_from_next_action, clickdelay_mod_bypass, clickdelay_ignores_next_action) + /obj/item/gun/proc/process_afterattack(atom/target, mob/living/user, flag, params) if(!target) return diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm index ae6050a68e..f965100846 100644 --- a/code/modules/projectiles/guns/energy/special.dm +++ b/code/modules/projectiles/guns/energy/special.dm @@ -45,7 +45,7 @@ desc = "A tool that discharges controlled radiation which induces mutation in plant cells." icon_state = "flora" item_state = "gun" - ammo_type = list(/obj/item/ammo_casing/energy/flora/yield, /obj/item/ammo_casing/energy/flora/mut) + ammo_type = list(/obj/item/ammo_casing/energy/flora/yield, /obj/item/ammo_casing/energy/flora/mut, /obj/item/ammo_casing/energy/flora/revolution) modifystate = 1 ammo_x_offset = 1 selfcharge = EGUN_SELFCHARGE diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index fb9e6ff6c6..481d3c2c68 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -471,11 +471,10 @@ if(paused || !isturf(loc)) return - var/ds = (SSprojectiles.flags & SS_TICKER)? (wait * world.tick_lag) : wait - var/required_pixels = (pixels_per_second * ds * 0.1) + pixels_tick_leftover + var/required_pixels = (pixels_per_second * wait) + pixels_tick_leftover if(required_pixels >= pixel_increment_amount) pixels_tick_leftover = MODULUS(required_pixels, pixel_increment_amount) - pixel_move(FLOOR(required_pixels / pixel_increment_amount, 1), FALSE, ds, SSprojectiles.global_projectile_speed_multiplier) + pixel_move(FLOOR(required_pixels / pixel_increment_amount, 1), FALSE, wait, SSprojectiles.global_projectile_speed_multiplier) else pixels_tick_leftover = required_pixels @@ -603,7 +602,7 @@ * Trajectory multiplier directly modifies the factor of pixel_increment_amount to go per time. * It's complicated, so probably just don't mess with this unless you know what you're doing. */ -/obj/item/projectile/proc/pixel_move(times, hitscanning = FALSE, deciseconds_equivalent = world.tick_lag, trajectory_multiplier = 1, allow_animation = TRUE) +/obj/item/projectile/proc/pixel_move(times, hitscanning = FALSE, seconds_equivalent = world.tick_lag * 0.1, trajectory_multiplier = 1, allow_animation = TRUE) if(!loc || !trajectory) return if(!nondirectional_sprite && !hitscanning) @@ -620,7 +619,7 @@ if(homing_target) // No datum/points, too expensive. var/angle = closer_angle_difference(Angle, get_projectile_angle(src, homing_target)) - var/max_turn = homing_turn_speed * deciseconds_equivalent * 0.1 + var/max_turn = homing_turn_speed * seconds_equivalent setAngle(Angle + clamp(angle, -max_turn, max_turn)) // HOMING END trajectory.increment(trajectory_multiplier) diff --git a/code/modules/projectiles/projectile/plasma.dm b/code/modules/projectiles/projectile/plasma.dm index 838dac34a0..474a3d95c7 100644 --- a/code/modules/projectiles/projectile/plasma.dm +++ b/code/modules/projectiles/projectile/plasma.dm @@ -1,4 +1,4 @@ -obj/item/projectile/energy/plasmabolt +/obj/item/projectile/energy/plasmabolt name = "plasma bolt" icon_state = "plasma" flag = "energy" diff --git a/code/modules/projectiles/projectile/reusable/foam_dart.dm b/code/modules/projectiles/projectile/reusable/foam_dart.dm index 7d21f663c2..b00c35cd18 100644 --- a/code/modules/projectiles/projectile/reusable/foam_dart.dm +++ b/code/modules/projectiles/projectile/reusable/foam_dart.dm @@ -20,8 +20,9 @@ newcasing.modified = modified var/obj/item/projectile/bullet/reusable/foam_dart/newdart = newcasing.BB newdart.modified = modified - newdart.damage = damage - newdart.nodamage = nodamage + if(modified) + newdart.damage = 5 + newdart.nodamage = FALSE newdart.damage_type = damage_type if(pen) newdart.pen = pen diff --git a/code/modules/projectiles/projectile/special/floral.dm b/code/modules/projectiles/projectile/special/floral.dm index c3fe1f0fcb..b855322f09 100644 --- a/code/modules/projectiles/projectile/special/floral.dm +++ b/code/modules/projectiles/projectile/special/floral.dm @@ -2,7 +2,7 @@ name = "alpha somatoray" icon_state = "energy" damage = 0 - damage_type = TOX + damage_type = TRUE nodamage = 1 flag = "energy" @@ -21,5 +21,13 @@ icon_state = "energy2" damage = 0 damage_type = TOX - nodamage = 1 + nodamage = TRUE + flag = "energy" + +/obj/item/projectile/energy/florarevolution + name = "gamma somatorary" + icon_state = "energy3" + damage = 0 + damage_type = TOX + nodamage = TRUE flag = "energy" diff --git a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm index a0de9f7a7f..aae21464b1 100644 --- a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm @@ -2288,6 +2288,7 @@ All effects don't start immediately, but rather get worse over time; the rate is //Race-Base-Drinks// //////////////////// /datum/reagent/consumable/ethanol/species_drink + name = "Species Drink" var/species_required var/disgust = 26 boozepwr = 50 diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm index 7ab50884e0..e55286ed3f 100644 --- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm @@ -272,10 +272,10 @@ overdose_threshold = 50 /datum/reagent/medicine/silver_sulfadiazine/reaction_obj(obj/O, reac_volume) - if(istype(O, /obj/item/stack/medical/gauze)) + if(istype(O, /obj/item/stack/medical/gauze/adv)) var/obj/item/stack/medical/gauze/G = O - reac_volume = min((reac_volume / 10), G.amount) - new/obj/item/stack/medical/mesh(get_turf(G), reac_volume) + reac_volume = min((reac_volume / 5), G.amount) + new /obj/item/stack/medical/mesh/five(get_turf(G), reac_volume) G.use(reac_volume) /datum/reagent/medicine/silver_sulfadiazine/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message = 1) @@ -358,10 +358,10 @@ ..() /datum/reagent/medicine/styptic_powder/reaction_obj(obj/O, reac_volume) - if(istype(O, /obj/item/stack/medical/gauze)) + if(istype(O, /obj/item/stack/medical/gauze/adv)) var/obj/item/stack/medical/gauze/G = O - reac_volume = min((reac_volume / 10), G.amount) - new/obj/item/stack/medical/suture(get_turf(G), reac_volume) + reac_volume = min((reac_volume / 5), G.amount) + new /obj/item/stack/medical/suture/five(get_turf(G), reac_volume) G.use(reac_volume) /datum/reagent/medicine/styptic_powder/on_mob_life(mob/living/carbon/M) diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index 17cde0611b..90f570e4d1 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -2528,7 +2528,7 @@ M.adjustStaminaLoss(-0.25*REM) // the more wounds, the more stamina regen ..() -datum/reagent/eldritch +/datum/reagent/eldritch name = "Eldritch Essence" description = "Strange liquid that defies the laws of physics" taste_description = "Ag'hsj'saje'sh" diff --git a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm index 0d0a234afc..c9fbf6928a 100644 --- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm @@ -783,6 +783,8 @@ value = REAGENT_VALUE_VERY_RARE /datum/reagent/toxin/rotatium/on_mob_life(mob/living/carbon/M) + return ..() // until fixed - the rotations never stop +/* if(M.hud_used) if(current_cycle >= 20 && current_cycle%20 == 0) var/list/screens = list(M.hud_used.plane_masters["[FLOOR_PLANE]"], M.hud_used.plane_masters["[GAME_PLANE]"], @@ -800,6 +802,7 @@ for(var/whole_screen in screens) animate(whole_screen, transform = matrix(), time = 5, easing = QUAD_EASING) ..() +*/ /datum/reagent/toxin/skewium name = "Skewium" diff --git a/code/modules/reagents/reagent_containers/blood_pack.dm b/code/modules/reagents/reagent_containers/blood_pack.dm index 98a117ea69..acfda85963 100644 --- a/code/modules/reagents/reagent_containers/blood_pack.dm +++ b/code/modules/reagents/reagent_containers/blood_pack.dm @@ -104,31 +104,44 @@ return ..() /obj/item/reagent_containers/blood/attack(mob/living/carbon/C, mob/user, def_zone) - if(user.a_intent == INTENT_HELP && reagents.total_volume > 0 && iscarbon(C) && user.a_intent == INTENT_HELP) - if(C.is_mouth_covered()) - to_chat(user, "You cant drink from the [src] while your mouth is covered.") - return - if(user != C) - user.visible_message("[user] forces [C] to drink from the [src].", \ - "You force [C] to drink from the [src]") - if(!do_mob(user, C, 50)) - return - else - if(!do_mob(user, C, 10)) - return + if(!iscarbon(C) || user.a_intent != INTENT_HELP || reagents.total_volume <= 0) + ..() - to_chat(user, "You take a sip from the [src].") - user.visible_message("[user] puts the [src] up to their mouth.") - if(reagents.total_volume <= 0) // Safety: In case you spam clicked the blood bag on yourself, and it is now empty (below will divide by zero) + if(C.is_mouth_covered()) + if(user != C) + to_chat(user, "You can't force [C] to drink from [src] while their mouth is covered.") return - var/gulp_size = 3 - var/fraction = min(gulp_size / reagents.total_volume, 1) - reagents.reaction(C, INGEST, fraction) //checkLiked(fraction, M) // Blood isn't food, sorry. - reagents.trans_to(C, gulp_size) - reagents.remove_reagent(src, 2) //Inneficency, so hey, IVs are usefull. - playsound(C.loc,'sound/items/drink.ogg', rand(10, 50), TRUE) + to_chat(user, "You can't drink from [src] while your mouth is covered.") return - ..() + + if(!user.CheckActionCooldown()) + return + if(user != C) + user.visible_message("[user] forces [C] to drink from [src].", \ + "You force [C] to drink from [src]") + user.DelayNextAction(50) + if(do_mob(user, C, 50)) + do_drink(C, user) + + else + user.DelayNextAction(10) + if(do_mob(user, C, 10)) + user.visible_message("[user] puts [src] up to their mouth.", \ + "You take a sip from [src].") + do_drink(C, user) + + +/obj/item/reagent_containers/blood/proc/do_drink(mob/living/carbon/C, mob/user) + if(reagents.total_volume <= 0) // Safety: In case you spam clicked the blood bag on yourself, and it is now empty (below will divide by zero) + to_chat(user, "...and notice [src] is empty.") + return + var/gulp_size = 3 + var/fraction = min(gulp_size / reagents.total_volume, 1) + reagents.reaction(C, INGEST, fraction) //checkLiked(fraction, M) // Blood isn't food, sorry. + reagents.remove_any(5) //Inneficency, so hey, IVs are usefull. + reagents.trans_to(C, gulp_size) + playsound(C.loc,'sound/items/drink.ogg', rand(10, 50), TRUE) + /obj/item/reagent_containers/blood/bluespace name = "bluespace blood pack" diff --git a/code/modules/reagents/reagent_containers/chem_pack.dm b/code/modules/reagents/reagent_containers/chem_pack.dm index 78ae1a3070..77d6067d3b 100644 --- a/code/modules/reagents/reagent_containers/chem_pack.dm +++ b/code/modules/reagents/reagent_containers/chem_pack.dm @@ -44,8 +44,7 @@ else . += "Alt-click to seal it." - -obj/item/reagent_containers/chem_pack/attack_self(mob/user) +/obj/item/reagent_containers/chem_pack/attack_self(mob/user) if(sealed) return ..() diff --git a/code/modules/recycling/disposal/bin.dm b/code/modules/recycling/disposal/bin.dm index b106005a15..ef3a053027 100644 --- a/code/modules/recycling/disposal/bin.dm +++ b/code/modules/recycling/disposal/bin.dm @@ -141,7 +141,7 @@ update_icon() /obj/machinery/disposal/proc/can_stuff_mob_in(mob/living/target, mob/living/user, pushing = FALSE) - if(!pushing && !iscarbon(user) && !user.ventcrawler) //only carbon and ventcrawlers can climb into disposal by themselves. + if(!pushing && !iscarbon(user) && !(SEND_SIGNAL(user, COMSIG_CHECK_VENTCRAWL))) //only carbon and ventcrawlers can climb into disposal by themselves. if(iscyborg(user)) var/mob/living/silicon/robot/borg = user if (!borg.module || !borg.module.canDispose) diff --git a/code/modules/recycling/disposal/construction.dm b/code/modules/recycling/disposal/construction.dm index 348e687e03..c6d015df34 100644 --- a/code/modules/recycling/disposal/construction.dm +++ b/code/modules/recycling/disposal/construction.dm @@ -14,12 +14,12 @@ var/obj/pipe_type = /obj/structure/disposalpipe/segment var/pipename -/obj/structure/disposalconstruct/Initialize(loc, _pipe_type, _dir = SOUTH, flip = FALSE, obj/make_from) +/obj/structure/disposalconstruct/Initialize(mapload, _pipe_type, _dir = SOUTH, flip = FALSE, obj/make_from) . = ..() if(make_from) pipe_type = make_from.type setDir(make_from.dir) - anchored = TRUE + set_anchored(TRUE) else if(_pipe_type) @@ -34,6 +34,8 @@ update_icon() + // AddElement(/datum/element/undertile, TRAIT_T_RAY_VISIBLE) + /obj/structure/disposalconstruct/Move() var/old_dir = dir ..() diff --git a/code/modules/recycling/disposal/holder.dm b/code/modules/recycling/disposal/holder.dm index 2e36a9deaa..f739057699 100644 --- a/code/modules/recycling/disposal/holder.dm +++ b/code/modules/recycling/disposal/holder.dm @@ -73,14 +73,16 @@ /obj/structure/disposalholder/proc/move() set waitfor = FALSE var/obj/structure/disposalpipe/last + var/ticks = 1 while(active) var/obj/structure/disposalpipe/curr = loc last = curr + set_glide_size(DELAY_TO_GLIDE_SIZE(ticks * world.tick_lag)) curr = curr.transfer(src) if(!curr && active) last.expel(src, loc, dir) - stoplag() + ticks = stoplag() if(!(count--)) active = FALSE diff --git a/code/modules/research/designs/machine_desings/machine_designs_engi.dm b/code/modules/research/designs/machine_desings/machine_designs_engi.dm index 8908241b83..ca522d2ce1 100644 --- a/code/modules/research/designs/machine_desings/machine_designs_engi.dm +++ b/code/modules/research/designs/machine_desings/machine_designs_engi.dm @@ -111,4 +111,4 @@ id = "spaceship_navigation_beacon" build_path = /obj/item/circuitboard/machine/spaceship_navigation_beacon category = list ("Teleportation Machinery") - departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING | DEPARTMENTAL_FLAG_SCIENCE \ No newline at end of file + departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING | DEPARTMENTAL_FLAG_SCIENCE diff --git a/code/modules/research/designs/weapon_designs.dm b/code/modules/research/designs/weapon_designs.dm index 8c934d39a9..11dd29a416 100644 --- a/code/modules/research/designs/weapon_designs.dm +++ b/code/modules/research/designs/weapon_designs.dm @@ -324,8 +324,7 @@ desc = "A tool that discharges controlled radiation which induces mutation in plant cells. Harmless to other organic life." id = "flora_gun" build_type = PROTOLATHE - materials = list(/datum/material/iron = 2000, /datum/material/glass = 500) - reagents_list = list(/datum/reagent/radium = 20) + materials = list(/datum/material/iron = 2000, /datum/material/glass = 500, /datum/material/uranium = 2000) build_path = /obj/item/gun/energy/floragun category = list("Weapons") departmental_flags = DEPARTMENTAL_FLAG_SERVICE | DEPARTMENTAL_FLAG_SCIENCE diff --git a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm index 9b19516f26..c35f062739 100644 --- a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm +++ b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm @@ -236,7 +236,7 @@ duration = -1 alert_type = null -datum/status_effect/rebreathing/tick() +/datum/status_effect/rebreathing/tick() owner.adjustOxyLoss(-6, 0) //Just a bit more than normal breathing. /////////////////////////////////////////////////////// @@ -524,7 +524,7 @@ datum/status_effect/rebreathing/tick() ADD_TRAIT(owner, TRAIT_NOSLIPWATER, "slimestatus") return ..() -datum/status_effect/stabilized/blue/on_remove() +/datum/status_effect/stabilized/blue/on_remove() REMOVE_TRAIT(owner, TRAIT_NOSLIPWATER, "slimestatus") return ..() diff --git a/code/modules/ruins/lavalandruin_code/alien_nest.dm b/code/modules/ruins/lavalandruin_code/alien_nest.dm index d98a6bf5c1..c204102b1b 100644 --- a/code/modules/ruins/lavalandruin_code/alien_nest.dm +++ b/code/modules/ruins/lavalandruin_code/alien_nest.dm @@ -5,6 +5,24 @@ name = "alien drone" mob_name = "alien drone" +/obj/effect/mob_spawn/alien/corpse/humanoid/hunter + mob_type = /mob/living/carbon/alien/humanoid/hunter + death = TRUE + name = "alien hunter" + mob_name = "alien hunter" + +/obj/effect/mob_spawn/alien/corpse/humanoid/sentinel + mob_type = /mob/living/carbon/alien/humanoid/sentinel + death = TRUE + name = "alien sentinel" + mob_name = "alien sentinel" + +/obj/effect/mob_spawn/alien/corpse/humanoid/praetorian + mob_type = /mob/living/carbon/alien/humanoid/royal/praetorian + death = TRUE + name = "alien praetorian" + mob_name = "alien praetorian" + /obj/effect/mob_spawn/alien/corpse/humanoid/queen mob_type = /mob/living/carbon/alien/humanoid/royal/queen death = TRUE diff --git a/code/modules/ruins/objects_and_mobs/necropolis_gate.dm b/code/modules/ruins/objects_and_mobs/necropolis_gate.dm index fd2f4377e7..5f9b810070 100644 --- a/code/modules/ruins/objects_and_mobs/necropolis_gate.dm +++ b/code/modules/ruins/objects_and_mobs/necropolis_gate.dm @@ -274,6 +274,7 @@ GLOBAL_DATUM(necropolis_gate, /obj/structure/necropolis_gate/legion_gate) return /obj/structure/stone_tile/Crossed(atom/movable/AM) + . = ..() if(falling || fallen) return var/turf/T = get_turf(src) diff --git a/code/modules/ruins/spaceruin_code/hilbertshotel.dm b/code/modules/ruins/spaceruin_code/hilbertshotel.dm index 4859fcfca0..33c4a70634 100644 --- a/code/modules/ruins/spaceruin_code/hilbertshotel.dm +++ b/code/modules/ruins/spaceruin_code/hilbertshotel.dm @@ -21,6 +21,9 @@ GLOBAL_VAR_INIT(hhmysteryRoomNumber, 1337) /obj/item/hilbertshotel/Initialize() . = ..() //Load templates + INVOKE_ASYNC(src, .proc/prepare_rooms) + +/obj/item/hilbertshotel/proc/prepare_rooms() hotelRoomTemp = new() hotelRoomTempEmpty = new() hotelRoomTempLore = new() diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm index 03ff509086..c8ecbf1906 100644 --- a/code/modules/shuttle/shuttle.dm +++ b/code/modules/shuttle/shuttle.dm @@ -807,7 +807,7 @@ for(var/mob/M in SSmobs.clients_by_zlevel[z]) var/dist_far = get_dist(M, distant_source) if(dist_far <= long_range && dist_far > range) - M.playsound_local(distant_source, "sound/effects/[selected_sound]_distance.ogg", 100, falloff = 20) + M.playsound_local(distant_source, "sound/effects/[selected_sound]_distance.ogg", 100) else if(dist_far <= range) var/source if(engine_list.len == 0) @@ -819,7 +819,7 @@ if(dist_near < closest_dist) source = O closest_dist = dist_near - M.playsound_local(source, "sound/effects/[selected_sound].ogg", 100, falloff = range / 2) + M.playsound_local(source, "sound/effects/[selected_sound].ogg", 100) // Losing all initial engines should get you 2 // Adding another set of engines at 0.5 time diff --git a/code/modules/shuttle/spaceship_navigation_beacon.dm b/code/modules/shuttle/spaceship_navigation_beacon.dm index f1861e0477..7488bdd205 100644 --- a/code/modules/shuttle/spaceship_navigation_beacon.dm +++ b/code/modules/shuttle/spaceship_navigation_beacon.dm @@ -21,7 +21,7 @@ . = ..() SSshuttle.beacons |= src -obj/machinery/spaceship_navigation_beacon/emp_act() +/obj/machinery/spaceship_navigation_beacon/emp_act() locked = TRUE /obj/machinery/spaceship_navigation_beacon/Destroy() @@ -60,4 +60,4 @@ obj/machinery/spaceship_navigation_beacon/emp_act() if(default_deconstruction_crowbar(W)) return - return ..() \ No newline at end of file + return ..() diff --git a/code/modules/smithing/finished_items.dm b/code/modules/smithing/finished_items.dm index 5db6b09452..20eaee8a08 100644 --- a/code/modules/smithing/finished_items.dm +++ b/code/modules/smithing/finished_items.dm @@ -231,7 +231,7 @@ /obj/item/melee/smith/twohand/katana name = "katana" - icon_state = "katana" + icon_state = "katana-s" overlay_state = "katanahilt" force = 7 wielded_mult = 2 diff --git a/code/modules/spells/spell_types/spacetime_distortion.dm b/code/modules/spells/spell_types/spacetime_distortion.dm index 5797cbf8b7..5a8776b16b 100644 --- a/code/modules/spells/spell_types/spacetime_distortion.dm +++ b/code/modules/spells/spell_types/spacetime_distortion.dm @@ -1,6 +1,6 @@ /obj/effect/proc_holder/spell/spacetime_dist name = "Spacetime Distortion" - desc = "Entangle the strings of spacetime to deny easy movement around you. The strings vibrate..." + desc = "Entangle the strings of space-time in an area around you, randomizing the layout and making proper movement impossible. The strings vibrate..." charge_max = 300 var/duration = 150 range = 7 @@ -10,8 +10,9 @@ sound = 'sound/effects/magic.ogg' cooldown_min = 300 level_max = 0 + // action_icon_state = "spacetime" -/obj/effect/proc_holder/spell/spacetime_dist/can_cast(mob/user = usr, skipcharge = FALSE, silent = FALSE) +/obj/effect/proc_holder/spell/spacetime_dist/can_cast(mob/user = usr) if(ready) return ..() return FALSE @@ -97,10 +98,11 @@ busy = TRUE flick("purplesparkles", src) AM.forceMove(get_turf(src)) - playsound(get_turf(src),sound,70,0) + playsound(get_turf(src),sound,70,FALSE) busy = FALSE /obj/effect/cross_action/spacetime_dist/Crossed(atom/movable/AM) + . = ..() if(!busy) walk_link(AM) @@ -110,7 +112,8 @@ else walk_link(user) -/obj/effect/cross_action/spacetime_dist/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) +//ATTACK HAND IGNORING PARENT RETURN VALUE +/obj/effect/cross_action/spacetime_dist/on_attack_hand(mob/user) walk_link(user) /obj/effect/cross_action/spacetime_dist/attack_paw(mob/user) diff --git a/code/modules/surgery/organs/heart.dm b/code/modules/surgery/organs/heart.dm index 6b3d47b587..aaa4e34f36 100644 --- a/code/modules/surgery/organs/heart.dm +++ b/code/modules/surgery/organs/heart.dm @@ -97,7 +97,7 @@ owner.set_heartattack(TRUE) failed = TRUE -obj/item/organ/heart/slime +/obj/item/organ/heart/slime name = "slime heart" desc = "It seems we've gotten to the slimy core of the matter." icon_state = "heart-s-on" @@ -221,7 +221,7 @@ obj/item/organ/heart/slime var/rid = /datum/reagent/medicine/epinephrine var/ramount = 10 -obj/item/organ/heart/cybernetic/upgraded/on_life() +/obj/item/organ/heart/cybernetic/upgraded/on_life() . = ..() if(!.) return diff --git a/code/modules/surgery/organs/vocal_cords.dm b/code/modules/surgery/organs/vocal_cords.dm index b6b74efe32..47b504c86e 100644 --- a/code/modules/surgery/organs/vocal_cords.dm +++ b/code/modules/surgery/organs/vocal_cords.dm @@ -1319,7 +1319,7 @@ if(E.phase > 1) if(user.ckey == E.enthrallID && user.real_name == E.master.real_name) E.master = user - addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, H, "[(E.lewd?"You hear the words of your [E.enthrallGender] again!! They're back!!":"You recognise the voice of [E.master].")]"), 5) + to_chat(H, "[(E.lewd?"You hear the words of your [E.enthrallGender] again!! They're back!!":"You recognise the voice of [E.master].")]") to_chat(user, "[H] looks at you with sparkling eyes, recognising you!") //I dunno how to do state objectives without them revealing they're an antag diff --git a/code/modules/unit_tests/README.md b/code/modules/unit_tests/README.md new file mode 100644 index 0000000000..420c805fbf --- /dev/null +++ b/code/modules/unit_tests/README.md @@ -0,0 +1,70 @@ +# Unit Tests + +## What is unit testing? + +Unit tests are automated code to verify that parts of the game work exactly as they should. For example, [a test to make sure that the amputation surgery actually amputates the limb](https://github.com/tgstation/tgstation/blob/e416283f162b86345a8623125ab866839b1ac40d/code/modules/unit_tests/surgeries.dm#L1-L13). These are ran every time a PR is made, and thus are very helpful for preventing bugs from cropping up in your code that would've otherwise gone unnoticed. For example, would you have thought to check [that beach boys would still work the same after editing pizza](https://github.com/tgstation/tgstation/pull/53641#issuecomment-691384934)? If you value your time, probably not. + +On their most basic level, when `UNIT_TESTS` is defined, all subtypes of `/datum/unit_test` will have their `Run` proc executed. From here, if `Fail` is called at any point, then the tests will report as failed. + +## How do I write one? +1. Find a relevant file. + +All unit test related code is in `code/modules/unit_tests`. If you are adding a new test for a surgery, for example, then you'd open `surgeries.dm`. If a relevant file does not exist, simply create one in this folder, then `#include` it in `_unit_tests.dm`. + +2. Create the unit test. + +To make a new unit test, you simply need to define a `/datum/unit_test`. + +For example, let's suppose that we are creating a test to make sure a proc `square` correctly raises inputs to the power of two. We'd start with first: + +``` +/datum/unit_test/square/Run() +``` + +This defines our new unit test, `/datum/unit_test/square`. Inside this function, we're then going to run through whatever we want to check. Tests provide a few assertion functions to make this easy. For now, we're going to use `TEST_ASSERT_EQUAL`. + +``` +/datum/unit_test/square/Run() + TEST_ASSERT_EQUAL(square(3), 9, "square(3) did not return 9") + TEST_ASSERT_EQUAL(square(4), 16, "square(4) did not return 16") +``` + +As you can hopefully tell, we're simply checking if the output of `square` matches the output we are expecting. If the test fails, it'll report the error message given as well as whatever the actual output was. + +3. Run the unit test + +Open `code/_compile_options.dm` and uncomment the following line. + +``` +//#define UNIT_TESTS //If this is uncommented, we do a single run though of the game setup and tear down process with unit tests in between +``` + +Then, run tgstation.dmb in Dream Daemon. Don't bother trying to connect, you won't need to. You'll be able to see the outputs of all the tests. You'll get to see which tests failed and for what reason. If they all pass, you're set! + +## How to think about tests + +Unit tests exist to prevent bugs that would happen in a real game. Thus, they should attempt to emulate the game world wherever possible. For example, the [quick swap sanity test](https://github.com/tgstation/tgstation/blob/e416283f162b86345a8623125ab866839b1ac40d/code/modules/unit_tests/quick_swap_sanity.dm) emulates a *real* scenario of the bug it fixed occurring by creating a character and giving it real items. The unrecommended alternative would be to create special test-only items. This isn't a hard rule, the [reagent method exposure tests](https://github.com/tgstation/tgstation/blob/e416283f162b86345a8623125ab866839b1ac40d/code/modules/unit_tests/reagent_mod_expose.dm) create a test-only reagent for example, but do keep it in mind. + +Unit tests should also be just that--testing *units* of code. For example, instead of having one massive test for reagents, there are instead several smaller tests for testing exposure, metabolization, etc. + +## The unit testing API + +You can find more information about all of these from their respective doc comments, but for a brief overview: + +`/datum/unit_test` - The base for all tests to be ran. Subtypes must override `Run()`. `New()` and `Destroy()` can be used for setup and teardown. To fail, use `Fail(reason)`. + +`/datum/unit_test/proc/allocate(type, ...)` - Allocates an instance of the provided type with the given arguments. Is automatically destroyed when the test is over. Commonly seen in the form of `var/mob/living/carbon/human/human = allocate(/mob/living/carbon/human)`. + +`TEST_ASSERT(assertion, reason)` - Stops the unit test and fails if the assertion is not met. For example: `TEST_ASSERT(powered(), "Machine is not powered")`. + +`TEST_ASSERT_EQUAL(a, b, message)` - Same as `TEST_ASSERT`, but checks if `a == b`. If not, gives a helpful message showing what both `a` and `b` were. For example: `TEST_ASSERT_EQUAL(2 + 2, 4, "The universe is falling apart before our eyes!")`. + +`TEST_ASSERT_NOTEQUAL(a, b, message)` - Same as `TEST_ASSERT_EQUAL`, but reversed. + +`TEST_FOCUS(test_path)` - *Only* run the test provided within the parameters. Useful for reducing noise. For example, if we only want to run our example square test, we can add `TEST_FOCUS(/datum/unit_test/square)`. Should *never* be pushed in a pull request--you will be laughed at. + +## Final Notes + +- Writing tests before you attempt to fix the bug can actually speed up development a lot! It means you don't have to go in game and folllow the same exact steps manually every time. This process is known as "TDD" (test driven development). Write the test first, make sure it fails, *then* start work on the fix/feature, and you'll know you're done when your tests pass. If you do try this, do make sure to confirm in a non-testing environment just to double check. +- Make sure that your tests don't accidentally call RNG functions like `prob`. Since RNG is seeded during tests, you may not realize you have until someone else makes a PR and the tests fail! +- Do your best not to change the behavior of non-testing code during tests. While it may sometimes be necessary in the case of situations such as the above, it is still a slippery slope that can lead to the code you're testing being too different from the production environment to be useful. diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm index 37fa35946c..2745d971ff 100644 --- a/code/modules/unit_tests/_unit_tests.dm +++ b/code/modules/unit_tests/_unit_tests.dm @@ -1,42 +1,80 @@ //include unit test files in this module in this ifdef //Keep this sorted alphabetically -#ifdef UNIT_TESTS +#if defined(UNIT_TESTS) || defined(SPACEMAN_DMM) + /// 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]" : ""]") } +#define TEST_ASSERT_EQUAL(a, b, message) do { \ + var/lhs = ##a; \ + var/rhs = ##b; \ + if (lhs != rhs) { \ + return Fail("Expected [isnull(lhs) ? "null" : lhs] to be equal to [isnull(rhs) ? "null" : rhs].[message ? " [message]" : ""]"); \ + } \ +} while (FALSE) + +/// Asserts that the two parameters passed are not equal, fails otherwise +/// Optionally allows an additional message in the case of a failure +#define TEST_ASSERT_NOTEQUAL(a, b, message) do { \ + var/lhs = ##a; \ + var/rhs = ##b; \ + if (lhs == rhs) { \ + return Fail("Expected [isnull(lhs) ? "null" : lhs] to not be equal to [isnull(rhs) ? "null" : rhs].[message ? " [message]" : ""]"); \ + } \ +} while (FALSE) + +/// *Only* run the test provided within the parentheses +/// This is useful for debugging when you want to reduce noise, but should never be pushed +/// Intended to be used in the manner of `TEST_FOCUS(/datum/unit_test/math)` +#define TEST_FOCUS(test_path) ##test_path { focus = TRUE; } #include "anchored_mobs.dm" #include "bespoke_id.dm" -// #include "binary_insert.dm" -// #include "card_mismatch.dm" shame we don't have this! +#include "binary_insert.dm" +// #include "card_mismatch.dm" #include "chain_pull_through_space.dm" -#include "character_saving.dm" +// #include "combat.dm" #include "component_tests.dm" // #include "confusion.dm" -// #include "keybinding_init.dm" +// #include "emoting.dm" +// #include "heretic_knowledge.dm" +// #include "holidays.dm" +#include "initialize_sanity.dm" +#include "keybinding_init.dm" #include "machine_disassembly.dm" #include "medical_wounds.dm" +#include "merge_type.dm" // #include "metabolizing.dm" // #include "outfit_sanity.dm" +// #include "pills.dm" // #include "plantgrowth_tests.dm" -// #include "quick_swap_sanity.dm" - we don't have quick swap yet +// #include "projectiles.dm" #include "reagent_id_typos.dm" +// #include "reagent_mod_expose.dm" +// #include "reagent_mod_procs.dm" #include "reagent_recipe_collisions.dm" #include "resist.dm" -// #include "say.dm" //no saymods, someone update saycode please. +// #include "say.dm" +// #include "serving_tray.dm" // #include "siunit.dm" #include "spawn_humans.dm" // #include "species_whitelists.dm" +// #include "stomach.dm" #include "subsystem_init.dm" -// #include "surgeries.dm" // fails at random due to a race condition, commented out for now +#include "surgeries.dm" +#include "teleporters.dm" #include "timer_sanity.dm" #include "unit_test.dm" +/// CIT TESTS +#include "character_saving.dm" + #undef TEST_ASSERT #undef TEST_ASSERT_EQUAL +#undef TEST_ASSERT_NOTEQUAL +#undef TEST_FOCUS #endif diff --git a/code/modules/unit_tests/card_mismatch.dm b/code/modules/unit_tests/card_mismatch.dm new file mode 100644 index 0000000000..506e88f19c --- /dev/null +++ b/code/modules/unit_tests/card_mismatch.dm @@ -0,0 +1,7 @@ +/datum/unit_test/card_mismatch + +/datum/unit_test/card_mismatch/Run() + var/message = checkCardpacks(SStrading_card_game.card_packs) + message += checkCardDatums() + if(message) + Fail(message) diff --git a/code/modules/unit_tests/combat.dm b/code/modules/unit_tests/combat.dm new file mode 100644 index 0000000000..30bad72175 --- /dev/null +++ b/code/modules/unit_tests/combat.dm @@ -0,0 +1,98 @@ +/datum/unit_test/harm_punch/Run() + var/mob/living/carbon/human/puncher = allocate(/mob/living/carbon/human) + var/mob/living/carbon/human/victim = allocate(/mob/living/carbon/human) + + // Avoid all randomness in tests + ADD_TRAIT(puncher, TRAIT_PERFECT_ATTACKER, INNATE_TRAIT) + + puncher.a_intent_change(INTENT_HARM) + victim.attack_hand(puncher) + + TEST_ASSERT(victim.getBruteLoss() > 0, "Victim took no brute damage after being punched") + +/datum/unit_test/harm_melee/Run() + var/mob/living/carbon/human/tider = allocate(/mob/living/carbon/human) + var/mob/living/carbon/human/victim = allocate(/mob/living/carbon/human) + var/obj/item/storage/toolbox/toolbox = allocate(/obj/item/storage/toolbox) + + tider.put_in_active_hand(toolbox, forced = TRUE) + tider.a_intent_change(INTENT_HARM) + victim.attackby(toolbox, tider) + + TEST_ASSERT(victim.getBruteLoss() > 0, "Victim took no brute damage after being hit by a toolbox") + +/datum/unit_test/harm_different_damage/Run() + var/mob/living/carbon/human/attacker = allocate(/mob/living/carbon/human) + var/mob/living/carbon/human/victim = allocate(/mob/living/carbon/human) + var/obj/item/weldingtool/welding_tool = allocate(/obj/item/weldingtool) + + attacker.put_in_active_hand(welding_tool, forced = TRUE) + attacker.a_intent_change(INTENT_HARM) + welding_tool.attack_self(attacker) // Turn it on + victim.attackby(welding_tool, attacker) + + TEST_ASSERT_EQUAL(victim.getBruteLoss(), 0, "Victim took brute damage from a lit welding tool") + TEST_ASSERT(victim.getFireLoss() > 0, "Victim took no burn damage after being hit by a lit welding tool") + +/datum/unit_test/attack_chain + var/attack_hit + var/post_attack_hit + var/pre_attack_hit + +/datum/unit_test/attack_chain/proc/attack_hit() + attack_hit = TRUE + +/datum/unit_test/attack_chain/proc/post_attack_hit() + post_attack_hit = TRUE + +/datum/unit_test/attack_chain/proc/pre_attack_hit() + pre_attack_hit = TRUE + +/datum/unit_test/attack_chain/Run() + var/mob/living/carbon/human/attacker = allocate(/mob/living/carbon/human) + var/mob/living/carbon/human/victim = allocate(/mob/living/carbon/human) + var/obj/item/storage/toolbox/toolbox = allocate(/obj/item/storage/toolbox) + + RegisterSignal(toolbox, COMSIG_ITEM_PRE_ATTACK, .proc/pre_attack_hit) + RegisterSignal(toolbox, COMSIG_ITEM_ATTACK, .proc/attack_hit) + RegisterSignal(toolbox, COMSIG_ITEM_AFTERATTACK, .proc/post_attack_hit) + + attacker.put_in_active_hand(toolbox, forced = TRUE) + attacker.a_intent_change(INTENT_HARM) + toolbox.melee_attack_chain(attacker, victim) + + TEST_ASSERT(pre_attack_hit, "Pre-attack signal was not fired") + TEST_ASSERT(attack_hit, "Attack signal was not fired") + TEST_ASSERT(post_attack_hit, "Post-attack signal was not fired") + +/datum/unit_test/disarm/Run() + var/mob/living/carbon/human/attacker = allocate(/mob/living/carbon/human) + var/mob/living/carbon/human/victim = allocate(/mob/living/carbon/human) + var/obj/item/storage/toolbox/toolbox = allocate(/obj/item/storage/toolbox) + + victim.put_in_active_hand(toolbox, forced = TRUE) + attacker.a_intent_change(INTENT_DISARM) + + var/obj/structure/barricade/dense_object = allocate(/obj/structure/barricade) + + // Attacker --> Victim --> Empty space --> Wall + attacker.forceMove(run_loc_bottom_left) + victim.forceMove(locate(run_loc_bottom_left.x + 1, run_loc_bottom_left.y, run_loc_bottom_left.z)) + dense_object.forceMove(locate(run_loc_bottom_left.x + 3, run_loc_bottom_left.y, run_loc_bottom_left.z)) + + // First disarm, world should now look like: + // Attacker --> Empty space --> Victim --> Wall + victim.attack_hand(attacker) + + TEST_ASSERT_EQUAL(victim.loc.x, run_loc_bottom_left.x + 2, "Victim wasn't moved back after being pushed") + TEST_ASSERT(!victim.has_status_effect(STATUS_EFFECT_KNOCKDOWN), "Victim was knocked down despite not being against a wall") + TEST_ASSERT_EQUAL(victim.get_active_held_item(), toolbox, "Victim dropped toolbox despite not being against a wall") + + attacker.forceMove(get_step(attacker, EAST)) + + // Second disarm, victim was against wall and should be down + victim.attack_hand(attacker) + + TEST_ASSERT_EQUAL(victim.loc.x, run_loc_bottom_left.x + 2, "Victim was moved after being pushed against a wall") + TEST_ASSERT(victim.has_status_effect(STATUS_EFFECT_KNOCKDOWN), "Victim was not knocked down after being pushed against a wall") + TEST_ASSERT_EQUAL(victim.get_active_held_item(), null, "Victim didn't drop toolbox after being pushed against a wall") diff --git a/code/modules/unit_tests/confusion.dm b/code/modules/unit_tests/confusion.dm new file mode 100644 index 0000000000..8282493c96 --- /dev/null +++ b/code/modules/unit_tests/confusion.dm @@ -0,0 +1,16 @@ +// Checks that the confusion symptom correctly gives, and removes, confusion +/datum/unit_test/confusion_symptom/Run() + var/mob/living/carbon/human/H = allocate(/mob/living/carbon/human) + var/datum/disease/advance/confusion/disease = allocate(/datum/disease/advance/confusion) + var/datum/symptom/confusion/confusion = disease.symptoms[1] + disease.processing = TRUE + disease.update_stage(5) + disease.infect(H, make_copy = FALSE) + confusion.Activate(disease) + TEST_ASSERT(H.get_confusion() > 0, "Human is not confused after getting symptom.") + disease.cure() + TEST_ASSERT_EQUAL(H.get_confusion(), 0, "Human is still confused after curing confusion.") + +/datum/disease/advance/confusion/New() + symptoms += new /datum/symptom/confusion + Refresh() diff --git a/code/modules/unit_tests/emoting.dm b/code/modules/unit_tests/emoting.dm new file mode 100644 index 0000000000..5795ab3437 --- /dev/null +++ b/code/modules/unit_tests/emoting.dm @@ -0,0 +1,25 @@ +/datum/unit_test/emoting + var/emotes_used = 0 + +/datum/unit_test/emoting/Run() + var/mob/living/carbon/human/human = allocate(/mob/living/carbon/human) + RegisterSignal(human, COMSIG_MOB_EMOTE, .proc/on_emote_used) + + human.say("*shrug") + TEST_ASSERT_EQUAL(emotes_used, 1, "Human did not shrug") + + human.say("*beep") + TEST_ASSERT_EQUAL(emotes_used, 1, "Human beeped, when that should be restricted to silicons") + + human.setOxyLoss(140) + + TEST_ASSERT(human.stat != CONSCIOUS, "Human is somehow conscious after receiving suffocation damage") + + human.say("*shrug") + TEST_ASSERT_EQUAL(emotes_used, 1, "Human shrugged while unconscious") + + human.say("*deathgasp") + TEST_ASSERT_EQUAL(emotes_used, 2, "Human could not deathgasp while unconscious") + +/datum/unit_test/emoting/proc/on_emote_used() + emotes_used += 1 diff --git a/code/modules/unit_tests/heretic_knowledge.dm b/code/modules/unit_tests/heretic_knowledge.dm new file mode 100644 index 0000000000..a433bce1ec --- /dev/null +++ b/code/modules/unit_tests/heretic_knowledge.dm @@ -0,0 +1,21 @@ +/// This test checks all heretic knowledge nodes - excluding the ones which are unreachable on purpose - and ensures players can reach them in game. +/// If it finds a node that is unreachable, it throws an error. +/datum/unit_test/heretic_knowledge/Run() + ///List of all knowledge excluding the unreachable base types. + var/list/blacklist = list(/datum/eldritch_knowledge/spell,/datum/eldritch_knowledge/curse,/datum/eldritch_knowledge/final,/datum/eldritch_knowledge/summon) + var/list/all_possible_knowledge = subtypesof(/datum/eldritch_knowledge) - blacklist + + var/list/list_to_check = GLOB.heretic_start_knowledge.Copy() + var/i = 0 + while(i < length(list_to_check)) + var/datum/eldritch_knowledge/eldritch_knowledge = allocate(list_to_check[++i]) + for(var/next_knowledge in eldritch_knowledge.next_knowledge) + if(next_knowledge in list_to_check) + continue + list_to_check += next_knowledge + + if(length(all_possible_knowledge) != length(all_possible_knowledge & list_to_check)) + var/list/unreachables = all_possible_knowledge - list_to_check + for(var/X in unreachables) + var/datum/eldritch_knowledge/eldritch_knowledge = X + Fail("[initial(eldritch_knowledge.name)] is unreachable by players! Add it to the blacklist in /code/modules/unit_tests/heretic_knowledge.dm if it is purposeful!") diff --git a/code/modules/unit_tests/holidays.dm b/code/modules/unit_tests/holidays.dm new file mode 100644 index 0000000000..4df5443e2e --- /dev/null +++ b/code/modules/unit_tests/holidays.dm @@ -0,0 +1,33 @@ +// test Jewish holiday +/datum/unit_test/hanukkah_2123/Run() + var/datum/holiday/hebrew/hanukkah/hanukkah = new + TEST_ASSERT(hanukkah.shouldCelebrate(14, DECEMBER, 2123, 2, TUESDAY), "December 14, 2123 was not Hanukkah.") + +// test Islamic holiday +/datum/unit_test/ramadan_2165/Run() + var/datum/holiday/islamic/ramadan/ramadan = new + TEST_ASSERT(ramadan.shouldCelebrate(6, NOVEMBER, 2165, 1, WEDNESDAY), "November 6, 2165 was not Ramadan.") + +// nth day of week +/datum/unit_test/thanksgiving_2020/Run() + var/datum/holiday/nth_week/thanksgiving/thanksgiving = new + TEST_ASSERT(thanksgiving.shouldCelebrate(26, NOVEMBER, 2020, 4, THURSDAY), "November 26, 2020 was not Thanksgiving.") + +// another nth day of week +/datum/unit_test/indigenous_3683/Run() + var/datum/holiday/nth_week/indigenous/indigenous = new + TEST_ASSERT(indigenous.shouldCelebrate(11, OCTOBER, 3683, 2, MONDAY), "October 11, 3683 was not Indigenous Peoples' Day.") + +// plain old simple holiday +/datum/unit_test/hello_2020/Run() + var/datum/holiday/hello/hello = new + TEST_ASSERT(hello.shouldCelebrate(21, NOVEMBER, 2020, 3, SATURDAY), "November 21, 2020 was not Hello day.") + +// holiday which goes across months +/datum/unit_test/new_year_1983/Run() + var/datum/holiday/new_year/new_year = new + TEST_ASSERT(new_year.shouldCelebrate(2, JANUARY, 1983, 1, SUNDAY), "January 2, 1983 was not New Year.") + +/datum/unit_test/moth_week_2020/Run() + var/datum/holiday/moth/moth = new + TEST_ASSERT(moth.shouldCelebrate(19, JULY, 2020, 3, SATURDAY), "July 19, 2020 was not Moth Week.") diff --git a/code/modules/unit_tests/initialize_sanity.dm b/code/modules/unit_tests/initialize_sanity.dm new file mode 100644 index 0000000000..d183f530c8 --- /dev/null +++ b/code/modules/unit_tests/initialize_sanity.dm @@ -0,0 +1,11 @@ +/datum/unit_test/initialize_sanity/Run() + if(length(SSatoms.BadInitializeCalls)) + Fail("Bad Initialize() calls detected. Please read logs.") + var/list/init_failures_to_text = list( + "[BAD_INIT_QDEL_BEFORE]" = "Qdeleted Before Initialized", + "[BAD_INIT_DIDNT_INIT]" = "Did Not Initialize", + "[BAD_INIT_SLEPT]" = "Initialize() Slept", + "[BAD_INIT_NO_HINT]" = "No Initialize() Hint Returned", + ) + for(var/failure in SSatoms.BadInitializeCalls) + log_world("[failure]: [init_failures_to_text["[SSatoms.BadInitializeCalls[failure]]"]]") // You like stacked brackets? diff --git a/code/modules/unit_tests/keybinding_init.dm b/code/modules/unit_tests/keybinding_init.dm new file mode 100644 index 0000000000..2bd2fdee1e --- /dev/null +++ b/code/modules/unit_tests/keybinding_init.dm @@ -0,0 +1,6 @@ +/datum/unit_test/keybinding_init/Run() + for(var/i in subtypesof(/datum/keybinding)) + var/datum/keybinding/KB = i + if(initial(KB.keybind_signal) || !initial(KB.name)) + continue + Fail("[KB.name] does not have a keybind signal defined.") diff --git a/code/modules/unit_tests/machine_disassembly.dm b/code/modules/unit_tests/machine_disassembly.dm index bcc769bcf2..59edb4ae9d 100644 --- a/code/modules/unit_tests/machine_disassembly.dm +++ b/code/modules/unit_tests/machine_disassembly.dm @@ -3,11 +3,10 @@ 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") + TEST_ASSERT(locate(/obj/item/circuitboard/machine/thermomachine) in freezer_location, "Couldn't find the circuit board when disassembling freezer") diff --git a/code/modules/unit_tests/merge_type.dm b/code/modules/unit_tests/merge_type.dm new file mode 100644 index 0000000000..ba3cfcf492 --- /dev/null +++ b/code/modules/unit_tests/merge_type.dm @@ -0,0 +1,15 @@ +/datum/unit_test/merge_type/Run() + var/list/blacklist = list(/obj/item/stack/sheet, + /obj/item/stack/sheet/mineral, + /obj/item/stack/ore, + /obj/item/stack/spacecash, + // /obj/item/stack/license_plates, + /obj/item/stack/tile/mineral, + /obj/item/stack/tile) + + var/list/paths = subtypesof(/obj/item/stack) - blacklist + + for(var/stackpath in paths) + var/obj/item/stack/stack = stackpath + if(!initial(stack.merge_type)) + Fail("([stack]) lacks set merge_type variable!") diff --git a/code/modules/unit_tests/metabolizing.dm b/code/modules/unit_tests/metabolizing.dm index 895762c0ec..b7f8fc4f6a 100644 --- a/code/modules/unit_tests/metabolizing.dm +++ b/code/modules/unit_tests/metabolizing.dm @@ -17,3 +17,22 @@ /datum/unit_test/metabolization/Destroy() SSmobs.ignite() return ..() + +/datum/unit_test/on_mob_end_metabolize/Run() + var/mob/living/carbon/human/user = allocate(/mob/living/carbon/human) + var/obj/item/reagent_containers/pill/pill = allocate(/obj/item/reagent_containers/pill) + var/datum/reagent/drug/methamphetamine/meth = /datum/reagent/drug/methamphetamine + + // Give them enough meth to be consumed in 2 metabolizations + pill.reagents.add_reagent(meth, initial(meth.metabolization_rate) * 1.9) + pill.attack(user, user) + + user.Life() + + TEST_ASSERT(user.reagents.has_reagent(meth), "User does not have meth in their system after consuming it") + TEST_ASSERT(user.has_movespeed_modifier(/datum/movespeed_modifier/reagent/methamphetamine), "User consumed meth, but did not gain movespeed modifier") + + user.Life() + + TEST_ASSERT(!user.reagents.has_reagent(meth), "User still has meth in their system when it should've finished metabolizing") + TEST_ASSERT(!user.has_movespeed_modifier(/datum/movespeed_modifier/reagent/methamphetamine), "User still has movespeed modifier despite not containing any more meth") diff --git a/code/modules/unit_tests/outfit_sanity.dm b/code/modules/unit_tests/outfit_sanity.dm index 235820f9e9..57ce22434e 100644 --- a/code/modules/unit_tests/outfit_sanity.dm +++ b/code/modules/unit_tests/outfit_sanity.dm @@ -30,8 +30,8 @@ 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) + CHECK_OUTFIT_SLOT(l_pocket, ITEM_SLOT_LPOCKET) + CHECK_OUTFIT_SLOT(r_pocket, ITEM_SLOT_RPOCKET) if (outfit.backpack_contents || outfit.box) var/list/backpack_contents = outfit.backpack_contents?.Copy() diff --git a/code/modules/unit_tests/pills.dm b/code/modules/unit_tests/pills.dm new file mode 100644 index 0000000000..ed8f64ce95 --- /dev/null +++ b/code/modules/unit_tests/pills.dm @@ -0,0 +1,10 @@ +/datum/unit_test/pills/Run() + var/mob/living/carbon/human/human = allocate(/mob/living/carbon/human) + var/obj/item/reagent_containers/pill/iron/pill = allocate(/obj/item/reagent_containers/pill/iron) + + TEST_ASSERT_EQUAL(human.has_reagent(/datum/reagent/iron), FALSE, "Human somehow has iron before taking pill") + + pill.attack(human, human) + human.Life() + + TEST_ASSERT(human.has_reagent(/datum/reagent/iron), "Human doesn't have iron after taking pill") diff --git a/code/modules/unit_tests/projectiles.dm b/code/modules/unit_tests/projectiles.dm new file mode 100644 index 0000000000..53ceef01d6 --- /dev/null +++ b/code/modules/unit_tests/projectiles.dm @@ -0,0 +1,5 @@ +/datum/unit_test/projectile_movetypes/Run() + for(var/path in typesof(/obj/item/projectile)) + var/obj/projectile/projectile = path + if(initial(projectile.movement_type) & PHASING) + Fail("[path] has default movement type PHASING. Piercing projectiles should be done using the projectile piercing system, not movement_types!") diff --git a/code/modules/unit_tests/reagent_mod_expose.dm b/code/modules/unit_tests/reagent_mod_expose.dm new file mode 100644 index 0000000000..3fe02e044d --- /dev/null +++ b/code/modules/unit_tests/reagent_mod_expose.dm @@ -0,0 +1,59 @@ +// testing the mob expose procs are working + +/datum/reagent/method_patch_test + name = "method patch test" + +/datum/reagent/method_patch_test/expose_mob(mob/living/target, methods = PATCH, reac_volume, show_message = TRUE) + . = ..() + if(methods & PATCH) + target.health = 90 + if(methods & INJECT) + target.health = 80 + +/datum/unit_test/reagent_mob_expose/Run() + // Life() is handled just by tests + SSmobs.pause() + + var/mob/living/carbon/human/human = allocate(/mob/living/carbon/human) + var/obj/item/reagent_containers/dropper/dropper = allocate(/obj/item/reagent_containers/dropper) + var/obj/item/reagent_containers/food/drinks/drink = allocate(/obj/item/reagent_containers/food/drinks/bottle) + var/obj/item/reagent_containers/pill/patch/patch = allocate(/obj/item/reagent_containers/pill/patch) + var/obj/item/reagent_containers/syringe/syringe = allocate(/obj/item/reagent_containers/syringe) + + // INGEST + TEST_ASSERT_EQUAL(human.fire_stacks, 0, "Human has fire stacks before taking phlogiston") + drink.reagents.add_reagent(/datum/reagent/phlogiston, 10) + drink.attack(human, human) + TEST_ASSERT_EQUAL(human.fire_stacks, 1, "Human does not have fire stacks after taking phlogiston") + human.Life() + TEST_ASSERT(human.fire_stacks > 1, "Human fire stacks did not increase after life tick") + + // TOUCH + dropper.reagents.add_reagent(/datum/reagent/water, 1) + dropper.afterattack(human, human, TRUE) + TEST_ASSERT_EQUAL(human.fire_stacks, 0, "Human still has fire stacks after touching water") + + // VAPOR + TEST_ASSERT_EQUAL(human.drowsyness, 0, "Human is drowsy at the start of testing") + drink.reagents.clear_reagents() + drink.reagents.add_reagent(/datum/reagent/nitrous_oxide, 10) + drink.reagents.trans_to(human, 10, methods = VAPOR) + TEST_ASSERT_NOTEQUAL(human.drowsyness, 0, "Human is not drowsy after exposure to vapors") + + // PATCH + human.health = 100 + TEST_ASSERT_EQUAL(human.health, 100, "Human health did not set properly") + patch.reagents.add_reagent(/datum/reagent/method_patch_test, 1) + patch.self_delay = 0 + patch.attack(human, human) + TEST_ASSERT_EQUAL(human.health, 90, "Human health did not update after patch was applied") + + // INJECT + syringe.reagents.add_reagent(/datum/reagent/method_patch_test, 1) + syringe.mode = SYRINGE_INJECT + syringe.afterattack(human, human, TRUE) + TEST_ASSERT_EQUAL(human.health, 80, "Human health did not update after injection from syringe") + +/datum/unit_test/reagent_mob_expose/Destroy() + SSmobs.ignite() + return ..() diff --git a/code/modules/unit_tests/reagent_mod_procs.dm b/code/modules/unit_tests/reagent_mod_procs.dm new file mode 100644 index 0000000000..a2087f8624 --- /dev/null +++ b/code/modules/unit_tests/reagent_mod_procs.dm @@ -0,0 +1,12 @@ +/datum/unit_test/reagent_mob_procs/Run() + var/mob/living/carbon/human/human = allocate(/mob/living/carbon/human) + var/obj/item/food/hotdog/debug/fooditem = allocate(/obj/item/food/hotdog/debug) + + TEST_ASSERT_EQUAL(human.has_reagent(/datum/reagent/consumable/ketchup), FALSE, "Human somehow has ketchup before eating") + TEST_ASSERT_EQUAL(human.has_reagent(/datum/reagent/medicine/epinephrine), FALSE, "Human somehow has epinephrine before injecting") + + fooditem.attack(human, human) + human.reagents.add_reagent(/datum/reagent/medicine/epinephrine, 5) + + TEST_ASSERT(human.has_reagent(/datum/reagent/consumable/ketchup), "Human doesn't have ketchup after eating") + TEST_ASSERT(human.has_reagent(/datum/reagent/medicine/epinephrine), "Human doesn't have epinephrine after injecting") diff --git a/code/modules/unit_tests/say.dm b/code/modules/unit_tests/say.dm index 3fe6675ab4..a7df5ad624 100644 --- a/code/modules/unit_tests/say.dm +++ b/code/modules/unit_tests/say.dm @@ -10,7 +10,6 @@ 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() diff --git a/code/modules/unit_tests/serving_tray.dm b/code/modules/unit_tests/serving_tray.dm new file mode 100644 index 0000000000..00e911ae50 --- /dev/null +++ b/code/modules/unit_tests/serving_tray.dm @@ -0,0 +1,47 @@ +/** + * Check that standard food items fit on the serving tray + */ +/datum/unit_test/servingtray/Run() + var/mob/living/carbon/human/human = allocate(/mob/living/carbon/human) + var/obj/structure/table/the_table = allocate(/obj/structure/table) + var/obj/item/storage/bag/tray/test_tray = allocate(/obj/item/storage/bag/tray) + var/obj/item/reagent_containers/food/banana = allocate(/obj/item/food/rationpack) + var/obj/item/food/the_bread = allocate(/obj/item/food/breadslice) + var/obj/item/reagent_containers/food/sugarcookie = allocate(/obj/item/food/cookie/sugar) + var/obj/item/clothing/under/jumpsuit = allocate(/obj/item/clothing/under/color/black) + + TEST_ASSERT_EQUAL((the_bread in test_tray.contents), FALSE, "The bread is on the serving tray at test start") + + // set the tray to single item mode the dirty way + var/datum/component/storage/tray_storage = test_tray.GetComponent(/datum/component/storage) + tray_storage.collection_mode = COLLECT_ONE + + test_tray.pre_attack(the_bread, human) + + TEST_ASSERT_EQUAL((the_bread in test_tray.contents), TRUE, "The bread did not get picked up by the serving tray") + + test_tray.pre_attack(banana, human) + + TEST_ASSERT_EQUAL((banana in test_tray.contents), TRUE, "The banana did not get picked up by the serving tray") + + the_table.attackby(test_tray, human) + + TEST_ASSERT_EQUAL(test_tray.contents.len, 0, "The serving tray did not drop all items on hitting the table") + + test_tray.pre_attack(sugarcookie, human) + + TEST_ASSERT_EQUAL((sugarcookie in test_tray.contents), TRUE, "The sugarcookie did not get picked up by the serving tray") + + human.equip_to_slot(jumpsuit, ITEM_SLOT_ICLOTHING) + TEST_ASSERT(human.get_item_by_slot(ITEM_SLOT_ICLOTHING), "Human does not have jumpsuit on") + + human.equip_to_slot(test_tray, ITEM_SLOT_LPOCKET) + TEST_ASSERT(human.get_item_by_slot(ITEM_SLOT_LPOCKET), "Serving tray failed to fit in the Left Pocket") + + human.equip_to_slot(test_tray, ITEM_SLOT_RPOCKET) + TEST_ASSERT(human.get_item_by_slot(ITEM_SLOT_RPOCKET), "Serving tray failed to fit in the Right Pocket") + + test_tray.attack(human, human) + + TEST_ASSERT_EQUAL(test_tray.contents.len, 0, "The serving tray did not drop all items on hitting a human") + diff --git a/code/modules/unit_tests/siunit.dm b/code/modules/unit_tests/siunit.dm new file mode 100644 index 0000000000..3a7a25a98d --- /dev/null +++ b/code/modules/unit_tests/siunit.dm @@ -0,0 +1,15 @@ +/datum/unit_test/siunit/Run() + TEST_ASSERT_EQUAL(siunit(0.5345, "A", 0), "535 mA", "") + TEST_ASSERT_EQUAL(siunit(0.5344, "A", 0), "534 mA", "") + TEST_ASSERT_EQUAL(siunit(-0.5344, "A", 0), "-534 mA", "") + TEST_ASSERT_EQUAL(siunit_pressure(1.234, 1), "1.2 kPa", "") // test for pascal require *10e-3, as the game thinks in kPa, the proc siunit in Pa + TEST_ASSERT_EQUAL(siunit_pressure(1.234, 2), "1.23 kPa", "") + TEST_ASSERT_EQUAL(siunit_pressure(1.234, 3), "1.234 kPa", "") + TEST_ASSERT_EQUAL(siunit_pressure(1, 4), "1 kPa", "") + TEST_ASSERT_EQUAL(siunit_pressure(0), "0 Pa", "") + TEST_ASSERT_EQUAL(siunit_pressure(1e3), "1 MPa", "") + TEST_ASSERT_EQUAL(siunit_pressure(999e3), "999 MPa", "") + TEST_ASSERT_EQUAL(siunit_pressure(999.9e3), "999.9 MPa" , "") + TEST_ASSERT_EQUAL(siunit_pressure(999.9e3, 0), "1 GPa", "") + TEST_ASSERT_EQUAL(siunit_pressure(1e6), "1 GPa", "") + TEST_ASSERT_EQUAL(siunit_pressure(3e17), "300000 PPa", "") diff --git a/code/modules/unit_tests/spawn_humans.dm b/code/modules/unit_tests/spawn_humans.dm index 7189e87277..0500deae0a 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/species_whitelists.dm b/code/modules/unit_tests/species_whitelists.dm new file mode 100644 index 0000000000..145f3a259f --- /dev/null +++ b/code/modules/unit_tests/species_whitelists.dm @@ -0,0 +1,5 @@ +/datum/unit_test/species_whitelist_check/Run() + for(var/typepath in subtypesof(/datum/species)) + var/datum/species/S = typepath + if(initial(S.changesource_flags) == NONE) + Fail("A species type was detected with no changesource flags: [S]") diff --git a/code/modules/unit_tests/stomach.dm b/code/modules/unit_tests/stomach.dm new file mode 100644 index 0000000000..06fdc71dd4 --- /dev/null +++ b/code/modules/unit_tests/stomach.dm @@ -0,0 +1,40 @@ +/datum/unit_test/stomach/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/obj/item/food/hotdog/debug/fooditem = allocate(/obj/item/food/hotdog/debug) + var/obj/item/organ/stomach/belly = human.getorganslot(ORGAN_SLOT_STOMACH) + var/obj/item/reagent_containers/pill/pill = allocate(/obj/item/reagent_containers/pill) + var/datum/reagent/drug/methamphetamine/meth = /datum/reagent/drug/methamphetamine + + TEST_ASSERT_EQUAL(human.has_reagent(/datum/reagent/consumable/ketchup), FALSE, "Human somehow has ketchup before eating") + + fooditem.attack(human, human) + + TEST_ASSERT(belly.reagents.has_reagent(/datum/reagent/consumable/ketchup), "Stomach doesn't have ketchup after eating") + TEST_ASSERT_EQUAL(human.reagents.has_reagent(/datum/reagent/consumable/ketchup), FALSE, "Human body has ketchup after eating it should only be in the stomach") + + //Give them meth and let it kick in + pill.reagents.add_reagent(meth, initial(meth.metabolization_rate) * 1.9) + pill.attack(human, human) + human.Life() + + TEST_ASSERT(human.reagents.has_reagent(meth), "Human body does not have meth after life tick") + TEST_ASSERT(human.has_movespeed_modifier(/datum/movespeed_modifier/reagent/methamphetamine), "Human consumed meth, but did not gain movespeed modifier") + + belly.Remove(human) + human.reagents.remove_all(human.reagents.total_volume) + + TEST_ASSERT_EQUAL(human.has_reagent(/datum/reagent/consumable/ketchup), FALSE, "Human has reagents after clearing") + + fooditem.attack(human, human) + + TEST_ASSERT_EQUAL(human.has_reagent(/datum/reagent/consumable/ketchup), FALSE, "Human has ketchup without a stomach") + + + +/datum/unit_test/stomach/Destroy() + SSmobs.ignite() + return ..() diff --git a/code/modules/unit_tests/surgeries.dm b/code/modules/unit_tests/surgeries.dm index 7b8145ac19..6348057f79 100644 --- a/code/modules/unit_tests/surgeries.dm +++ b/code/modules/unit_tests/surgeries.dm @@ -2,14 +2,14 @@ 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") + TEST_ASSERT_EQUAL(length(patient.get_missing_limbs()), 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(length(patient.get_missing_limbs()), 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() @@ -27,6 +27,33 @@ 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/head_transplant/Run() + var/mob/living/carbon/human/user = allocate(/mob/living/carbon/human) + var/mob/living/carbon/human/alice = allocate(/mob/living/carbon/human) + var/mob/living/carbon/human/bob = allocate(/mob/living/carbon/human) + + alice.fully_replace_character_name(null, "Alice") + bob.fully_replace_character_name(null, "Bob") + + var/obj/item/bodypart/head/alices_head = alice.get_bodypart(BODY_ZONE_HEAD) + alices_head.drop_limb() + + var/obj/item/bodypart/head/bobs_head = bob.get_bodypart(BODY_ZONE_HEAD) + bobs_head.drop_limb() + + TEST_ASSERT_EQUAL(alice.get_bodypart(BODY_ZONE_HEAD), null, "Alice still has a head after dismemberment") + TEST_ASSERT_EQUAL(alice.get_visible_name(), "Unknown", "Alice's head was dismembered, but they are not Unknown") + + TEST_ASSERT_EQUAL(bobs_head.real_name, "Bob", "Bob's head does not remember that it is from Bob") + + // Put Bob's head onto Alice's body + var/datum/surgery_step/add_prosthetic/add_prosthetic = new + user.put_in_active_hand(bobs_head) + add_prosthetic.success(user, alice, BODY_ZONE_HEAD, bobs_head) + + TEST_ASSERT(!isnull(alice.get_bodypart(BODY_ZONE_HEAD)), "Alice has no head after prosthetic replacement") + TEST_ASSERT_EQUAL(alice.get_visible_name(), "Bob", "Bob's head was transplanted onto Alice's body, but their name is not Bob") + /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) @@ -41,8 +68,6 @@ TEST_ASSERT(surgery_for_zero.step_in_progress, "Surgery on patient zero was not initiated") var/datum/surgery/organ_manipulation/surgery_for_one = new - - sleep(0.2) // if we don't have this, then the next surgery step can start *before* the previous one does, which is no good // 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") diff --git a/code/modules/unit_tests/teleporters.dm b/code/modules/unit_tests/teleporters.dm new file mode 100644 index 0000000000..fa2624adaa --- /dev/null +++ b/code/modules/unit_tests/teleporters.dm @@ -0,0 +1,10 @@ +/datum/unit_test/auto_teleporter_linking/Run() + // Put down the teleporter machinery + var/obj/machinery/teleport/hub/hub = allocate(/obj/machinery/teleport/hub) + var/obj/machinery/teleport/station/station = allocate(/obj/machinery/teleport/station, locate(run_loc_bottom_left.x + 1, run_loc_bottom_left.y, run_loc_bottom_left.z)) + var/obj/machinery/computer/teleporter/computer = allocate(/obj/machinery/computer/teleporter, locate(run_loc_bottom_left.x + 2, run_loc_bottom_left.y, run_loc_bottom_left.z)) + + TEST_ASSERT_EQUAL(hub.power_station, station, "Hub didn't link to the station") + TEST_ASSERT_EQUAL(station.teleporter_console, computer, "Station didn't link to the teleporter console") + TEST_ASSERT_EQUAL(station.teleporter_hub, hub, "Station didn't link to the hub") + TEST_ASSERT_EQUAL(computer.power_station, station, "Teleporter console didn't link to the hub") diff --git a/code/modules/unit_tests/unit_test.dm b/code/modules/unit_tests/unit_test.dm index 36b406e75e..15fe6b466c 100644 --- a/code/modules/unit_tests/unit_test.dm +++ b/code/modules/unit_tests/unit_test.dm @@ -1,9 +1,14 @@ /* + 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) @@ -14,19 +19,33 @@ GLOBAL_VAR(test_log) //Bit of metadata for the future maybe var/list/procs_tested - //usable vars + /// The bottom left turf of the testing zone var/turf/run_loc_bottom_left + + /// The top right turf of the testing zone var/turf/run_loc_top_right + /// The type of turf to allocate for the testing zone + var/test_turf_type = /turf/open/floor/plasteel + //internal shit + var/focus = FALSE var/succeeded = TRUE var/list/allocated var/list/fail_reasons + var/static/datum/turf_reservation/turf_reservation + /datum/unit_test/New() + if (isnull(turf_reservation)) + turf_reservation = SSmapping.RequestBlockReservation(5, 5) + + for (var/turf/reserved_turf in turf_reservation.reserved_turfs) + reserved_turf.ChangeTurf(test_turf_type) + allocated = new - run_loc_bottom_left = locate(1, 1, 1) - run_loc_top_right = locate(5, 5, 1) + run_loc_bottom_left = locate(turf_reservation.bottom_left_coords[1], turf_reservation.bottom_left_coords[2], turf_reservation.bottom_left_coords[3]) + run_loc_top_right = locate(turf_reservation.top_right_coords[1], turf_reservation.top_right_coords[2], turf_reservation.top_right_coords[3]) /datum/unit_test/Destroy() //clear the test area @@ -61,7 +80,14 @@ GLOBAL_VAR(test_log) /proc/RunUnitTests() CHECK_TICK - for(var/I in subtypesof(/datum/unit_test)) + var/tests_to_run = subtypesof(/datum/unit_test) + for (var/_test_to_run in tests_to_run) + var/datum/unit_test/test_to_run = _test_to_run + if (initial(test_to_run.focus)) + tests_to_run = list(test_to_run) + break + + for(var/I in tests_to_run) var/datum/unit_test/test = new I GLOB.current_test = test diff --git a/code/modules/uplink/uplink_items/uplink_stealth.dm b/code/modules/uplink/uplink_items/uplink_stealth.dm index ff6d66a483..18a7707a88 100644 --- a/code/modules/uplink/uplink_items/uplink_stealth.dm +++ b/code/modules/uplink/uplink_items/uplink_stealth.dm @@ -115,7 +115,7 @@ cost = 4 exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) -datum/uplink_item/stealthy_weapons/taeclowndo_shoes +/datum/uplink_item/stealthy_weapons/taeclowndo_shoes name = "Tae-clown-do Shoes" desc = "A pair of shoes for the most elite agents of the honkmotherland. They grant the mastery of taeclowndo with some honk-fu moves as long as they're worn." cost = 12 diff --git a/code/modules/vending/autodrobe.dm b/code/modules/vending/autodrobe.dm index b4490f715b..264d262a1d 100644 --- a/code/modules/vending/autodrobe.dm +++ b/code/modules/vending/autodrobe.dm @@ -120,7 +120,14 @@ /obj/item/clothing/ears/headphones = 2, /obj/item/clothing/head/wig/random = 3, /obj/item/clothing/suit/ran = 2, - /obj/item/clothing/head/ran = 2) + /obj/item/clothing/head/ran = 2, + /obj/item/clothing/mask/gas/timidcostume = 3, + /obj/item/clothing/suit/hooded/wintercoat/timidcostume = 3, + /obj/item/clothing/shoes/timidcostume = 3, + /obj/item/clothing/mask/gas/timidcostume/man = 3, + /obj/item/clothing/suit/hooded/wintercoat/timidcostume/man = 3, + /obj/item/clothing/shoes/timidcostume/man = 3, + ) contraband = list(/obj/item/clothing/suit/judgerobe = 1, /obj/item/clothing/head/powdered_wig = 1, /obj/item/gun/magic/wand = 2, diff --git a/code/modules/vending/clothesmate.dm b/code/modules/vending/clothesmate.dm index 462d4b5cb5..4c69f6bb27 100644 --- a/code/modules/vending/clothesmate.dm +++ b/code/modules/vending/clothesmate.dm @@ -35,6 +35,19 @@ /obj/item/clothing/under/misc/overalls = 3, /obj/item/clothing/under/suit/sl = 3, /obj/item/clothing/under/sweater = 3, + /obj/item/clothing/accessory/sweater = 3, + /obj/item/clothing/accessory/sweater/pink = 3, + /obj/item/clothing/accessory/sweater/heart = 3, + /obj/item/clothing/accessory/sweater/blue = 3, + /obj/item/clothing/accessory/sweater/nt = 3, + /obj/item/clothing/accessory/sweater/mint = 3, + /obj/item/clothing/accessory/sweater/shoulderless = 3, + /obj/item/clothing/accessory/sweater/flower = 3, + /obj/item/clothing/accessory/turtleneck = 2, + /obj/item/clothing/accessory/turtleneck/red = 2, + /obj/item/clothing/accessory/turtleneck/tactifool = 2, + /obj/item/clothing/accessory/turtleneck/tactifool/green = 2, + /obj/item/clothing/accessory/turtleneck/tactifool/blue = 2, /obj/item/clothing/under/sweater/black = 3, /obj/item/clothing/under/sweater/purple = 3, /obj/item/clothing/under/sweater/green = 3, @@ -50,6 +63,11 @@ /obj/item/clothing/under/pants/black = 4, /obj/item/clothing/under/pants/tan = 4, /obj/item/clothing/under/pants/track = 3, + /obj/item/clothing/accessory/suitjacket = 2, + /obj/item/clothing/accessory/suitjacket/charcoal = 2, + /obj/item/clothing/accessory/suitjacket/navy = 2, + /obj/item/clothing/accessory/suitjacket/burgundy = 2, + /obj/item/clothing/accessory/suitjacket/checkered = 2, /obj/item/clothing/suit/jacket/miljacket = 5, /obj/item/clothing/under/suit/white_on_white/skirt = 2, /obj/item/clothing/under/rank/captain/suit/skirt = 2, @@ -74,6 +92,12 @@ /obj/item/clothing/neck/stripedbluescarf = 3, /obj/item/clothing/neck/stripedgreenscarf = 3, /obj/item/clothing/accessory/waistcoat = 2, + /obj/item/clothing/accessory/waistcoat/red = 2, + /obj/item/clothing/accessory/waistcoat/grey = 2, + /obj/item/clothing/accessory/waistcoat/brown = 2, + /obj/item/clothing/accessory/waistcoat/sweatervest = 2, + /obj/item/clothing/accessory/waistcoat/sweatervest/blue = 2, + /obj/item/clothing/accessory/waistcoat/sweatervest/red = 2, /obj/item/clothing/under/dress/skirt = 3, /obj/item/clothing/under/dress/skirt/blue = 3, /obj/item/clothing/under/dress/skirt/red = 3, @@ -132,22 +156,22 @@ /obj/item/clothing/ears/headphones = 10, /obj/item/clothing/suit/apron/purple_bartender = 4, /obj/item/clothing/under/rank/civilian/bartender/purple = 4, + /* Commenting out until next Christmas or made automatic + /obj/item/clothing/accessory/sweater/uglyxmas = 3, /obj/item/clothing/under/costume/christmas = 3, /obj/item/clothing/under/costume/christmas/green = 3, /obj/item/clothing/under/costume/christmas/croptop = 3, /obj/item/clothing/under/costume/christmas/croptop/green = 3, - */ /obj/item/clothing/suit/hooded/wintercoat/christmascoatr = 3, /obj/item/clothing/suit/hooded/wintercoat/christmascoatg = 3, /obj/item/clothing/suit/hooded/wintercoat/christmascoatrg = 3, - /*Commenting out until next Christmas or made automatic /obj/item/clothing/head/christmashat = 3, /obj/item/clothing/head/christmashatg = 3, - */ /obj/item/clothing/shoes/winterboots/christmasbootsr = 3, /obj/item/clothing/shoes/winterboots/christmasbootsg = 3, /obj/item/clothing/shoes/winterboots/santaboots = 3, + */ /obj/item/clothing/head/cowboyhat = 3, /obj/item/clothing/head/cowboyhat/black = 3, /obj/item/clothing/head/cowboyhat/white = 3, @@ -161,7 +185,8 @@ /obj/item/clothing/under/costume/cheongsam/white = 3, /obj/item/clothing/under/costume/cheongsam/red = 3, /obj/item/storage/backpack/snail = 3) - contraband = list(/obj/item/clothing/under/syndicate/tacticool = 3, + contraband = list(/obj/item/clothing/accessory/turtleneck/tactifool/syndicate = 3, + /obj/item/clothing/under/syndicate/tacticool = 3, /obj/item/clothing/under/syndicate/tacticool/skirt = 3, /obj/item/clothing/mask/balaclava = 3, /obj/item/clothing/head/ushanka = 3, diff --git a/code/modules/vending/kinkmate.dm b/code/modules/vending/kinkmate.dm index e522583772..2316682e68 100644 --- a/code/modules/vending/kinkmate.dm +++ b/code/modules/vending/kinkmate.dm @@ -2,7 +2,6 @@ name = "KinkMate" desc = "A vending machine for all your unmentionable desires." icon_state = "kink" - circuit = /obj/item/circuitboard/machine/kinkmate product_slogans = "Kinky!;Sexy!;Check me out, big boy!" vend_reply = "Have fun, you shameless pervert!" products = list( @@ -13,6 +12,7 @@ /obj/item/clothing/neck/petcollar = 5, /obj/item/clothing/neck/petcollar/choker = 5, /obj/item/clothing/neck/petcollar/leather = 5, + /obj/item/clothing/neck/necklace/cowbell = 5, /obj/item/restraints/handcuffs/fake/kinky = 5, /obj/item/clothing/glasses/sunglasses/blindfold = 4, /obj/item/clothing/mask/muzzle = 4, diff --git a/code/modules/vore/eating/belly_obj.dm b/code/modules/vore/eating/belly_obj.dm index 7f8aed83ef..8e74dd3c92 100644 --- a/code/modules/vore/eating/belly_obj.dm +++ b/code/modules/vore/eating/belly_obj.dm @@ -248,7 +248,7 @@ for(var/mob/living/H in hearing_mobs) if(H && H.client && (isturf(H.loc) || (H.loc != src.contents))) var/sound/releasement = GLOB.pred_release_sounds[release_sound] - H.playsound_local(owner.loc, releasement, vol = 75, vary = 1, falloff = VORE_SOUND_FALLOFF) + H.playsound_local(owner.loc, releasement, 75, TRUE) else if(H?.client && (H in contents)) var/sound/releasement = GLOB.prey_release_sounds[release_sound] SEND_SOUND(H,releasement) @@ -304,7 +304,7 @@ for(var/mob/living/H in hearing_mobs) if(H && H.client && (isturf(H.loc) || (H.loc != src.contents))) var/sound/releasement = GLOB.pred_release_sounds[release_sound] - H.playsound_local(owner.loc, releasement, vol = 75, vary = 1, falloff = VORE_SOUND_FALLOFF) + H.playsound_local(owner.loc, releasement, 75, TRUE) else if(H?.client && (H in contents)) var/sound/releasement = GLOB.prey_release_sounds[release_sound] SEND_SOUND(H,releasement) @@ -366,7 +366,7 @@ for(var/mob/living/H in hearing_mobs) if(H && H.client && (isturf(H.loc) || (H.loc != src.contents))) var/sound/eating = GLOB.pred_vore_sounds[vore_sound] - H.playsound_local(owner.loc, eating, vol = 75, vary = 1, falloff = VORE_SOUND_FALLOFF) + H.playsound_local(owner.loc, eating, 75, TRUE) else if(H?.client && (H in contents)) var/sound/eating = GLOB.prey_vore_sounds[vore_sound] SEND_SOUND(H,eating) @@ -585,14 +585,14 @@ if(is_wet) for(var/mob/living/H in hearing_mobs) if(H && H.client && (isturf(H.loc) || (H.loc != src.contents))) - H.playsound_local(owner.loc, pred_struggle_snuggle, vol = 75, vary = 1, falloff = VORE_SOUND_FALLOFF) + H.playsound_local(owner.loc, pred_struggle_snuggle, 75, TRUE) else if(H && H.client && (H in contents)) SEND_SOUND(H,prey_struggle_snuggle) else for(var/mob/living/H in hearing_mobs) if(H && H.client) - H.playsound_local(owner.loc, struggle_rustle, vol = 75, vary = 1, falloff = VORE_SOUND_FALLOFF) + H.playsound_local(owner.loc, struggle_rustle, 75, TRUE) for(var/mob/living/H in hearing_mobs) if(H && H.client && (isturf(H.loc))) diff --git a/code/modules/vore/eating/bellymodes.dm b/code/modules/vore/eating/bellymodes.dm index 291ef8654f..7cf36ebc50 100644 --- a/code/modules/vore/eating/bellymodes.dm +++ b/code/modules/vore/eating/bellymodes.dm @@ -245,7 +245,7 @@ last_hearcheck = world.time for(var/mob/M in hearing_mobs) //so we don't fill the whole room with the sound effect if(M && M.client && (isturf(M.loc) || (M.loc != src.contents))) //to avoid people on the inside getting the outside sounds and their direct sounds + built in sound pref check - M.playsound_local(owner.loc, play_sound, vol = 75, vary = 1, falloff = VORE_SOUND_FALLOFF) + M.playsound_local(owner.loc, play_sound, 75, TRUE) //these are all external sound triggers now, so it's ok. if(to_update) for(var/mob/living/M in contents) diff --git a/code/world.dm b/code/world.dm index 344ca9be79..71a9853d01 100644 --- a/code/world.dm +++ b/code/world.dm @@ -1,12 +1,22 @@ //This file is just for the necessary /world definition //Try looking in game/world.dm +/** + * # World + * + * Two possibilities exist: either we are alone in the Universe or we are not. Both are equally terrifying. ~ Arthur C. Clarke + * + * The byond world object stores some basic byond level config, and has a few hub specific procs for managing hub visiblity + * + * The world /New() is the root of where a round itself begins + */ /world mob = /mob/dead/new_player turf = /turf/open/space/basic area = /area/space view = "15x15" hub = "Exadv1.spacestation13" + hub_password = "kMZy3U5jJHSiBQjr" name = "/tg/ Station 13" fps = 20 #ifdef FIND_REF_NO_CHECK_TICK diff --git a/dependencies.sh b/dependencies.sh index 75e49f3fe1..e8709d10b1 100644 --- a/dependencies.sh +++ b/dependencies.sh @@ -11,16 +11,13 @@ export BYOND_MINOR=${LIST[1]} unset LIST #rust_g git tag -export RUST_G_VERSION=0.4.4 - -#bsql git tag -export BSQL_VERSION=v1.4.0.0 +export RUST_G_VERSION=0.4.7 #node version export NODE_VERSION=12 -# PHP version -export PHP_VERSION=5.6 - # SpacemanDMM git tag -export SPACEMAN_DMM_VERSION=suite-1.4 +export SPACEMAN_DMM_VERSION=suite-1.6 + +# Extools git tag +export EXTOOLS_VERSION=v0.0.6 diff --git a/html/changelog.html b/html/changelog.html index 8a1401744e..dc3b4e8c74 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -50,896 +50,785 @@ -->
    -

    04 October 2020

    -

    DeltaFire15 updated:

    +

    29 January 2021

    +

    MrJWhit updated:

      -
    • Synths / IPCs are no longer wound immune.
    • -
    • Husked IPCs / Synths should now be rendered correctly.
    • -
    • Falling vendors now squish synths / IPCs' limbs again.
    • -
    • Synths and IPCs now do not have some fun roundstart oversights anymore.
    • -
    • Regenerate_limbs now works for carbons with the ROBOTIC_LIMBS trait.
    • -
    • Pacifists no longer counterattack on parries if that attack would be harmful.
    • -
    • Heretic sacrifices now husk with the reason of burn, and deal some additional damage.
    • -
    • Neovgre can no longer become invincible on clock tiles.
    • -
    • Plushlings no longer break when absorbing snowflake plushies.
    • +
    • Ported the QM, Captain, CMO, and HoS cloaks from beestation.
    • +
    • Removes excess air alarms from boxstation
    -

    Detective-Google updated:

    +

    TripleShades updated:

      -
    • the snow cabin doors actually bolt now
    • -
    -

    Putnam3145 updated:

    -
      -
    • Ghosts are no longer incapable of going away.
    • -
    -

    monster860 updated:

    -
      -
    • The slimeperson swap-body UI stays open when you switch bodies
    • +
    • fixes engineering secure storage being the wrong area because I fucked that up previously my bad
    • +
    • removes funny extra light switch under right surgery table in surgery oops
    • +
    • Added chairs to the corpse launch viewing area
    • +
    • Small garden plot for flowers for parity with other station Chapels
    • +
    • Plain Bible to glass tables in Chapel
    • +
    • Candles and Matchbox to glass tables in Chapel
    • +
    • More glass tables, with a chaplain figure and another spare bible.
    • +
    • Bookcase to Box Chapel for parity with other station Chapels
    • +
    • Minimoog to Box Chapel as substitute for a church organ
    • +
    • Holy department sign just below Chapel change: Expanded the corpse launching area to feel less congested change: Added windows to the corpse launch so you can look inside I guess? change: Moved flowers and burial garments to the corner next to the corpse launcher change: Box Chaplain's office door is moved over one change: Confessional is now connected to Chaplain's office for parity with other station Chapels change: Moved coffins over to old confessional location change: Box Chapel now has pews instead of stools change: Box Chapel Confessional is now lit instead of being nearly pitch black remove: Two coffins from Chapel

    timothyteakettle updated:

      -
    • limb id entry in mutant bodyparts now supports switching to/from species with gendered body parts
    • -
    • the minimum brightness of mutant parts is now a define
    • +
    • the miner bedsheet will now increment its progress when you redeem points from the ORM
    • +
    • you can add custom names and descriptions to item's on the loadout now
    • +
    +

    zeroisthebiggay updated:

    +
      +
    • roundstart aesthetic sterile masks and roundstart paper masks
    • +
    • more accessory slot items
    • +
    • cowbell necklace happy 2021
    • +
    • shibari ropes & torn pantyhose
    -

    02 October 2020

    -

    ArcaneMusic, with minor tweaks by TheObserver-sys updated:

    +

    28 January 2021

    +

    silicons updated:

      -
    • Adds and modifies fertilizers, as well as a new stat, Instability.
    • -
    • Removes the rather disused functionality of irrigation hoses, temporarily disables circuit use on hydroponics trays.
    • -
    • Plant Analyzer have been upgraded. Using one in hand will now switch between a stat view of your plant, and a chemical view of your plant. tweak:Trays now accept and store reagents, as well as coming with an autogrow mode. However, these upgrades came at the cost of old self sufficiency, meaning you must attend to your plants a bit more often.
    • -
    • Earthsblood, while not being able to gild trays anymore, has been found to still be quite powerful as a fertilizer.
    • +
    • colormates can now paint some mobs.
    • +
    • 1 dev explosions shouldn't delete brains anymore
    -

    CoreFlare updated:

    + +

    27 January 2021

    +

    ArcaneMusic, ported by Hatterhat updated:

      -
    • Altcloaks! Available in loadout.
    • +
    • Strike a hydroponics tray with a fully-charged floral somatoray to lock in a mutation.
    • +
    • Floral somatorays now have the ability to force a mutation in a plant. This should drain the cell in a single shot, but we'll see.
    • +
    • Somatorays now take uranium to craft instead of radium.
    -

    Detective-Google updated:

    +

    Arturlang updated:

      -
    • a smattering of clothes from the RP server
    • -
    • detective wardrobe
    • +
    • Actually adds a right click give option
    • +
    • Revenants can now clickdrag to throw stuff at people, with some items doing various things at the same time.
    -

    EmeraldSundisk updated:

    +

    DeltaFire15 updated:

      -
    • Adds the "Skelter" space ruin
    • -
    • Creates a few new area designations for the Skelter
    • -
    • Cargo techs now have access to a "long pants" variant of their standard work uniform
    • -
    • Adds said uniform to CargoDrobes and the loadout menu
    • +
    • The woundmending rite no longer causes runtimes.
    • +
    • Ratvarian borgs can now use their tier-0 spells.
    • +
    • Ratvarian borgs can always use their assigned spells, if there is enough power.
    • +
    • The heretic antag panel now shows their sacrifices & current sacrifice targets.
    • +
    • The heretic roundend report now shows their sacrifices and nonsacrificed targets.
    • +
    • Living hearts can no longer select the same target as another living heart, removing a certain problem.
    -

    ItzGabby updated:

    +

    Hatterhat updated:

      -
    • Three new turf tiles.
    • -
    • Turf icons with multiple damage icons, with in-hand icons for each tile.
    • -
    • Edited the name and description to wooden.
    • -
    -

    LetterN updated:

    -
      -
    • craftable railings
    • -
    • ports robust savefiles
    • +
    • Department budget cards have been readded. TO THE CODE. NOT LOCKERS.
    • +
    • Also budget cards now look more like every other ID - see tgstation#55001.
    • +
    • One of the contractor tablet's payouts has been raised from a small payout to a medium payout.
    • +
    • The free golem ship's GPSes no longer start on. They were never meant to, but they did.
    • +
    • Headsets can't be found on most legion corpses now.
    • +
    • The flash on the assistant corpse is gone, too.

    MrJWhit updated:

      -
    • tweaked heavy suit dmi
    • -
    • Fixes drones not being able to quickslot items
    • -
    -

    Putnam3145 updated:

    -
      -
    • New policy config for pyroclastic slimes.
    • -
    • SDGF clones now naked.
    • -
    • SDGF is now way more likely to make a clone that will align with the creator's goals, with purity, making it a better antagging tool.
    • -
    • SDGF clones now have the same traits as the original.
    • -
    • transfer_ckey now resets view, preventing things like SDGF clones with much larger view range.
    • -
    • Policy configs have been added for SDGF, currently unused: SDGF, SDGF_ALIGNED, SDGF_UNALIGNED.
    • -
    • Shivering now has thresholds and fever's thresholds now work.
    • -
    • Made allturfs setup actually set up all turfs.
    • -
    • Dynamic is now more aggressive with adding antags.
    • -
    • Fixes vore pref saving.
    • +
    • Remaps some air alarms for sanity.

    SandPoot updated:

      -
    • Fixes headslugs being unable to recover their human form.
    • -
    -

    Tupinambis updated:

    -
      -
    • Adds methane and methyl bromide gases.
    • -
    • Minor gas name/desc changes to improve consistency
    • -
    • Ports the methyl bromide tank from bay. Adds two new canister sprites for the new gases and CH4 screen alerts.
    • -
    • fixed a mispelling in the wound armor value for the bounty hunter suit
    • -
    -

    dapnee updated:

    -
      -
    • atrium, clinic, an extra office, a pseudo public mining area, two more deluxe dorms, micro beach, aux bathroom, two construction areas, mass driver, more intercoms
    • -
    • moved all of service, chapel, dorms, garden, holodeck to a different z-level, RnD is more open, maintenance is a bit more random, more firelocks, added more mine-able rock
    • -
    • fixed the buttons in xenobio, gave shutters to cargo's storage area, fixed holodeck so it works now, fixed some techfabs being lathes, added sensors to atmos tanks, more decals, couple more signs, little floral areas and sitting areas added to break up hallway monotony, mech chargers are no longer missing their consoles, whiteship won't crash into arrivals anymore while the area it takes up is more telegraphed, APC placement on AI sat entrance, missing wire node for the outer portion of the AI sat, civilian level now has a telecom relay
    • -
    -

    lolman360 updated:

    -
      -
    • smonk machine runtimes
    • -
    • automatic hydro tray has a unique sprite now (fancy robot arm)
    • -
    -

    timothyteakettle updated:

    -
      -
    • added luminescent and stargazer sprites as selectable body sprites for slimes
    • -
    • wound exponent lowered slightly from 1.225 to 1.2
    • -
    • wound exponent and limb damage multiplier are now config values
    • -
    • ipcs and synthlizards are now treated as actual robots, with robotic limbs, an extra organ, and better emp acts
    • -
    • surgeries for healing robotic limbs, and brain surgery for robotic heads
    • -
    • androids limbs now show up as intended
    • -
    • emps now work from 1-100 severity instead of 1/2 and the severity reduces as you move from the epicentre
    • -
    -

    zeroisthebiggay updated:

    -
      -
    • ratvar gf is complete
    • -
    - -

    01 October 2020

    -

    BlueWildrose updated:

    -
      -
    • Slimepeople are given unique laughs and screams.
    • -
    • Adds "warbles", "chimpers", and "puffs" to the customizable speech verbs for character.
    • -
    - -

    29 September 2020

    -

    timothyteakettle updated:

    -
      -
    • fixed a typo causing your right eye colour to save as the left eye colour
    • -
    - -

    28 September 2020

    -

    ArchieBeepBoop updated:

    -
      -
    • Craftable Micro Powered Fans
    • -
    -

    Degirin2120 updated:

    -
      -
    • Added engineering hazard jumpsuits, can be found in the engidrobe, comes in 3 varieties.
    • -
    -

    Putnam3145 updated:

    -
      -
    • Added a brute-force check-every-single-tile step to SSair when it has enough time to run.
    • -
    • G fuid production is now much lower.
    • -
    • Supermatter sabotage objective's gone.
    • -
    • Subterfuge objectives are now all equally likely.
    • -
    • Replaced a "(hopefully) 1" with a "2"
    • -
    • Cryoing no longer unwins already-won objectives.
    • -
    -

    SiliconMain updated:

    -
      -
    • Minor adjustment to material cost of long range atmos analyzer
    • -
    -

    Trilbyspaceclone updated:

    -
      -
    • Most drinks now have some animation in them, from basic soda bubbles fizzing around to ice cubes bobbing just a bit.
    • -
    -

    Tupinambis updated:

    -
      -
    • Ghost poly's color value is now a hex value instead of an oct value. This has been a thing for OVER FIVE YEARS
    • -
    • Updates TEG, Antimatter, Jetpack sprites (CO2 and Oxy from Eris).
    • -
    • Replaced old chair sprites with new ones ported and modified from eris.
    • -
    • Beds can now be placed both right and left.
    • -
    • Subtle changes to stool legs to give them more of a shine.
    • +
    • The drop circuit can no longer drop things that are not inside it.

    raspy-on-osu updated:

      -
    • TEG power generation
    • -
    -

    thakyZ updated:

    -
      -
    • Added the ability to print the Light Replacer at the Engineering Protolathe
    • -
    -

    timothyteakettle updated:

    -
      -
    • turrets can once again be broken
    • -
    • you can now have heterochromia and select individual eye colours
    • -
    - -

    27 September 2020

    -

    SiliconMain updated:

    -
      -
    • Holograms made from projectors (atmos, engi, sec, medical, ect...) can no longer be contaminated by radiation
    • -
    - -

    26 September 2020

    -

    CoreFlare updated:

    -
      -
    • IPC's can have hair. Why wasn't this added earlier. Use the bald hairstyle for no hair.
    • -
    - -

    25 September 2020

    -

    Putnam3145 updated:

    -
      -
    • Removed a non-working proc that already had its functionality implemented in another proc in the same file.
    • -
    - -

    24 September 2020

    -

    Putnam3145 updated:

    -
      -
    • Atmos is free.
    • -
    - -

    22 September 2020

    -

    Arturlang updated:

    -
      -
    • TGUI Statpanel
    • -
    -

    YakumoChen updated:

    -
      -
    • Mechsuits, robotics jumpsuits added to RoboDrobe
    • -
    -

    timothyteakettle updated:

    -
      -
    • character previews should be more consistent now
    • -
    - -

    20 September 2020

    -

    DeltaFire15 updated:

    -
      -
    • Sutures work on simplemobs again.
    • -
    • Attacking dismembered bodyparts now targets the chest instead, for weapons aswell as unarmed attacks.
    • -
    -

    MrJWhit updated:

    -
      -
    • New sprites for chess pieces! You can craft them in-game with metal sheets.
    • -
    -

    silicons updated:

    -
      -
    • hulks can smash again (walls no longer break their hands)
    • -
    • acid no longer degrades armor
    • -
    - -

    17 September 2020

    -

    DeltaFire15 updated:

    -
      -
    • Failing the plushmium reaction can now create peculiar plushies, depending on reaction volume.
    • -
    • The mood-buff from petting a plushie now works properly again.
    • -
    • Fixed wacky necropolis loot chest behavior
    • -
    -

    EmeraldSundisk updated:

    -
      -
    • Adds the Research Director's office to Omega Station
    • -
    • Adds 2 new solar arrays (and control rooms)
    • -
    • Adds some action figures that weren't there previously
    • -
    • The CMO's office now has a light switch
    • -
    • Slight readjustments to impacted areas
    • -
    • Readjusts the toxins air supply line to (ideally) be easier to service
    • -
    • Department camera consoles should now be able to actually check appropriate cameras
    • -
    • Xenobiology can now be locked down (by the Research Director)
    • -
    -

    MrJWhit updated:

    -
      -
    • Adds a brain damage line
    • -
    -

    Putnam3145 updated:

    -
      -
    • Your balls finally feel full, again.
    • -
    -

    timothyteakettle updated:

    -
      -
    • due to changes in policy, and several lawsuits, Nanotrasen has been forced to allow disabled people to sign up
    • -
    - -

    16 September 2020

    -

    timothyteakettle updated:

    -
      -
    • fixed an icon path
    • -
    - -

    12 September 2020

    -

    01 October 2020

    -

    BlueWildrose updated:

    -
      -
    • Slimepeople are given unique laughs and screams.
    • -
    • Adds "warbles", "chimpers", and "puffs" to the customizable speech verbs for character.
    • -
    - -

    30 August 2020

    -

    raspy-on-osu updated:

    -
      -
    • new explosion echoes
    • -
    • explosion echo range
    • -
    • 5 new explosion related sounds
    • -
    - -

    28 August 2020

    -

    EmeraldSundisk updated:

    -
      -
    • Adds more paper to the library
    • -
    • The law office now has a desk window
    • -
    • Expands most of CogStation's exterior airlocks. Slightly adjusts surrounding areas to accommodate this.
    • -
    • Updates some of CogStation's paperwork
    • -
    • The rat in the morgue turned themselves into a possum. Funniest shit I've ever seen.
    • -
    • Adjusts some area designations so cameras should receive power properly
    • -
    • Cleans up an errant decal
    • -
    -

    Hatterhat updated:

    -
      -
    • Traitor holoparasites can now only be bought once, because apparently you can only have one active holopara.
    • -
    • PDA bombs can now only be bought once per uplink.
    • -
    -

    lolman360 updated:

    -
      -
    • atmos = radiation = chemistry.
    • +
    • bespoke ventcrawling element not detaching due to malformed call

    shellspeed1 updated:

      -
    • Adds slow mode for iv drips
    • +
    • Floorbots had had a software update, preventing them from dogpiling on their target as easily as they did before.
    • +
    • Floorbots will now play a small chime when stacked on top of each other to indicate that they're moving apart.

    timothyteakettle updated:

      -
    • an ancient game over a thousand years old has re-emerged among crewmembers - rock paper scissors
    • -
    • customization features appear in alphabetical order where necessary
    • -
    • bokken do two more stamina damage now
    • -
    • you can now choose a body sprite as an anthromorph or anthromorphic insect, and can choose from aquatic/avian and apid respectively (and obviously back to the defaults too)
    • +
    • blobs can use the 'me' verb
    • +
    • adminhelps and pms only sanitize once instead of twice
    -

    27 August 2020

    -

    silicons updated:

    +

    25 January 2021

    +

    MrJWhit updated:

      -
    • eyebeam lighting can only have 128 maximum HSV saturation now.
    • -
    • no more shotgun stripper clips in boxes.
    • -
    • goliath tentacles now do 20 damage to mechs at 25% ap
    • -
    -

    timothyteakettle updated:

    -
      -
    • changing your character's gender won't randomize its hairstyle and facial hairstyle now
    • -
    - -

    26 August 2020

    -

    ancientpower updated:

    -
      -
    • Ghosts can read newscasters by clicking on them.
    • -
    -

    silicons updated:

    -
      -
    • hierophant vortex blasts now have 50% armor penetration vs mecha
    • -
    • ventcrawling now kicks off every attached/buckled mob, even for non humans.
    • -
    - -

    25 August 2020

    -

    Hatterhat updated:

    -
      -
    • Insidious combat gloves have been replaced by insidious guerilla gloves. They're generally the same, except now you can tackle with them.
    • -
    -

    Literallynotpickles updated:

    -
      -
    • You can now equip handheld crew monitors on all medical-related winter coats.
    • -
    -

    Putnam3145 updated:

    -
      -
    • vore now ejects occupants on death
    • +
    • Alien radio code
    • +
    • Microwave can now be cleaned by a damp rag as well as soap.
    • +
    • Removes some unused code, and improves some other code.
    • +
    • The AI has a verb to look up and down z-levels
    • +
    • Making a monkey into a human doesn't unanchor random things on the tile
    • +
    • Makes a few slight improvements to drinking code
    • +
    • Makes encryption keys be put in the hands of the user when able instead of being dropped on the floor when removed from headsets

    raspy-on-osu updated:

      -
    • Thermoelectric Generator power output
    • -
    -

    timothyteakettle updated:

    -
      -
    • I.P.Cs now short their circuits when expressing emotion, causing sparks to appear around them.
    • -
    - -

    24 August 2020

    -

    MrJWhit updated:

    -
      -
    • Fixes areas on expanded airlocks
    • +
    • ventcrawling

    silicons updated:

      -
    • wormhole jaunters work
    • -
    • wormhole jaunters no longer get interference from bags of holding
    • -
    • airlocks now only shock on pulse/wirecutters instead of on tgui panel open.
    • -
    -

    timothyteakettle updated:

    -
      -
    • three new items are in the loadout for all donators
    • -
    -

    zeroisthebiggay updated:

    -
      -
    • contraband black evening gloves in kinkvend
    • +
    • you can now shove yourself up in any intent, not just help.
    -

    23 August 2020

    +

    22 January 2021

    +

    Arturlang updated:

    +
      +
    • Adds a way to give items to people, you can combat mode rightclick to offer it to one person, right click on people without mode and click the give verb, or use the hotkey CTRL G to offer it to everyone around you
    • +
    + +

    21 January 2021

    +

    Acer202 updated:

    +
      +
    • Main mining shuttle should no longer look at the public mining shuttle and attempt to dock ontop of it. Monastery shuttle should now function again.
    • +
    +

    Acer202, with minor help from The0bserver updated:

    +
      +
    • After internal deliberation, CentCom has decided to run a limited reinstatement of public mining shuttles for use in more tried and true station classes. CentCom would like to remind you that this privilege is easily revoked, and that abuse may result in immediate detonation.
    • +
    • Restores the mining shuttle on Pubby, Box, Delta, Meta, and Lambda Station.
    • +
    +

    ArcaneMusic, The0bserver-sys updated:

    +
      +
    • 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!
    • +
    • Gives Hydrotrays plumbing pipes automatically, allowing you to make a self sustaining tray via plumbing.
    • +
    • Gives Service access to Bluespace Beakers, at last, gives Cargo, Science, and Medical the ability to construct reinforced plungers for use on lavaland.
    • +
    +

    ArchieBeepBoop updated:

    +
      +
    • Upgraded Advanced RTG Machine Preset
    • +
    • Outlet Injector Mapping Asset Layer Fix
    • +
    • Jacqueen and the Christmas tree should no longer spawn abstract things that can cause shittons of runtimes.
    • +
    +

    Arturlang updated:

    +
      +
    • You can't tackle in nograv anymore
    • +
    • You cannot spam drink from blood bags anymore
    • +
    • Blood bag drinking inefficiency is now the right way, so you loose some of the blood drinking it straight
    • +
    • Handles more edge cases with construct soul returning
    • +
    • Being sacrificed by the cult no longer removes all hope of rescue.
    • +
    • Makes construct mind returning more robust
    • +
    • Prayers to admins now do a wee ding sound for all prayers, instead of just chaplains
    • +
    • Fixes the mint machine's UI
    • +
    • Hopefully fixes whitescreen issues for TGUI UI's by giving assets more time to get to the client
    • +
    • Fixes hijack implant APC UI, again
    • +
    • Comments out spaceman dmm do not sleeps for mob/proc/CommonClickOn, atom/proc/attack_hand, datum/proc/keyLoop and mob/living/proc/Life
    • +
    • Bloodsuckers tresspass ability can no longer work while they are not awake.
    • +
    • The cursed heart now only takes away half as much blood every loop, and can be used as long as you are alive, instead if only you are awake/able to use your hands
    • +
    +

    Bhijn updated:

    +
      +
    • Changeling loudness is now determined as an average of all their abilities, rather than the sum
    • +
    • To compensate for this, blood tests now require a loudness value of 1 or higher to detect ling blood. Additionally, blood test explosions are now triggered only when the loudness value is higher than 2.
    • +
    +

    BlackMajor updated:

    +
      +
    • Cyborg hypospray no longer injects if it means OD'ing while on help intent.
    • +
    +

    BlueWildrose updated:

    +
      +
    • Nyctophobia quirk now has some light lag compensation.
    • +
    • Fixes cloning computer UI not updating when pressing certain buttons - also adds extra check for names to update a message
    • +
    • Removes oversized genitalia analysis from medical scanners, since huge dick and titty are no longer a problem anymore thanks to advancements in that kind of technology when it comes to chemical fun times growth.
    • +
    • Fixed species-specific drinks not giving a mood boost if you are that species.
    • +
    • You will now only unbuckle fireman-carried/piggybacked people on disarm or harm intent.
    • +
    • The traitor AI can no longer activate the doomsday device while carded.
    • +
    • Fixes noodle size appearance for 12+ inch members.
    • +
    • Fixed the subtle hotkey being weird with its input prompts.
    • +
    • Adds a subtler anti-ghost hotkey. Default key is 6.
    • +
    • No more straining when your cock or breasts are growing via incubus draft or succubus milk.
    • +
    • PubbyStation now has two Christmas Tree spawners.
    • +
    • You can now have a max-roundstart-dicksize-config inch long johnson before you start suffering blood loss and slowdowns instead of a 20 inch one.
    • +
    • Color Mates have been added to all stations (except Snaxi). Enjoy coloring your attire without having to bug science!
    • +
    • Polychromic hoodies that were obtained from the loadout have functional colorable hoods now.
    • +
    • Adds in timid woman/man costumes. Available at your autodrobe! Also adds in garters as some new socks.
    • +
    • Corrected the capitalization in gasmask concealment examine text
    • +
    +

    Chiirno updated:

    +
      +
    • Added the paramedics EVA suit as a purchase from the cargo console.
    • +
    • Paramedics office and Surgery Storage Room
    • +
    • Remodeled the surgery room, as well as shrunk Morgue and Starboard Emergency Storage. Fiddled with some areas for better map edit clarity and fixed one runtime in Vacant Office A.
    • +
    • Added the paramedic closet sprite, a paramedic colored medical3 closet.
    • +
    • Added a paramedic closet, which is the standard medical3 closet with their suit, a pinpointer, and a crew monitor added.
    • +
    • Nightmare now deals additional damage to most light sources.
    • +
    • Nightmare now one-shots miners beacons and glowshrooms
    • +
    • Portable Chem Mixer now researchable from biotech node.
    • +
    • Chem masters can now dispense 20 instances of its outputs instead of 10.
    • +
    +

    Delams-The-SM updated:

    +
      +
    • Added 3 new emotes *hiss *purr *meow
    • +
    • ported sounds from Citadel RP for *purr and *meow
    • +
    • fixed randomization of colors for things like mulligan and Stabilized green slime extract for matrixed body parts
    • +

    DeltaFire15 updated:

      -
    • silicons and clockies can now access APCs properly
    • +
    • Biomechanical (hybrid) bodyparts now have access to wound-fixing surgeries.
    • +
    • A wound being fixed no longer just qdel()s surgeries connected to it.
    • +
    • Some robotic surgery steps are now a bit more clear.
    • +
    • Organs no longer get fed to people after successfully being inserted into them.
    • +
    • Not completing the do_after of a surgery no longer causes you to attack the target with whatever you were holding.
    • +
    • IPC cells & power cords are now printable after they are researched.
    • +
    • A new surgery, allowing revival of synths without a defib at hand.
    • +
    • Semi-permanent damage of Synth limbs caused by passing the damage threshold: 10 <- 15.
    • +
    • The embed removal surgery now has a version for Synths.
    • +
    • EMPs no longer hardstun Synths.
    • +
    • Portals no longer runtime because of incorrect args.
    • +
    • Abductors now can use experimental organ replacement surgery on robots / synthetics.
    • +
    • Fixes a minor incorrectness in ratvarian borg slabs (ratvar_act -> ui_act)
    • +
    • Changelings no longer double-deathgasp when activating the regen stasis ability while not dead.
    • +
    • People installing KA modkits in miner borgs is no longer broken.
    • +
    • Fixes the tail entwine messages displaying incorrectly.
    • +
    • Antagging / Deantagging Heretics now properly sets their special role.
    • +
    • The borg VTEC ability now actually gets removed when the upgrade is removed.
    • +
    • Supplypods shouldn't cause runtimes anymore, and shrapnel (pelletclouds) should work for them.
    • +
    • Robots (anyone with the robotic_organism trait) have toxins damage replaced with system corruption. See the PR for details.
    • +
    • Clockwork rites now support hiding specific rites from neutered servants.
    • +
    • AIs now only have to kill people once instead of permanently.
    • +
    • Scripture no longer sometimes eats part of its invocation.
    • +
    • APCs and silicons are now more susceptible to powerdrains (by the power_drain() proc, which is rare)
    • +
    • Void Volt has been modified from a chant to a singular pulse.
    • +
    • Robotpeople are now fully immune to the effects of alcohol (drunkness etc.)
    • +
    • Renames the alcohol intolerance trait in the code to make what it does more clear.
    • +
    • Self-fueling weldingtools recharge fuel properly again.
    • +
    • Brass welders now actually recharge faster than experimental ones.
    • +
    • Repeatable surgery steps can no longer cause an infinite loop if not completing the do_after
    • +
    • The Revenant self-revive ability is no longer broken.
    • +
    • Loot items mobs drop are no longer always failing to initialize.
    • +
    • Instant summons can no longer do wacky stuff with disposals (and nukes).
    • +
    • Objectives are no longer very broken.
    • +
    • Bloodcult stunhands now work against clockies like they were supposed to instead of hardstunning.
    • +
    • zeolites are now actual fermichems instead of being incredibly easy to make.
    • +
    • Using syringes / droppers on chem heaters with beakers in them works again.
    • +
    • Some edge cases causing issues with system corruption shouldn't be able to occur anymore.
    • +
    • Cyborg B.o.r.i.s. installation now checks for if the chest has a cell, just like how it does with MMIs.
    • +
    • The 'Your body is in a cloner' notification works again
    • +
    • Hijack implants should work properly again (or, at least better)
    • +
    • Liches are now good skeletons again instead of weak ones
    • +
    • The piratepad control cannot be destroyed again.
    • +
    • Pirates have received new supplies of jetpacks instead of useless oxygen tanks
    • +
    • Ratvarian AIs are once again able to show their linked borgs Ratvar's light
    • +
    • Hijackers are once again unable to detonate borgs without being adjacent to the console
    • +
    • Automated annoucement systems and gulag ore consoles no longer waste emag charges
    • +
    • Automated announcement systems once again can be remote controlled by non-AIs with silicon access
    • +
    • APCs being hijacked multiple times at once is no longer possible, preventing some issues
    • +
    • Recharging APCs no longer use 0.2% of the power they should be using.
    • +
    • APCs no longer always use as much power as they can for their cell, even if it is full.
    • +
    • Vampire shapeshifting should now behave as intended
    • +
    • Some synth damage stuff has been a bit rebalanced, see the PR for details.
    • +
    • Nanogel, available at medical and robotics, which fixes internal damage in sufficiently repaired robotic limbs.
    • +
    • Robotic Limbs now each have their own damage threshhold values
    • +
    • Robotic Limb damage threshholds are now seperated into threshhold itself and mindamage when passed balance; Hybrid limbs can now be injected with hypos, but not sprayed (Still not healed by chems)
    • +
    • Brain surgery has been tweaked back to allowing robotic limbs, blacklisting IPC brains instead.
    • +
    • Robot brain surgery can now be used on organic heads, if there is a IPC brain in them somehow.
    • +
    • The robot limb heal surgery can now be used even if the target's torso is not robotic, as long as they have robotic limbs
    • +
    • BODYPART_ROBOTIC / BODYPART_ORGANIC checks replaced with helper-procs whereever possible.
    • +
    • Added a BODYPART_HYBRID define for robotic bodyparts that behave organic in some regards.
    • +
    • The transmission sigil power drain works now
    • +
    • A certain lizard (totally not me) being stupid is no longer going to break regenerate_bodyparts
    • +
    • Combat mode now will not stay permanently disabled due to status effects not working as intended.
    • +
    • Attacking some certain objects no longer has no clickdelay.
    • +
    • the blacksmithing skill now works properly
    • +
    • Anvils cannot be interacted with with hammers whilst they are already being used
    • +
    • If someone has no gloves when interacting with heated ingots, they no longer ignore their effects.
    • +
    • A runtime caused by hallucinations is gone.
    • +
    • Cargo packs marked as 'no private buying' now actually register as such.
    • +
    • Fleshmend, Anatomic Panacea and bloodsucker healing now work for Synths / IPCs.
    • +
    • Medibots now ignore people they cannot help due to their biology.
    • +
    • get_damaged_bodyparts() is no longer broken.
    • +
    • Your target cryoing will no longer give you a free greentext.
    • +
    • Sleeper UI interactiveness now behaves correctly.
    • +
    +

    Detective-Google updated:

    +
      +
    • arcade carpet
    • +
    • explosions now get broadcasted to deadchat.
    • +
    • Lick radial
    • +
    • Hilbert's jukebox works
    • +
    • arcade carpets now actually work
    • +
    • the snow taxi is no longer the slow taxi
    • +
    +

    ERP mains updated:

    +
      +
    • Subtler Around Table is now a verb
    • +
    +

    EdgeLordExe, MoonFalcon updated:

    +
      +
    • Ported a bunch of heretic-related tweaks and changes from tg

    EmeraldSundisk updated:

      -
    • Medbay now has a smartfridge for organ storage
    • -
    • Slight enhancements to the station's electrical wiring layout
    • -
    • Very small library renovation
    • -
    • Exterior airlocks have been given proper air systems for safety's sake
    • +
    • Adds a few new area designations primarily for CogStation, incorporates them into said map
    • +
    • Reorganizes some area designations for ease of use, along with renaming the central "Router" to "Routing Depot"
    • +
    • Fixes an incorrectly designated area in CogStation
    • +
    • Changes the area designations to be not varedited since the code didn't like that anymore
    • +
    • The cargo bay conveyor belts not only work with the shuttle now but go in the right direction to boot
    • +
    • Slight visual adjustments to cargo in light of this
    • +
    • The arcade's got RAD carpet now
    • +
    • Fixes the conveyor belt issues in Delta Station's cargo wing
    • +
    • Removes some of the dirt around the affected area (presumably they would have cleaned it up while working on it)
    • +
    • Adds a floor light to fix the "dark spot" cargo had
    • +
    • Adds a new "Computer Core" area designation for CogStation
    • +
    • Fixes some missing area strings
    • +
    • Replaces some firelocks with directional ones as to ensure desks/counters can still be accessed
    • +
    • The "Skelter ruin" now has stechkins as opposed to M1911s
    • +
    • Skelter's decorative bullet casings replaced to factor in the change in caliber
    • +
    • Skelter now has a combat knife and fluff note

    Ghommie updated:

      -
    • Stops shielded hardsuits from slowly turning the wearer into a big glowing ball of stacked energy shield overlays.
    • -
    • the shielding overlay is merely visual as result. Aim your clicks.
    • +
    • You can access the mime / clown mask skins radial menu once again.
    • +
    • Dice bags no longer act like cardboard boxes.
    • +
    • Abductors should be no longer mute.
    • +
    • Item action buttons should now properly show the item current overlays, most times.
    • +
    • The blackbox should now go into your hand slot when pried out, rather than tumbling on the ground everytime.
    • +
    • The Quick Equip hotkey is now usable by all living mobs (so long they have hands and equipment slots)
    -

    Ludox235 updated:

    +

    Ghommie, porting PRs by MMMiracles and pireamaineach, credits to BlueWildrose too. updated:

      -
    • no more 10 pop xenos (25pop now)
    • -
    -

    MrJWhit updated:

    -
      -
    • Increases the majority of airlocks by 1 tile.
    • -
    • Minor adjustments to the TEG engine.
    • -
    -

    Putnam3145 updated:

    -
      -
    • Simplemobs no longer count in dynamic.
    • -
    • "Story" storyteller no longer starts at a ludicrously low threat, always.
    • -
    • Blob threat now scales with coverage.
    • -
    • One person with their pref on no longer overpowers 40 people who might not even know there is one.
    • -
    • Negative-weight rulesets are no longer put into the list.
    • -
    -

    kiwedespars updated:

    -
      -
    • removed durathread from armwraps recipe.
    • -
    -

    lolman360 updated:

    -
      -
    • breath mask balaclava
    • -
    -

    timothyteakettle updated:

    -
      -
    • lizards are now a recommended species for mam snouts
    • -
    -

    zeroisthebiggay updated:

    -
      -
    • new sprites for the temporal katana
    • -
    • suiciding with the temporal katana omae wa mou shinderius you into the shadow realm
    • -
    • twilight isnt earrape
    • -
    - -

    22 August 2020

    -

    Time-Green (copypasta'd by lolman360) updated:

    -
      -
    • plumbing
    • -
    • automatic hydro trays
    • -
    - -

    21 August 2020

    -

    LetterN updated:

    -
      -
    • Updates and adds some of the tips
    • -
    -

    Putnam3145 updated:

    -
      -
    • added reftracking as a compile flag
    • -
    -

    SmArtKar updated:

    -
      -
    • RSD limitation is now 500 tiles
    • -
    • Fixed broken RSD sprites
    • -
    • Removed that shuttle limit
    • -
    -

    timothyteakettle updated:

    -
      -
    • two snouts can once again be chosen in customization
    • -
    • lizard snouts work again
    • -
    - -

    20 August 2020

    -

    DeltaFire15 updated:

    -
      -
    • The cooking oil damage formula is no longer scuffed.
    • -
    • Changed the clockie help-link to lead to our own wiki.
    • -
    -

    Fikou updated:

    -
      -
    • admins can now do html in ahelps properly
    • +
    • You can now draw on plasmaman helmets with a crayon to turn their frown upside-down.
    • +
    • Plasmaman helmets no longer hide your identity when worn by themselves.
    • +
    • Plasmaman helmets now have welding visors, which can't stack with their torches in the helmet and are visible.

    Hatterhat updated:

      -
    • Pirate threats are now announced as "business propositions", and their arrivals are now also announced properly.
    • +
    • Energy sabre reskin for the energy sword - access via alt-click.
    • +
    • Alt-click reskins are fixed.
    • +
    • Defibrillators and their many, many overlays were moved to another .dmi.
    • +
    • You can now change the color of an energy sword via multitool. Not deswords. Yet.
    • +
    • The Syndicate appear to be issuing new revolver variants.
    • +
    • Basic sticky technology is now a roundstart tech. Advanced sticky technology is BEPIS-locked, though. Theoretically.
    • +
    • Non-smithed katanas (including the temporal katana) can now fit in the twin sheath.
    • +
    • Cotton and durathread processing by hand now acts like grass. Stand on a pile of cotton (or durathread) and use a single bundle from it.
    • +
    • Utility uniforms now comply with the "nonproper equipment names" thing.
    • +
    • The CapDrobe now allows the captain to get his own clothes for free. Probably.
    • +
    • All captains' clothes now offer 15 woundarmor, up from the 5. Because apparently only the suit and tie and its suitskirt subtype have this wound armor, which is dumb.
    • +
    • The nature interaction shuttle with the monkeys now has tiny fans on the airlocks in, because that's apparently a feature that was missing.
    • +
    • More bags have been added to department vendors.
    • +
    • Every roundstart species (and also ash walkers) now has flesh and bone that can be wounded.
    • +
    • Recipes for sutures, regen mesh, and sterilized gauze have been adjusted to be easier, mostly.
    • +
    • Sterilized gauze is better at absorbing blood and being a splint.
    • +
    • Energy sabres now have an off inhand.
    • +
    • The bone gauntlets should be slightly less murderously punchy on the fast punches mode.
    • +
    • RPEDs now drop their lowest part tier first when quick-emptied (used inhand).
    • +
    • Improvised gauzes can now be crafted in stacks up to 10, like their maximum stacksize implies they should be capable of doing.
    • +
    • Pouring sterilizine on gauze now takes the proper 5u per sterilized gauze instead of 10u.
    • +
    • Cryogenics now screams on common again when your fuckbuddy heads out.
    • +
    • Survival daggers! A slightly more expensive survival knife that comes with a brighter flashlight. On the blade.
    • +
    • Luxury pod capsules look different from normal capsules.
    • +
    • The wastes of Lavaland and the icy caverns of Snow Taxi rumble in unison.
    • +
    • Exosuits sold on the Supply shuttle no longer leave wreckages.
    • +
    • Apparently, shrink rays were buyable again, despite a PR having been made a while ago specifically for removing shrink rays. They're gone again.
    • +
    • Changeling bone gauntlets! They punch the shit out of people really good.
    • +
    • Guerilla gloves and gorilla gloves inherit the strip modifiers of their predecessors, because apparently they had those.
    • +
    • Pugilists now always hit the targeted limb and never miss.
    • +
    • The dock-silver standard set by Box and Meta has been enforced across maps in rotation (Delta, Pubby, Lambda).
    • +
    • The Box whiteship now has its missing tiny fan back.
    • +
    • The survival dagger light on the sprite now actually turns on and off.
    • +
    • The survival dagger in the glaive kit that can also be bought by itself is now better at butchering things.
    -

    tiramisuapimancer updated:

    +

    HeroWithYay updated:

      -
    • Ethereal hair is now their body color instead of accidentally white
    • -
    - -

    18 August 2020

    -

    DeltaFire15 updated:

    -
      -
    • kindle cast time: 15ds -> 25ds
    • -
    • Moved the Belligerent Scripture to where it should be in the code
    • -
    -

    Detective-Google updated:

    -
      -
    • glass floors
    • -
    • uncrowbarrable plasma floors tweak:disco inferno's plasma floors can no longer be crowbarred.
    • -
    • ghost cafe has funky fresh art
    • -
    • you can actually remove glass floors now
    • -
    • get_equipped_items is hopefully less gross
    • -
    • plasma cutters are no longer gay
    • -
    -

    Hatterhat updated:

    -
      -
    • Slaughter demons (and laughter demons, being a subtype) are MOB_SIZE_LARGE, with one of the more immediate effects being able to mark them with a crusher and backstab them.
    • -
    • The funny blyat men have stumbled upon another surplus of Mosin-Nagants and are starting to pack them into crates again.
    • -
    • Vehicle riders can now, by default, get shot in the face and/or chest.
    • -
    • Adminspawn only .357 DumDum rounds! Because sometimes the other guy just really needs to hurt.
    • -
    • Bluespace beakers now have a chemical window through the side that shows chemical overlays.
    • -
    • Plant DNA manipulators now let you chuck things over them. Or they WOULD, if LETPASSTHROW worked half a damn.
    • -
    -

    LetterN updated:

    -
      -
    • uplink implant states
    • -
    • tweaks how role assigning works
    • -
    -

    MrJWhit updated:

    -
      -
    • Gives ashwalkers nightvision
    • -
    • Makes tesla blast people, not the environment, to save the server.
    • -
    -

    TheObserver-sys updated:

    -
      -
    • moves Garlic sprites from growing.dmi to growing_vegetable.dmi
    • -
    • Removes the unused Electric Lime mutation, it just takes up space with no actual function nor sprites.
    • -
    • Gives Catnip growing sprites
    • -
    • Removes redundant images in growing.dmi
    • -
    -

    kiwedespars updated:

    -
      -
    • 10 force to a fucking rubber cock.
    • -
    -

    lolman360 updated:

    -
      -
    • shotgun stripper clip nerf. ammoboxes can now accept a load_delay that happens when they attack a magazine, internal or external.
    • -
    -

    ported from tg updated:

    -
      -
    • bronze airlocks and windows can now be built
    • -
    • i also tweaked bronze flooring to be cheaper.
    • -
    -

    silicons updated:

    -
      -
    • stamina draining projectiles without stamina for their primary damage type now has their stamina damage taken into account for shield blocking, rather than the block being done for free for that.
    • -
    -

    timothyteakettle updated:

    -
      -
    • snowflake code tidyup
    • -
    • snowflake code for mutant bodypart selection has been rewritten to be ~14x shorter
    • -
    • meat type and horns can now be selected by any species
    • -
    - -

    17 August 2020

    -

    DeltaFire15 updated:

    -
      -
    • Cogscarabs are no longer always Pogscarabs
    • -
    -

    Strazyplus updated:

    -
      -
    • Added drakeborgs
    • -
    • Added drakeplushies
    • -
    • added drakeborg sprites
    • -
    • added drakeplushie sprites
    • -
    • changed some code - added drakeplushies to backpack loadout Removed duplicate voresleeper belly sprites from engdrake & jantidrake. [CC BY-NC-SA 3.0](https://creativecommons.org/licenses/by-nc-sa/3.0/)
    • -
    • Added CC BY-NC-SA 3.0 license details to icon/mob/cyborg moved drakeborg.dmi to icon/mob/cyborg
    • -
    - -

    16 August 2020

    -

    kiwedespars updated:

    -
      -
    • nerfed hypereut chaplain weapon.
    • -
    • 50% rng blockchance -> 0%
    • -
    • parry made much worse because it's an actual weapon and a roundstart one at that.
    • -
    -

    zeroisthebiggay updated:

    -
      -
    • tips
    • -
    - -

    15 August 2020

    -

    LetterN updated:

    -
      -
    • missing anomaly core icons
    • -
    • wrong state. blame the tg vertion i copied
    • -
    -

    silicons updated:

    -
      -
    • the 8 rotation limit from clockwork chairs has been removed. please don't abuse this.
    • -
    • ethereals can now wear underwear
    • -
    - -

    14 August 2020

    -

    silicons updated:

    -
      -
    • abductors can buy things
    • -
    - -

    13 August 2020

    -

    LetterN updated:

    -
      -
    • Removes fermisleepers and reverts them to tg ones
    • -
    - -

    12 August 2020

    -

    DeltaFire15 updated:

    -
      -
    • hellgun single-pack classification: goodies -> armory
    • -
    -

    Detective-Google updated:

    -
      -
    • hallway table hallway table
    • -
    -

    Hatterhat updated:

    -
      -
    • The temporal katana is now slightly more worthy of the 2 spell point cost, with a smaller, antimagic respecting timestop, less force, and no random blockchance. Society has progressed past the need for blockchance.
    • -
    -

    LetterN updated:

    -
      -
    • Mafia Component
    • -
    • Fixed missing icons and handtele
    • -
    -

    Putnam3145 updated:

    -
      -
    • a whole lot of jank regarding funny part sprite display.
    • -
    -

    Toriate updated:

    -
      -
    • Opossums have migrated into the maintenance tunnels! Seek them out at your own peril!
    • -
    -

    ancientpower updated:

    -
      -
    • Doors added to the west side of box medbay to make things a bit more manageable.
    • -
    -

    kappa-sama updated:

    -
      -
    • smuggler satchel cost 2->1
    • -
    • radio jammer cost 5->2
    • -
    • smuggler satchel uplink description now implies that persistence is disabled
    • -
    -

    lolman360 updated:

    -
      -
    • renameable necklace (accessory, attaches to suit) and ring (glove slot.)
    • -
    • custom rename is now 2048 characters? i think it's characters.
    • -
    -

    silicons updated:

    -
      -
    • You can now use anything as an emoji by doing :/obj/item/path/to/item:. This works for any /atom or subtype.
    • -
    -

    timothyteakettle updated:

    -
      -
    • syndicate agents now have access to mechanical aim enhancers which allow them to aim bullets to bounce off walls
    • -
    • ricochets work properly now for the bullets that support them
    • -
    -

    zeroisthebiggay updated:

    -
      -
    • hair and some sechuds
    • -
    • ce hardsuit radproofing
    • -
    - -

    11 August 2020

    -

    Hatterhat updated:

    -
      -
    • PDA uplinks can now steal from pens. Properly. Just make sure to have a pen in your PDA, first.
    • -
    -

    kappa-sama updated:

    -
      -
    • tracer no longer gives you full stamheals per use
    • -
    -

    zeroisthebiggay updated:

    -
      -
    • volaju two
    • -
    - -

    10 August 2020

    -

    Hatterhat updated:

    -
      -
    • Parry counterattack text now shows up.
    • -
    • Sterilized gauze is now better at stopping bleeding, and applies slightly faster. Very slightly faster.
    • -
    • Ointment and sutures now hold more in a stack (12 and 15, respectively).
    • -
    • Sterilized gauze can now be made by just pouring 10u sterilizine onto standard medical gauze, instead of having to craft it. Why you had to craft it, I will honestly never know.
    • -
    • Proto-kinetic glaives are more expensive, stagger/cooldown on failed parries increased slightly, perfect parries required for counterattack.
    • -
    • New item: Temporal Katana. 2 points for wizards, timestops upon successful parry, bokken quickparry stats (100 force on melee counter!).
    • -
    • Also you can *smirk. This has no mechanical effect, other than being smug.
    • +
    • Changed description of Necrotizing Fasciitis symptom.
    • +
    • Wormhole Projector and Gravity Gun now require anomaly cores to function instead of firing pins.

    KeRSedChaplain updated:

      -
    • Added a guide for romerol usage
    • -
    • made infectious zombies not enter softcrit and take no stamina damage
    • +
    • Resprited the brass claw

    LetterN updated:

      -
    • clocktheme color
    • -
    • Ports TGUI-4
    • -
    -

    Lynxless updated:

    -
      -
    • Ports TG #51879
    • -
    -

    Owai-Seek updated:

    -
      -
    • Meatballs now spawn raw from food processors.
    • -
    -

    Putnam3145 updated:

    -
      -
    • Ethereals
    • -
    • (Hexa)crocin
    • -
    • (Hexa)camphor
    • -
    • Tweaked wording for marking tickets IC issue.
    • -
    • Rerolling your traitor goals will ONLY give you "proper" objectives.
    • -
    -

    Seris02 updated:

    -
      -
    • borgs being able to select and use a module when it's too damaged
    • -
    -

    Sishen1542 updated:

    -
      -
    • gave chairs active block/parry in exchange for removal of block_chance
    • -
    • replaces box whiteship tbaton with truncheon
    • -
    -

    kappa-sama updated:

    -
      -
    • made the Dirty Magazines crate cost 4000 instead of 12000 credits
    • -
    • MODS I SPILLED MU JUICE HEJPPHRLP HELPJ JLEP HELP
    • -
    -

    silicons updated:

    -
      -
    • player made areas are no longer valid for malf hacking
    • -
    • default space levels is 4 again.
    • -
    • rats now swarm instead of stacking on one spot.
    • -
    • getting hit by an explosion will now barely hard knockdown, but will leave you somewhat winded.
    • -
    -

    timothyteakettle updated:

    -
      -
    • speech verbs copy through dna copying now
    • -
    - -

    09 August 2020

    -

    Hatterhat updated:

    -
      -
    • Proto-kinetic glaives (not crushers) can parry now.
    • -
    -

    MrJWhit updated:

    -
      -
    • Adds a second shutter on the top of the hop line
    • -
    -

    silicons updated:

    -
      -
    • immovable rods no longer drop down chasms
    • -
    • fun removal: squeaking objects now have an 1 second cooldown between squeaks, and will have a 33% chance of interrupting any other squeaking object when Cross()ing, meaning no more ear-fuck conveyor belts.
    • -
    - -

    08 August 2020

    -

    DeltaFire15 updated:

    -
      -
    • Roundstart cultists now start with a replica fabricator - no brass though, make your own.
    • -
    • Kindle cast time: 10 > 15, mute after stun end: 2 > 5, slur after mute end: 3 > 5
    • -
    • The ratvarian spear no longer adds negative vitality under very specific circumstances.
    • -
    • The Ratvarian Spear can parry now! Short parries with low leeway, but low cooldown.
    • -
    • The brass claw, a implant-based weapon which gains combo on consecutive hits against the same target.
    • -
    • The sigil of rites, a sigil used to perform various rites with a cost of power and materials
    • -
    • The Rite of Advancement: Used to add a organ or cyberimplant to a clockie without need for surgery.
    • -
    • The Rite of Woundmending: Used to heal all wounds on another cultist, causing toxins damage in return.
    • -
    • The Rite of the Claw: Used to summon a brass claw implant. Maximum of 4 uses per round.
    • -
    -

    Hatterhat updated:

    -
      -
    • You can now buy a toolbox's worth of Mosin-Nagant ammo for a fairly discounted price.
    • -
    • Revolvers from the dedicated kit now have reskinning capabilities.
    • -
    • You can now actually buy the riflery primer, which lets you pump shotguns and work the Mosin's bolt faster.
    • -
    • Bulldog slug magazines now have a unique sprite.
    • -
    -

    Ludox235 updated:

    -
      -
    • Removed an abductee objective that told you to remove all oxygen.
    • -
    • Added a new abductee objective to replace the removed one.
    • -
    -

    Sishen1542 updated:

    -
      -
    • 🅱️oneless
    • -
    • squishy slime emotes
    • -
    -

    timothyteakettle updated:

    -
      -
    • heparin makes you bleed half as much now
    • -
    • cuts make you bleed 25% less now
    • -
    • more items in the loadout and loadout has subcategories now for easier searching
    • -
    - -

    07 August 2020

    -

    dapnee updated:

    -
      -
    • fixed active tufs on some space ruins, murderdome VR, and a few on pubby, changed cargo autolathe to techfab, messed with pipe room leading to monastery.
    • -
    -

    lolman360 updated:

    -
      -
    • vendors are now unanchored when tipped. it just fell over it's not bolted to the ground anymore.
    • -
    • podpeople no fat when sunbathing.
    • -
    -

    silicons updated:

    -
      -
    • explosions only recurse one level into storage before dropping 1 level per storage layer.
    • -
    • volumetric storage is now minimum 16 pixels per item because 8 was ridiculous
    • -
    • shieldbash balanace --> balance
    • -
    • attempting to send too long of an emote will now reflect it back to you instead of cutting it off and discarding the overflow.
    • -
    • holoparasites can now play music
    • -
    • lethal blood now causes damaging bleeding instead of outright gibbing
    • -
    - -

    06 August 2020

    -

    Auris456852 updated:

    -
      -
    • Added B.O.O.P. Remote Control cartridges to the PTech.
    • -
    -

    Hatterhat updated:

    -
      -
    • Proto-kinetic glaives! Essentially a proto-kinetic crusher with a different blade, handguard, and goliath hide grip. Expensive, but elegant.
    • -
    • Door charges no longer knock people out.
    • -
    -

    Ludox235 updated:

    -
      -
    • You can now buy damaged AI upload modules in the traitor's uplink.
    • -
    -

    Seris02 updated:

    -
      -
    • fixed ghost chilis
    • -
    -

    Trilbyspaceclone updated:

    -
      -
    • 4 New blends of tea have been shipped to the station, and how to make them has been leaked!
    • -
    -

    b1tt3r1n0 updated:

    -
      -
    • Added the warp implant
    • -
    -

    dapnee updated:

    -
      -
    • added a hallway to telecoms for engineers to get there on meta
    • -
    -

    kappa-sama updated:

    -
      -
    • dildo circuit assemblies
    • -
    -

    lolman360 updated:

    -
      -
    • The Tendril-Mother on Lavaland has remembered how to make ashwalkers who know how to speak Draconic again.
    • -
    -

    timothyteakettle updated:

    -
      -
    • nanotrasen has decided to fire all disabled members of the security division and confiscate certain sentimental items from doctors
    • -
    • the custom tongue preference now passes through cloning so you spawn with your selected tongue
    • -
    • several changes to travelling traders so they look better and spawn slightly less often
    • -
    -

    zeroisthebiggay updated:

    -
      -
    • nukies can buy holoparasites
    • -
    - -

    04 August 2020

    -

    Seris02 updated:

    -
      -
    • lizard spines
    • -
    -

    timothyteakettle updated:

    -
      -
    • due to further advancements in medical technology, you can now have holes poked into your body for fun and enjoyment
    • -
    -

    zeroisthebiggay updated:

    -
      -
    • prefs for headpat wagging
    • -
    - -

    03 August 2020

    -

    KeRSedChaplain updated:

    -
      -
    • fixed clockwork guardians being able to reflect ranged weapons
    • +
    • 2 more ways to get up from z1
    • +
    • tweaked the z2 garden to be less blank
    • +
    • fixed telecomms pda log
    • +
    • Coin & Holochip support for slot machine
    • +
    • Stickybans are now saved in the DB too
    • +
    • Immersive ™ audio reverbs. (also adds multiz audio)
    • +
    • Semi-hardsync from TG
    • +
    • Updates rust-g
    • +
    • Uses git CI instead of travis/appveyor now
    • +
    • Updates git and build tests.
    • +
    • minimap text
    • +
    • ports cinematic upgrades

    Linzolle updated:

      -
    • uv penlight no longer invisible
    • +
    • entertainment monitors no longer invisible
    • +
    • entertainment monitors now light up and display text when motion is detected in thunderdome
    • +
    • lizard snouts are no longer *slightly* lighter than they are supposed to be.
    -

    dapnee updated:

    +

    MrJWhit updated:

      -
    • active turfs on box and xenohive, maintenance bar APC not being stringed correctly, turned a monitor to face a direction that makes sense, changed tag of camera in gravgen being misnamed
    • +
    • Expanded space hermit base
    • +
    • Replaced engineering fuel tank with a large fuel tank
    • +
    • Changed access to sec suit storage from armory access in every map to other security access
    • +
    • Adds a space loop to every map in toxins
    • +
    • +
    • Added the ability for cargo to buy a large welding tank
    • +
    • Tweaked large tank reagent sprites to /tg/'s
    • +
    • Gives metastation toxins storage a scrubber and a vent
    • +
    • Updates suit storage info on Tip Of the Round.
    • +
    • Increased christmas event from 22th to 27th to 10th to 27th
    • +
    • Removes an opposum from the wall
    • +
    • Donut boxes show what's inside of them now
    • +
    • Updated meat icons
    • +
    • Canceling events gives more time to stop from 10 to 30
    • +
    • Fixes two chairs on one table
    • +
    • Removed the wires connecting the AI from the rest of the station on cogstation.
    • +
    • Fixes experimenter on cogstation.
    • +
    • Less pipes in the overall area in toxins on cogstation
    • +
    • Small fixes on security on boxstation
    • +
    • Updated jukebox sprite.
    • +
    • Fixes maint area in boxstation
    • +
    • Christmas starts on the 18th now
    • +
    • Adds a goose bar sign
    • +
    • Effects can no longer trigger landmines
    • +
    • Removes the screen flashing on climax.
    • +
    • Makes gas sensors fireproof.
    • +
    • A small bucket of random fixes,
    • +
    • Minor fixes to kilo
    • +
    • Porting garbage collection tweak from /tg/
    • +
    • Updates our dark gygax sprites to /tg/'s
    • +
    • Bugfix of a morph becoming an AI eye
    • +
    • Mining station oxygen locker on the cycling airlock starts out wrenched.
    • +
    • Nerf combat knife damage
    • +
    • Code improvement on ventcrawling
    • +
    +

    NT Cleaning Crews On Break updated:

    +
      +
    • Most kinds of dirt, grime, and debris are now persistent. Get to work, jannies.
    • +
    • Dirt can now be removed by tile replacements. Other cleanable decals can't, though.
    • +
    +

    Putnam3145 updated:

    +
      +
    • Replaces majority judgement with usual judgement.
    • +
    • Toilet loot spawners don't lag the server on server start with forced hard dels.
    • +
    • vore prefs save now
    • +
    • gear harness no longer magically covers up the body mechanically despite covering up nothing visually
    • +
    • Regen coma now puts into a coma even from crit or while unconscious.
    • +
    • Regen coma now properly weakens while asleep.
    • +
    • Multi-surgery unit test no longer fails at random.
    • +
    • Dwarf speech is no longer absolutely paranoid about word replacement.
    • +
    • Spontaneous brain trauma now requires minimum 5 players
    • +
    • Grab bag works as advertised.
    • +
    • Xeno threat in dynamic tripled.
    • +
    • Vote system #defines are now strings
    • +
    • Stat panel UI for ranked choice votes
    • +
    • A fallback for dynamic antag rolling that allows for it to just try between traitor, blood brothers, heretics, changeling, bloodsucker and devil until there are enough roundstart antags. This can also happen randomly anyway. Blood brothers and devil are disabled for now, but the code is there to enable them.
    • +
    • A new storyteller, "Grab Bag", that forces the above round type.
    • +
    • atmos subsystem no longer dies if there's too many gases
    • +
    • Emotes can properly be filtered for in TGUI.
    • +
    • Holofirelocks work now.
    • +
    • adminhelping no longer removes entire admin tab
    • +
    • end of round no longer removes entire admin tab
    • +
    • Fixed a runtime in every healing nanite program.
    • +
    • removed a unit test causing master to fail
    • +
    • Planetary atmos no longer does superconduction.
    • +
    • Dynamic vote no longer shows the none-storyteller.
    • +
    • You can now exit polycircuit input
    • +
    • Polycircuits now check for range
    • +
    • gear harness alt-click is now sane
    • +
    • rolldown() and toggle_jumpsuit_adjust() now no longer mix behavior-that-should-be-overridden and behavior-that-shouldn't-be-overridden in ways that make no sense.
    • +
    • Gear harness now covers nothing.
    • +
    • Chemical stuff now displays fermichem stuff properly
    • +
    • Rad collectors now get 1.25x as much energy from radiation
    • +
    • Rad collectors now put out 1.25x as much stored energy per tick
    • +
    • Above two rad collector changes give a total 56.25% power output increase
    • +
    • Zeolites now only generate 1/5 the heat when reacting and don't require a catalyst.
    • +
    +

    Ryll/Shaps updated:

    +
      +
    • Fixed an issue with player logs becoming confused when someone triggers multiple events within one second (like being attacked by two people at the same time) that would cause holes in the logs
    • +
    +

    SandPoot updated:

    +
      +
    • You can attack a pile of money on the floor with your id to put it all in quickly.
    • +
    • Changes the limb grower a lot.
    • +
    • "Limb" costs on limbgrower are actually displayed like it was meant to all along.
    • +
    • Swaps the gift static blacklist with a global list one.
    • +
    +

    SiliconMain updated:

    +
      +
    • Engi department has gas masks in loadout
    • +
    • hololocks (which haven't worked for god knows how long) commented out until auxmos is merged
    • +
    +

    Sonic121x updated:

    +
      +
    • alarm ert hardsuit sprite for naga and canine
    • +
    • adjust the naga ert hardsuit to cover the hand
    • +
    • cydonia hardsuit helmet
    • +
    • digi sprite uniform
    • +
    • digi leg suit
    • +
    +

    SpaceManiac updated:

    +
      +
    • Fixed the maphook
    • +
    +

    Thalpy updated:

    +
      +
    • fixes some bugs in jacqs code from edits to the codebase
    • +
    +

    The Grinch updated:

    +
      +
    • infinite presents from hilbert hotel
    • +
    +

    TheObserver updated:

    +
      +
    • Re-adds the rifle stock, and sets the improv shotgun to be as it was.
    • +
    • The maintenance rifle has been shelved - for now. Watch this space.
    • +
    +

    TheObserver-sys updated:

    +
      +
    • Drake? Where's the dead fairygrass sprite?
    • +
    +

    TheSpaghetti updated:

    +
      +
    • no more tumor bread double punctuation
    • +
    +

    Trilbyspaceclone updated:

    +
      +
    • Zeolites now use gold rather then uranium for catalyst
    • +
    • Zeolites are not as hard to make ph wise
    • +
    • Making Zeolites heats up the beaker less allowing for better control
    • +
    • ASP 9mm and M1911 can now have suppressers added
    • +
    • Brass welders are 50% faster at refueling
    • +
    • redoes self fueling welders in the code to be less speggie
    • +
    • the corporate unifoms can now be gotton in the clothing mate vender
    • +
    +

    TripleShades updated:

    +
      +
    • Firelock to Surgery Bay drapes change: Swapped Nanomed and Fire Alarm button locations in both Surgery Bays change: Removes the double mirror in both Surgery Bays to be a singular mirror change: Moved an intercom to not be doorstuck below Paramedical Office remove: One Surgery Observation Fire Alarm button
    • +
    • New Paramedic Office next to Genetics where the old Genetics Reception used to be change: Surgery, Surgery Observation, and Recovery Hall layout revamped drastically change: Maints below Surgery lowered by one tile to recover lost tile space from Surgery expansion
    • +
    +

    Tupinambis updated:

    +
      +
    • Arachnids (spider people) with limited night vision, flash vulnerability, and webbing.
    • +
    +

    Vynzill updated:

    +
      +
    • new gateway mission mapadd: jungleresort map
    • +
    • fixes high luminosity eyes
    • +
    +

    Xantholne updated:

    +
      +
    • Fixed new birds changing back to basic parrot when sitting
    • +
    • New parrots from the RP server, can be found in Bird Crate in Cargo
    • +
    • You can now tuck disky into bed
    • +
    • You can now make beds by applying a bed sheet to them
    • +
    • You can now tuck in pai cards into bed
    • +
    • Added bed tucking element, can be added to any held object to allow tucking into beds
    • +
    • Twin Sword Sheaths have an equipment icon and icon when worn now and make a sound when sheathed/unsheathed
    • +
    +

    Yakumo Chen updated:

    +
      +
    • Slime Jelly is no longer obtainable from slimepeople. Go ask Xenobio
    • +
    +

    YakumoChen updated:

    +
      +
    • To lower production costs, Buzz Fuzz is now manufactured with Real™️ Synthetic honey.
    • +
    +

    Zandario updated:

    +
      +
    • Added some framework for future species expansions, including clothing refitting.
    • +
    • Made majority of the relevant Species IDs and Categories pre-defined, also for easier expansion and use.
    • +
    • lum slime sprites work again
    • +
    • Slapped the Species Defines where relevant
    • +
    +

    corin9090 updated:

    +
      +
    • The chaplain's prayer beads can now be worn on your belt slot
    • +
    +

    kappa-sama updated:

    +
      +
    • super saiyan
    • +
    • ishotgun crafting recipe no longer requires plasteel and is slightly more convenient
    • +
    • ishotgun does 45 damage now instead of 40.5
    • +
    • s
    • +
    • A new spell for the wizard and his martial apprentices, the Inner Mantra technique. It makes you punch people really good and makes you durable, but drains your energy while it's active.
    • +
    • A self-buffing spell for valiant bubblegum slayers that is ultimately useless on lavaland and probably overpowered for miner antagonists. Go figure. At least all it does is let you punch hard while draining your health every second.
    • +
    • bubblegum now drops a book that makes you into an abusive father instead of a shotgun that plays like pre-nerf shotguns
    • +
    • a powerup and powerdown sound effect
    • +
    • two icons for two buff spells
    • +
    +

    keronshb updated:

    +
      +
    • Allows Energy Bola to be caught
    • +
    • This also allows them to be dropped/picked up.
    • +
    • Adds a reduced stamina buffer for SCarp users
    • +
    • Gives SCarp users a better parry
    • +
    • Adds the SCarp bundle which includes a bo staff
    • +
    • Lets Carp costumes carry Bo Staffs
    • +
    • reduces the stamina damage of scarp slightly
    • +
    • reduced the blockchance of the bo staff
    • +
    • Adds more room to northwest maint
    • +
    • Adds a bridge between Atmos and the Turbine.
    • +
    • Blob Resource Tower to 2 points per instead of 1 point per.
    • +
    • Blob Factory Towers can be placed 5 tiles apart instead of 7.
    • +
    • Fixes Blobbernaut Factories consuming Factories if no naut is chosen.
    • +
    • Fixes Reflective Blobs
    • +
    • Re-adds the Clown Car to the clown uplink
    • +
    • 15 >16 TC cost
    • +
    • bonks on external airlocks
    • +
    • Fixes the parry data for scarp
    • +
    +

    kittycat2002 updated:

    +
      +
    • set the name of /datum/reagent/consumable/ethanol/species_drink to Species Drink
    • +
    +

    kiwedespars updated:

    +
      +
    • balanced bone gauntlets.
    • +
    • the robust dildo weapon now has sound.
    • +
    +

    necromanceranne updated:

    +
      +
    • Fixes various sprites for bokken, as well as being unable to craft certain parts and duplicate entries.
    • +
    • Bokken now come in two lengths; full and wakizashi, and two varieties: wood and ironwood. They have different stats for all four.
    • +
    • Bokken require menu crafting and part construction, as well as more complicated materials.
    • +
    • Bokken (long and short) require wood, cloth and leather to craft with a hatchet and screwdriver.
    • +
    • Ironwood bokken (long and short) require ironcap logs, cloth and leather to craft with a hatchet, screwdriver and welder.
    • +
    • Twin sheathes can only fit a pair of blades (longsword + shortsword) or they can fit two shortswords.
    • +
    • Fixed a twin sheath runtime.
    • +
    • A lot of bokken related sprites received an overhaul. Added overlay sprites for weapons sheathed in the twin sheathes.
    • +
    • The extradimensional blade received improved sprites for inhands/back sprites.
    • +
    • You can now make all the variants of the bokken.
    • +
    • Removes a duplicate sprite.
    • +
    • Renames all instances of 'ironwood' to 'steelwood'.
    • +
    • Adds new roboticist labcoat sprites!
    • +
    +

    qwertyquerty updated:

    +
      +
    • Flash the screen on climax
    • +
    +

    raspy-on-osu updated:

    +
      +
    • salicylic acid
    • +
    • space heater heating range and power
    • +
    • windoor open length
    • +
    +

    shellspeed1 updated:

    +
      +
    • Wings from Cit RP have been ported over
    • +
    • Moth wings from cit have been ported over
    • +
    • Cleaned up some pixels on existing moth wings.
    • +
    • Organized the lists for wings by if they are for moths or not and than by alphabetical.
    • +
    • Lings now have infinite space for DNA.
    • +
    • All xenomorph types have been added as corpses for mapping purposes
    • +
    • The dead xenomorphs in the lavaland xenomorph hive now have more variety.
    • +
    • Floor bots are now buildable with all toolboxes.
    • +
    • Xenomorph hybrids can now select wings ~~add: Xenomorph hybrids can now speak xenomorph~~
    • +
    • Xenomorph tongues are available for customization.
    • +
    • Mining borgs can claim points again
    • +
    • Construction bags have been added, use them to carry all sorts of construction bits.
    • +
    • A recipe has been added to cloth stacks to make material and construction bags.
    • +
    • Material bags and construction bags are now available in engineering lockers.
    • +
    • Adds the disposable sentry gun from tg for 11tc each.
    • +
    • The exofab can now print prosthetic limbs
    • +
    • The exofab was missing access to multiple cybernetic organs. This has now been rectified.
    • +
    • A new recipe for a spicy has been given to us by a strange business man.
    • +
    • The bluespace navigation gigabeacon design has been added to shuttle research for those wanting to take their ships around space more.
    • +
    • Xenomorph powers now list plasma cost in their description.

    silicons updated:

      -
    • shoves have been buffed to apply a status effect rather than a 0.85 movespeed modifier, meaning repeatedly shoving someone now renews the debuff
    • -
    • shoves now stagger for 3.5 seconds.
    • -
    • war operatives now actually time 20 minutes since roundstart to depart instead of 15.
    • -
    • explosive stand bombs can now be examined from any distance
    • -
    • explosive stand bombs are now a component.
    • +
    • nanite resistances tweaked
    • +
    • new nanite programs added for locking the user out from being modified by consoles or antivirals.
    • +
    • anomalies no longer spawn in walls
    • +
    • Twitch Plays: Clown Car
    • +
    • pugilists can now parry
    • +
    • c4 can no longer gib mobs
    • +
    • medium screens are better now
    • +
    • text formatting now uses one character instead of two around the text to emphasize.
    • +
    • colormates
    • +
    • shoving yourself up now costs 50% more
    • +
    • dullahans enabled
    • +
    • tailed individuals can now target groin to intertwine tails on grab intent.
    • +
    • Clowns now have unpredictable effects on supermatter crystals when dusting from contact.
    • +
    • anyone new to the server is lucky enough to have their sprint default to toggle instead of hold
    • +
    • stamina crit is only removed when at or under 100 stamina, rather than 140. stamina crit threshold is still at 140.
    • +
    • luxury shuttle no longer has noteleport
    • +
    • now only poly gets a headset on spawn, not all birds.
    • +
    • the warp implant now actually warps you back 10 seconds. leaves a trail, though. now unlimited us.
    • +
    • things in DEATHCOMA do not deathgasp on death
    • +
    • Meth and changeling adrenals no longer ignore all slowdowns, rather damage slowdowns.
    • +
    • you can now be an angel using a magic mirror again
    • +
    • command headsets are 120% instead of 160%
    • +
    • no more emote italics
    • +
    • players can now respawn/return to lobby as a ghost after a 15 minute (default) delay and rejoin on another character with some/many restrictions
    • +
    • cryo now preserves everything
    • +
    • Magrifle ammo no longer glows.
    • +
    • temperature slowdown divisor nerfed to 35 from 20.
    • +
    • dna melt drops all items being destroying you
    • +
    • keybinds generate anti-collision bindings where necessary automatically now
    • +
    • changeling combat mutations rebalanced. most of them take chemicals to upkeep now.
    • +
    • set-pose has been added
    • +
    • temporary flavor text renamed to set pose, fully visible in examine
    • +
    • ninja gloves no longer hardstun
    • +
    • ninja gloves now cost half as much to use to compensate
    • +
    • simple mobs are now immune to radioactive contamination
    • +
    +

    timothyteakettle updated:

    +
      +
    • time for memory loss message to show up when being revived is now correctly 300 seconds, instead of 30
    • +
    • the load away mission verb won't crash the server now
    • +
    • roundstart slimes can turn into puddles now
    • +
    • all gas masks (but welding + glass) can be alt clicked to show/hide identity
    • +
    • autosurgeons from travelling trader rewards now only have one use
    • +
    • fixes held items proccing crossed when passing someone
    • +
    • you can now get a family heirlooms based off your species instead of job
    • +
    • changeling stings retract upon turning into a slime puddle
    • +
    • you cannot transform into a slime puddle with a no drop item in your hands
    • +
    • slime puddles are now transparent and their colour looks more natural in comparison to the user
    • +
    • slime puddles are now even slower
    • +
    • slime puddles now get no protection from worn clothing
    • +
    • removes two debug messages left in from my prior eye customization pr
    • +
    • adds unlockable loadout items, corresponding category in loadouts, etc
    • +
    • added in-game age verification as an alternative to access requests
    • +
    • disabling adminhelp noises no longer disables looc
    • +
    • apids render now
    • +
    • you can now only entwine tails with people who have a tail
    • +
    • custom eyes and tongues now properly carry across cloning
    • +
    • re-adds the holoform verb for people who want to use it over going through the char list
    • +
    • eye sprites should look normal once more
    • +
    • licking people washes pie off their face
    • +
    • you can now pick your eye sprites from customization
    • +
    • looking at loadout equips loadout items on your preview image instead of job items
    • +
    • custom holoforms are now accessible through an action instead of through verbs
    • +
    • AI holoforms can now emote
    • +
    • cloning now correctly copies your blood colour, body sprite type and eye type
    • +
    • species with NOTRANSSTING cannot have envy's knife used on them
    • +
    • avian/digitigrade legs have been added for slimes
    • +
    • you can teleport bread
    • +
    • slime puddles are no longer layered down one layer
    • +
    • you cannot tackle with two paralysed arms
    • +
    • tackling with a single paralysed arm lowers your tackle roll by 2
    • +
    • circuits get pin data proc is sanitized when text is returned as data
    • +
    • loadout now has save slot support and colour choosing/saving for polychromic items
    • +
    • polychromic maid outfit
    • +
    • you can rebind communication hotkeys and they're the default now
    • +
    • you can now customize your size from 90% to 130%, going below 100% makes you have 10 less max health
    • +
    • *squeak
    • +
    • anthromorphic synth species
    • +
    • improvements to the automatic age gate
    • +
    • antag items are now of critical importance and wont fail to be placed on the character
    • +
    • a tonne of fixes to colourisation of parts, too many to name, including some sprite fixes
    • +
    • things now have their own individual primary/(secondary)/(tertiary) colours as required, and these can be modified by you
    • +
    +

    uomo91 updated:

    +
      +
    • Fixed "Show All" tab in player panel logs being broken.
    • +
    • Whispers, OOC, and various other things display differently in logs, visually distinguishing them from say logs.
    • +
    • Player panel logs will now show all logs chronologically, so you'll see commingled say and attack logs if you're on the "Show All" tab, etc...
    • +
    +

    yorii updated:

    +
      +
    • fixed botany rounding error that caused grass and other plants to misbehave
    • +
    +

    zeroisthebiggay updated:

    +
      +
    • legion now drops chests
    • +
    • Traitor assistants can now purchase the patented POGBox! Put TC into it for even higher damage!
    • +
    • MEGAFAUNA DROPS ARE LAVAPROOF
    • +
    • cool codex cicatrix inhands
    • +
    • gravitokinetic stands from tg
    • +
    • buffs stands overall
    • +
    • protector stands no longer become tposing invisible apes sometimes
    • +
    • jacqueline spawns on boxstation
    • +
    • secsheath for your cool stunsword at your local security vendor. you gotta hack it first though.
    • +
    • fuck the r*d cr*ss
    • +
    • The legion megafauna has been reworked. The fight should now be both slightly harder and faster.
    • +
    • You can no longer cheese the colossus by being a sand golem and simply being immune.
    diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml index 99ffc455c3..06b2a7037e 100644 --- a/html/changelogs/.all_changelog.yml +++ b/html/changelogs/.all_changelog.yml @@ -27524,3 +27524,831 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py. - bugfix: limb id entry in mutant bodyparts now supports switching to/from species with gendered body parts - tweak: the minimum brightness of mutant parts is now a define +2021-01-21: + Acer202: + - bugfix: Main mining shuttle should no longer look at the public mining shuttle + and attempt to dock ontop of it. Monastery shuttle should now function again. + Acer202, with minor help from The0bserver: + - rscadd: After internal deliberation, CentCom has decided to run a limited reinstatement + of public mining shuttles for use in more tried and true station classes. CentCom + would like to remind you that this privilege is easily revoked, and that abuse + may result in immediate detonation. + - rscadd: Restores the mining shuttle on Pubby, Box, Delta, Meta, and Lambda Station. + ArcaneMusic, The0bserver-sys: + - 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. + ArchieBeepBoop: + - rscadd: Upgraded Advanced RTG Machine Preset + - bugfix: Outlet Injector Mapping Asset Layer Fix + - bugfix: Jacqueen and the Christmas tree should no longer spawn abstract things + that can cause shittons of runtimes. + Arturlang: + - bugfix: You can't tackle in nograv anymore + - tweak: You cannot spam drink from blood bags anymore + - bugfix: Blood bag drinking inefficiency is now the right way, so you loose some + of the blood drinking it straight + - bugfix: Handles more edge cases with construct soul returning + - tweak: Being sacrificed by the cult no longer removes all hope of rescue. + - bugfix: Makes construct mind returning more robust + - tweak: Prayers to admins now do a wee ding sound for all prayers, instead of just + chaplains + - bugfix: Fixes the mint machine's UI + - bugfix: Hopefully fixes whitescreen issues for TGUI UI's by giving assets more + time to get to the client + - bugfix: Fixes hijack implant APC UI, again + - code_imp: Comments out spaceman dmm do not sleeps for mob/proc/CommonClickOn, + atom/proc/attack_hand, datum/proc/keyLoop and mob/living/proc/Life + - bugfix: Bloodsuckers tresspass ability can no longer work while they are not awake. + - tweak: The cursed heart now only takes away half as much blood every loop, and + can be used as long as you are alive, instead if only you are awake/able to + use your hands + Bhijn: + - tweak: Changeling loudness is now determined as an average of all their abilities, + rather than the sum + - tweak: To compensate for this, blood tests now require a loudness value of 1 or + higher to detect ling blood. Additionally, blood test explosions are now triggered + only when the loudness value is higher than 2. + BlackMajor: + - tweak: Cyborg hypospray no longer injects if it means OD'ing while on help intent. + BlueWildrose: + - tweak: Nyctophobia quirk now has some light lag compensation. + - bugfix: Fixes cloning computer UI not updating when pressing certain buttons - + also adds extra check for names to update a message + - rscdel: Removes oversized genitalia analysis from medical scanners, since huge + dick and titty are no longer a problem anymore thanks to advancements in that + kind of technology when it comes to chemical fun times growth. + - bugfix: Fixed species-specific drinks not giving a mood boost if you are that + species. + - tweak: You will now only unbuckle fireman-carried/piggybacked people on disarm + or harm intent. + - balance: The traitor AI can no longer activate the doomsday device while carded. + - bugfix: Fixes noodle size appearance for 12+ inch members. + - bugfix: Fixed the subtle hotkey being weird with its input prompts. + - rscadd: Adds a subtler anti-ghost hotkey. Default key is 6. + - tweak: No more straining when your cock or breasts are growing via incubus draft + or succubus milk. + - rscadd: PubbyStation now has two Christmas Tree spawners. + - tweak: You can now have a max-roundstart-dicksize-config inch long johnson before + you start suffering blood loss and slowdowns instead of a 20 inch one. + - rscadd: Color Mates have been added to all stations (except Snaxi). Enjoy coloring + your attire without having to bug science! + - bugfix: Polychromic hoodies that were obtained from the loadout have functional + colorable hoods now. + - rscadd: Adds in timid woman/man costumes. Available at your autodrobe! Also adds + in garters as some new socks. + - spellcheck: Corrected the capitalization in gasmask concealment examine text + Chiirno: + - rscadd: Added the paramedics EVA suit as a purchase from the cargo console. + - rscadd: Paramedics office and Surgery Storage Room + - tweak: Remodeled the surgery room, as well as shrunk Morgue and Starboard Emergency + Storage. Fiddled with some areas for better map edit clarity and fixed one runtime + in Vacant Office A. + - imageadd: Added the paramedic closet sprite, a paramedic colored medical3 closet. + - code_imp: Added a paramedic closet, which is the standard medical3 closet with + their suit, a pinpointer, and a crew monitor added. + - tweak: Nightmare now deals additional damage to most light sources. + - bugfix: Nightmare now one-shots miners beacons and glowshrooms + - bugfix: Portable Chem Mixer now researchable from biotech node. + - tweak: Chem masters can now dispense 20 instances of its outputs instead of 10. + Delams-The-SM: + - rscadd: Added 3 new emotes *hiss *purr *meow + - soundadd: ported sounds from Citadel RP for *purr and *meow + - bugfix: fixed randomization of colors for things like mulligan and Stabilized + green slime extract for matrixed body parts + DeltaFire15: + - balance: Biomechanical (hybrid) bodyparts now have access to wound-fixing surgeries. + - tweak: A wound being fixed no longer just qdel()s surgeries connected to it. + - tweak: Some robotic surgery steps are now a bit more clear. + - bugfix: Organs no longer get fed to people after successfully being inserted into + them. + - tweak: Not completing the do_after of a surgery no longer causes you to attack + the target with whatever you were holding. + - rscadd: IPC cells & power cords are now printable after they are researched. + - rscadd: A new surgery, allowing revival of synths without a defib at hand. + - balance: 'Semi-permanent damage of Synth limbs caused by passing the damage threshold: + 10 <- 15.' + - tweak: The embed removal surgery now has a version for Synths. + - balance: EMPs no longer hardstun Synths. + - bugfix: Portals no longer runtime because of incorrect args. + - tweak: Abductors now can use experimental organ replacement surgery on robots + / synthetics. + - bugfix: Fixes a minor incorrectness in ratvarian borg slabs (ratvar_act -> ui_act) + - bugfix: Changelings no longer double-deathgasp when activating the regen stasis + ability while not dead. + - bugfix: People installing KA modkits in miner borgs is no longer broken. + - bugfix: Fixes the tail entwine messages displaying incorrectly. + - bugfix: Antagging / Deantagging Heretics now properly sets their special role. + - bugfix: The borg VTEC ability now actually gets removed when the upgrade is removed. + - bugfix: Supplypods shouldn't cause runtimes anymore, and shrapnel (pelletclouds) + should work for them. + - rscadd: Robots (anyone with the robotic_organism trait) have toxins damage replaced + with system corruption. See the PR for details. + - code_imp: Clockwork rites now support hiding specific rites from neutered servants. + - tweak: AIs now only have to kill people once instead of permanently. + - bugfix: Scripture no longer sometimes eats part of its invocation. + - balance: APCs and silicons are now more susceptible to powerdrains (by the power_drain() + proc, which is rare) + - balance: Void Volt has been modified from a chant to a singular pulse. + - balance: Robotpeople are now fully immune to the effects of alcohol (drunkness + etc.) + - tweak: Renames the alcohol intolerance trait in the code to make what it does + more clear. + - bugfix: Self-fueling weldingtools recharge fuel properly again. + - bugfix: Brass welders now actually recharge faster than experimental ones. + - bugfix: Repeatable surgery steps can no longer cause an infinite loop if not completing + the do_after + - bugfix: The Revenant self-revive ability is no longer broken. + - bugfix: Loot items mobs drop are no longer always failing to initialize. + - tweak: Instant summons can no longer do wacky stuff with disposals (and nukes). + - bugfix: Objectives are no longer very broken. + - bugfix: Bloodcult stunhands now work against clockies like they were supposed + to instead of hardstunning. + - balance: zeolites are now actual fermichems instead of being incredibly easy to + make. + - bugfix: Using syringes / droppers on chem heaters with beakers in them works again. + - bugfix: Some edge cases causing issues with system corruption shouldn't be able + to occur anymore. + - bugfix: Cyborg B.o.r.i.s. installation now checks for if the chest has a cell, + just like how it does with MMIs. + - bugfix: The 'Your body is in a cloner' notification works again + - bugfix: Hijack implants should work properly again (or, at least better) + - bugfix: Liches are now good skeletons again instead of weak ones + - bugfix: The piratepad control cannot be destroyed again. + - bugfix: Pirates have received new supplies of jetpacks instead of useless oxygen + tanks + - bugfix: Ratvarian AIs are once again able to show their linked borgs Ratvar's + light + - bugfix: Hijackers are once again unable to detonate borgs without being adjacent + to the console + - bugfix: Automated annoucement systems and gulag ore consoles no longer waste emag + charges + - bugfix: Automated announcement systems once again can be remote controlled by + non-AIs with silicon access + - bugfix: APCs being hijacked multiple times at once is no longer possible, preventing + some issues + - bugfix: Recharging APCs no longer use 0.2% of the power they should be using. + - bugfix: APCs no longer always use as much power as they can for their cell, even + if it is full. + - bugfix: Vampire shapeshifting should now behave as intended + - balance: Some synth damage stuff has been a bit rebalanced, see the PR for details. + - rscadd: Nanogel, available at medical and robotics, which fixes internal damage + in sufficiently repaired robotic limbs. + - balance: Robotic Limbs now each have their own damage threshhold values + - balance: Robotic Limb damage threshholds are now seperated into threshhold itself + and mindamage when passed balance; Hybrid limbs can now be injected with hypos, + but not sprayed (Still not healed by chems) + - tweak: Brain surgery has been tweaked back to allowing robotic limbs, blacklisting + IPC brains instead. + - tweak: Robot brain surgery can now be used on organic heads, if there is a IPC + brain in them somehow. + - tweak: The robot limb heal surgery can now be used even if the target's torso + is not robotic, as long as they have robotic limbs + - refactor: BODYPART_ROBOTIC / BODYPART_ORGANIC checks replaced with helper-procs + whereever possible. + - code_imp: Added a BODYPART_HYBRID define for robotic bodyparts that behave organic + in some regards. + - bugfix: The transmission sigil power drain works now + - bugfix: A certain lizard (totally not me) being stupid is no longer going to break + regenerate_bodyparts + - bugfix: Combat mode now will not stay permanently disabled due to status effects + not working as intended. + - bugfix: Attacking some certain objects no longer has no clickdelay. + - bugfix: the blacksmithing skill now works properly + - tweak: Anvils cannot be interacted with with hammers whilst they are already being + used + - tweak: If someone has no gloves when interacting with heated ingots, they no longer + ignore their effects. + - bugfix: A runtime caused by hallucinations is gone. + - bugfix: Cargo packs marked as 'no private buying' now actually register as such. + - balance: Fleshmend, Anatomic Panacea and bloodsucker healing now work for Synths + / IPCs. + - tweak: Medibots now ignore people they cannot help due to their biology. + - bugfix: get_damaged_bodyparts() is no longer broken. + - bugfix: Your target cryoing will no longer give you a free greentext. + - bugfix: Sleeper UI interactiveness now behaves correctly. + Detective-Google: + - rscadd: arcade carpet + - rscadd: explosions now get broadcasted to deadchat. + - rscadd: Lick radial + - bugfix: Hilbert's jukebox works + - bugfix: arcade carpets now actually work + - tweak: the snow taxi is no longer the slow taxi + ERP mains: + - rscadd: Subtler Around Table is now a verb + EdgeLordExe, MoonFalcon: + - balance: Ported a bunch of heretic-related tweaks and changes from tg + EmeraldSundisk: + - rscadd: Adds a few new area designations primarily for CogStation, incorporates + them into said map + - tweak: Reorganizes some area designations for ease of use, along with renaming + the central "Router" to "Routing Depot" + - bugfix: Fixes an incorrectly designated area in CogStation + - bugfix: Changes the area designations to be not varedited since the code didn't + like that anymore + - bugfix: The cargo bay conveyor belts not only work with the shuttle now but go + in the right direction to boot + - tweak: Slight visual adjustments to cargo in light of this + - rscadd: The arcade's got RAD carpet now + - bugfix: Fixes the conveyor belt issues in Delta Station's cargo wing + - rscdel: Removes some of the dirt around the affected area (presumably they would + have cleaned it up while working on it) + - rscadd: Adds a floor light to fix the "dark spot" cargo had + - rscadd: Adds a new "Computer Core" area designation for CogStation + - bugfix: Fixes some missing area strings + - tweak: Replaces some firelocks with directional ones as to ensure desks/counters + can still be accessed + - balance: The "Skelter ruin" now has stechkins as opposed to M1911s + - tweak: Skelter's decorative bullet casings replaced to factor in the change in + caliber + - rscadd: Skelter now has a combat knife and fluff note + Ghommie: + - bugfix: You can access the mime / clown mask skins radial menu once again. + - bugfix: Dice bags no longer act like cardboard boxes. + - bugfix: Abductors should be no longer mute. + - bugfix: Item action buttons should now properly show the item current overlays, + most times. + - bugfix: The blackbox should now go into your hand slot when pried out, rather + than tumbling on the ground everytime. + - tweak: The Quick Equip hotkey is now usable by all living mobs (so long they have + hands and equipment slots) + Ghommie, porting PRs by MMMiracles and pireamaineach, credits to BlueWildrose too.: + - rscadd: You can now draw on plasmaman helmets with a crayon to turn their frown + upside-down. + - balance: Plasmaman helmets no longer hide your identity when worn by themselves. + - balance: Plasmaman helmets now have welding visors, which can't stack with their + torches in the helmet and are visible. + Hatterhat: + - 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. + - imageadd: The Syndicate appear to be issuing new revolver variants. + - rscadd: Basic sticky technology is now a roundstart tech. Advanced sticky technology + is BEPIS-locked, though. Theoretically. + - tweak: Non-smithed katanas (including the temporal katana) can now fit in the + twin sheath. + - tweak: Cotton and durathread processing by hand now acts like grass. Stand on + a pile of cotton (or durathread) and use a single bundle from it. + - spellcheck: Utility uniforms now comply with the "nonproper equipment names" thing. + - bugfix: The CapDrobe now allows the captain to get his own clothes for free. Probably. + - tweak: All captains' clothes now offer 15 woundarmor, up from the 5. Because apparently + only the suit and tie and its suitskirt subtype have this wound armor, which + is dumb. + - rscadd: The nature interaction shuttle with the monkeys now has tiny fans on the + airlocks in, because that's apparently a feature that was missing. + - rscadd: More bags have been added to department vendors. + - balance: Every roundstart species (and also ash walkers) now has flesh and bone + that can be wounded. + - balance: Recipes for sutures, regen mesh, and sterilized gauze have been adjusted + to be easier, mostly. + - balance: Sterilized gauze is better at absorbing blood and being a splint. + - bugfix: Energy sabres now have an off inhand. + - balance: The bone gauntlets should be slightly less murderously punchy on the + fast punches mode. + - tweak: RPEDs now drop their lowest part tier first when quick-emptied (used inhand). + - tweak: Improvised gauzes can now be crafted in stacks up to 10, like their maximum + stacksize implies they should be capable of doing. + - bugfix: Pouring sterilizine on gauze now takes the proper 5u per sterilized gauze + instead of 10u. + - bugfix: Cryogenics now screams on common again when your fuckbuddy heads out. + - rscadd: Survival daggers! A slightly more expensive survival knife that comes + with a brighter flashlight. On the blade. + - tweak: Luxury pod capsules look different from normal capsules. + - rscadd: The wastes of Lavaland and the icy caverns of Snow Taxi rumble in unison. + - tweak: Exosuits sold on the Supply shuttle no longer leave wreckages. + - rscdel: Apparently, shrink rays were buyable again, despite a PR having been made + a while ago specifically for removing shrink rays. They're gone again. + - 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. + - rscadd: The dock-silver standard set by Box and Meta has been enforced across + maps in rotation (Delta, Pubby, Lambda). + - bugfix: The Box whiteship now has its missing tiny fan back. + - bugfix: The survival dagger light on the sprite now actually turns on and off. + - balance: The survival dagger in the glaive kit that can also be bought by itself + is now better at butchering things. + HeroWithYay: + - bugfix: Changed description of Necrotizing Fasciitis symptom. + - tweak: Wormhole Projector and Gravity Gun now require anomaly cores to function + instead of firing pins. + KeRSedChaplain: + - imageadd: Resprited the brass claw + LetterN: + - rscadd: 2 more ways to get up from z1 + - tweak: tweaked the z2 garden to be less blank + - bugfix: fixed telecomms pda log + - rscadd: Coin & Holochip support for slot machine + - admin: Stickybans are now saved in the DB too + - soundadd: Immersive ™ audio reverbs. (also adds multiz audio) + - code_imp: Semi-hardsync from TG + - code_imp: Updates rust-g + - code_imp: Uses git CI instead of travis/appveyor now + - code_imp: Updates git and build tests. + - bugfix: minimap text + - code_imp: ports cinematic upgrades + Linzolle: + - bugfix: entertainment monitors no longer invisible + - rscadd: entertainment monitors now light up and display text when motion is detected + in thunderdome + - bugfix: lizard snouts are no longer *slightly* lighter than they are supposed + to be. + MrJWhit: + - rscadd: Expanded space hermit base + - tweak: Replaced engineering fuel tank with a large fuel tank + - tweak: Changed access to sec suit storage from armory access in every map to other + security access + - rscadd: Adds a space loop to every map in toxins + - rscadd: '' + - tweak: Added the ability for cargo to buy a large welding tank + - imageadd: Tweaked large tank reagent sprites to /tg/'s + - tweak: Gives metastation toxins storage a scrubber and a vent + - tweak: Updates suit storage info on Tip Of the Round. + - tweak: Increased christmas event from 22th to 27th to 10th to 27th + - tweak: Removes an opposum from the wall + - tweak: Donut boxes show what's inside of them now + - tweak: Updated meat icons + - admin: Canceling events gives more time to stop from 10 to 30 + - tweak: Fixes two chairs on one table + - tweak: Removed the wires connecting the AI from the rest of the station on cogstation. + - tweak: Fixes experimenter on cogstation. + - tweak: Less pipes in the overall area in toxins on cogstation + - tweak: Small fixes on security on boxstation + - tweak: Updated jukebox sprite. + - tweak: Fixes maint area in boxstation + - tweak: Christmas starts on the 18th now + - rscadd: Adds a goose bar sign + - bugfix: Effects can no longer trigger landmines + - rscdel: Removes the screen flashing on climax. + - rscadd: Makes gas sensors fireproof. + - tweak: A small bucket of random fixes, + - tweak: Minor fixes to kilo + - tweak: Porting garbage collection tweak from /tg/ + - tweak: Updates our dark gygax sprites to /tg/'s + - tweak: Bugfix of a morph becoming an AI eye + - tweak: Mining station oxygen locker on the cycling airlock starts out wrenched. + - balance: Nerf combat knife damage + - bugfix: Code improvement on ventcrawling + NT Cleaning Crews On Break: + - rscadd: Most kinds of dirt, grime, and debris are now persistent. Get to work, + jannies. + - rscadd: Dirt can now be removed by tile replacements. Other cleanable decals can't, + though. + Putnam3145: + - tweak: Replaces majority judgement with usual judgement. + - bugfix: Toilet loot spawners don't lag the server on server start with forced + hard dels. + - bugfix: vore prefs save now + - tweak: gear harness no longer magically covers up the body mechanically despite + covering up nothing visually + - balance: Regen coma now puts into a coma even from crit or while unconscious. + - bugfix: Regen coma now properly weakens while asleep. + - bugfix: Multi-surgery unit test no longer fails at random. + - refactor: Dwarf speech is no longer absolutely paranoid about word replacement. + - balance: Spontaneous brain trauma now requires minimum 5 players + - tweak: Grab bag works as advertised. + - balance: Xeno threat in dynamic tripled. + - code_imp: 'Vote system #defines are now strings' + - rscadd: Stat panel UI for ranked choice votes + - rscadd: A fallback for dynamic antag rolling that allows for it to just try between + traitor, blood brothers, heretics, changeling, bloodsucker and devil until there + are enough roundstart antags. This can also happen randomly anyway. Blood brothers + and devil are disabled for now, but the code is there to enable them. + - rscadd: A new storyteller, "Grab Bag", that forces the above round type. + - bugfix: atmos subsystem no longer dies if there's too many gases + - bugfix: Emotes can properly be filtered for in TGUI. + - bugfix: Holofirelocks work now. + - bugfix: adminhelping no longer removes entire admin tab + - bugfix: end of round no longer removes entire admin tab + - bugfix: Fixed a runtime in every healing nanite program. + - bugfix: removed a unit test causing master to fail + - tweak: Planetary atmos no longer does superconduction. + - bugfix: Dynamic vote no longer shows the none-storyteller. + - tweak: You can now exit polycircuit input + - bugfix: Polycircuits now check for range + - bugfix: gear harness alt-click is now sane + - code_imp: rolldown() and toggle_jumpsuit_adjust() now no longer mix behavior-that-should-be-overridden + and behavior-that-shouldn't-be-overridden in ways that make no sense. + - tweak: Gear harness now covers nothing. + - bugfix: Chemical stuff now displays fermichem stuff properly + - balance: Rad collectors now get 1.25x as much energy from radiation + - balance: Rad collectors now put out 1.25x as much stored energy per tick + - balance: Above two rad collector changes give a total 56.25% power output increase + - balance: Zeolites now only generate 1/5 the heat when reacting and don't require + a catalyst. + Ryll/Shaps: + - admin: Fixed an issue with player logs becoming confused when someone triggers + multiple events within one second (like being attacked by two people at the + same time) that would cause holes in the logs + SandPoot: + - tweak: You can attack a pile of money on the floor with your id to put it all + in quickly. + - refactor: Changes the limb grower a lot. + - bugfix: '"Limb" costs on limbgrower are actually displayed like it was meant to + all along.' + - code_imp: Swaps the gift static blacklist with a global list one. + SiliconMain: + - tweak: Engi department has gas masks in loadout + - tweak: hololocks (which haven't worked for god knows how long) commented out until + auxmos is merged + Sonic121x: + - rscadd: alarm ert hardsuit sprite for naga and canine + - tweak: adjust the naga ert hardsuit to cover the hand + - bugfix: cydonia hardsuit helmet + - rscadd: digi sprite uniform + - bugfix: digi leg suit + SpaceManiac: + - bugfix: Fixed the maphook + Thalpy: + - bugfix: fixes some bugs in jacqs code from edits to the codebase + The Grinch: + - rscdel: infinite presents from hilbert hotel + TheObserver: + - rscadd: Re-adds the rifle stock, and sets the improv shotgun to be as it was. + - rscdel: The maintenance rifle has been shelved - for now. Watch this space. + TheObserver-sys: + - bugfix: Drake? Where's the dead fairygrass sprite? + TheSpaghetti: + - bugfix: no more tumor bread double punctuation + Trilbyspaceclone: + - tweak: Zeolites now use gold rather then uranium for catalyst + - tweak: Zeolites are not as hard to make ph wise + - tweak: Making Zeolites heats up the beaker less allowing for better control + - tweak: ASP 9mm and M1911 can now have suppressers added + - balance: Brass welders are 50% faster at refueling + - code_imp: redoes self fueling welders in the code to be less speggie + - rscadd: the corporate unifoms can now be gotton in the clothing mate vender + TripleShades: + - rscadd: 'Firelock to Surgery Bay drapes change: Swapped Nanomed and Fire Alarm + button locations in both Surgery Bays change: Removes the double mirror in both + Surgery Bays to be a singular mirror change: Moved an intercom to not be doorstuck + below Paramedical Office remove: One Surgery Observation Fire Alarm button' + - rscadd: 'New Paramedic Office next to Genetics where the old Genetics Reception + used to be change: Surgery, Surgery Observation, and Recovery Hall layout revamped + drastically change: Maints below Surgery lowered by one tile to recover lost + tile space from Surgery expansion' + Tupinambis: + - rscadd: Arachnids (spider people) with limited night vision, flash vulnerability, + and webbing. + Vynzill: + - rscadd: 'new gateway mission mapadd: jungleresort map' + - bugfix: fixes high luminosity eyes + Xantholne: + - bugfix: Fixed new birds changing back to basic parrot when sitting + - rscadd: New parrots from the RP server, can be found in Bird Crate in Cargo + - rscadd: You can now tuck disky into bed + - rscadd: You can now make beds by applying a bed sheet to them + - rscadd: You can now tuck in pai cards into bed + - rscadd: Added bed tucking element, can be added to any held object to allow tucking + into beds + - bugfix: Twin Sword Sheaths have an equipment icon and icon when worn now and make + a sound when sheathed/unsheathed + Yakumo Chen: + - balance: Slime Jelly is no longer obtainable from slimepeople. Go ask Xenobio + YakumoChen: + - balance: "To lower production costs, Buzz Fuzz is now manufactured with Real\u2122\ + \uFE0F Synthetic honey." + Zandario: + - 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. + - bugfix: lum slime sprites work again + - code_imp: Slapped the Species Defines where relevant + corin9090: + - tweak: The chaplain's prayer beads can now be worn on your belt slot + kappa-sama: + - bugfix: super saiyan + - tweak: ishotgun crafting recipe no longer requires plasteel and is slightly more + convenient + - balance: ishotgun does 45 damage now instead of 40.5 + - rscadd: s + - tweak: s + - balance: s + - bugfix: s + - rscadd: A new spell for the wizard and his martial apprentices, the Inner Mantra + technique. It makes you punch people really good and makes you durable, but + drains your energy while it's active. + - rscadd: A self-buffing spell for valiant bubblegum slayers that is ultimately + useless on lavaland and probably overpowered for miner antagonists. Go figure. + At least all it does is let you punch hard while draining your health every + second. + - balance: bubblegum now drops a book that makes you into an abusive father instead + of a shotgun that plays like pre-nerf shotguns + - soundadd: a powerup and powerdown sound effect + - imageadd: two icons for two buff spells + keronshb: + - bugfix: Allows Energy Bola to be caught + - balance: This also allows them to be dropped/picked up. + - rscadd: Adds a reduced stamina buffer for SCarp users + - rscadd: Gives SCarp users a better parry + - rscadd: Adds the SCarp bundle which includes a bo staff + - rscadd: Lets Carp costumes carry Bo Staffs + - balance: reduces the stamina damage of scarp slightly + - balance: reduced the blockchance of the bo staff + - rscadd: Adds more room to northwest maint + - rscadd: Adds a bridge between Atmos and the Turbine. + - balance: Blob Resource Tower to 2 points per instead of 1 point per. + - balance: Blob Factory Towers can be placed 5 tiles apart instead of 7. + - bugfix: Fixes Blobbernaut Factories consuming Factories if no naut is chosen. + - bugfix: Fixes Reflective Blobs + - rscadd: Re-adds the Clown Car to the clown uplink + - balance: 15 >16 TC cost + - balance: bonks on external airlocks + - bugfix: Fixes the parry data for scarp + kittycat2002: + - rscadd: set the name of /datum/reagent/consumable/ethanol/species_drink to Species + Drink + kiwedespars: + - balance: balanced bone gauntlets. + - rscadd: the robust dildo weapon now has sound. + necromanceranne: + - bugfix: Fixes various sprites for bokken, as well as being unable to craft certain + parts and duplicate entries. + - rscadd: 'Bokken now come in two lengths; full and wakizashi, and two varieties: + wood and ironwood. They have different stats for all four.' + - rscadd: Bokken require menu crafting and part construction, as well as more complicated + materials. + - tweak: Bokken (long and short) require wood, cloth and leather to craft with a + hatchet and screwdriver. + - tweak: Ironwood bokken (long and short) require ironcap logs, cloth and leather + to craft with a hatchet, screwdriver and welder. + - balance: Twin sheathes can only fit a pair of blades (longsword + shortsword) + or they can fit two shortswords. + - bugfix: Fixed a twin sheath runtime. + - imageadd: A lot of bokken related sprites received an overhaul. Added overlay + sprites for weapons sheathed in the twin sheathes. + - imageadd: The extradimensional blade received improved sprites for inhands/back + sprites. + - bugfix: You can now make all the variants of the bokken. + - bugfix: Removes a duplicate sprite. + - tweak: Renames all instances of 'ironwood' to 'steelwood'. + - rscadd: Adds new roboticist labcoat sprites! + qwertyquerty: + - bugfix: Flash the screen on climax + raspy-on-osu: + - spellcheck: salicylic acid + - tweak: space heater heating range and power + - tweak: windoor open length + shellspeed1: + - rscadd: Wings from Cit RP have been ported over + - rscadd: Moth wings from cit have been ported over + - bugfix: Cleaned up some pixels on existing moth wings. + - tweak: Organized the lists for wings by if they are for moths or not and than + by alphabetical. + - balance: Lings now have infinite space for DNA. + - rscadd: All xenomorph types have been added as corpses for mapping purposes + - balance: The dead xenomorphs in the lavaland xenomorph hive now have more variety. + - tweak: Floor bots are now buildable with all toolboxes. + - rscadd: 'Xenomorph hybrids can now select wings ~~add: Xenomorph hybrids can now + speak xenomorph~~' + - rscadd: Xenomorph tongues are available for customization. + - rscadd: Mining borgs can claim points again + - rscadd: Construction bags have been added, use them to carry all sorts of construction + bits. + - rscadd: A recipe has been added to cloth stacks to make material and construction + bags. + - balance: Material bags and construction bags are now available in engineering + lockers. + - rscadd: Adds the disposable sentry gun from tg for 11tc each. + - rscadd: The exofab can now print prosthetic limbs + - bugfix: The exofab was missing access to multiple cybernetic organs. This has + now been rectified. + - rscadd: A new recipe for a spicy has been given to us by a strange business man. + - rscadd: The bluespace navigation gigabeacon design has been added to shuttle research + for those wanting to take their ships around space more. + - tweak: Xenomorph powers now list plasma cost in their description. + silicons: + - tweak: nanite resistances tweaked + - rscadd: new nanite programs added for locking the user out from being modified + by consoles or antivirals. + - rscdel: anomalies no longer spawn in walls + - rscadd: 'Twitch Plays: Clown Car' + - rscadd: pugilists can now parry + - balance: c4 can no longer gib mobs + - tweak: medium screens are better now + - tweak: text formatting now uses one character instead of two around the text to + emphasize. + - rscadd: colormates + - balance: shoving yourself up now costs 50% more + - bugfix: dullahans enabled + - rscadd: tailed individuals can now target groin to intertwine tails on grab intent. + - rscadd: Clowns now have unpredictable effects on supermatter crystals when dusting + from contact. + - tweak: anyone new to the server is lucky enough to have their sprint default to + toggle instead of hold + - balance: stamina crit is only removed when at or under 100 stamina, rather than + 140. stamina crit threshold is still at 140. + - tweak: luxury shuttle no longer has noteleport + - rscdel: now only poly gets a headset on spawn, not all birds. + - tweak: the warp implant now actually warps you back 10 seconds. leaves a trail, + though. now unlimited us. + - bugfix: things in DEATHCOMA do not deathgasp on death + - tweak: Meth and changeling adrenals no longer ignore all slowdowns, rather damage + slowdowns. + - rscadd: you can now be an angel using a magic mirror again + - tweak: command headsets are 120% instead of 160% + - bugfix: no more emote italics + - rscadd: players can now respawn/return to lobby as a ghost after a 15 minute (default) + delay and rejoin on another character with some/many restrictions + - rscadd: cryo now preserves everything + - bugfix: Magrifle ammo no longer glows. + - tweak: temperature slowdown divisor nerfed to 35 from 20. + - balance: dna melt drops all items being destroying you + - bugfix: keybinds generate anti-collision bindings where necessary automatically + now + - balance: changeling combat mutations rebalanced. most of them take chemicals to + upkeep now. + - rscadd: set-pose has been added + - tweak: temporary flavor text renamed to set pose, fully visible in examine + - bugfix: ninja gloves no longer hardstun + - balance: ninja gloves now cost half as much to use to compensate + - bugfix: simple mobs are now immune to radioactive contamination + timothyteakettle: + - bugfix: time for memory loss message to show up when being revived is now correctly + 300 seconds, instead of 30 + - bugfix: the load away mission verb won't crash the server now + - rscadd: roundstart slimes can turn into puddles now + - rscadd: all gas masks (but welding + glass) can be alt clicked to show/hide identity + - tweak: autosurgeons from travelling trader rewards now only have one use + - bugfix: fixes held items proccing crossed when passing someone + - tweak: you can now get a family heirlooms based off your species instead of job + - tweak: changeling stings retract upon turning into a slime puddle + - tweak: you cannot transform into a slime puddle with a no drop item in your hands + - tweak: slime puddles are now transparent and their colour looks more natural in + comparison to the user + - tweak: slime puddles are now even slower + - tweak: slime puddles now get no protection from worn clothing + - rscdel: removes two debug messages left in from my prior eye customization pr + - rscadd: adds unlockable loadout items, corresponding category in loadouts, etc + - rscadd: added in-game age verification as an alternative to access requests + - bugfix: disabling adminhelp noises no longer disables looc + - bugfix: apids render now + - bugfix: you can now only entwine tails with people who have a tail + - bugfix: custom eyes and tongues now properly carry across cloning + - rscadd: re-adds the holoform verb for people who want to use it over going through + the char list + - bugfix: eye sprites should look normal once more + - rscadd: licking people washes pie off their face + - rscadd: you can now pick your eye sprites from customization + - tweak: looking at loadout equips loadout items on your preview image instead of + job items + - tweak: custom holoforms are now accessible through an action instead of through + verbs + - tweak: AI holoforms can now emote + - tweak: cloning now correctly copies your blood colour, body sprite type and eye + type + - bugfix: species with NOTRANSSTING cannot have envy's knife used on them + - rscadd: avian/digitigrade legs have been added for slimes + - rscadd: you can teleport bread + - tweak: slime puddles are no longer layered down one layer + - tweak: you cannot tackle with two paralysed arms + - tweak: tackling with a single paralysed arm lowers your tackle roll by 2 + - bugfix: circuits get pin data proc is sanitized when text is returned as data + - rscadd: loadout now has save slot support and colour choosing/saving for polychromic + items + - rscadd: polychromic maid outfit + - rscadd: you can rebind communication hotkeys and they're the default now + - rscadd: you can now customize your size from 90% to 130%, going below 100% makes + you have 10 less max health + - rscadd: '*squeak' + - rscadd: anthromorphic synth species + - rscadd: improvements to the automatic age gate + - tweak: antag items are now of critical importance and wont fail to be placed on + the character + - bugfix: a tonne of fixes to colourisation of parts, too many to name, including + some sprite fixes + - rscadd: things now have their own individual primary/(secondary)/(tertiary) colours + as required, and these can be modified by you + uomo91: + - bugfix: Fixed "Show All" tab in player panel logs being broken. + - bugfix: Whispers, OOC, and various other things display differently in logs, visually + distinguishing them from say logs. + - refactor: Player panel logs will now show all logs chronologically, so you'll + see commingled say and attack logs if you're on the "Show All" tab, etc... + yorii: + - bugfix: fixed botany rounding error that caused grass and other plants to misbehave + zeroisthebiggay: + - bugfix: legion now drops chests + - rscadd: Traitor assistants can now purchase the patented POGBox! Put TC into it + for even higher damage! + - balance: MEGAFAUNA DROPS ARE LAVAPROOF + - imageadd: cool codex cicatrix inhands + - rscadd: gravitokinetic stands from tg + - balance: buffs stands overall + - bugfix: protector stands no longer become tposing invisible apes sometimes + - bugfix: jacqueline spawns on boxstation + - rscadd: secsheath for your cool stunsword at your local security vendor. you gotta + hack it first though. + - imageadd: fuck the r*d cr*ss + - rscadd: The legion megafauna has been reworked. The fight should now be both slightly + harder and faster. + - balance: You can no longer cheese the colossus by being a sand golem and simply + being immune. +2021-01-22: + Arturlang: + - rscadd: Adds a way to give items to people, you can combat mode rightclick to + offer it to one person, right click on people without mode and click the give + verb, or use the hotkey CTRL G to offer it to everyone around you +2021-01-25: + MrJWhit: + - bugfix: Alien radio code + - rscadd: Microwave can now be cleaned by a damp rag as well as soap. + - bugfix: Removes some unused code, and improves some other code. + - rscadd: The AI has a verb to look up and down z-levels + - bugfix: Making a monkey into a human doesn't unanchor random things on the tile + - bugfix: Makes a few slight improvements to drinking code + - tweak: Makes encryption keys be put in the hands of the user when able instead + of being dropped on the floor when removed from headsets + raspy-on-osu: + - refactor: ventcrawling + silicons: + - tweak: you can now shove yourself up in any intent, not just help. +2021-01-27: + ArcaneMusic, ported by Hatterhat: + - rscadd: Strike a hydroponics tray with a fully-charged floral somatoray to lock + in a mutation. + - rscadd: Floral somatorays now have the ability to force a mutation in a plant. + This should drain the cell in a single shot, but we'll see. + - balance: Somatorays now take uranium to craft instead of radium. + Arturlang: + - rscadd: Actually adds a right click give option + - rscadd: Revenants can now clickdrag to throw stuff at people, with some items + doing various things at the same time. + DeltaFire15: + - bugfix: The woundmending rite no longer causes runtimes. + - bugfix: Ratvarian borgs can now use their tier-0 spells. + - balance: Ratvarian borgs can always use their assigned spells, if there is enough + power. + - admin: The heretic antag panel now shows their sacrifices & current sacrifice + targets. + - tweak: The heretic roundend report now shows their sacrifices and nonsacrificed + targets. + - bugfix: Living hearts can no longer select the same target as another living heart, + removing a certain problem. + Hatterhat: + - tweak: Department budget cards have been readded. TO THE CODE. NOT LOCKERS. + - tweak: Also budget cards now look more like every other ID - see tgstation#55001. + - balance: One of the contractor tablet's payouts has been raised from a small payout + to a medium payout. + - balance: The free golem ship's GPSes no longer start on. They were never meant + to, but they did. + - rscdel: Headsets can't be found on most legion corpses now. + - rscdel: The flash on the assistant corpse is gone, too. + MrJWhit: + - tweak: Remaps some air alarms for sanity. + SandPoot: + - bugfix: The drop circuit can no longer drop things that are not inside it. + raspy-on-osu: + - bugfix: bespoke ventcrawling element not detaching due to malformed call + shellspeed1: + - bugfix: Floorbots had had a software update, preventing them from dogpiling on + their target as easily as they did before. + - soundadd: Floorbots will now play a small chime when stacked on top of each other + to indicate that they're moving apart. + timothyteakettle: + - rscadd: blobs can use the 'me' verb + - admin: adminhelps and pms only sanitize once instead of twice +2021-01-28: + silicons: + - rscadd: colormates can now paint some mobs. + - bugfix: 1 dev explosions shouldn't delete brains anymore +2021-01-29: + MrJWhit: + - tweak: Ported the QM, Captain, CMO, and HoS cloaks from beestation. + - rscdel: Removes excess air alarms from boxstation + TripleShades: + - bugfix: fixes engineering secure storage being the wrong area because I fucked + that up previously my bad + - bugfix: removes funny extra light switch under right surgery table in surgery + oops + - rscadd: Added chairs to the corpse launch viewing area + - rscadd: Small garden plot for flowers for parity with other station Chapels + - rscadd: Plain Bible to glass tables in Chapel + - rscadd: Candles and Matchbox to glass tables in Chapel + - rscadd: More glass tables, with a chaplain figure and another spare bible. + - rscadd: Bookcase to Box Chapel for parity with other station Chapels + - rscadd: Minimoog to Box Chapel as substitute for a church organ + - rscadd: 'Holy department sign just below Chapel change: Expanded the corpse launching + area to feel less congested change: Added windows to the corpse launch so you + can look inside I guess? change: Moved flowers and burial garments to the corner + next to the corpse launcher change: Box Chaplain''s office door is moved over + one change: Confessional is now connected to Chaplain''s office for parity with + other station Chapels change: Moved coffins over to old confessional location + change: Box Chapel now has pews instead of stools change: Box Chapel Confessional + is now lit instead of being nearly pitch black remove: Two coffins from Chapel' + timothyteakettle: + - bugfix: the miner bedsheet will now increment its progress when you redeem points + from the ORM + - rscadd: you can add custom names and descriptions to item's on the loadout now + zeroisthebiggay: + - rscadd: roundstart aesthetic sterile masks and roundstart paper masks + - rscadd: more accessory slot items + - rscadd: cowbell necklace happy 2021 + - rscadd: shibari ropes & torn pantyhose diff --git a/html/changelogs/AutoChangeLog-pr-13014.yml b/html/changelogs/AutoChangeLog-pr-13014.yml deleted file mode 100644 index 861e797669..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13014.yml +++ /dev/null @@ -1,4 +0,0 @@ -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 deleted file mode 100644 index 980a9366d8..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13193.yml +++ /dev/null @@ -1,4 +0,0 @@ -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 deleted file mode 100644 index 4366abec64..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13233.yml +++ /dev/null @@ -1,6 +0,0 @@ -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-13252.yml b/html/changelogs/AutoChangeLog-pr-13252.yml deleted file mode 100644 index 5de40bb80b..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13252.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - tweak: "looking at loadout equips loadout items on your preview image instead of job items" diff --git a/html/changelogs/AutoChangeLog-pr-13346.yml b/html/changelogs/AutoChangeLog-pr-13346.yml deleted file mode 100644 index 2e3d4e3280..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13346.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Putnam3145" -delete-after: True -changes: - - refactor: "Dwarf speech is no longer absolutely paranoid about word replacement." diff --git a/html/changelogs/AutoChangeLog-pr-13349.yml b/html/changelogs/AutoChangeLog-pr-13349.yml deleted file mode 100644 index 2469b31ecd..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13349.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "LetterN" -delete-after: True -changes: - - code_imp: "Updates git and build tests." diff --git a/html/changelogs/AutoChangeLog-pr-13405.yml b/html/changelogs/AutoChangeLog-pr-13405.yml deleted file mode 100644 index 176e886b0d..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13405.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "silicons" -delete-after: True -changes: - - tweak: "the warp implant now actually warps you back 10 seconds. leaves a trail, though. now unlimited us." diff --git a/html/changelogs/AutoChangeLog-pr-13444.yml b/html/changelogs/AutoChangeLog-pr-13444.yml deleted file mode 100644 index d24babda2e..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13444.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - tweak: "you can now get a family heirlooms based off your species instead of job" diff --git a/html/changelogs/AutoChangeLog-pr-13461.yml b/html/changelogs/AutoChangeLog-pr-13461.yml deleted file mode 100644 index e2397a7aa0..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13461.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Detective-Google" -delete-after: True -changes: - - rscadd: "arcade carpet" diff --git a/html/changelogs/AutoChangeLog-pr-13472.yml b/html/changelogs/AutoChangeLog-pr-13472.yml deleted file mode 100644 index 8e8d043de6..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13472.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - rscadd: "roundstart slimes can turn into puddles now" diff --git a/html/changelogs/AutoChangeLog-pr-13473.yml b/html/changelogs/AutoChangeLog-pr-13473.yml deleted file mode 100644 index aebdfbb3cb..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13473.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Tupinambis" -delete-after: True -changes: - - rscadd: "Arachnids (spider people) with limited night vision, flash vulnerability, and webbing." diff --git a/html/changelogs/AutoChangeLog-pr-13479.yml b/html/changelogs/AutoChangeLog-pr-13479.yml deleted file mode 100644 index fcfe65a47e..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13479.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "LetterN" -delete-after: True -changes: - - bugfix: "minimap text" - - code_imp: "ports cinematic upgrades" diff --git a/html/changelogs/AutoChangeLog-pr-13481.yml b/html/changelogs/AutoChangeLog-pr-13481.yml deleted file mode 100644 index f6049c552b..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13481.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - bugfix: "the blacksmithing skill now works properly" - - tweak: "Anvils cannot be interacted with with hammers whilst they are already being used" - - tweak: "If someone has no gloves when interacting with heated ingots, they no longer ignore their effects." diff --git a/html/changelogs/AutoChangeLog-pr-13483.yml b/html/changelogs/AutoChangeLog-pr-13483.yml deleted file mode 100644 index 1db9304ffb..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13483.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - bugfix: "The Revenant self-revive ability is no longer broken." diff --git a/html/changelogs/AutoChangeLog-pr-13487.yml b/html/changelogs/AutoChangeLog-pr-13487.yml deleted file mode 100644 index 4b0f92adfb..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13487.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - bugfix: "People installing KA modkits in miner borgs is no longer broken." diff --git a/html/changelogs/AutoChangeLog-pr-13496.yml b/html/changelogs/AutoChangeLog-pr-13496.yml deleted file mode 100644 index 30308efaff..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13496.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Detective-Google" -delete-after: True -changes: - - rscadd: "explosions now get broadcasted to deadchat." diff --git a/html/changelogs/AutoChangeLog-pr-13497.yml b/html/changelogs/AutoChangeLog-pr-13497.yml deleted file mode 100644 index c5f569bad3..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13497.yml +++ /dev/null @@ -1,5 +0,0 @@ -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-13498.yml b/html/changelogs/AutoChangeLog-pr-13498.yml deleted file mode 100644 index f956ee4b07..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13498.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Bhijn" -delete-after: True -changes: - - tweak: "Changeling loudness is now determined as an average of all their abilities, rather than the sum" - - tweak: "To compensate for this, blood tests now require a loudness value of 1 or higher to detect ling blood. Additionally, blood test explosions are now triggered only when the loudness value is higher than 2." diff --git a/html/changelogs/AutoChangeLog-pr-13499.yml b/html/changelogs/AutoChangeLog-pr-13499.yml deleted file mode 100644 index 804fa9fc34..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13499.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Putnam3145" -delete-after: True -changes: - - bugfix: "Toilet loot spawners don't lag the server on server start with forced hard dels." diff --git a/html/changelogs/AutoChangeLog-pr-13500.yml b/html/changelogs/AutoChangeLog-pr-13500.yml deleted file mode 100644 index 7ba1eb64f3..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13500.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "LetterN" -delete-after: True -changes: - - rscadd: "2 more ways to get up from z1" - - tweak: "tweaked the z2 garden to be less blank" diff --git a/html/changelogs/AutoChangeLog-pr-13501.yml b/html/changelogs/AutoChangeLog-pr-13501.yml deleted file mode 100644 index dcdd868e37..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13501.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Putnam3145" -delete-after: True -changes: - - bugfix: "Holofirelocks work now." diff --git a/html/changelogs/AutoChangeLog-pr-13503.yml b/html/changelogs/AutoChangeLog-pr-13503.yml deleted file mode 100644 index c68eaf44f0..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13503.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Hatterhat" -delete-after: True -changes: - - rscadd: "Survival daggers! A slightly more expensive survival knife that comes with a brighter flashlight. On the blade." - - tweak: "Luxury pod capsules look different from normal capsules." diff --git a/html/changelogs/AutoChangeLog-pr-13504.yml b/html/changelogs/AutoChangeLog-pr-13504.yml deleted file mode 100644 index 7f59b120b6..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13504.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "zeroisthebiggay" -delete-after: True -changes: - - rscadd: "gravitokinetic stands from tg" - - balance: "buffs stands overall" - - bugfix: "protector stands no longer become tposing invisible apes sometimes" diff --git a/html/changelogs/AutoChangeLog-pr-13509.yml b/html/changelogs/AutoChangeLog-pr-13509.yml deleted file mode 100644 index e666a6b2a4..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13509.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "EmeraldSundisk" -delete-after: True -changes: - - balance: "The \"Skelter ruin\" now has stechkins as opposed to M1911s" - - tweak: "Skelter's decorative bullet casings replaced to factor in the change in caliber" - - rscadd: "Skelter now has a combat knife and fluff note" diff --git a/html/changelogs/AutoChangeLog-pr-13511.yml b/html/changelogs/AutoChangeLog-pr-13511.yml deleted file mode 100644 index e819d8752d..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13511.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Hatterhat" -delete-after: True -changes: - - imageadd: "The Syndicate appear to be issuing new revolver variants." diff --git a/html/changelogs/AutoChangeLog-pr-13512.yml b/html/changelogs/AutoChangeLog-pr-13512.yml deleted file mode 100644 index f96f13a156..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13512.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Hatterhat" -delete-after: True -changes: - - bugfix: "Cryogenics now screams on common again when your fuckbuddy heads out." diff --git a/html/changelogs/AutoChangeLog-pr-13513.yml b/html/changelogs/AutoChangeLog-pr-13513.yml deleted file mode 100644 index 0cff979e8c..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13513.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - rscadd: "you can now pick your eye sprites from customization" diff --git a/html/changelogs/AutoChangeLog-pr-13514.yml b/html/changelogs/AutoChangeLog-pr-13514.yml deleted file mode 100644 index bd1605fb96..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13514.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Thalpy" -delete-after: True -changes: - - bugfix: "fixes some bugs in jacqs code from edits to the codebase" diff --git a/html/changelogs/AutoChangeLog-pr-13516.yml b/html/changelogs/AutoChangeLog-pr-13516.yml deleted file mode 100644 index 30e22f4f48..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13516.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "yorii" -delete-after: True -changes: - - bugfix: "fixed botany rounding error that caused grass and other plants to misbehave" diff --git a/html/changelogs/AutoChangeLog-pr-13517.yml b/html/changelogs/AutoChangeLog-pr-13517.yml deleted file mode 100644 index 8f29517058..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13517.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "silicons" -delete-after: True -changes: - - bugfix: "simple mobs are now immune to radioactive contamination" diff --git a/html/changelogs/AutoChangeLog-pr-13518.yml b/html/changelogs/AutoChangeLog-pr-13518.yml deleted file mode 100644 index 565754f48b..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13518.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "TheObserver-sys" -delete-after: True -changes: - - bugfix: "Drake? Where's the dead fairygrass sprite?" diff --git a/html/changelogs/AutoChangeLog-pr-13519.yml b/html/changelogs/AutoChangeLog-pr-13519.yml deleted file mode 100644 index 0c4978a7d8..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13519.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Detective-Google" -delete-after: True -changes: - - rscadd: "Lick radial" diff --git a/html/changelogs/AutoChangeLog-pr-13521.yml b/html/changelogs/AutoChangeLog-pr-13521.yml deleted file mode 100644 index 77aca8c363..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13521.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - balance: "zeolites are now actual fermichems instead of being incredibly easy to make." - - bugfix: "Using syringes / droppers on chem heaters with beakers in them works again." diff --git a/html/changelogs/AutoChangeLog-pr-13523.yml b/html/changelogs/AutoChangeLog-pr-13523.yml deleted file mode 100644 index ac2019bb88..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13523.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Detective-Google" -delete-after: True -changes: - - bugfix: "arcade carpets now actually work" diff --git a/html/changelogs/AutoChangeLog-pr-13525.yml b/html/changelogs/AutoChangeLog-pr-13525.yml deleted file mode 100644 index eb441f04c3..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13525.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Detective-Google" -delete-after: True -changes: - - bugfix: "Hilbert's jukebox works" diff --git a/html/changelogs/AutoChangeLog-pr-13526.yml b/html/changelogs/AutoChangeLog-pr-13526.yml deleted file mode 100644 index 104b76bd94..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13526.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Putnam3145" -delete-after: True -changes: - - bugfix: "vore prefs save now" diff --git a/html/changelogs/AutoChangeLog-pr-13527.yml b/html/changelogs/AutoChangeLog-pr-13527.yml deleted file mode 100644 index 7e65116e83..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13527.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "ArchieBeepBoop" -delete-after: True -changes: - - rscadd: "Upgraded Advanced RTG Machine Preset" diff --git a/html/changelogs/AutoChangeLog-pr-13528.yml b/html/changelogs/AutoChangeLog-pr-13528.yml deleted file mode 100644 index b7bd0d4618..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13528.yml +++ /dev/null @@ -1,11 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - balance: "Robotic Limbs now each have their own damage threshhold values" - - balance: "Robotic Limb damage threshholds are now seperated into threshhold itself and mindamage when passed -balance; Hybrid limbs can now be injected with hypos, but not sprayed (Still not healed by chems)" - - tweak: "Brain surgery has been tweaked back to allowing robotic limbs, blacklisting IPC brains instead." - - tweak: "Robot brain surgery can now be used on organic heads, if there is a IPC brain in them somehow." - - tweak: "The robot limb heal surgery can now be used even if the target's torso is not robotic, as long as they have robotic limbs" - - refactor: "BODYPART_ROBOTIC / BODYPART_ORGANIC checks replaced with helper-procs whereever possible." - - code_imp: "Added a BODYPART_HYBRID define for robotic bodyparts that behave organic in some regards." diff --git a/html/changelogs/AutoChangeLog-pr-13529.yml b/html/changelogs/AutoChangeLog-pr-13529.yml deleted file mode 100644 index 54f775b5c8..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13529.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Putnam3145" -delete-after: True -changes: - - tweak: "Planetary atmos no longer does superconduction." diff --git a/html/changelogs/AutoChangeLog-pr-13530.yml b/html/changelogs/AutoChangeLog-pr-13530.yml deleted file mode 100644 index b99ed1c545..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13530.yml +++ /dev/null @@ -1,4 +0,0 @@ -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-13531.yml b/html/changelogs/AutoChangeLog-pr-13531.yml deleted file mode 100644 index 3c138ef98d..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13531.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - bugfix: "A certain lizard (totally not me) being stupid is no longer going to break regenerate_bodyparts" diff --git a/html/changelogs/AutoChangeLog-pr-13533.yml b/html/changelogs/AutoChangeLog-pr-13533.yml deleted file mode 100644 index 1ba14c689c..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13533.yml +++ /dev/null @@ -1,4 +0,0 @@ -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 deleted file mode 100644 index b020587eb8..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13535.yml +++ /dev/null @@ -1,7 +0,0 @@ -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-13539.yml b/html/changelogs/AutoChangeLog-pr-13539.yml deleted file mode 100644 index a1f3df4fd0..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13539.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - rscdel: "removes two debug messages left in from my prior eye customization pr" diff --git a/html/changelogs/AutoChangeLog-pr-13540.yml b/html/changelogs/AutoChangeLog-pr-13540.yml deleted file mode 100644 index 0d7d9b8d2c..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13540.yml +++ /dev/null @@ -1,6 +0,0 @@ -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-13543.yml b/html/changelogs/AutoChangeLog-pr-13543.yml deleted file mode 100644 index be2cb215c9..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13543.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "zeroisthebiggay" -delete-after: True -changes: - - rscadd: "The legion megafauna has been reworked. The fight should now be both slightly harder and faster." - - balance: "You can no longer cheese the colossus by being a sand golem and simply being immune." diff --git a/html/changelogs/AutoChangeLog-pr-13544.yml b/html/changelogs/AutoChangeLog-pr-13544.yml deleted file mode 100644 index 61cf99090d..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13544.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - bugfix: "Portals no longer runtime because of incorrect args." diff --git a/html/changelogs/AutoChangeLog-pr-13547.yml b/html/changelogs/AutoChangeLog-pr-13547.yml deleted file mode 100644 index 0355a871d1..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13547.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "zeroisthebiggay" -delete-after: True -changes: - - rscadd: "secsheath for your cool stunsword at your local security vendor. you gotta hack it first though." diff --git a/html/changelogs/AutoChangeLog-pr-13549.yml b/html/changelogs/AutoChangeLog-pr-13549.yml deleted file mode 100644 index 5d46fbcb6c..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13549.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "BlueWildrose" -delete-after: True -changes: - - bugfix: "Fixes cloning computer UI not updating when pressing certain buttons - also adds extra check for names to update a message" diff --git a/html/changelogs/AutoChangeLog-pr-13552.yml b/html/changelogs/AutoChangeLog-pr-13552.yml deleted file mode 100644 index 1504d1d3a0..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13552.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Putnam3145" -delete-after: True -changes: - - bugfix: "Multi-surgery unit test no longer fails at random." diff --git a/html/changelogs/AutoChangeLog-pr-13553.yml b/html/changelogs/AutoChangeLog-pr-13553.yml deleted file mode 100644 index 2759fa2754..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13553.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - bugfix: "eye sprites should look normal once more" diff --git a/html/changelogs/AutoChangeLog-pr-13554.yml b/html/changelogs/AutoChangeLog-pr-13554.yml deleted file mode 100644 index 3a14adff37..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13554.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Vynzill" -delete-after: True -changes: - - bugfix: "fixes high luminosity eyes" diff --git a/html/changelogs/AutoChangeLog-pr-13558.yml b/html/changelogs/AutoChangeLog-pr-13558.yml deleted file mode 100644 index 2a5b2dc576..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13558.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Zandario" -delete-after: True -changes: - - bugfix: "lum slime sprites work again" - - code_imp: "Slapped the Species Defines where relevant" diff --git a/html/changelogs/AutoChangeLog-pr-13561.yml b/html/changelogs/AutoChangeLog-pr-13561.yml deleted file mode 100644 index 097336bc3b..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13561.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - bugfix: "Your target cryoing will no longer give you a free greentext." diff --git a/html/changelogs/AutoChangeLog-pr-13562.yml b/html/changelogs/AutoChangeLog-pr-13562.yml deleted file mode 100644 index 7fabc05c7b..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13562.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - bugfix: "Vampire shapeshifting should now behave as intended" diff --git a/html/changelogs/AutoChangeLog-pr-13563.yml b/html/changelogs/AutoChangeLog-pr-13563.yml deleted file mode 100644 index c4c9b68c39..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13563.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - tweak: "cloning now correctly copies your blood colour, body sprite type and eye type" diff --git a/html/changelogs/AutoChangeLog-pr-13566.yml b/html/changelogs/AutoChangeLog-pr-13566.yml deleted file mode 100644 index 14ee8755a9..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13566.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "zeroisthebiggay" -delete-after: True -changes: - - bugfix: "legion now drops chests" diff --git a/html/changelogs/AutoChangeLog-pr-13567.yml b/html/changelogs/AutoChangeLog-pr-13567.yml deleted file mode 100644 index d51db8e3b8..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13567.yml +++ /dev/null @@ -1,8 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - tweak: "changeling stings retract upon turning into a slime puddle" - - tweak: "you cannot transform into a slime puddle with a no drop item in your hands" - - tweak: "slime puddles are now transparent and their colour looks more natural in comparison to the user" - - tweak: "slime puddles are now even slower" - - tweak: "slime puddles now get no protection from worn clothing" diff --git a/html/changelogs/AutoChangeLog-pr-13570.yml b/html/changelogs/AutoChangeLog-pr-13570.yml deleted file mode 100644 index 6a4fb6af66..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13570.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Putnam3145" -delete-after: True -changes: - - bugfix: "Fixed a runtime in every healing nanite program." diff --git a/html/changelogs/AutoChangeLog-pr-13571.yml b/html/changelogs/AutoChangeLog-pr-13571.yml deleted file mode 100644 index 864967dffc..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13571.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "MrJWhit" -delete-after: True -changes: - - bugfix: "Code improvement on ventcrawling" diff --git a/html/changelogs/AutoChangeLog-pr-13573.yml b/html/changelogs/AutoChangeLog-pr-13573.yml deleted file mode 100644 index 9bac0ce44d..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13573.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Putnam3145" -delete-after: True -changes: - - bugfix: "removed a unit test causing master to fail" diff --git a/html/changelogs/AutoChangeLog-pr-13575.yml b/html/changelogs/AutoChangeLog-pr-13575.yml deleted file mode 100644 index 164581b11f..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13575.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "BlueWildrose" -delete-after: True -changes: - - bugfix: "Fixed the subtle hotkey being weird with its input prompts." - - rscadd: "Adds a subtler anti-ghost hotkey. Default key is 6." diff --git a/html/changelogs/AutoChangeLog-pr-13576.yml b/html/changelogs/AutoChangeLog-pr-13576.yml deleted file mode 100644 index 9443b13dcb..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13576.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Sonic121x" -delete-after: True -changes: - - rscadd: "digi sprite uniform" - - bugfix: "digi leg suit" diff --git a/html/changelogs/AutoChangeLog-pr-13577.yml b/html/changelogs/AutoChangeLog-pr-13577.yml deleted file mode 100644 index 7463a3ad39..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13577.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Putnam3145" -delete-after: True -changes: - - bugfix: "Chemical stuff now displays fermichem stuff properly" diff --git a/html/changelogs/AutoChangeLog-pr-13581.yml b/html/changelogs/AutoChangeLog-pr-13581.yml deleted file mode 100644 index 42db54450b..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13581.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "Ghommie, porting PRs by MMMiracles and pireamaineach, credits to BlueWildrose too." -delete-after: True -changes: - - rscadd: "You can now draw on plasmaman helmets with a crayon to turn their frown upside-down." - - balance: "Plasmaman helmets no longer hide your identity when worn by themselves." - - balance: "Plasmaman helmets now have welding visors, which can't stack with their torches in the helmet and are visible." diff --git a/html/changelogs/AutoChangeLog-pr-13582.yml b/html/changelogs/AutoChangeLog-pr-13582.yml deleted file mode 100644 index 78f8be1cd0..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13582.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - bugfix: "a tonne of fixes to colourisation of parts, too many to name, including some sprite fixes" - - rscadd: "things now have their own individual primary/(secondary)/(tertiary) colours as required, and these can be modified by you" diff --git a/html/changelogs/AutoChangeLog-pr-13585.yml b/html/changelogs/AutoChangeLog-pr-13585.yml deleted file mode 100644 index 0369e0827f..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13585.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "BlueWildrose" -delete-after: True -changes: - - bugfix: "Fixed species-specific drinks not giving a mood boost if you are that species." diff --git a/html/changelogs/AutoChangeLog-pr-13586.yml b/html/changelogs/AutoChangeLog-pr-13586.yml deleted file mode 100644 index 5f61b1dc54..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13586.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "KeRSedChaplain" -delete-after: True -changes: - - imageadd: "Resprited the brass claw" diff --git a/html/changelogs/AutoChangeLog-pr-13587.yml b/html/changelogs/AutoChangeLog-pr-13587.yml deleted file mode 100644 index ea3f4c5efa..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13587.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Detective-Google" -delete-after: True -changes: - - tweak: "the snow taxi is no longer the slow taxi" diff --git a/html/changelogs/AutoChangeLog-pr-13588.yml b/html/changelogs/AutoChangeLog-pr-13588.yml deleted file mode 100644 index 7ab9d67bab..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13588.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Delams-The-SM" -delete-after: True -changes: - - rscadd: "Added 3 new emotes *hiss *purr *meow" - - soundadd: "ported sounds from Citadel RP for *purr and *meow" diff --git a/html/changelogs/AutoChangeLog-pr-13589.yml b/html/changelogs/AutoChangeLog-pr-13589.yml deleted file mode 100644 index 877012914e..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13589.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - tweak: "autosurgeons from travelling trader rewards now only have one use" diff --git a/html/changelogs/AutoChangeLog-pr-13592.yml b/html/changelogs/AutoChangeLog-pr-13592.yml deleted file mode 100644 index 76e12e8c89..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13592.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Putnam3145" -delete-after: True -changes: - - rscadd: "Stat panel UI for ranked choice votes" diff --git a/html/changelogs/AutoChangeLog-pr-13593.yml b/html/changelogs/AutoChangeLog-pr-13593.yml deleted file mode 100644 index 08310f6013..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13593.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Putnam3145" -delete-after: True -changes: - - code_imp: "Vote system #defines are now strings" diff --git a/html/changelogs/AutoChangeLog-pr-13598.yml b/html/changelogs/AutoChangeLog-pr-13598.yml deleted file mode 100644 index 7bef81fa1a..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13598.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Arturlang" -delete-after: True -changes: - - bugfix: "Fixes hijack implant APC UI, again" diff --git a/html/changelogs/AutoChangeLog-pr-13599.yml b/html/changelogs/AutoChangeLog-pr-13599.yml deleted file mode 100644 index 3deea2b2be..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13599.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Delams-The-SM" -delete-after: True -changes: - - bugfix: "fixed randomization of colors for things like mulligan and Stabilized green slime extract for matrixed body parts" diff --git a/html/changelogs/AutoChangeLog-pr-13601.yml b/html/changelogs/AutoChangeLog-pr-13601.yml deleted file mode 100644 index 0cfb64b48b..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13601.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - tweak: "antag items are now of critical importance and wont fail to be placed on the character" diff --git a/html/changelogs/AutoChangeLog-pr-13602.yml b/html/changelogs/AutoChangeLog-pr-13602.yml deleted file mode 100644 index 24185b1792..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13602.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Putnam3145" -delete-after: True -changes: - - rscadd: "A fallback for dynamic antag rolling that allows for it to just try between traitor, blood brothers, heretics, changeling, bloodsucker and devil until there are enough roundstart antags. This can also happen randomly anyway. Blood brothers and devil are disabled for now, but the code is there to enable them." - - rscadd: "A new storyteller, \"Grab Bag\", that forces the above round type." diff --git a/html/changelogs/AutoChangeLog-pr-13603.yml b/html/changelogs/AutoChangeLog-pr-13603.yml deleted file mode 100644 index 4fcff30da0..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13603.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "kappa-sama" -delete-after: True -changes: - - tweak: "ishotgun crafting recipe no longer requires plasteel and is slightly more convenient" - - balance: "ishotgun does 45 damage now instead of 40.5" diff --git a/html/changelogs/AutoChangeLog-pr-13604.yml b/html/changelogs/AutoChangeLog-pr-13604.yml deleted file mode 100644 index 2ac141215b..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13604.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Trilbyspaceclone" -delete-after: True -changes: - - balance: "Brass welders are 50% faster at refueling" - - code_imp: "redoes self fueling welders in the code to be less speggie" diff --git a/html/changelogs/AutoChangeLog-pr-13605.yml b/html/changelogs/AutoChangeLog-pr-13605.yml deleted file mode 100644 index 707de17870..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13605.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Trilbyspaceclone" -delete-after: True -changes: - - rscadd: "the corporate unifoms can now be gotton in the clothing mate vender" diff --git a/html/changelogs/AutoChangeLog-pr-13606.yml b/html/changelogs/AutoChangeLog-pr-13606.yml deleted file mode 100644 index 568f8cf7e6..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13606.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Putnam3145" -delete-after: True -changes: - - bugfix: "adminhelping no longer removes entire admin tab" - - bugfix: "end of round no longer removes entire admin tab" diff --git a/html/changelogs/AutoChangeLog-pr-13607.yml b/html/changelogs/AutoChangeLog-pr-13607.yml deleted file mode 100644 index 0ed47b1d44..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13607.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - rscadd: "polychromic maid outfit" diff --git a/html/changelogs/AutoChangeLog-pr-13608.yml b/html/changelogs/AutoChangeLog-pr-13608.yml deleted file mode 100644 index b7c0201cab..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13608.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SpaceManiac" -delete-after: True -changes: - - bugfix: "Fixed the maphook" diff --git a/html/changelogs/AutoChangeLog-pr-13611.yml b/html/changelogs/AutoChangeLog-pr-13611.yml deleted file mode 100644 index d7e6e8f9a1..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13611.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "MrJWhit" -delete-after: True -changes: - - rscadd: "Adds a space loop to every map in toxins" diff --git a/html/changelogs/AutoChangeLog-pr-13612.yml b/html/changelogs/AutoChangeLog-pr-13612.yml deleted file mode 100644 index 9a67ec5aa3..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13612.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "MrJWhit" -delete-after: True -changes: - - rscadd: "Expanded space hermit base" diff --git a/html/changelogs/AutoChangeLog-pr-13616.yml b/html/changelogs/AutoChangeLog-pr-13616.yml deleted file mode 100644 index 3032d0331f..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13616.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Ghommie" -delete-after: True -changes: - - bugfix: "You can access the mime / clown mask skins radial menu once again." diff --git a/html/changelogs/AutoChangeLog-pr-13617.yml b/html/changelogs/AutoChangeLog-pr-13617.yml deleted file mode 100644 index 532882eecc..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13617.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - rscadd: "loadout now has save slot support and colour choosing/saving for polychromic items" diff --git a/html/changelogs/AutoChangeLog-pr-13618.yml b/html/changelogs/AutoChangeLog-pr-13618.yml deleted file mode 100644 index b301c39e6b..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13618.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Vynzill" -delete-after: True -changes: - - rscadd: "new gateway mission -mapadd: jungleresort map" diff --git a/html/changelogs/AutoChangeLog-pr-13626.yml b/html/changelogs/AutoChangeLog-pr-13626.yml deleted file mode 100644 index fa5331e005..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13626.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "zeroisthebiggay" -delete-after: True -changes: - - balance: "MEGAFAUNA DROPS ARE LAVAPROOF" diff --git a/html/changelogs/AutoChangeLog-pr-13627.yml b/html/changelogs/AutoChangeLog-pr-13627.yml deleted file mode 100644 index 087cbde3ae..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13627.yml +++ /dev/null @@ -1,8 +0,0 @@ -author: "Ghommie" -delete-after: True -changes: - - bugfix: "Dice bags no longer act like cardboard boxes." - - bugfix: "Abductors should be no longer mute." - - bugfix: "Item action buttons should now properly show the item current overlays, most times." - - bugfix: "The blackbox should now go into your hand slot when pried out, rather than tumbling on the ground everytime." - - tweak: "The Quick Equip hotkey is now usable by all living mobs (so long they have hands and equipment slots)" diff --git a/html/changelogs/AutoChangeLog-pr-13629.yml b/html/changelogs/AutoChangeLog-pr-13629.yml deleted file mode 100644 index 954f6972ec..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13629.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "silicons" -delete-after: True -changes: - - rscdel: "anomalies no longer spawn in walls" diff --git a/html/changelogs/AutoChangeLog-pr-13630.yml b/html/changelogs/AutoChangeLog-pr-13630.yml deleted file mode 100644 index f7e80aaf9e..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13630.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - rscadd: "you can now customize your size from 90% to 130%, going below 100% makes you have 10 less max health" diff --git a/html/changelogs/AutoChangeLog-pr-13632.yml b/html/changelogs/AutoChangeLog-pr-13632.yml deleted file mode 100644 index bf478ec97c..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13632.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - bugfix: "time for memory loss message to show up when being revived is now correctly 300 seconds, instead of 30" diff --git a/html/changelogs/AutoChangeLog-pr-13633.yml b/html/changelogs/AutoChangeLog-pr-13633.yml deleted file mode 100644 index d9246cfff6..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13633.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "ArchieBeepBoop" -delete-after: True -changes: - - bugfix: "Outlet Injector Mapping Asset Layer Fix" diff --git a/html/changelogs/AutoChangeLog-pr-13635.yml b/html/changelogs/AutoChangeLog-pr-13635.yml deleted file mode 100644 index 21730d4cf5..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13635.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Hatterhat" -delete-after: True -changes: - - balance: "The bone gauntlets should be slightly less murderously punchy on the fast punches mode." diff --git a/html/changelogs/AutoChangeLog-pr-13636.yml b/html/changelogs/AutoChangeLog-pr-13636.yml deleted file mode 100644 index 75124f759f..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13636.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SiliconMain" -delete-after: True -changes: - - tweak: "Engi department has gas masks in loadout" diff --git a/html/changelogs/AutoChangeLog-pr-13639.yml b/html/changelogs/AutoChangeLog-pr-13639.yml deleted file mode 100644 index a511d0a909..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13639.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Trilbyspaceclone" -delete-after: True -changes: - - tweak: "ASP 9mm and M1911 can now have suppressers added" diff --git a/html/changelogs/AutoChangeLog-pr-13641.yml b/html/changelogs/AutoChangeLog-pr-13641.yml deleted file mode 100644 index b0c429da75..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13641.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "MrJWhit" -delete-after: True -changes: - - balance: "Nerf combat knife damage" diff --git a/html/changelogs/AutoChangeLog-pr-13644.yml b/html/changelogs/AutoChangeLog-pr-13644.yml deleted file mode 100644 index 71417788a7..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13644.yml +++ /dev/null @@ -1,8 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - balance: "Biomechanical (hybrid) bodyparts now have access to wound-fixing surgeries." - - tweak: "A wound being fixed no longer just qdel()s surgeries connected to it." - - tweak: "Some robotic surgery steps are now a bit more clear." - - bugfix: "Organs no longer get fed to people after successfully being inserted into them." - - tweak: "Not completing the do_after of a surgery no longer causes you to attack the target with whatever you were holding." diff --git a/html/changelogs/AutoChangeLog-pr-13647.yml b/html/changelogs/AutoChangeLog-pr-13647.yml deleted file mode 100644 index b3211ee759..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13647.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "zeroisthebiggay" -delete-after: True -changes: - - bugfix: "jacqueline spawns on boxstation" diff --git a/html/changelogs/AutoChangeLog-pr-13648.yml b/html/changelogs/AutoChangeLog-pr-13648.yml deleted file mode 100644 index 4148230385..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13648.yml +++ /dev/null @@ -1,13 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - bugfix: "The 'Your body is in a cloner' notification works again" - - bugfix: "Hijack implants should work properly again (or, at least better)" - - bugfix: "Liches are now good skeletons again instead of weak ones" - - bugfix: "The piratepad control cannot be destroyed again." - - bugfix: "Pirates have received new supplies of jetpacks instead of useless oxygen tanks" - - bugfix: "Ratvarian AIs are once again able to show their linked borgs Ratvar's light" - - bugfix: "Hijackers are once again unable to detonate borgs without being adjacent to the console" - - bugfix: "Automated annoucement systems and gulag ore consoles no longer waste emag charges" - - bugfix: "Automated announcement systems once again can be remote controlled by non-AIs with silicon access" - - bugfix: "APCs being hijacked multiple times at once is no longer possible, preventing some issues" diff --git a/html/changelogs/AutoChangeLog-pr-13653.yml b/html/changelogs/AutoChangeLog-pr-13653.yml deleted file mode 100644 index 2f920da353..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13653.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "MrJWhit" -delete-after: True -changes: - - tweak: "Minor fixes to kilo" diff --git a/html/changelogs/AutoChangeLog-pr-13654.yml b/html/changelogs/AutoChangeLog-pr-13654.yml deleted file mode 100644 index cb67c6e6be..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13654.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "ArchieBeepBoop" -delete-after: True -changes: - - bugfix: "Jacqueen and the Christmas tree should no longer spawn abstract things that can cause shittons of runtimes." diff --git a/html/changelogs/AutoChangeLog-pr-13655.yml b/html/changelogs/AutoChangeLog-pr-13655.yml deleted file mode 100644 index 6e48c84054..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13655.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - bugfix: "fixes held items proccing crossed when passing someone" diff --git a/html/changelogs/AutoChangeLog-pr-13656.yml b/html/changelogs/AutoChangeLog-pr-13656.yml deleted file mode 100644 index 017f0d99c2..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13656.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "MrJWhit" -delete-after: True -changes: - - admin: "Canceling events gives more time to stop from 10 to 30" diff --git a/html/changelogs/AutoChangeLog-pr-13657.yml b/html/changelogs/AutoChangeLog-pr-13657.yml deleted file mode 100644 index 6f445f6b71..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13657.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - bugfix: "The transmission sigil power drain works now" diff --git a/html/changelogs/AutoChangeLog-pr-13658.yml b/html/changelogs/AutoChangeLog-pr-13658.yml deleted file mode 100644 index 09b22d38ad..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13658.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - bugfix: "Scripture no longer sometimes eats part of its invocation." - - balance: "APCs and silicons are now more susceptible to powerdrains (by the power_drain() proc, which is rare)" - - balance: "Void Volt has been modified from a chant to a singular pulse." diff --git a/html/changelogs/AutoChangeLog-pr-13659.yml b/html/changelogs/AutoChangeLog-pr-13659.yml deleted file mode 100644 index 85eee3b78d..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13659.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - bugfix: "the load away mission verb won't crash the server now" diff --git a/html/changelogs/AutoChangeLog-pr-13661.yml b/html/changelogs/AutoChangeLog-pr-13661.yml deleted file mode 100644 index 81b5a735dc..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13661.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - rscadd: "added in-game age verification as an alternative to access requests" diff --git a/html/changelogs/AutoChangeLog-pr-13662.yml b/html/changelogs/AutoChangeLog-pr-13662.yml deleted file mode 100644 index 6ac16937d8..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13662.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "silicons" -delete-after: True -changes: - - rscadd: "you can now be an angel using a magic mirror again" diff --git a/html/changelogs/AutoChangeLog-pr-13669.yml b/html/changelogs/AutoChangeLog-pr-13669.yml deleted file mode 100644 index c682500501..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13669.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Arturlang" -delete-after: True -changes: - - tweak: "Being sacrificed by the cult no longer removes all hope of rescue." diff --git a/html/changelogs/AutoChangeLog-pr-13670.yml b/html/changelogs/AutoChangeLog-pr-13670.yml deleted file mode 100644 index 594e459d5a..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13670.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "shellspeed1" -delete-after: True -changes: - - tweak: "Floor bots are now buildable with all toolboxes." diff --git a/html/changelogs/AutoChangeLog-pr-13671.yml b/html/changelogs/AutoChangeLog-pr-13671.yml deleted file mode 100644 index 855028d9ed..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13671.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - code_imp: "Clockwork rites now support hiding specific rites from neutered servants." diff --git a/html/changelogs/AutoChangeLog-pr-13673.yml b/html/changelogs/AutoChangeLog-pr-13673.yml deleted file mode 100644 index 40b45d80f4..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13673.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Arturlang" -delete-after: True -changes: - - bugfix: "Makes construct mind returning more robust" diff --git a/html/changelogs/AutoChangeLog-pr-13674.yml b/html/changelogs/AutoChangeLog-pr-13674.yml deleted file mode 100644 index ccbd96aeb4..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13674.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - bugfix: "The borg VTEC ability now actually gets removed when the upgrade is removed." diff --git a/html/changelogs/AutoChangeLog-pr-13675.yml b/html/changelogs/AutoChangeLog-pr-13675.yml deleted file mode 100644 index d46d4490d3..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13675.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - bugfix: "Sleeper UI interactiveness now behaves correctly." diff --git a/html/changelogs/AutoChangeLog-pr-13676.yml b/html/changelogs/AutoChangeLog-pr-13676.yml deleted file mode 100644 index d584af38dc..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13676.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - bugfix: "Fixes a minor incorrectness in ratvarian borg slabs (ratvar_act -> ui_act)" diff --git a/html/changelogs/AutoChangeLog-pr-13678.yml b/html/changelogs/AutoChangeLog-pr-13678.yml deleted file mode 100644 index 261ecc3475..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13678.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Arturlang" -delete-after: True -changes: - - code_imp: "Comments out spaceman dmm do not sleeps for mob/proc/CommonClickOn, atom/proc/attack_hand, datum/proc/keyLoop and mob/living/proc/Life" diff --git a/html/changelogs/AutoChangeLog-pr-13679.yml b/html/changelogs/AutoChangeLog-pr-13679.yml deleted file mode 100644 index 37b9d287b0..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13679.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - rscadd: "Robots (anyone with the robotic_organism trait) have toxins damage replaced with system corruption. See the PR for details." diff --git a/html/changelogs/AutoChangeLog-pr-13680.yml b/html/changelogs/AutoChangeLog-pr-13680.yml deleted file mode 100644 index a1e58ac3a5..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13680.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - bugfix: "A runtime caused by hallucinations is gone." diff --git a/html/changelogs/AutoChangeLog-pr-13681.yml b/html/changelogs/AutoChangeLog-pr-13681.yml deleted file mode 100644 index c51a7b51b0..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13681.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - bugfix: "Supplypods shouldn't cause runtimes anymore, and shrapnel (pelletclouds) should work for them." diff --git a/html/changelogs/AutoChangeLog-pr-13682.yml b/html/changelogs/AutoChangeLog-pr-13682.yml deleted file mode 100644 index e5fececf4e..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13682.yml +++ /dev/null @@ -1,7 +0,0 @@ -author: "EmeraldSundisk" -delete-after: True -changes: - - bugfix: "Changes the area designations to be not varedited since the code didn't like that anymore" - - bugfix: "The cargo bay conveyor belts not only work with the shuttle now but go in the right direction to boot" - - tweak: "Slight visual adjustments to cargo in light of this" - - rscadd: "The arcade's got RAD carpet now" diff --git a/html/changelogs/AutoChangeLog-pr-13683.yml b/html/changelogs/AutoChangeLog-pr-13683.yml deleted file mode 100644 index da7ecab5c6..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13683.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SandPoot" -delete-after: True -changes: - - code_imp: "Swaps the gift static blacklist with a global list one." diff --git a/html/changelogs/AutoChangeLog-pr-13685.yml b/html/changelogs/AutoChangeLog-pr-13685.yml deleted file mode 100644 index 10d53c9065..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13685.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "uomo91" -delete-after: True -changes: - - bugfix: "Fixed \"Show All\" tab in player panel logs being broken." - - bugfix: "Whispers, OOC, and various other things display differently in logs, visually distinguishing them from say logs." - - refactor: "Player panel logs will now show all logs chronologically, so you'll see commingled say and attack logs if you're on the \"Show All\" tab, etc..." diff --git a/html/changelogs/AutoChangeLog-pr-13686.yml b/html/changelogs/AutoChangeLog-pr-13686.yml deleted file mode 100644 index 72f9a2bd54..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13686.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Arturlang" -delete-after: True -changes: - - bugfix: "Hopefully fixes whitescreen issues for TGUI UI's by giving assets more time to get to the client" diff --git a/html/changelogs/AutoChangeLog-pr-13687.yml b/html/changelogs/AutoChangeLog-pr-13687.yml deleted file mode 100644 index e2baddbd2a..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13687.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "silicons" -delete-after: True -changes: - - rscadd: "tailed individuals can now target groin to intertwine tails on grab intent." diff --git a/html/changelogs/AutoChangeLog-pr-13688.yml b/html/changelogs/AutoChangeLog-pr-13688.yml deleted file mode 100644 index 4013705549..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13688.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - bugfix: "Repeatable surgery steps can no longer cause an infinite loop if not completing the do_after" diff --git a/html/changelogs/AutoChangeLog-pr-13689.yml b/html/changelogs/AutoChangeLog-pr-13689.yml deleted file mode 100644 index eb476895e7..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13689.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - bugfix: "Recharging APCs no longer use 0.2% of the power they should be using." - - bugfix: "APCs no longer always use as much power as they can for their cell, even if it is full." diff --git a/html/changelogs/AutoChangeLog-pr-13694.yml b/html/changelogs/AutoChangeLog-pr-13694.yml deleted file mode 100644 index 75a4bbb549..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13694.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Acer202, with minor help from The0bserver" -delete-after: True -changes: - - rscadd: "After internal deliberation, CentCom has decided to run a limited reinstatement of public mining shuttles for use in more tried and true station classes. CentCom would like to remind you that this privilege is easily revoked, and that abuse may result in immediate detonation." - - rscadd: "Restores the mining shuttle on Pubby, Box, Delta, Meta, and Lambda Station." diff --git a/html/changelogs/AutoChangeLog-pr-13695.yml b/html/changelogs/AutoChangeLog-pr-13695.yml deleted file mode 100644 index 551d1f4df5..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13695.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "shellspeed1" -delete-after: True -changes: - - balance: "Lings now have infinite space for DNA." diff --git a/html/changelogs/AutoChangeLog-pr-13697.yml b/html/changelogs/AutoChangeLog-pr-13697.yml deleted file mode 100644 index 329a621c48..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13697.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Putnam3145" -delete-after: True -changes: - - balance: "Spontaneous brain trauma now requires minimum 5 players" diff --git a/html/changelogs/AutoChangeLog-pr-13698.yml b/html/changelogs/AutoChangeLog-pr-13698.yml deleted file mode 100644 index 10072ba948..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13698.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - rscadd: "you can rebind communication hotkeys and they're the default now" diff --git a/html/changelogs/AutoChangeLog-pr-13699.yml b/html/changelogs/AutoChangeLog-pr-13699.yml deleted file mode 100644 index 5b2234224e..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13699.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "silicons" -delete-after: True -changes: - - tweak: "nanite resistances tweaked" - - rscadd: "new nanite programs added for locking the user out from being modified by consoles or antivirals." diff --git a/html/changelogs/AutoChangeLog-pr-13702.yml b/html/changelogs/AutoChangeLog-pr-13702.yml deleted file mode 100644 index 24f79c7cda..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13702.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Putnam3145" -delete-after: True -changes: - - tweak: "gear harness no longer magically covers up the body mechanically despite covering up nothing visually" diff --git a/html/changelogs/AutoChangeLog-pr-13703.yml b/html/changelogs/AutoChangeLog-pr-13703.yml deleted file mode 100644 index fd3ba2198f..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13703.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Putnam3145" -delete-after: True -changes: - - bugfix: "Dynamic vote no longer shows the none-storyteller." diff --git a/html/changelogs/AutoChangeLog-pr-13704.yml b/html/changelogs/AutoChangeLog-pr-13704.yml deleted file mode 100644 index 0ef8ca4a1d..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13704.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Putnam3145" -delete-after: True -changes: - - bugfix: "Emotes can properly be filtered for in TGUI." diff --git a/html/changelogs/AutoChangeLog-pr-13705.yml b/html/changelogs/AutoChangeLog-pr-13705.yml deleted file mode 100644 index c1b366aeb7..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13705.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "Putnam3145" -delete-after: True -changes: - - balance: "Rad collectors now get 1.25x as much energy from radiation" - - balance: "Rad collectors now put out 1.25x as much stored energy per tick" - - balance: "Above two rad collector changes give a total 56.25% power output increase" diff --git a/html/changelogs/AutoChangeLog-pr-13707.yml b/html/changelogs/AutoChangeLog-pr-13707.yml deleted file mode 100644 index a7dd977cca..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13707.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - balance: "Robotpeople are now fully immune to the effects of alcohol (drunkness etc.)" - - tweak: "Renames the alcohol intolerance trait in the code to make what it does more clear." diff --git a/html/changelogs/AutoChangeLog-pr-13711.yml b/html/changelogs/AutoChangeLog-pr-13711.yml deleted file mode 100644 index e6fde23e8c..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13711.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - tweak: "Medibots now ignore people they cannot help due to their biology." - - bugfix: "get_damaged_bodyparts() is no longer broken." diff --git a/html/changelogs/AutoChangeLog-pr-13713.yml b/html/changelogs/AutoChangeLog-pr-13713.yml deleted file mode 100644 index 36228f10c5..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13713.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - rscadd: "all gas masks (but welding + glass) can be alt clicked to show/hide identity" diff --git a/html/changelogs/AutoChangeLog-pr-13715.yml b/html/changelogs/AutoChangeLog-pr-13715.yml deleted file mode 100644 index 70b22a9bc9..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13715.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "MrJWhit" -delete-after: True -changes: - - tweak: "Removes an opposum from the wall" diff --git a/html/changelogs/AutoChangeLog-pr-13717.yml b/html/changelogs/AutoChangeLog-pr-13717.yml deleted file mode 100644 index 268730c58e..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13717.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Acer202" -delete-after: True -changes: - - bugfix: "Main mining shuttle should no longer look at the public mining shuttle and attempt to dock ontop of it. Monastery shuttle should now function again." diff --git a/html/changelogs/AutoChangeLog-pr-13719.yml b/html/changelogs/AutoChangeLog-pr-13719.yml deleted file mode 100644 index c676072a35..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13719.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "shellspeed1" -delete-after: True -changes: - - rscadd: "Construction bags have been added, use them to carry all sorts of construction bits." - - rscadd: "A recipe has been added to cloth stacks to make material and construction bags." - - balance: "Material bags and construction bags are now available in engineering lockers." diff --git a/html/changelogs/AutoChangeLog-pr-13721.yml b/html/changelogs/AutoChangeLog-pr-13721.yml deleted file mode 100644 index 44b3c7283c..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13721.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "MrJWhit" -delete-after: True -changes: - - tweak: "Increased christmas event from 22th to 27th to 10th to 27th" diff --git a/html/changelogs/AutoChangeLog-pr-13725.yml b/html/changelogs/AutoChangeLog-pr-13725.yml deleted file mode 100644 index 5105de865e..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13725.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "silicons" -delete-after: True -changes: - - bugfix: "keybinds generate anti-collision bindings where necessary automatically now" diff --git a/html/changelogs/AutoChangeLog-pr-13733.yml b/html/changelogs/AutoChangeLog-pr-13733.yml deleted file mode 100644 index a10719fdc6..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13733.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - bugfix: "Fixes the tail entwine messages displaying incorrectly." diff --git a/html/changelogs/AutoChangeLog-pr-13734.yml b/html/changelogs/AutoChangeLog-pr-13734.yml deleted file mode 100644 index a4ea9fdfac..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13734.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "keronshb" -delete-after: True -changes: - - bugfix: "Fixes Reflective Blobs" diff --git a/html/changelogs/AutoChangeLog-pr-13736.yml b/html/changelogs/AutoChangeLog-pr-13736.yml deleted file mode 100644 index dfa5e7cb66..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13736.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - tweak: "Abductors now can use experimental organ replacement surgery on robots / synthetics." diff --git a/html/changelogs/AutoChangeLog-pr-13737.yml b/html/changelogs/AutoChangeLog-pr-13737.yml deleted file mode 100644 index 6c1121256f..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13737.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "qwertyquerty" -delete-after: True -changes: - - bugfix: "Flash the screen on climax" diff --git a/html/changelogs/AutoChangeLog-pr-13738.yml b/html/changelogs/AutoChangeLog-pr-13738.yml deleted file mode 100644 index f34f9d505a..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13738.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "EdgeLordExe, MoonFalcon" -delete-after: True -changes: - - balance: "Ported a bunch of heretic-related tweaks and changes from tg" diff --git a/html/changelogs/AutoChangeLog-pr-13739.yml b/html/changelogs/AutoChangeLog-pr-13739.yml deleted file mode 100644 index 6db29bf922..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13739.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - bugfix: "custom eyes and tongues now properly carry across cloning" diff --git a/html/changelogs/AutoChangeLog-pr-13740.yml b/html/changelogs/AutoChangeLog-pr-13740.yml deleted file mode 100644 index 2bbd9b877a..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13740.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Linzolle" -delete-after: True -changes: - - bugfix: "lizard snouts are no longer *slightly* lighter than they are supposed to be." diff --git a/html/changelogs/AutoChangeLog-pr-13741.yml b/html/changelogs/AutoChangeLog-pr-13741.yml deleted file mode 100644 index c49015ab28..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13741.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - bugfix: "Objectives are no longer very broken." diff --git a/html/changelogs/AutoChangeLog-pr-13743.yml b/html/changelogs/AutoChangeLog-pr-13743.yml deleted file mode 100644 index 00ff1a55bd..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13743.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Linzolle" -delete-after: True -changes: - - bugfix: "entertainment monitors no longer invisible" - - rscadd: "entertainment monitors now light up and display text when motion is detected in thunderdome" diff --git a/html/changelogs/AutoChangeLog-pr-13745.yml b/html/changelogs/AutoChangeLog-pr-13745.yml deleted file mode 100644 index af6cb787b6..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13745.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Arturlang" -delete-after: True -changes: - - bugfix: "Handles more edge cases with construct soul returning" diff --git a/html/changelogs/AutoChangeLog-pr-13746.yml b/html/changelogs/AutoChangeLog-pr-13746.yml deleted file mode 100644 index 73c7ab4058..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13746.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "keronshb" -delete-after: True -changes: - - rscadd: "Adds more room to northwest maint" - - rscadd: "Adds a bridge between Atmos and the Turbine." diff --git a/html/changelogs/AutoChangeLog-pr-13747.yml b/html/changelogs/AutoChangeLog-pr-13747.yml deleted file mode 100644 index f8b6111c08..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13747.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "MrJWhit" -delete-after: True -changes: - - rscadd: "" - - tweak: "Added the ability for cargo to buy a large welding tank" - - imageadd: "Tweaked large tank reagent sprites to /tg/'s" diff --git a/html/changelogs/AutoChangeLog-pr-13750.yml b/html/changelogs/AutoChangeLog-pr-13750.yml deleted file mode 100644 index a89abdd440..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13750.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "EmeraldSundisk" -delete-after: True -changes: - - bugfix: "Fixes the conveyor belt issues in Delta Station's cargo wing" - - rscdel: "Removes some of the dirt around the affected area (presumably they would have cleaned it up while working on it)" - - rscadd: "Adds a floor light to fix the \"dark spot\" cargo had" diff --git a/html/changelogs/AutoChangeLog-pr-13751.yml b/html/changelogs/AutoChangeLog-pr-13751.yml deleted file mode 100644 index 2d8c964a14..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13751.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "silicons" -delete-after: True -changes: - - tweak: "text formatting now uses one character instead of two around the text to emphasize." diff --git a/html/changelogs/AutoChangeLog-pr-13752.yml b/html/changelogs/AutoChangeLog-pr-13752.yml deleted file mode 100644 index 2175ed469b..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13752.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "silicons" -delete-after: True -changes: - - balance: "stamina crit is only removed when at or under 100 stamina, rather than 140. stamina crit threshold is still at 140." diff --git a/html/changelogs/AutoChangeLog-pr-13753.yml b/html/changelogs/AutoChangeLog-pr-13753.yml deleted file mode 100644 index e752df79a0..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13753.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "silicons" -delete-after: True -changes: - - balance: "shoving yourself up now costs 50% more" diff --git a/html/changelogs/AutoChangeLog-pr-13755.yml b/html/changelogs/AutoChangeLog-pr-13755.yml deleted file mode 100644 index e50cd0199f..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13755.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "silicons" -delete-after: True -changes: - - rscadd: "colormates" diff --git a/html/changelogs/AutoChangeLog-pr-13757.yml b/html/changelogs/AutoChangeLog-pr-13757.yml deleted file mode 100644 index a36e67943e..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13757.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - rscadd: "improvements to the automatic age gate" diff --git a/html/changelogs/AutoChangeLog-pr-13758.yml b/html/changelogs/AutoChangeLog-pr-13758.yml deleted file mode 100644 index fc4adc1614..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13758.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - tweak: "custom holoforms are now accessible through an action instead of through verbs" - - tweak: "AI holoforms can now emote" diff --git a/html/changelogs/AutoChangeLog-pr-13761.yml b/html/changelogs/AutoChangeLog-pr-13761.yml deleted file mode 100644 index c8ab365fe3..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13761.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "silicons" -delete-after: True -changes: - - balance: "dna melt drops all items being destroying you" diff --git a/html/changelogs/AutoChangeLog-pr-13762.yml b/html/changelogs/AutoChangeLog-pr-13762.yml deleted file mode 100644 index 841e4d91c0..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13762.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "silicons" -delete-after: True -changes: - - tweak: "luxury shuttle no longer has noteleport" diff --git a/html/changelogs/AutoChangeLog-pr-13763.yml b/html/changelogs/AutoChangeLog-pr-13763.yml deleted file mode 100644 index 68eeaf1022..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13763.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Hatterhat" -delete-after: True -changes: - - tweak: "RPEDs now drop their lowest part tier first when quick-emptied (used inhand)." diff --git a/html/changelogs/AutoChangeLog-pr-13764.yml b/html/changelogs/AutoChangeLog-pr-13764.yml deleted file mode 100644 index 514705fd78..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13764.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Hatterhat" -delete-after: True -changes: - - tweak: "Exosuits sold on the Supply shuttle no longer leave wreckages." diff --git a/html/changelogs/AutoChangeLog-pr-13765.yml b/html/changelogs/AutoChangeLog-pr-13765.yml deleted file mode 100644 index 7ca1695d0f..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13765.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "MrJWhit" -delete-after: True -changes: - - tweak: "Updated jukebox sprite." diff --git a/html/changelogs/AutoChangeLog-pr-13766.yml b/html/changelogs/AutoChangeLog-pr-13766.yml deleted file mode 100644 index 8ba317afed..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13766.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "MrJWhit" -delete-after: True -changes: - - tweak: "Updates our dark gygax sprites to /tg/'s" diff --git a/html/changelogs/AutoChangeLog-pr-13767.yml b/html/changelogs/AutoChangeLog-pr-13767.yml deleted file mode 100644 index 2d38af77e3..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13767.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "MrJWhit" -delete-after: True -changes: - - tweak: "Updated meat icons" diff --git a/html/changelogs/AutoChangeLog-pr-13769.yml b/html/changelogs/AutoChangeLog-pr-13769.yml deleted file mode 100644 index 04d1cbc11c..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13769.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "MrJWhit" -delete-after: True -changes: - - rscadd: "Adds a goose bar sign" diff --git a/html/changelogs/AutoChangeLog-pr-13771.yml b/html/changelogs/AutoChangeLog-pr-13771.yml deleted file mode 100644 index e450508681..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13771.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "MrJWhit" -delete-after: True -changes: - - tweak: "Donut boxes show what's inside of them now" diff --git a/html/changelogs/AutoChangeLog-pr-13772.yml b/html/changelogs/AutoChangeLog-pr-13772.yml deleted file mode 100644 index 109360cace..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13772.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "silicons" -delete-after: True -changes: - - rscadd: "players can now respawn/return to lobby as a ghost after a 15 minute (default) delay and rejoin on another character with some/many restrictions" - - rscadd: "cryo now preserves everything" diff --git a/html/changelogs/AutoChangeLog-pr-13773.yml b/html/changelogs/AutoChangeLog-pr-13773.yml deleted file mode 100644 index 498ac42561..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13773.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "Trilbyspaceclone" -delete-after: True -changes: - - tweak: "Zeolites now use gold rather then uranium for catalyst" - - tweak: "Zeolites are not as hard to make ph wise" - - tweak: "Making Zeolites heats up the beaker less allowing for better control" diff --git a/html/changelogs/AutoChangeLog-pr-13774.yml b/html/changelogs/AutoChangeLog-pr-13774.yml deleted file mode 100644 index ea3af475f2..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13774.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "keronshb" -delete-after: True -changes: - - rscadd: "Re-adds the Clown Car to the clown uplink" - - balance: "15 >16 TC cost" - - balance: "bonks on external airlocks" diff --git a/html/changelogs/AutoChangeLog-pr-13776.yml b/html/changelogs/AutoChangeLog-pr-13776.yml deleted file mode 100644 index 773aae9745..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13776.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - tweak: "AIs now only have to kill people once instead of permanently." diff --git a/html/changelogs/AutoChangeLog-pr-13777.yml b/html/changelogs/AutoChangeLog-pr-13777.yml deleted file mode 100644 index 0013a93ef5..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13777.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "The Grinch" -delete-after: True -changes: - - rscdel: "infinite presents from hilbert hotel" diff --git a/html/changelogs/AutoChangeLog-pr-13784.yml b/html/changelogs/AutoChangeLog-pr-13784.yml deleted file mode 100644 index df8cf7ad57..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13784.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "MrJWhit" -delete-after: True -changes: - - bugfix: "Effects can no longer trigger landmines" diff --git a/html/changelogs/AutoChangeLog-pr-13785.yml b/html/changelogs/AutoChangeLog-pr-13785.yml deleted file mode 100644 index 973fb3f74e..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13785.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Putnam3145" -delete-after: True -changes: - - tweak: "Grab bag works as advertised." - - balance: "Xeno threat in dynamic tripled." diff --git a/html/changelogs/AutoChangeLog-pr-13790.yml b/html/changelogs/AutoChangeLog-pr-13790.yml deleted file mode 100644 index 45ebf00ee7..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13790.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "MrJWhit" -delete-after: True -changes: - - tweak: "Replaced engineering fuel tank with a large fuel tank" - - tweak: "Changed access to sec suit storage from armory access in every map to other security access" diff --git a/html/changelogs/AutoChangeLog-pr-13796.yml b/html/changelogs/AutoChangeLog-pr-13796.yml deleted file mode 100644 index 827cbf7443..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13796.yml +++ /dev/null @@ -1,9 +0,0 @@ -author: "keronshb" -delete-after: True -changes: - - rscadd: "Adds a reduced stamina buffer for SCarp users" - - rscadd: "Gives SCarp users a better parry" - - rscadd: "Adds the SCarp bundle which includes a bo staff" - - rscadd: "Lets Carp costumes carry Bo Staffs" - - balance: "reduces the stamina damage of scarp slightly" - - balance: "reduced the blockchance of the bo staff" diff --git a/html/changelogs/AutoChangeLog-pr-13799.yml b/html/changelogs/AutoChangeLog-pr-13799.yml deleted file mode 100644 index 4f8168aa45..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13799.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "silicons" -delete-after: True -changes: - - bugfix: "ninja gloves no longer hardstun" - - balance: "ninja gloves now cost half as much to use to compensate" diff --git a/html/changelogs/AutoChangeLog-pr-13801.yml b/html/changelogs/AutoChangeLog-pr-13801.yml deleted file mode 100644 index e33b6f4056..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13801.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "SandPoot" -delete-after: True -changes: - - refactor: "Changes the limb grower a lot." - - bugfix: "\"Limb\" costs on limbgrower are actually displayed like it was meant to all along." diff --git a/html/changelogs/AutoChangeLog-pr-13803.yml b/html/changelogs/AutoChangeLog-pr-13803.yml deleted file mode 100644 index 68791ea87a..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13803.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "BlueWildrose" -delete-after: True -changes: - - balance: "The traitor AI can no longer activate the doomsday device while carded." diff --git a/html/changelogs/AutoChangeLog-pr-13804.yml b/html/changelogs/AutoChangeLog-pr-13804.yml deleted file mode 100644 index 6b6d56dc5c..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13804.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - bugfix: "circuits get pin data proc is sanitized when text is returned as data" diff --git a/html/changelogs/AutoChangeLog-pr-13808.yml b/html/changelogs/AutoChangeLog-pr-13808.yml deleted file mode 100644 index fc97da6161..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13808.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Putnam3145" -delete-after: True -changes: - - tweak: "You can now exit polycircuit input" - - bugfix: "Polycircuits now check for range" diff --git a/html/changelogs/AutoChangeLog-pr-13809.yml b/html/changelogs/AutoChangeLog-pr-13809.yml deleted file mode 100644 index d63ee33ff1..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13809.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Putnam3145" -delete-after: True -changes: - - tweak: "Gear harness now covers nothing." diff --git a/html/changelogs/AutoChangeLog-pr-13811.yml b/html/changelogs/AutoChangeLog-pr-13811.yml deleted file mode 100644 index da2691d8f5..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13811.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "BlackMajor" -delete-after: True -changes: - - tweak: "Cyborg hypospray no longer injects if it means OD'ing while on help intent." diff --git a/html/changelogs/AutoChangeLog-pr-13813.yml b/html/changelogs/AutoChangeLog-pr-13813.yml deleted file mode 100644 index ce283eb788..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13813.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "silicons" -delete-after: True -changes: - - tweak: "command headsets are 120% instead of 160%" - - bugfix: "no more emote italics" diff --git a/html/changelogs/AutoChangeLog-pr-13814.yml b/html/changelogs/AutoChangeLog-pr-13814.yml deleted file mode 100644 index 9bd0be5ac0..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13814.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Xantholne" -delete-after: True -changes: - - bugfix: "Twin Sword Sheaths have an equipment icon and icon when worn now and make a sound when sheathed/unsheathed" diff --git a/html/changelogs/AutoChangeLog-pr-13815.yml b/html/changelogs/AutoChangeLog-pr-13815.yml deleted file mode 100644 index 630ca9d7f7..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13815.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Yakumo Chen" -delete-after: True -changes: - - balance: "Slime Jelly is no longer obtainable from slimepeople. Go ask Xenobio" diff --git a/html/changelogs/AutoChangeLog-pr-13819.yml b/html/changelogs/AutoChangeLog-pr-13819.yml deleted file mode 100644 index 77b1ec9a3d..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13819.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Hatterhat" -delete-after: True -changes: - - bugfix: "The survival dagger light on the sprite now actually turns on and off." - - balance: "The survival dagger in the glaive kit that can also be bought by itself is now better at butchering things." diff --git a/html/changelogs/AutoChangeLog-pr-13822.yml b/html/changelogs/AutoChangeLog-pr-13822.yml deleted file mode 100644 index 743bdb500b..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13822.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - bugfix: "Bloodcult stunhands now work against clockies like they were supposed to instead of hardstunning." diff --git a/html/changelogs/AutoChangeLog-pr-13823.yml b/html/changelogs/AutoChangeLog-pr-13823.yml deleted file mode 100644 index 35d70339f7..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13823.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "MrJWhit" -delete-after: True -changes: - - tweak: "Christmas starts on the 18th now" diff --git a/html/changelogs/AutoChangeLog-pr-13825.yml b/html/changelogs/AutoChangeLog-pr-13825.yml deleted file mode 100644 index ae82c1cd8e..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13825.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "raspy-on-osu" -delete-after: True -changes: - - tweak: "windoor open length" diff --git a/html/changelogs/AutoChangeLog-pr-13828.yml b/html/changelogs/AutoChangeLog-pr-13828.yml deleted file mode 100644 index 282b8a01e0..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13828.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - bugfix: "you can now only entwine tails with people who have a tail" diff --git a/html/changelogs/AutoChangeLog-pr-13830.yml b/html/changelogs/AutoChangeLog-pr-13830.yml deleted file mode 100644 index c126670246..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13830.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - bugfix: "apids render now" diff --git a/html/changelogs/AutoChangeLog-pr-13832.yml b/html/changelogs/AutoChangeLog-pr-13832.yml deleted file mode 100644 index 756edb7657..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13832.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Arturlang" -delete-after: True -changes: - - bugfix: "Bloodsuckers tresspass ability can no longer work while they are not awake." diff --git a/html/changelogs/AutoChangeLog-pr-13833.yml b/html/changelogs/AutoChangeLog-pr-13833.yml deleted file mode 100644 index 8312c7a5a3..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13833.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "kiwedespars" -delete-after: True -changes: - - balance: "balanced bone gauntlets." diff --git a/html/changelogs/AutoChangeLog-pr-13834.yml b/html/changelogs/AutoChangeLog-pr-13834.yml deleted file mode 100644 index 46cedff5d5..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13834.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "zeroisthebiggay" -delete-after: True -changes: - - rscadd: "Traitor assistants can now purchase the patented POGBox! Put TC into it for even higher damage!" diff --git a/html/changelogs/AutoChangeLog-pr-13835.yml b/html/changelogs/AutoChangeLog-pr-13835.yml deleted file mode 100644 index 0ac90921c3..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13835.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "silicons" -delete-after: True -changes: - - rscadd: "pugilists can now parry" diff --git a/html/changelogs/AutoChangeLog-pr-13837.yml b/html/changelogs/AutoChangeLog-pr-13837.yml deleted file mode 100644 index eda0b77a83..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13837.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "silicons" -delete-after: True -changes: - - tweak: "anyone new to the server is lucky enough to have their sprint default to toggle instead of hold" diff --git a/html/changelogs/AutoChangeLog-pr-13838.yml b/html/changelogs/AutoChangeLog-pr-13838.yml deleted file mode 100644 index deff5913b3..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13838.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "silicons" -delete-after: True -changes: - - bugfix: "things in DEATHCOMA do not deathgasp on death" diff --git a/html/changelogs/AutoChangeLog-pr-13844.yml b/html/changelogs/AutoChangeLog-pr-13844.yml deleted file mode 100644 index cd1f7a25d4..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13844.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Arturlang" -delete-after: True -changes: - - bugfix: "Fixes the mint machine's UI" diff --git a/html/changelogs/AutoChangeLog-pr-13845.yml b/html/changelogs/AutoChangeLog-pr-13845.yml deleted file mode 100644 index d10485ae9f..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13845.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "silicons" -delete-after: True -changes: - - bugfix: "dullahans enabled" diff --git a/html/changelogs/AutoChangeLog-pr-13846.yml b/html/changelogs/AutoChangeLog-pr-13846.yml deleted file mode 100644 index 68e013acf0..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13846.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - balance: "Fleshmend, Anatomic Panacea and bloodsucker healing now work for Synths / IPCs." diff --git a/html/changelogs/AutoChangeLog-pr-13850.yml b/html/changelogs/AutoChangeLog-pr-13850.yml deleted file mode 100644 index 64c47ade40..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13850.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - bugfix: "Self-fueling weldingtools recharge fuel properly again." - - bugfix: "Brass welders now actually recharge faster than experimental ones." diff --git a/html/changelogs/AutoChangeLog-pr-13855.yml b/html/changelogs/AutoChangeLog-pr-13855.yml deleted file mode 100644 index 0eed195acd..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13855.yml +++ /dev/null @@ -1,8 +0,0 @@ -author: "Chiirno" -delete-after: True -changes: - - rscadd: "Paramedics office and Surgery Storage Room" - - tweak: "Remodeled the surgery room, as well as shrunk Morgue and Starboard Emergency Storage. -Fiddled with some areas for better map edit clarity and fixed one runtime in Vacant Office A." - - imageadd: "Added the paramedic closet sprite, a paramedic colored medical3 closet." - - code_imp: "Added a paramedic closet, which is the standard medical3 closet with their suit, a pinpointer, and a crew monitor added." diff --git a/html/changelogs/AutoChangeLog-pr-13856.yml b/html/changelogs/AutoChangeLog-pr-13856.yml deleted file mode 100644 index 583fb38cc2..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13856.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Putnam3145" -delete-after: True -changes: - - bugfix: "gear harness alt-click is now sane" - - code_imp: "rolldown() and toggle_jumpsuit_adjust() now no longer mix behavior-that-should-be-overridden and behavior-that-shouldn't-be-overridden in ways that make no sense." diff --git a/html/changelogs/AutoChangeLog-pr-13859.yml b/html/changelogs/AutoChangeLog-pr-13859.yml deleted file mode 100644 index 2d6dc5c25a..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13859.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - rscadd: "adds unlockable loadout items, corresponding category in loadouts, etc" diff --git a/html/changelogs/AutoChangeLog-pr-13867.yml b/html/changelogs/AutoChangeLog-pr-13867.yml deleted file mode 100644 index dd1e44e64c..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13867.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Putnam3145" -delete-after: True -changes: - - balance: "Zeolites now only generate 1/5 the heat when reacting and don't require a catalyst." diff --git a/html/changelogs/AutoChangeLog-pr-13869.yml b/html/changelogs/AutoChangeLog-pr-13869.yml deleted file mode 100644 index 5d4ca4817c..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13869.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - tweak: "slime puddles are no longer layered down one layer" - - tweak: "you cannot tackle with two paralysed arms" - - tweak: "tackling with a single paralysed arm lowers your tackle roll by 2" diff --git a/html/changelogs/AutoChangeLog-pr-13870.yml b/html/changelogs/AutoChangeLog-pr-13870.yml deleted file mode 100644 index 820c524224..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13870.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "silicons" -delete-after: True -changes: - - bugfix: "Magrifle ammo no longer glows." diff --git a/html/changelogs/AutoChangeLog-pr-13871.yml b/html/changelogs/AutoChangeLog-pr-13871.yml deleted file mode 100644 index f667abe816..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13871.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "NT Cleaning Crews On Break" -delete-after: True -changes: - - rscadd: "Most kinds of dirt, grime, and debris are now persistent. Get to work, jannies." - - rscadd: "Dirt can now be removed by tile replacements. Other cleanable decals can't, though." diff --git a/html/changelogs/AutoChangeLog-pr-13873.yml b/html/changelogs/AutoChangeLog-pr-13873.yml deleted file mode 100644 index 320a5b69a4..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13873.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "BlueWildrose" -delete-after: True -changes: - - tweak: "Nyctophobia quirk now has some light lag compensation." diff --git a/html/changelogs/AutoChangeLog-pr-13881.yml b/html/changelogs/AutoChangeLog-pr-13881.yml deleted file mode 100644 index 0ad2d3afc8..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13881.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "BlueWildrose" -delete-after: True -changes: - - rscadd: "PubbyStation now has two Christmas Tree spawners." diff --git a/html/changelogs/AutoChangeLog-pr-13882.yml b/html/changelogs/AutoChangeLog-pr-13882.yml deleted file mode 100644 index fe545bdc23..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13882.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "ERP mains" -delete-after: True -changes: - - rscadd: "Subtler Around Table is now a verb" diff --git a/html/changelogs/AutoChangeLog-pr-13883.yml b/html/changelogs/AutoChangeLog-pr-13883.yml deleted file mode 100644 index 884adafffe..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13883.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "silicons" -delete-after: True -changes: - - rscadd: "set-pose has been added" - - tweak: "temporary flavor text renamed to set pose, fully visible in examine" diff --git a/html/changelogs/AutoChangeLog-pr-13884.yml b/html/changelogs/AutoChangeLog-pr-13884.yml deleted file mode 100644 index f2b9233690..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13884.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Hatterhat" -delete-after: True -changes: - - rscadd: "The dock-silver standard set by Box and Meta has been enforced across maps in rotation (Delta, Pubby, Lambda)." - - bugfix: "The Box whiteship now has its missing tiny fan back." diff --git a/html/changelogs/AutoChangeLog-pr-13885.yml b/html/changelogs/AutoChangeLog-pr-13885.yml deleted file mode 100644 index 88c23d30f1..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13885.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "raspy-on-osu" -delete-after: True -changes: - - tweak: "space heater heating range and power" diff --git a/html/changelogs/AutoChangeLog-pr-13887.yml b/html/changelogs/AutoChangeLog-pr-13887.yml deleted file mode 100644 index 83069a4e64..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13887.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "HeroWithYay" -delete-after: True -changes: - - bugfix: "Changed description of Necrotizing Fasciitis symptom." diff --git a/html/changelogs/AutoChangeLog-pr-13892.yml b/html/changelogs/AutoChangeLog-pr-13892.yml deleted file mode 100644 index 976b395826..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13892.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "silicons" -delete-after: True -changes: - - balance: "changeling combat mutations rebalanced. most of them take chemicals to upkeep now." diff --git a/html/changelogs/AutoChangeLog-pr-13893.yml b/html/changelogs/AutoChangeLog-pr-13893.yml deleted file mode 100644 index 9eb7a3f79d..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13893.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "silicons" -delete-after: True -changes: - - tweak: "Meth and changeling adrenals no longer ignore all slowdowns, rather damage slowdowns." diff --git a/html/changelogs/AutoChangeLog-pr-13894.yml b/html/changelogs/AutoChangeLog-pr-13894.yml deleted file mode 100644 index 31e1e66328..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13894.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "silicons" -delete-after: True -changes: - - tweak: "temperature slowdown divisor nerfed to 35 from 20." diff --git a/html/changelogs/AutoChangeLog-pr-13896.yml b/html/changelogs/AutoChangeLog-pr-13896.yml deleted file mode 100644 index f733efa09d..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13896.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "Sonic121x" -delete-after: True -changes: - - rscadd: "alarm ert hardsuit sprite for naga and canine" - - tweak: "adjust the naga ert hardsuit to cover the hand" - - bugfix: "cydonia hardsuit helmet" diff --git a/html/changelogs/AutoChangeLog-pr-13897.yml b/html/changelogs/AutoChangeLog-pr-13897.yml deleted file mode 100644 index 05637b0908..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13897.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "keronshb" -delete-after: True -changes: - - bugfix: "Allows Energy Bola to be caught" - - balance: "This also allows them to be dropped/picked up." diff --git a/html/changelogs/AutoChangeLog-pr-13898.yml b/html/changelogs/AutoChangeLog-pr-13898.yml deleted file mode 100644 index cb4e0fd52d..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13898.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Putnam3145" -delete-after: True -changes: - - balance: "Regen coma now puts into a coma even from crit or while unconscious." - - bugfix: "Regen coma now properly weakens while asleep." diff --git a/html/changelogs/AutoChangeLog-pr-13900.yml b/html/changelogs/AutoChangeLog-pr-13900.yml deleted file mode 100644 index a25c8af1ed..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13900.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Xantholne" -delete-after: True -changes: - - rscadd: "New parrots from the RP server, can be found in Bird Crate in Cargo" diff --git a/html/changelogs/AutoChangeLog-pr-13902.yml b/html/changelogs/AutoChangeLog-pr-13902.yml deleted file mode 100644 index ca548d816f..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13902.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - rscadd: "avian/digitigrade legs have been added for slimes" diff --git a/html/changelogs/AutoChangeLog-pr-13903.yml b/html/changelogs/AutoChangeLog-pr-13903.yml deleted file mode 100644 index fd66c4b0c6..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13903.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - bugfix: "Changelings no longer double-deathgasp when activating the regen stasis ability while not dead." diff --git a/html/changelogs/AutoChangeLog-pr-13904.yml b/html/changelogs/AutoChangeLog-pr-13904.yml deleted file mode 100644 index 90f7d77e17..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13904.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - tweak: "Instant summons can no longer do wacky stuff with disposals (and nukes)." diff --git a/html/changelogs/AutoChangeLog-pr-13905.yml b/html/changelogs/AutoChangeLog-pr-13905.yml deleted file mode 100644 index 16b464bc20..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13905.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "zeroisthebiggay" -delete-after: True -changes: - - imageadd: "cool codex cicatrix inhands" diff --git a/html/changelogs/AutoChangeLog-pr-13909.yml b/html/changelogs/AutoChangeLog-pr-13909.yml deleted file mode 100644 index e4f0f1e401..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13909.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "silicons" -delete-after: True -changes: - - rscadd: "Twitch Plays: Clown Car" diff --git a/html/changelogs/AutoChangeLog-pr-13911.yml b/html/changelogs/AutoChangeLog-pr-13911.yml deleted file mode 100644 index 9e96103b2b..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13911.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "raspy-on-osu" -delete-after: True -changes: - - spellcheck: "salicylic acid" diff --git a/html/changelogs/AutoChangeLog-pr-13913.yml b/html/changelogs/AutoChangeLog-pr-13913.yml deleted file mode 100644 index a25e054a6f..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13913.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "keronshb" -delete-after: True -changes: - - bugfix: "Fixes the parry data for scarp" diff --git a/html/changelogs/AutoChangeLog-pr-13914.yml b/html/changelogs/AutoChangeLog-pr-13914.yml deleted file mode 100644 index b9efe2a893..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13914.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "EmeraldSundisk" -delete-after: True -changes: - - rscadd: "Adds a few new area designations primarily for CogStation, incorporates them into said map" - - tweak: "Reorganizes some area designations for ease of use, along with renaming the central \"Router\" to \"Routing Depot\"" - - bugfix: "Fixes an incorrectly designated area in CogStation" diff --git a/html/changelogs/AutoChangeLog-pr-13915.yml b/html/changelogs/AutoChangeLog-pr-13915.yml deleted file mode 100644 index 2853dcb9ad..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13915.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Xantholne" -delete-after: True -changes: - - bugfix: "Fixed new birds changing back to basic parrot when sitting" diff --git a/html/changelogs/AutoChangeLog-pr-13916.yml b/html/changelogs/AutoChangeLog-pr-13916.yml deleted file mode 100644 index 0ec04707a5..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13916.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - rscadd: "re-adds the holoform verb for people who want to use it over going through the char list" diff --git a/html/changelogs/AutoChangeLog-pr-13917.yml b/html/changelogs/AutoChangeLog-pr-13917.yml deleted file mode 100644 index 5eabd640f7..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13917.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - rscadd: "*squeak" diff --git a/html/changelogs/AutoChangeLog-pr-13924.yml b/html/changelogs/AutoChangeLog-pr-13924.yml deleted file mode 100644 index 71092c567d..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13924.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SandPoot" -delete-after: True -changes: - - tweak: "You can attack a pile of money on the floor with your id to put it all in quickly." diff --git a/html/changelogs/AutoChangeLog-pr-13926.yml b/html/changelogs/AutoChangeLog-pr-13926.yml deleted file mode 100644 index 4e92bacdb4..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13926.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "MrJWhit" -delete-after: True -changes: - - rscdel: "Removes the screen flashing on climax." diff --git a/html/changelogs/AutoChangeLog-pr-13930.yml b/html/changelogs/AutoChangeLog-pr-13930.yml deleted file mode 100644 index 282f3fa30a..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13930.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "MrJWhit" -delete-after: True -changes: - - tweak: "Small fixes on security on boxstation" diff --git a/html/changelogs/AutoChangeLog-pr-13931.yml b/html/changelogs/AutoChangeLog-pr-13931.yml deleted file mode 100644 index fd903f2d6e..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13931.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "shellspeed1" -delete-after: True -changes: - - rscadd: "Adds the disposable sentry gun from tg for 11tc each." diff --git a/html/changelogs/AutoChangeLog-pr-13932.yml b/html/changelogs/AutoChangeLog-pr-13932.yml deleted file mode 100644 index 955d9f5741..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13932.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "shellspeed1" -delete-after: True -changes: - - tweak: "Xenomorph powers now list plasma cost in their description." diff --git a/html/changelogs/AutoChangeLog-pr-13934.yml b/html/changelogs/AutoChangeLog-pr-13934.yml deleted file mode 100644 index 74f8ece6fc..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13934.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "shellspeed1" -delete-after: True -changes: - - rscadd: "The bluespace navigation gigabeacon design has been added to shuttle research for those wanting to take their ships around space more." diff --git a/html/changelogs/AutoChangeLog-pr-13936.yml b/html/changelogs/AutoChangeLog-pr-13936.yml deleted file mode 100644 index 9b15d2232a..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13936.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "BlueWildrose" -delete-after: True -changes: - - bugfix: "Polychromic hoodies that were obtained from the loadout have functional colorable hoods now." diff --git a/html/changelogs/AutoChangeLog-pr-13938.yml b/html/changelogs/AutoChangeLog-pr-13938.yml deleted file mode 100644 index 34d76a190b..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13938.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - rscadd: "anthromorphic synth species" diff --git a/html/changelogs/AutoChangeLog-pr-13940.yml b/html/changelogs/AutoChangeLog-pr-13940.yml deleted file mode 100644 index 60cbcc9a19..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13940.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Chiirno" -delete-after: True -changes: - - rscadd: "Added the paramedics EVA suit as a purchase from the cargo console." diff --git a/html/changelogs/AutoChangeLog-pr-13941.yml b/html/changelogs/AutoChangeLog-pr-13941.yml deleted file mode 100644 index 5a72376ebb..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13941.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Chiirno" -delete-after: True -changes: - - bugfix: "Portable Chem Mixer now researchable from biotech node." diff --git a/html/changelogs/AutoChangeLog-pr-13943.yml b/html/changelogs/AutoChangeLog-pr-13943.yml deleted file mode 100644 index 405d6b0d93..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13943.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "Hatterhat" -delete-after: True -changes: - - spellcheck: "Utility uniforms now comply with the \"nonproper equipment names\" thing." - - bugfix: "The CapDrobe now allows the captain to get his own clothes for free. Probably." - - tweak: "All captains' clothes now offer 15 woundarmor, up from the 5. Because apparently only the suit and tie and its suitskirt subtype have this wound armor, which is dumb." diff --git a/html/changelogs/AutoChangeLog-pr-13945.yml b/html/changelogs/AutoChangeLog-pr-13945.yml deleted file mode 100644 index 91b8bb9498..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13945.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - rscadd: "IPC cells & power cords are now printable after they are researched." diff --git a/html/changelogs/AutoChangeLog-pr-13946.yml b/html/changelogs/AutoChangeLog-pr-13946.yml deleted file mode 100644 index d7f3e15024..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13946.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Ryll/Shaps" -delete-after: True -changes: - - admin: "Fixed an issue with player logs becoming confused when someone triggers multiple events within one second (like being attacked by two people at the same time) that would cause holes in the logs" diff --git a/html/changelogs/AutoChangeLog-pr-13947.yml b/html/changelogs/AutoChangeLog-pr-13947.yml deleted file mode 100644 index 0388efc701..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13947.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Chiirno" -delete-after: True -changes: - - tweak: "Chem masters can now dispense 20 instances of its outputs instead of 10." diff --git a/html/changelogs/AutoChangeLog-pr-13948.yml b/html/changelogs/AutoChangeLog-pr-13948.yml deleted file mode 100644 index 73c5ba6b1a..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13948.yml +++ /dev/null @@ -1,11 +0,0 @@ -author: "necromanceranne" -delete-after: True -changes: - - rscadd: "Bokken now come in two lengths; full and wakizashi, and two varieties: wood and ironwood. They have different stats for all four." - - rscadd: "Bokken require menu crafting and part construction, as well as more complicated materials." - - tweak: "Bokken (long and short) require wood, cloth and leather to craft with a hatchet and screwdriver." - - tweak: "Ironwood bokken (long and short) require ironcap logs, cloth and leather to craft with a hatchet, screwdriver and welder." - - balance: "Twin sheathes can only fit a pair of blades (longsword + shortsword) or they can fit two shortswords." - - bugfix: "Fixed a twin sheath runtime." - - imageadd: "A lot of bokken related sprites received an overhaul. Added overlay sprites for weapons sheathed in the twin sheathes." - - imageadd: "The extradimensional blade received improved sprites for inhands/back sprites." diff --git a/html/changelogs/AutoChangeLog-pr-13950.yml b/html/changelogs/AutoChangeLog-pr-13950.yml deleted file mode 100644 index 28affe7ebe..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13950.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "TripleShades" -delete-after: True -changes: - - rscadd: "New Paramedic Office next to Genetics where the old Genetics Reception used to be -change: Surgery, Surgery Observation, and Recovery Hall layout revamped drastically -change: Maints below Surgery lowered by one tile to recover lost tile space from Surgery expansion" diff --git a/html/changelogs/AutoChangeLog-pr-13951.yml b/html/changelogs/AutoChangeLog-pr-13951.yml deleted file mode 100644 index fe3ac84523..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13951.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "BlueWildrose" -delete-after: True -changes: - - tweak: "You can now have a max-roundstart-dicksize-config inch long johnson before you start suffering blood loss and slowdowns instead of a 20 inch one." diff --git a/html/changelogs/AutoChangeLog-pr-13954.yml b/html/changelogs/AutoChangeLog-pr-13954.yml deleted file mode 100644 index a8751d66ca..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13954.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "EmeraldSundisk" -delete-after: True -changes: - - rscadd: "Adds a new \"Computer Core\" area designation for CogStation" - - bugfix: "Fixes some missing area strings" - - tweak: "Replaces some firelocks with directional ones as to ensure desks/counters can still be accessed" diff --git a/html/changelogs/AutoChangeLog-pr-13955.yml b/html/changelogs/AutoChangeLog-pr-13955.yml deleted file mode 100644 index 1d43dd6b95..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13955.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Chiirno" -delete-after: True -changes: - - tweak: "Nightmare now deals additional damage to most light sources." - - bugfix: "Nightmare now one-shots miners beacons and glowshrooms" diff --git a/html/changelogs/AutoChangeLog-pr-13959.yml b/html/changelogs/AutoChangeLog-pr-13959.yml deleted file mode 100644 index 1303768344..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13959.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "necromanceranne" -delete-after: True -changes: - - bugfix: "You can now make all the variants of the bokken." - - bugfix: "Removes a duplicate sprite." - - tweak: "Renames all instances of 'ironwood' to 'steelwood'." diff --git a/html/changelogs/AutoChangeLog-pr-13961.yml b/html/changelogs/AutoChangeLog-pr-13961.yml deleted file mode 100644 index f0a6cc267d..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13961.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "MrJWhit" -delete-after: True -changes: - - tweak: "Removed the wires connecting the AI from the rest of the station on cogstation." - - tweak: "Fixes experimenter on cogstation." - - tweak: "Less pipes in the overall area in toxins on cogstation" diff --git a/html/changelogs/AutoChangeLog-pr-13963.yml b/html/changelogs/AutoChangeLog-pr-13963.yml deleted file mode 100644 index 8a1e923aa0..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13963.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "necromanceranne" -delete-after: True -changes: - - rscadd: "Adds new roboticist labcoat sprites!" diff --git a/html/changelogs/AutoChangeLog-pr-13965.yml b/html/changelogs/AutoChangeLog-pr-13965.yml deleted file mode 100644 index 69f5a90122..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13965.yml +++ /dev/null @@ -1,7 +0,0 @@ -author: "Xantholne" -delete-after: True -changes: - - rscadd: "You can now tuck disky into bed" - - rscadd: "You can now make beds by applying a bed sheet to them" - - rscadd: "You can now tuck in pai cards into bed" - - rscadd: "Added bed tucking element, can be added to any held object to allow tucking into beds" diff --git a/html/changelogs/AutoChangeLog-pr-13967.yml b/html/changelogs/AutoChangeLog-pr-13967.yml deleted file mode 100644 index d2e580b531..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13967.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "keronshb" -delete-after: True -changes: - - balance: "Blob Resource Tower to 2 points per instead of 1 point per." - - balance: "Blob Factory Towers can be placed 5 tiles apart instead of 7." - - bugfix: "Fixes Blobbernaut Factories consuming Factories if no naut is chosen." diff --git a/html/changelogs/AutoChangeLog-pr-13968.yml b/html/changelogs/AutoChangeLog-pr-13968.yml deleted file mode 100644 index e3ce9e4615..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13968.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Arturlang" -delete-after: True -changes: - - tweak: "Prayers to admins now do a wee ding sound for all prayers, instead of just chaplains" diff --git a/html/changelogs/AutoChangeLog-pr-13970.yml b/html/changelogs/AutoChangeLog-pr-13970.yml deleted file mode 100644 index 54d8d9992d..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13970.yml +++ /dev/null @@ -1,8 +0,0 @@ -author: "TripleShades" -delete-after: True -changes: - - rscadd: "Firelock to Surgery Bay drapes -change: Swapped Nanomed and Fire Alarm button locations in both Surgery Bays -change: Removes the double mirror in both Surgery Bays to be a singular mirror -change: Moved an intercom to not be doorstuck below Paramedical Office -remove: One Surgery Observation Fire Alarm button" diff --git a/html/changelogs/AutoChangeLog-pr-13972.yml b/html/changelogs/AutoChangeLog-pr-13972.yml deleted file mode 100644 index fdfdd4786d..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13972.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "MrJWhit" -delete-after: True -changes: - - tweak: "Fixes maint area in boxstation" diff --git a/html/changelogs/AutoChangeLog-pr-13975.yml b/html/changelogs/AutoChangeLog-pr-13975.yml deleted file mode 100644 index ff643cd19c..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13975.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "zeroisthebiggay" -delete-after: True -changes: - - imageadd: "fuck the r*d cr*ss" diff --git a/html/changelogs/AutoChangeLog-pr-13976.yml b/html/changelogs/AutoChangeLog-pr-13976.yml deleted file mode 100644 index dac85f8e9a..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13976.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - rscadd: "you can teleport bread" diff --git a/html/changelogs/AutoChangeLog-pr-13978.yml b/html/changelogs/AutoChangeLog-pr-13978.yml deleted file mode 100644 index 94c19edec4..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13978.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "silicons" -delete-after: True -changes: - - balance: "c4 can no longer gib mobs" diff --git a/html/changelogs/AutoChangeLog-pr-13980.yml b/html/changelogs/AutoChangeLog-pr-13980.yml deleted file mode 100644 index 6838ba48a2..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13980.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "MrJWhit" -delete-after: True -changes: - - rscadd: "Makes gas sensors fireproof." diff --git a/html/changelogs/AutoChangeLog-pr-13983.yml b/html/changelogs/AutoChangeLog-pr-13983.yml deleted file mode 100644 index ba0bf62e6a..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13983.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "shellspeed1" -delete-after: True -changes: - - rscadd: "Xenomorph hybrids can now select wings -~~add: Xenomorph hybrids can now speak xenomorph~~" - - rscadd: "Xenomorph tongues are available for customization." diff --git a/html/changelogs/AutoChangeLog-pr-13988.yml b/html/changelogs/AutoChangeLog-pr-13988.yml deleted file mode 100644 index 262e5f804f..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13988.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - bugfix: "Cargo packs marked as 'no private buying' now actually register as such." diff --git a/html/changelogs/AutoChangeLog-pr-13993.yml b/html/changelogs/AutoChangeLog-pr-13993.yml deleted file mode 100644 index d99ed0e0d1..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13993.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Arturlang" -delete-after: True -changes: - - tweak: "The cursed heart now only takes away half as much blood every loop, and can be used as long as you are alive, instead if only you are awake/able to use your hands" diff --git a/html/changelogs/AutoChangeLog-pr-13995.yml b/html/changelogs/AutoChangeLog-pr-13995.yml deleted file mode 100644 index e58ee3103c..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13995.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - bugfix: "Attacking some certain objects no longer has no clickdelay." diff --git a/html/changelogs/AutoChangeLog-pr-13996.yml b/html/changelogs/AutoChangeLog-pr-13996.yml deleted file mode 100644 index 5bea075460..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13996.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "MrJWhit" -delete-after: True -changes: - - tweak: "Bugfix of a morph becoming an AI eye" diff --git a/html/changelogs/AutoChangeLog-pr-13997.yml b/html/changelogs/AutoChangeLog-pr-13997.yml deleted file mode 100644 index 354f66010a..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13997.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "MrJWhit" -delete-after: True -changes: - - tweak: "Porting garbage collection tweak from /tg/" diff --git a/html/changelogs/AutoChangeLog-pr-14001.yml b/html/changelogs/AutoChangeLog-pr-14001.yml deleted file mode 100644 index 31c9e560ab..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14001.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "MrJWhit" -delete-after: True -changes: - - tweak: "Fixes two chairs on one table" diff --git a/html/changelogs/AutoChangeLog-pr-14005.yml b/html/changelogs/AutoChangeLog-pr-14005.yml deleted file mode 100644 index 253f4e137a..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14005.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - bugfix: "Loot items mobs drop are no longer always failing to initialize." diff --git a/html/changelogs/AutoChangeLog-pr-14006.yml b/html/changelogs/AutoChangeLog-pr-14006.yml deleted file mode 100644 index 519ad32752..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14006.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - bugfix: "Cyborg B.o.r.i.s. installation now checks for if the chest has a cell, just like how it does with MMIs." diff --git a/html/changelogs/AutoChangeLog-pr-14007.yml b/html/changelogs/AutoChangeLog-pr-14007.yml deleted file mode 100644 index 498aa6b807..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14007.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - bugfix: "Antagging / Deantagging Heretics now properly sets their special role." diff --git a/html/changelogs/AutoChangeLog-pr-14008.yml b/html/changelogs/AutoChangeLog-pr-14008.yml deleted file mode 100644 index 836eefd99a..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14008.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "TheSpaghetti" -delete-after: True -changes: - - bugfix: "no more tumor bread double punctuation" diff --git a/html/changelogs/AutoChangeLog-pr-14009.yml b/html/changelogs/AutoChangeLog-pr-14009.yml deleted file mode 100644 index 03a1ca39dd..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14009.yml +++ /dev/null @@ -1,7 +0,0 @@ -author: "shellspeed1" -delete-after: True -changes: - - rscadd: "Wings from Cit RP have been ported over" - - rscadd: "Moth wings from cit have been ported over" - - bugfix: "Cleaned up some pixels on existing moth wings." - - tweak: "Organized the lists for wings by if they are for moths or not and than by alphabetical." diff --git a/html/changelogs/AutoChangeLog-pr-14010.yml b/html/changelogs/AutoChangeLog-pr-14010.yml deleted file mode 100644 index 643f28dc99..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14010.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "shellspeed1" -delete-after: True -changes: - - rscadd: "The exofab can now print prosthetic limbs" - - bugfix: "The exofab was missing access to multiple cybernetic organs. This has now been rectified." diff --git a/html/changelogs/AutoChangeLog-pr-14014.yml b/html/changelogs/AutoChangeLog-pr-14014.yml deleted file mode 100644 index ac29b1567b..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14014.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "necromanceranne" -delete-after: True -changes: - - bugfix: "Fixes various sprites for bokken, as well as being unable to craft certain parts and duplicate entries." diff --git a/html/changelogs/AutoChangeLog-pr-14015.yml b/html/changelogs/AutoChangeLog-pr-14015.yml deleted file mode 100644 index fe507d0a1e..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14015.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - balance: "Some synth damage stuff has been a bit rebalanced, see the PR for details." diff --git a/html/changelogs/AutoChangeLog-pr-14016.yml b/html/changelogs/AutoChangeLog-pr-14016.yml deleted file mode 100644 index 1aab587190..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14016.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - bugfix: "disabling adminhelp noises no longer disables looc" diff --git a/html/changelogs/AutoChangeLog-pr-14019.yml b/html/changelogs/AutoChangeLog-pr-14019.yml deleted file mode 100644 index 37bdd52948..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14019.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - bugfix: "species with NOTRANSSTING cannot have envy's knife used on them" diff --git a/html/changelogs/AutoChangeLog-pr-14021.yml b/html/changelogs/AutoChangeLog-pr-14021.yml deleted file mode 100644 index aab94ae724..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14021.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - bugfix: "Combat mode now will not stay permanently disabled due to status effects not working as intended." diff --git a/html/changelogs/AutoChangeLog-pr-14025.yml b/html/changelogs/AutoChangeLog-pr-14025.yml deleted file mode 100644 index 6db185baa3..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14025.yml +++ /dev/null @@ -1,7 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - rscadd: "A new surgery, allowing revival of synths without a defib at hand." - - balance: "Semi-permanent damage of Synth limbs caused by passing the damage threshold: 10 <- 15." - - tweak: "The embed removal surgery now has a version for Synths." - - balance: "EMPs no longer hardstun Synths." diff --git a/html/changelogs/AutoChangeLog-pr-14026.yml b/html/changelogs/AutoChangeLog-pr-14026.yml deleted file mode 100644 index 1ae9cb5c28..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14026.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "BlueWildrose" -delete-after: True -changes: - - bugfix: "Fixes noodle size appearance for 12+ inch members." diff --git a/html/changelogs/AutoChangeLog-pr-14029.yml b/html/changelogs/AutoChangeLog-pr-14029.yml deleted file mode 100644 index 2d4e0cdb17..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14029.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "HeroWithYay" -delete-after: True -changes: - - tweak: "Wormhole Projector and Gravity Gun now require anomaly cores to function instead of firing pins." diff --git a/html/changelogs/AutoChangeLog-pr-14030.yml b/html/changelogs/AutoChangeLog-pr-14030.yml deleted file mode 100644 index 9d4ee2647b..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14030.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Putnam3145" -delete-after: True -changes: - - tweak: "Replaces majority judgement with usual judgement." diff --git a/html/changelogs/AutoChangeLog-pr-14032.yml b/html/changelogs/AutoChangeLog-pr-14032.yml deleted file mode 100644 index 67f0a80f83..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14032.yml +++ /dev/null @@ -1,8 +0,0 @@ -author: "kappa-sama" -delete-after: True -changes: - - rscadd: "A new spell for the wizard and his martial apprentices, the Inner Mantra technique. It makes you punch people really good and makes you durable, but drains your energy while it's active." - - rscadd: "A self-buffing spell for valiant bubblegum slayers that is ultimately useless on lavaland and probably overpowered for miner antagonists. Go figure. At least all it does is let you punch hard while draining your health every second." - - balance: "bubblegum now drops a book that makes you into an abusive father instead of a shotgun that plays like pre-nerf shotguns" - - soundadd: "a powerup and powerdown sound effect" - - imageadd: "two icons for two buff spells" diff --git a/html/changelogs/AutoChangeLog-pr-14033.yml b/html/changelogs/AutoChangeLog-pr-14033.yml deleted file mode 100644 index db6a6b0691..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14033.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "BlueWildrose" -delete-after: True -changes: - - rscadd: "Color Mates have been added to all stations (except Snaxi). Enjoy coloring your attire without having to bug science!" diff --git a/html/changelogs/AutoChangeLog-pr-14034.yml b/html/changelogs/AutoChangeLog-pr-14034.yml deleted file mode 100644 index ecd0d4ca10..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14034.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - bugfix: "Some edge cases causing issues with system corruption shouldn't be able to occur anymore." diff --git a/html/changelogs/AutoChangeLog-pr-14035.yml b/html/changelogs/AutoChangeLog-pr-14035.yml deleted file mode 100644 index b8690368a3..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14035.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SiliconMain" -delete-after: True -changes: - - tweak: "hololocks (which haven't worked for god knows how long) commented out until auxmos is merged" diff --git a/html/changelogs/AutoChangeLog-pr-14036.yml b/html/changelogs/AutoChangeLog-pr-14036.yml deleted file mode 100644 index a2bb654233..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14036.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "BlueWildrose" -delete-after: True -changes: - - tweak: "You will now only unbuckle fireman-carried/piggybacked people on disarm or harm intent." diff --git a/html/changelogs/AutoChangeLog-pr-14037.yml b/html/changelogs/AutoChangeLog-pr-14037.yml deleted file mode 100644 index b105b5e19a..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14037.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - rscadd: "Nanogel, available at medical and robotics, which fixes internal damage in sufficiently repaired robotic limbs." diff --git a/html/changelogs/AutoChangeLog-pr-14038.yml b/html/changelogs/AutoChangeLog-pr-14038.yml deleted file mode 100644 index 906f6f7053..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14038.yml +++ /dev/null @@ -1,9 +0,0 @@ -author: "Hatterhat" -delete-after: True -changes: - - rscadd: "The nature interaction shuttle with the monkeys now has tiny fans on the airlocks in, because that's apparently a feature that was missing." - - rscadd: "More bags have been added to department vendors." - - balance: "Every roundstart species (and also ash walkers) now has flesh and bone that can be wounded." - - balance: "Recipes for sutures, regen mesh, and sterilized gauze have been adjusted to be easier, mostly." - - balance: "Sterilized gauze is better at absorbing blood and being a splint." - - bugfix: "Energy sabres now have an off inhand." diff --git a/html/changelogs/AutoChangeLog-pr-14039.yml b/html/changelogs/AutoChangeLog-pr-14039.yml deleted file mode 100644 index a799003a02..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14039.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Hatterhat" -delete-after: True -changes: - - rscadd: "Basic sticky technology is now a roundstart tech. Advanced sticky technology is BEPIS-locked, though. Theoretically." diff --git a/html/changelogs/AutoChangeLog-pr-14040.yml b/html/changelogs/AutoChangeLog-pr-14040.yml deleted file mode 100644 index 6202f0b3e1..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14040.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "LetterN" -delete-after: True -changes: - - bugfix: "fixed telecomms pda log" diff --git a/html/changelogs/AutoChangeLog-pr-14042.yml b/html/changelogs/AutoChangeLog-pr-14042.yml deleted file mode 100644 index a924ff582f..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14042.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "kiwedespars" -delete-after: True -changes: - - rscadd: "the robust dildo weapon now has sound." diff --git a/html/changelogs/AutoChangeLog-pr-14043.yml b/html/changelogs/AutoChangeLog-pr-14043.yml deleted file mode 100644 index 03a347724f..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14043.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - rscadd: "licking people washes pie off their face" diff --git a/html/changelogs/AutoChangeLog-pr-14044.yml b/html/changelogs/AutoChangeLog-pr-14044.yml deleted file mode 100644 index e19b6266a7..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14044.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "corin9090" -delete-after: True -changes: - - tweak: "The chaplain's prayer beads can now be worn on your belt slot" diff --git a/html/changelogs/AutoChangeLog-pr-14048.yml b/html/changelogs/AutoChangeLog-pr-14048.yml deleted file mode 100644 index b7b1448b37..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14048.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "MrJWhit" -delete-after: True -changes: - - tweak: "Updates suit storage info on Tip Of the Round." diff --git a/html/changelogs/AutoChangeLog-pr-14054.yml b/html/changelogs/AutoChangeLog-pr-14054.yml deleted file mode 100644 index 406e6b2713..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14054.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "TheObserver" -delete-after: True -changes: - - rscadd: "Re-adds the rifle stock, and sets the improv shotgun to be as it was." - - rscdel: "The maintenance rifle has been shelved - for now. Watch this space." diff --git a/html/changelogs/AutoChangeLog-pr-14055.yml b/html/changelogs/AutoChangeLog-pr-14055.yml deleted file mode 100644 index 95baa857fa..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14055.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "BlueWildrose" -delete-after: True -changes: - - tweak: "No more straining when your cock or breasts are growing via incubus draft or succubus milk." diff --git a/html/changelogs/AutoChangeLog-pr-14060.yml b/html/changelogs/AutoChangeLog-pr-14060.yml deleted file mode 100644 index f9750fc9be..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14060.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Hatterhat" -delete-after: True -changes: - - rscdel: "Apparently, shrink rays were buyable again, despite a PR having been made a while ago specifically for removing shrink rays. They're gone again." diff --git a/html/changelogs/AutoChangeLog-pr-14061.yml b/html/changelogs/AutoChangeLog-pr-14061.yml deleted file mode 100644 index c10eded1df..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14061.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Hatterhat" -delete-after: True -changes: - - tweak: "Improvised gauzes can now be crafted in stacks up to 10, like their maximum stacksize implies they should be capable of doing." - - bugfix: "Pouring sterilizine on gauze now takes the proper 5u per sterilized gauze instead of 10u." diff --git a/html/changelogs/AutoChangeLog-pr-14062.yml b/html/changelogs/AutoChangeLog-pr-14062.yml deleted file mode 100644 index 84e40850ec..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14062.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "kappa-sama" -delete-after: True -changes: - - bugfix: "super saiyan" diff --git a/html/changelogs/AutoChangeLog-pr-14065.yml b/html/changelogs/AutoChangeLog-pr-14065.yml deleted file mode 100644 index 96a0a7cb3a..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14065.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "MrJWhit" -delete-after: True -changes: - - tweak: "A small bucket of random fixes," diff --git a/html/changelogs/AutoChangeLog-pr-14070.yml b/html/changelogs/AutoChangeLog-pr-14070.yml deleted file mode 100644 index f9a694c6ff..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14070.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "YakumoChen" -delete-after: True -changes: - - balance: "To lower production costs, Buzz Fuzz is now manufactured with Real™️ Synthetic honey." diff --git a/html/changelogs/example.yml b/html/changelogs/example.yml index 48aa13aa11..c44f796755 100644 --- a/html/changelogs/example.yml +++ b/html/changelogs/example.yml @@ -8,16 +8,41 @@ # # Valid Prefixes: # bugfix -# wip (For works in progress) +# - (fixes bugs) +# wip +# - (work in progress) # tweak +# - (tweaks something) # soundadd +# - (adds a sound) # sounddel -# rscadd (general adding of nice things) -# rscdel (general deleting of nice things) +# - (removes a sound) +# rscdel +# - (adds a feature) +# rscadd +# - (removes a feature) # imageadd +# - (adds an image or sprite) # imagedel -# spellcheck (typo fixes) +# - (removes an image or sprite) +# spellcheck +# - (fixes spelling or grammar) # experiment +# - (experimental change) +# tgs +# - (TGS change) +# balance +# - (balance changes) +# code_imp +# - (misc internal code change) +# refactor +# - (refactors code) +# config +# - (makes a change to the config files) +# admin +# - (makes changes to administrator tools) +# server +# - (miscellaneous changes to server) ################################# # Your name. diff --git a/html/safe_dial.png b/html/safe_dial.png new file mode 100644 index 0000000000..de24f16b67 Binary files /dev/null and b/html/safe_dial.png differ diff --git a/icons/mob/clothing/accessories.dmi b/icons/mob/clothing/accessories.dmi index 743ed03f48..96308a6e70 100644 Binary files a/icons/mob/clothing/accessories.dmi and b/icons/mob/clothing/accessories.dmi differ diff --git a/icons/mob/clothing/feet.dmi b/icons/mob/clothing/feet.dmi index 67d1849ef6..227ae83166 100644 Binary files a/icons/mob/clothing/feet.dmi and b/icons/mob/clothing/feet.dmi differ diff --git a/icons/mob/clothing/feet_digi.dmi b/icons/mob/clothing/feet_digi.dmi index f798850ee7..43244e99b9 100644 Binary files a/icons/mob/clothing/feet_digi.dmi and b/icons/mob/clothing/feet_digi.dmi differ diff --git a/icons/mob/clothing/head.dmi b/icons/mob/clothing/head.dmi index 4b0c56c4d2..23b981031c 100644 Binary files a/icons/mob/clothing/head.dmi and b/icons/mob/clothing/head.dmi differ diff --git a/icons/mob/clothing/mask.dmi b/icons/mob/clothing/mask.dmi index ecc6e2dd2c..7d9433525a 100644 Binary files a/icons/mob/clothing/mask.dmi and b/icons/mob/clothing/mask.dmi differ diff --git a/icons/mob/clothing/mask_muzzled.dmi b/icons/mob/clothing/mask_muzzled.dmi index a1404cfbce..8ca05969bf 100644 Binary files a/icons/mob/clothing/mask_muzzled.dmi and b/icons/mob/clothing/mask_muzzled.dmi differ diff --git a/icons/mob/clothing/neck.dmi b/icons/mob/clothing/neck.dmi index 084a2c3649..df1037b8fa 100644 Binary files a/icons/mob/clothing/neck.dmi and b/icons/mob/clothing/neck.dmi differ diff --git a/icons/mob/clothing/suit.dmi b/icons/mob/clothing/suit.dmi index 6098b8342a..ae7117d53b 100644 Binary files a/icons/mob/clothing/suit.dmi and b/icons/mob/clothing/suit.dmi differ diff --git a/icons/mob/clothing/suit_digi.dmi b/icons/mob/clothing/suit_digi.dmi index 5c361feb5f..f80cb4a426 100644 Binary files a/icons/mob/clothing/suit_digi.dmi and b/icons/mob/clothing/suit_digi.dmi differ diff --git a/icons/mob/clothing/underwear.dmi b/icons/mob/clothing/underwear.dmi index 8cf1144a68..71461e21e8 100644 Binary files a/icons/mob/clothing/underwear.dmi and b/icons/mob/clothing/underwear.dmi differ diff --git a/icons/mob/hair.dmi b/icons/mob/hair.dmi index 6dfa78fcff..278c5de311 100644 Binary files a/icons/mob/hair.dmi and b/icons/mob/hair.dmi differ diff --git a/icons/mob/inhands/64x64_lefthand.dmi b/icons/mob/inhands/64x64_lefthand.dmi index 6dc8d82753..95106e3dbf 100644 Binary files a/icons/mob/inhands/64x64_lefthand.dmi and b/icons/mob/inhands/64x64_lefthand.dmi differ diff --git a/icons/mob/inhands/64x64_righthand.dmi b/icons/mob/inhands/64x64_righthand.dmi index ca87f74a6f..2c1909108b 100644 Binary files a/icons/mob/inhands/64x64_righthand.dmi and b/icons/mob/inhands/64x64_righthand.dmi differ diff --git a/icons/obj/card.dmi b/icons/obj/card.dmi index 13a0725b05..1bd94f2424 100644 Binary files a/icons/obj/card.dmi and b/icons/obj/card.dmi differ diff --git a/icons/obj/clothing/accessories.dmi b/icons/obj/clothing/accessories.dmi index 510adc97b4..3731c9e706 100644 Binary files a/icons/obj/clothing/accessories.dmi and b/icons/obj/clothing/accessories.dmi differ diff --git a/icons/obj/clothing/belt_overlays.dmi b/icons/obj/clothing/belt_overlays.dmi index 1178588ee7..5f31a65ffa 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/cloaks.dmi b/icons/obj/clothing/cloaks.dmi index cc5f4f3392..7ea22d34bc 100644 Binary files a/icons/obj/clothing/cloaks.dmi and b/icons/obj/clothing/cloaks.dmi differ diff --git a/icons/obj/clothing/hats.dmi b/icons/obj/clothing/hats.dmi index ee6cf90597..9fa3e527ca 100644 Binary files a/icons/obj/clothing/hats.dmi and b/icons/obj/clothing/hats.dmi differ diff --git a/icons/obj/clothing/masks.dmi b/icons/obj/clothing/masks.dmi index 106195e968..acd64bb424 100644 Binary files a/icons/obj/clothing/masks.dmi and b/icons/obj/clothing/masks.dmi differ diff --git a/icons/obj/clothing/neck.dmi b/icons/obj/clothing/neck.dmi index c4c9c94f48..d7e0c9c24b 100644 Binary files a/icons/obj/clothing/neck.dmi and b/icons/obj/clothing/neck.dmi differ diff --git a/icons/obj/clothing/shoes.dmi b/icons/obj/clothing/shoes.dmi index d3e4c0f7e9..42ef740c4a 100644 Binary files a/icons/obj/clothing/shoes.dmi and b/icons/obj/clothing/shoes.dmi differ diff --git a/icons/obj/clothing/suits.dmi b/icons/obj/clothing/suits.dmi index 6ddac703a0..ba9f94e67a 100644 Binary files a/icons/obj/clothing/suits.dmi and b/icons/obj/clothing/suits.dmi differ diff --git a/icons/obj/guns/energy.dmi b/icons/obj/guns/energy.dmi index 7e7e4a644b..158c95ee5d 100644 Binary files a/icons/obj/guns/energy.dmi and b/icons/obj/guns/energy.dmi differ diff --git a/icons/obj/projectiles.dmi b/icons/obj/projectiles.dmi index 71391a035e..740c64b1dc 100644 Binary files a/icons/obj/projectiles.dmi and b/icons/obj/projectiles.dmi differ diff --git a/icons/obj/smith.dmi b/icons/obj/smith.dmi index cbd6b9e85e..19e12dec86 100644 Binary files a/icons/obj/smith.dmi and b/icons/obj/smith.dmi differ diff --git a/modular_citadel/code/modules/client/loadout/_loadout.dm b/modular_citadel/code/modules/client/loadout/_loadout.dm index 2a7b77bd47..5f895c4805 100644 --- a/modular_citadel/code/modules/client/loadout/_loadout.dm +++ b/modular_citadel/code/modules/client/loadout/_loadout.dm @@ -53,7 +53,7 @@ GLOBAL_LIST_EMPTY(loadout_whitelist_ids) var/path //item-to-spawn path var/cost = 1 //normally, each loadout costs a single point. var/geargroupID //defines the ID that the gear inherits from the config - var/loadout_flags = 0 + var/loadout_flags = LOADOUT_CAN_NAME | LOADOUT_CAN_DESCRIPTION var/list/loadout_initial_colors = list() //NEW DONATOR SYTSEM STUFF diff --git a/modular_citadel/code/modules/client/loadout/mask.dm b/modular_citadel/code/modules/client/loadout/mask.dm index 9468c9303d..576b29cddc 100644 --- a/modular_citadel/code/modules/client/loadout/mask.dm +++ b/modular_citadel/code/modules/client/loadout/mask.dm @@ -20,3 +20,14 @@ path = /obj/item/clothing/mask/gas cost = 2 restricted_roles = list("Chief Engineer", "Atmospheric Technician", "Station Engineer") //*shrug + +/datum/gear/mask/sterile + name = "Aesthetic sterile mask" + path = /obj/item/clothing/mask/surgical/aesthetic + cost = 2 + +/datum/gear/mask/paper + name = "Paper mask" + path = /obj/item/clothing/mask/paper + cost = 2 + diff --git a/modular_citadel/code/modules/client/loadout/neck.dm b/modular_citadel/code/modules/client/loadout/neck.dm index 7c3c11f25c..300b98fbe9 100644 --- a/modular_citadel/code/modules/client/loadout/neck.dm +++ b/modular_citadel/code/modules/client/loadout/neck.dm @@ -30,6 +30,10 @@ name = "Choker" path = /obj/item/clothing/neck/petcollar/choker +/datum/gear/neck/cowbell + name = "Cowbell collar" + path = /obj/item/clothing/neck/necklace/cowbell + /datum/gear/neck/scarf name = "White scarf" subcategory = LOADOUT_SUBCATEGORY_NECK_SCARVES @@ -86,7 +90,7 @@ /datum/gear/neck/polycloak name = "Polychromatic Cloak" path = /obj/item/clothing/neck/cloak/polychromic - loadout_flags = LOADOUT_CAN_COLOR_POLYCHROMIC + loadout_flags = LOADOUT_CAN_NAME | LOADOUT_CAN_DESCRIPTION | LOADOUT_CAN_COLOR_POLYCHROMIC loadout_initial_colors = list("#FFFFFF", "#FFFFFF", "#808080") /datum/gear/neck/altpolycloak diff --git a/modular_citadel/code/modules/client/loadout/suit.dm b/modular_citadel/code/modules/client/loadout/suit.dm index 7c21ed84d0..f7ef891104 100644 --- a/modular_citadel/code/modules/client/loadout/suit.dm +++ b/modular_citadel/code/modules/client/loadout/suit.dm @@ -101,7 +101,7 @@ name = "Polychromic winter coat" path = /obj/item/clothing/suit/hooded/wintercoat/polychromic cost = 4 //too many people with neon green coats is hard on the eyes - loadout_flags = LOADOUT_CAN_COLOR_POLYCHROMIC + loadout_flags = LOADOUT_CAN_NAME | LOADOUT_CAN_DESCRIPTION | LOADOUT_CAN_COLOR_POLYCHROMIC loadout_initial_colors = list("#6A6964", "#C4B8A6", "#0000FF") /datum/gear/suit/coat/med diff --git a/modular_citadel/code/modules/client/loadout/uniform.dm b/modular_citadel/code/modules/client/loadout/uniform.dm index b76e223f25..303783e1c5 100644 --- a/modular_citadel/code/modules/client/loadout/uniform.dm +++ b/modular_citadel/code/modules/client/loadout/uniform.dm @@ -47,7 +47,7 @@ /datum/gear/uniform/maidcostume/polychromic name = "Polychromic maid costume" path = /obj/item/clothing/under/rank/civilian/janitor/maid/polychromic - loadout_flags = LOADOUT_CAN_COLOR_POLYCHROMIC + loadout_flags = LOADOUT_CAN_NAME | LOADOUT_CAN_DESCRIPTION | LOADOUT_CAN_COLOR_POLYCHROMIC loadout_initial_colors = list("#FFFFFF", "#000000") /datum/gear/uniform/mailmanuniform @@ -229,49 +229,49 @@ name = "Polychromic Jumpsuit" path = /obj/item/clothing/under/misc/polyjumpsuit cost = 2 - loadout_flags = LOADOUT_CAN_COLOR_POLYCHROMIC + loadout_flags = LOADOUT_CAN_NAME | LOADOUT_CAN_DESCRIPTION | LOADOUT_CAN_COLOR_POLYCHROMIC loadout_initial_colors = list("#FFFFFF", "#808080", "#353535") /datum/gear/uniform/skirt/poly name = "Polychromic Jumpskirt" path = /obj/item/clothing/under/dress/skirt/polychromic cost = 2 - loadout_flags = LOADOUT_CAN_COLOR_POLYCHROMIC + loadout_flags = LOADOUT_CAN_NAME | LOADOUT_CAN_DESCRIPTION | LOADOUT_CAN_COLOR_POLYCHROMIC loadout_initial_colors = list("#FFFFFF", "#F08080", "#808080") /datum/gear/uniform/suit/poly name = "Polychromic Button-up Shirt" path = /obj/item/clothing/under/misc/poly_shirt cost = 3 - loadout_flags = LOADOUT_CAN_COLOR_POLYCHROMIC + loadout_flags = LOADOUT_CAN_NAME | LOADOUT_CAN_DESCRIPTION | LOADOUT_CAN_COLOR_POLYCHROMIC loadout_initial_colors = list("#FFFFFF", "#353535", "#353535") /datum/gear/uniform/skirt/poly/pleated name = "Polychromic Pleated Sweaterskirt" path = /obj/item/clothing/under/dress/skirt/polychromic/pleated cost = 3 - loadout_flags = LOADOUT_CAN_COLOR_POLYCHROMIC + loadout_flags = LOADOUT_CAN_NAME | LOADOUT_CAN_DESCRIPTION | LOADOUT_CAN_COLOR_POLYCHROMIC loadout_initial_colors = list("#8CC6FF", "#808080", "#FF3535") /datum/gear/uniform/polykilt name = "Polychromic Kilt" path = /obj/item/clothing/under/costume/kilt/polychromic cost = 3 - loadout_flags = LOADOUT_CAN_COLOR_POLYCHROMIC + loadout_flags = LOADOUT_CAN_NAME | LOADOUT_CAN_DESCRIPTION | LOADOUT_CAN_COLOR_POLYCHROMIC loadout_initial_colors = list("#FFFFFF", "#F08080") /datum/gear/uniform/shorts/poly name = "Polychromic Shorts" path = /obj/item/clothing/under/misc/polyshorts cost = 3 - loadout_flags = LOADOUT_CAN_COLOR_POLYCHROMIC + loadout_flags = LOADOUT_CAN_NAME | LOADOUT_CAN_DESCRIPTION | LOADOUT_CAN_COLOR_POLYCHROMIC loadout_initial_colors = list("#353535", "#808080", "#808080") /datum/gear/uniform/shorts/poly/athletic name = "Polychromic Athletic Shorts" path = /obj/item/clothing/under/shorts/polychromic cost = 2 - loadout_flags = LOADOUT_CAN_COLOR_POLYCHROMIC + loadout_flags = LOADOUT_CAN_NAME | LOADOUT_CAN_DESCRIPTION | LOADOUT_CAN_COLOR_POLYCHROMIC loadout_initial_colors = list("#FFFFFF", "#F08080") /datum/gear/uniform/hopcasual diff --git a/modular_citadel/code/modules/client/loadout/unlockable.dm b/modular_citadel/code/modules/client/loadout/unlockable.dm index 6e522812b8..67e0c06d8c 100644 --- a/modular_citadel/code/modules/client/loadout/unlockable.dm +++ b/modular_citadel/code/modules/client/loadout/unlockable.dm @@ -27,4 +27,4 @@ path = /obj/item/bedsheet/unlockable/miner progress_required = 100000 - progress_key = "miner" \ No newline at end of file + progress_key = "miner" diff --git a/modular_citadel/code/modules/clothing/trek.dm b/modular_citadel/code/modules/clothing/trek.dm index f7e8b6778e..dd02a6d0f8 100644 --- a/modular_citadel/code/modules/clothing/trek.dm +++ b/modular_citadel/code/modules/clothing/trek.dm @@ -51,58 +51,58 @@ blood_overlay_type = "coat" body_parts_covered = CHEST|GROIN|ARMS allowed = list( - /obj/item/tank/internals/emergency_oxygen, - /obj/item/flashlight, - /obj/item/analyzer, - /obj/item/radio, - /obj/item/gun, - /obj/item/melee/baton, - /obj/item/restraints/handcuffs, - /obj/item/reagent_containers/hypospray, - /obj/item/hypospray, - /obj/item/healthanalyzer, - /obj/item/reagent_containers/syringe, - /obj/item/reagent_containers/glass/bottle/vial, - /obj/item/reagent_containers/glass/beaker, - /obj/item/storage/pill_bottle, - /obj/item/taperecorder) + /obj/item/tank/internals/emergency_oxygen, + /obj/item/flashlight, + /obj/item/analyzer, + /obj/item/radio, + /obj/item/gun, + /obj/item/melee/baton, + /obj/item/restraints/handcuffs, + /obj/item/reagent_containers/hypospray, + /obj/item/hypospray, + /obj/item/healthanalyzer, + /obj/item/reagent_containers/syringe, + /obj/item/reagent_containers/glass/bottle/vial, + /obj/item/reagent_containers/glass/beaker, + /obj/item/storage/pill_bottle, + /obj/item/taperecorder) armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0) - var/unbuttoned = 0 + var/unbuttoned = FALSE - verb/toggle() - set name = "Toggle coat buttons" - set category = "Object" - set src in usr +/obj/item/clothing/suit/storage/fluff/fedcoat/verb/toggle() + set name = "Toggle coat buttons" + set category = "Object" + set src in usr - var/mob/living/L = usr - if(!istype(L) || !CHECK_MOBILITY(L, MOBILITY_USE)) - return FALSE + var/mob/living/L = usr + if(!istype(L) || !CHECK_MOBILITY(L, MOBILITY_USE)) + return FALSE - switch(unbuttoned) - if(0) - icon_state = "[initial(icon_state)]_open" - item_state = "[initial(item_state)]_open" - unbuttoned = 1 - to_chat(usr,"You unbutton the coat.") - if(1) - icon_state = "[initial(icon_state)]" - item_state = "[initial(item_state)]" - unbuttoned = 0 - to_chat(usr,"You button up the coat.") - usr.update_inv_wear_suit() + switch(unbuttoned) + if(FALSE) + icon_state = "[initial(icon_state)]_open" + item_state = "[initial(item_state)]_open" + unbuttoned = TRUE + to_chat(usr,"You unbutton the coat.") + if(TRUE) + icon_state = "[initial(icon_state)]" + item_state = "[initial(item_state)]" + unbuttoned = FALSE + to_chat(usr,"You button up the coat.") + usr.update_inv_wear_suit() - //Variants +//Variants /obj/item/clothing/suit/storage/fluff/fedcoat/medsci - icon_state = "fedblue" - item_state = "fedblue" + icon_state = "fedblue" + item_state = "fedblue" /obj/item/clothing/suit/storage/fluff/fedcoat/eng - icon_state = "fedeng" - item_state = "fedeng" + icon_state = "fedeng" + item_state = "fedeng" /obj/item/clothing/suit/storage/fluff/fedcoat/capt - icon_state = "fedcapt" - item_state = "fedcapt" + icon_state = "fedcapt" + item_state = "fedcapt" //"modern" ones for fancy @@ -124,18 +124,18 @@ ) armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0) - //Variants +//Variants /obj/item/clothing/suit/storage/fluff/modernfedcoat/medsci - icon_state = "fedmodernblue" - item_state = "fedmodernblue" + icon_state = "fedmodernblue" + item_state = "fedmodernblue" /obj/item/clothing/suit/storage/fluff/modernfedcoat/eng - icon_state = "fedmoderneng" - item_state = "fedmoderneng" + icon_state = "fedmoderneng" + item_state = "fedmoderneng" /obj/item/clothing/suit/storage/fluff/modernfedcoat/sec - icon_state = "fedmodernsec" - item_state = "fedmodernsec" + icon_state = "fedmodernsec" + item_state = "fedmodernsec" /obj/item/clothing/head/caphat/formal/fedcover name = "Federation Officer's Cap" @@ -146,22 +146,22 @@ mob_overlay_icon = 'modular_citadel/icons/mob/clothing/trek_mob_icon.dmi' item_state = "fedcapofficer" - //Variants +//Variants /obj/item/clothing/head/caphat/formal/fedcover/medsci - icon_state = "fedcapsci" - item_state = "fedcapsci" + icon_state = "fedcapsci" + item_state = "fedcapsci" /obj/item/clothing/head/caphat/formal/fedcover/eng - icon_state = "fedcapeng" - item_state = "fedcapeng" + icon_state = "fedcapeng" + item_state = "fedcapeng" /obj/item/clothing/head/caphat/formal/fedcover/sec - icon_state = "fedcapsec" - item_state = "fedcapsec" + icon_state = "fedcapsec" + item_state = "fedcapsec" /obj/item/clothing/head/caphat/formal/fedcover/black - icon_state = "fedcapblack" - item_state = "fedcapblack" + icon_state = "fedcapblack" + item_state = "fedcapblack" //orvilike caps /obj/item/clothing/head/kepi/orvi diff --git a/modular_citadel/code/modules/projectiles/guns/energy/energy_gun.dm b/modular_citadel/code/modules/projectiles/guns/energy/energy_gun.dm index 65609f5830..9a8ee4bab1 100644 --- a/modular_citadel/code/modules/projectiles/guns/energy/energy_gun.dm +++ b/modular_citadel/code/modules/projectiles/guns/energy/energy_gun.dm @@ -2,7 +2,7 @@ The Recolourable Energy Gun *////////////////////////////////////////////////////////////////////////////////////////////// -obj/item/gun/energy/e_gun/cx +/obj/item/gun/energy/e_gun/cx name = "\improper CX Model D Energy Gun" desc = "An overpriced hybrid energy gun with two settings: disable, and kill. Manufactured by CX Armories. Has a polychromic coating." icon = 'modular_citadel/icons/obj/guns/cit_guns.dmi' @@ -14,18 +14,18 @@ obj/item/gun/energy/e_gun/cx flight_y_offset = 10 var/body_color = "#252528" -obj/item/gun/energy/e_gun/cx/ComponentInitialize() +/obj/item/gun/energy/e_gun/cx/ComponentInitialize() . = ..() AddElement(/datum/element/update_icon_updates_onmob) -obj/item/gun/energy/e_gun/cx/update_overlays() +/obj/item/gun/energy/e_gun/cx/update_overlays() . = ..() var/mutable_appearance/body_overlay = mutable_appearance('modular_citadel/icons/obj/guns/cit_guns.dmi', "cxegun_body") if(body_color) body_overlay.color = body_color . += body_overlay -obj/item/gun/energy/e_gun/cx/AltClick(mob/living/user) +/obj/item/gun/energy/e_gun/cx/AltClick(mob/living/user) . = ..() if(!in_range(src, user)) //Basic checks to prevent abuse return @@ -39,7 +39,7 @@ obj/item/gun/energy/e_gun/cx/AltClick(mob/living/user) body_color = sanitize_hexcolor(body_color_input, desired_format=6, include_crunch=1) update_icon() -obj/item/gun/energy/e_gun/cx/worn_overlays(isinhands, icon_file, used_state, style_flags = NONE) +/obj/item/gun/energy/e_gun/cx/worn_overlays(isinhands, icon_file, used_state, style_flags = NONE) . = ..() if(isinhands) var/mutable_appearance/body_inhand = mutable_appearance(icon_file, "cxe_body") diff --git a/modular_citadel/code/modules/reagents/chemistry/reagents/fermi_reagents.dm b/modular_citadel/code/modules/reagents/chemistry/reagents/fermi_reagents.dm index 1801986ebe..2d4d363efb 100644 --- a/modular_citadel/code/modules/reagents/chemistry/reagents/fermi_reagents.dm +++ b/modular_citadel/code/modules/reagents/chemistry/reagents/fermi_reagents.dm @@ -216,7 +216,6 @@ ..() /datum/reagent/fermi/nanite_b_gone/overdose_process(mob/living/carbon/C) - //var/component/nanites/N = M.GetComponent(/datum/component/nanites) var/datum/component/nanites/N = C.GetComponent(/datum/component/nanites) if(prob(5)) to_chat(C, "The residual voltage from the nanites causes you to seize up!") @@ -230,7 +229,7 @@ N.adjust_nanites(-10*cached_purity) ..() -datum/reagent/fermi/nanite_b_gone/reaction_obj(obj/O, reac_volume) +/datum/reagent/fermi/nanite_b_gone/reaction_obj(obj/O, reac_volume) for(var/active_obj in react_objs) if(O == active_obj) return diff --git a/rust_g.dll b/rust_g.dll old mode 100755 new mode 100644 index 8cd62b8ca4..8ef1c59a10 Binary files a/rust_g.dll and b/rust_g.dll differ diff --git a/sound/effects/whistlereset.ogg b/sound/effects/whistlereset.ogg new file mode 100644 index 0000000000..cf55c06ca8 Binary files /dev/null and b/sound/effects/whistlereset.ogg differ diff --git a/sound/machines/grill/grillsizzle.ogg b/sound/machines/grill/grillsizzle.ogg new file mode 100644 index 0000000000..056ce45941 Binary files /dev/null and b/sound/machines/grill/grillsizzle.ogg differ diff --git a/tgstation.dme b/tgstation.dme index 1a7d19d6e0..519f692e7b 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -79,6 +79,7 @@ #include "code\__DEFINES\mobs.dm" #include "code\__DEFINES\monkeys.dm" #include "code\__DEFINES\move_force.dm" +#include "code\__DEFINES\movement.dm" #include "code\__DEFINES\movespeed_modification.dm" #include "code\__DEFINES\nanites.dm" #include "code\__DEFINES\networks.dm" @@ -154,7 +155,6 @@ #include "code\__DEFINES\storage\_storage.dm" #include "code\__DEFINES\storage\volumetrics.dm" #include "code\__HELPERS\_cit_helpers.dm" -#include "code\__HELPERS\_extools_api.dm" #include "code\__HELPERS\_lists.dm" #include "code\__HELPERS\_logging.dm" #include "code\__HELPERS\_string_lists.dm" @@ -202,6 +202,7 @@ #include "code\__HELPERS\sorts\InsertSort.dm" #include "code\__HELPERS\sorts\MergeSort.dm" #include "code\__HELPERS\sorts\TimSort.dm" +#include "code\_globalvars\admin.dm" #include "code\_globalvars\bitfields.dm" #include "code\_globalvars\configuration.dm" #include "code\_globalvars\game_modes.dm" @@ -619,6 +620,7 @@ #include "code\datums\elements\tactical.dm" #include "code\datums\elements\update_icon_blocker.dm" #include "code\datums\elements\update_icon_updates_onmob.dm" +#include "code\datums\elements\ventcrawling.dm" #include "code\datums\elements\wuv.dm" #include "code\datums\helper_datums\events.dm" #include "code\datums\helper_datums\getrev.dm" diff --git a/tools/TGUICompiler.php b/tools/TGUICompiler.php deleted file mode 100644 index a393e1d3c6..0000000000 --- a/tools/TGUICompiler.php +++ /dev/null @@ -1,198 +0,0 @@ - 0 && strpos($name, '\\') == false && strpos($name, '/') == false){ - $ext = pathinfo($name, PATHINFO_EXTENSION); - $mime = $finfo->file($F['tmp_name']); - if($ext == 'ract' && $mime == 'text/plain') - $good_files[] = $F; - } - } - $the_count = count($good_files); - if($the_count > 0 && $the_count < $max_number_of_uploads){ - $tgtgui_path = $tgdir . $path_to_tgui_from_repo; - $requests_dir = $parent_dir . '/requests'; - if(!is_dir($requests_dir)) - mkdir($requests_dir); - $target_path = str_replace('\\', '/', tempnam($requests_dir, 'tgui')); - unlink($target_path); - recurse_copy($tgtgui_path, $target_path); - $parent_node = $parent_dir . '/node_modules'; - $target_node = $target_path . '/node_modules'; - exec('mklink /j "' . str_replace('/', '\\', $target_node) . '" "' . str_replace('/', '\\', $parent_node) . '"'); - - //now copy the uploads to the thing - $target_interfaces = $target_path . '/src/interfaces/'; - foreach($good_files as $F){ - $target_name = $target_interfaces . $F['name']; - if(file_exists($target_name)) - unlink($target_name); //remove the file - move_uploaded_file($F['tmp_name'], $target_name); - } - - //compile - $command = '"' . $full_path_to_gulp . '" --cwd "' . str_replace('/', '\\', $target_path) . '" --min 2>&1'; - $output = shell_exec($command); - - $zip = new ZipArchive(); - $zippath = $target_path . '/TGUI.zip'; - if($zip->open($zippath, ZipArchive::CREATE) == TRUE){ - $zip->addFile($target_path . '/assets/tgui.css', 'tgui.css'); - $zip->addFile($target_path . '/assets/tgui.js', 'tgui.js'); - $zip->addFromString('gulp_output.txt', $output); - $zip->close(); - download_file($zippath); - } - else - $error = 'Unable to create output zipfile!'; - exec('rmdir "' . str_replace('/', '\\', $target_node) . '"'); //improtant - rrmdir($target_path); - } - else if(!$updated_git) - throw new RuntimeException('No valid files uploaded!'); - } -} -catch(Exception $e){ - $error = $e->getMessage(); -} - -?> - - - - TGUI .ract Compiler - - - An error occured: ' . $error . '

    '; ?> -

    Upload up to .ract files

    -

    Based off revision: ' . $revision . '' : $revision; ?> -
    - Update to latest revision (don't use this unless you have to)
    -
    -
    -
    - - -
    - - - - diff --git a/tools/WebhookProcessor/github_webhook_processor.php b/tools/WebhookProcessor/github_webhook_processor.php index b2bcaeb884..035d777feb 100644 --- a/tools/WebhookProcessor/github_webhook_processor.php +++ b/tools/WebhookProcessor/github_webhook_processor.php @@ -5,11 +5,13 @@ * For documentation on the changelog generator see https://tgstation13.org/phpBB/viewtopic.php?f=5&t=5157 * To hide prs from being announced in game, place a [s] in front of the title * All runtime errors are echo'ed to the webhook's logs in github + * Events to be sent via GitHub webhook: Pull Requests, Pushes + * Any other Event will result in a 404 returned to the webhook. */ /**CREDITS: * GitHub webhook handler template. - * + * * @see https://developer.github.com/webhooks/ * @author Miloslav Hula (https://github.com/milo) */ @@ -23,6 +25,7 @@ define('F_UNVALIDATED_USER', 1<<0); define('F_SECRET_PR', 1<<1); //CONFIGS ARE IN SECRET.PHP, THESE ARE JUST DEFAULTS! + $hookSecret = '08ajh0qj93209qj90jfq932j32r'; $apiKey = '209ab8d879c0f987d06a09b9d879c0f987d06a09b9d8787d0a089c'; $repoOwnerAndName = "tgstation/tgstation"; @@ -32,7 +35,7 @@ $path_to_script = 'tools/WebhookProcessor/github_webhook_processor.php'; $tracked_branch = "master"; $trackPRBalance = true; $prBalanceJson = ''; -$startingPRBalance = 5; +$startingPRBalance = 30; $maintainer_team_id = 133041; $validation = "org"; $validation_count = 1; @@ -123,24 +126,24 @@ switch (strtolower($_SERVER['HTTP_X_GITHUB_EVENT'])) { function apisend($url, $method = 'GET', $content = null, $authorization = null) { if (is_array($content)) $content = json_encode($content); - + $headers = array(); $headers[] = 'Content-type: application/json'; if ($authorization) $headers[] = 'Authorization: ' . $authorization; - + $scontext = array('http' => array( 'method' => $method, 'header' => implode("\r\n", $headers), 'ignore_errors' => true, 'user_agent' => 'tgstation13.org-Github-Automation-Tools' )); - + if ($content) $scontext['http']['content'] = $content; - + return file_get_contents($url, false, stream_context_create($scontext)); - + } function github_apisend($url, $method = 'GET', $content = NULL) { @@ -175,7 +178,7 @@ function validate_user($payload) { $res = github_apisend('https://api.github.com/search/issues?q='.$querystring); $res = json_decode($res, TRUE); return $res['total_count'] >= (int)$validation_count; - + } function get_labels($payload){ @@ -224,7 +227,7 @@ function tag_pr($payload, $opened) { sleep(10); $payload['pull_request'] = json_decode(github_apisend($url), TRUE); } - + $tags = array(); $title = $payload['pull_request']['title']; if($opened) { //you only have one shot on these ones so as to not annoy maintainers @@ -232,7 +235,7 @@ function tag_pr($payload, $opened) { if(strpos(strtolower($title), 'refactor') !== FALSE) $tags[] = 'Refactor'; - + if(strpos(strtolower($title), 'revert') !== FALSE) $tags[] = 'Revert'; if(strpos(strtolower($title), 'removes') !== FALSE) @@ -299,7 +302,7 @@ function check_ready_for_review($payload, $labels = null, $remove = array()){ if($L == $r4rlabel) $has_label_already = true; } - + if($has_label_already && $should_not_have_label){ $remove[] = $r4rlabel; return $returned; @@ -337,7 +340,7 @@ function check_ready_for_review($payload, $labels = null, $remove = array()){ //make sure they are part of an offending review if(!in_array($C['pull_request_review_id'], $reviews_ids_with_changes_requested)) continue; - + //review comments which are outdated have a null position if($C['position'] !== null){ if($has_label_already) @@ -360,10 +363,10 @@ function check_dismiss_changelog_review($payload){ if(!$require_changelog) return; - + if(!$no_changelog) checkchangelog($payload, false); - + $review_message = 'Your changelog for this PR is either malformed or non-existent. Please create one to document your changes.'; $reviews = get_reviews($payload); @@ -392,14 +395,12 @@ function handle_pr($payload) { set_labels($payload, $labels, $remove); if($no_changelog) check_dismiss_changelog_review($payload); - /* if(get_pr_code_friendliness($payload) <= 0){ $balances = pr_balances(); $author = $payload['pull_request']['user']['login']; if(isset($balances[$author]) && $balances[$author] < 0 && !is_maintainer($payload, $author)) create_comment($payload, 'You currently have a negative Fix/Feature pull request delta of ' . $balances[$author] . '. Maintainers may close this PR at will. Fixing issues or improving the codebase will improve this score.'); } - */ break; case 'edited': check_dismiss_changelog_review($payload); @@ -426,8 +427,8 @@ function handle_pr($payload) { break; default: return; - } - + } + $pr_flags = 0; if (strpos(strtolower($payload['pull_request']['title']), '[s]') !== false) { $pr_flags |= F_SECRET_PR; @@ -437,7 +438,7 @@ function handle_pr($payload) { } discord_announce($action, $payload, $pr_flags); game_announce($action, $payload, $pr_flags); - + } function filter_announce_targets($targets, $owner, $repo, $action, $pr_flags) { @@ -446,7 +447,7 @@ function filter_announce_targets($targets, $owner, $repo, $action, $pr_flags) { unset($targets[$i]); continue; } - + if (isset($target['announce_secret']) && $target['announce_secret']) { if (!($pr_flags & F_SECRET_PR) && $target['announce_secret'] === 'only') { unset($targets[$i]); @@ -456,7 +457,7 @@ function filter_announce_targets($targets, $owner, $repo, $action, $pr_flags) { unset($targets[$i]); continue; } - + if (isset($target['announce_unvalidated']) && $target['announce_unvalidated']) { if (!($pr_flags & F_UNVALIDATED_USER) && $target['announce_unvalidated'] === 'only') { unset($targets[$i]); @@ -466,7 +467,7 @@ function filter_announce_targets($targets, $owner, $repo, $action, $pr_flags) { unset($targets[$i]); continue; } - + $wildcard = false; if (isset($target['include_repos'])) { foreach ($target['include_repos'] as $match_string) { @@ -489,7 +490,7 @@ function filter_announce_targets($targets, $owner, $repo, $action, $pr_flags) { continue; } } - + if (isset($target['exclude_repos'])) foreach ($target['exclude_repos'] as $match_string) { $owner_repo_pair = explode('/', strtolower($match_string)); @@ -516,13 +517,13 @@ function filter_announce_targets($targets, $owner, $repo, $action, $pr_flags) { function game_announce($action, $payload, $pr_flags) { global $servers; - + $msg = '['.$payload['pull_request']['base']['repo']['full_name'].'] Pull Request '.$action.' by '.htmlSpecialChars($payload['sender']['login']).': '.htmlSpecialChars('#'.$payload['pull_request']['number'].' '.$payload['pull_request']['user']['login'].' - '.$payload['pull_request']['title']).''; $game_servers = filter_announce_targets($servers, $payload['pull_request']['base']['repo']['owner']['login'], $payload['pull_request']['base']['repo']['name'], $action, $pr_flags); - + $msg = '?announce='.urlencode($msg).'&payload='.urlencode(json_encode($payload)); - + foreach ($game_servers as $serverid => $server) { $server_message = $msg; if (isset($server['comskey'])) @@ -553,9 +554,9 @@ function discord_announce($action, $payload, $pr_flags) { 'username' => 'GitHub', 'avatar_url' => $payload['pull_request']['base']['user']['avatar_url'], ); - + $content = 'Pull Request #'.$payload['pull_request']['number'].' *'.$action.'* by '.discord_sanitize($payload['sender']['login'])."\n".discord_sanitize($payload['pull_request']['user']['login']).' - __**'.discord_sanitize($payload['pull_request']['title']).'**__'."\n".'<'.$payload['pull_request']['html_url'].'>'; - + $embeds = array( array( 'title' => '__**'.discord_sanitize($payload['pull_request']['title'], S_MARKDOWN).'**__', @@ -585,22 +586,22 @@ function discord_announce($action, $payload, $pr_flags) { } discord_webhook_send($discordWebHook['url'], $sending_data); } - + } -function discord_sanitize($text, $flags = S_MENTIONS|S_LINK_EMBED|S_MARKDOWN) { +function discord_sanitize($text, $flags = S_MENTIONS|S_LINK_EMBED|S_MARKDOWN) { if ($flags & S_MARKDOWN) $text = str_ireplace(array('\\', '*', '_', '~', '`', '|'), (array('\\\\', '\\*', '\\_', '\\~', '\\`', '\\|')), $text); - + if ($flags & S_HTML_COMMENTS) $text = preg_replace('//Uis', '', $text); - + if ($flags & S_MENTIONS) $text = str_ireplace(array('@everyone', '@here', '<@'), array('`@everyone`', '`@here`', '@<'), $text); if ($flags & S_LINK_EMBED) $text = preg_replace("/((https?|ftp|byond)\:\/\/)([a-z0-9-.]*)\.([a-z]{2,3})(\:[0-9]{2,5})?(\/(?:[a-z0-9+\$_-]\.?)+)*\/?(\?[a-z+&\$_.-][a-z0-9;:@&%=+\/\$_.-]*)?(#[a-z_.-][a-z0-9+\$_.-]*)?/mi", '<$0>', $text); - + return $text; } @@ -642,36 +643,40 @@ function get_pr_code_friendliness($payload, $oldbalance = null){ $labels = get_pr_labels_array($payload); //anything not in this list defaults to 0 $label_values = array( - 'Fix' => 2, - 'Refactor' => 2, - 'CI/Tests' => 3, - 'Code Improvement' => 1, + 'Fix' => 3, + 'Refactor' => 10, + 'Code Improvement' => 2, 'Grammar and Formatting' => 1, - 'Priority: High' => 4, - 'Priority: CRITICAL' => 5, + 'Priority: High' => 15, + 'Priority: CRITICAL' => 20, + 'Unit Tests' => 6, 'Logging' => 1, - 'Feedback' => 1, - 'Performance' => 3, - 'Feature' => -1, - 'Balance/Rebalance' => -1, - 'PRB: Reset' => $startingPRBalance - $oldbalance, + 'Feedback' => 2, + 'Performance' => 12, + 'Feature' => -10, + 'Balance/Rebalance' => -8, + 'Tweak' => -2, + 'Sound' => 1, + 'Sprites' => 1, + 'GBP: Reset' => $startingPRBalance - $oldbalance, ); - $affecting = 0; - $is_neutral = FALSE; - $found_something_positive = false; + $maxNegative = 0; + $maxPositive = 0; foreach($labels as $l){ - if($l == 'PRB: No Update') { //no effect on balance - $affecting = 0; - break; + if($l == 'GBP: No Update') { //no effect on balance + return 0; } else if(isset($label_values[$l])) { $friendliness = $label_values[$l]; if($friendliness > 0) - $found_something_positive = true; - $affecting = $found_something_positive ? max($affecting, $friendliness) : $friendliness; + $maxPositive = max($friendliness, $maxPositive); + else + $maxNegative = min($friendliness, $maxNegative); } } + + $affecting = abs($maxNegative) >= $maxPositive ? $maxNegative : $maxPositive; return $affecting; } @@ -802,7 +807,7 @@ function checkchangelog($payload, $compile = true) { } if (!$incltag) continue; - + $firstword = explode(' ', $line)[0]; $pos = strpos($line, " "); $item = ''; @@ -812,7 +817,7 @@ function checkchangelog($payload, $compile = true) { } else { $firstword = $line; } - + if (!strlen($firstword)) { $currentchangelogblock[count($currentchangelogblock)-1]['body'] .= "\n"; continue; @@ -930,7 +935,7 @@ function checkchangelog($payload, $compile = true) { case 'server': if($item != 'something server ops should know') $currentchangelogblock[] = array('type' => 'server', 'body' => $item); - break; + break; default: //we add it to the last changelog entry as a separate line if (count($currentchangelogblock) > 0) @@ -966,11 +971,11 @@ function checkchangelog($payload, $compile = true) { function game_server_send($addr, $port, $str) { // All queries must begin with a question mark (ie "?players") - if($str{0} != '?') $str = ('?' . $str); - + if($str[0] != '?') $str = ('?' . $str); + /* --- Prepare a packet to send to the server (based on a reverse-engineered packet structure) --- */ $query = "\x00\x83" . pack('n', strlen($str) + 6) . "\x00\x00\x00\x00\x00" . $str . "\x00"; - + /* --- Create a socket and connect it to the server --- */ $server = socket_create(AF_INET,SOCK_STREAM,SOL_TCP) or exit("ERROR"); socket_set_option($server, SOL_SOCKET, SO_SNDTIMEO, array('sec' => 2, 'usec' => 0)); //sets connect and send timeout to 2 seconds @@ -978,7 +983,7 @@ function game_server_send($addr, $port, $str) { return "ERROR: Connection failed"; } - + /* --- Send bytes to the server. Loop until all bytes have been sent --- */ $bytestosend = strlen($query); $bytessent = 0; @@ -986,33 +991,33 @@ function game_server_send($addr, $port, $str) { //echo $bytessent.'
    '; $result = socket_write($server,substr($query,$bytessent),$bytestosend-$bytessent); //echo 'Sent '.$result.' bytes
    '; - if ($result===FALSE) + if ($result===FALSE) return "ERROR: " . socket_strerror(socket_last_error()); $bytessent += $result; } - + /* --- Idle for a while until recieved bytes from game server --- */ $result = socket_read($server, 10000, PHP_BINARY_READ); socket_close($server); // we don't need this anymore - + if($result != "") { - if($result{0} == "\x00" || $result{1} == "\x83") { // make sure it's the right packet format - + if($result[0] == "\x00" || $result[1] == "\x83") { // make sure it's the right packet format + // Actually begin reading the output: - $sizebytes = unpack('n', $result{2} . $result{3}); // array size of the type identifier and content + $sizebytes = unpack('n', $result[2] . $result[3]); // array size of the type identifier and content $size = $sizebytes[1] - 1; // size of the string/floating-point (minus the size of the identifier byte) - - if($result{4} == "\x2a") { // 4-byte big-endian floating-point - $unpackint = unpack('f', $result{5} . $result{6} . $result{7} . $result{8}); // 4 possible bytes: add them up together, unpack them as a floating-point + + if($result[4] == "\x2a") { // 4-byte big-endian floating-point + $unpackint = unpack('f', $result[5] . $result[6] . $result[7] . $result[8]); // 4 possible bytes: add them up together, unpack them as a floating-point return $unpackint[1]; } - else if($result{4} == "\x06") { // ASCII string + else if($result[4] == "\x06") { // ASCII string $unpackstr = ""; // result string $index = 5; // string index - + while($size > 0) { // loop through the entire ASCII string $size--; - $unpackstr .= $result{$index}; // add the string position to return string + $unpackstr .= $result[$index]; // add the string position to return string $index++; } return $unpackstr; diff --git a/tools/WebhookProcessor/secret.php b/tools/WebhookProcessor/secret.php index 9d1dc5a903..02dad3d627 100644 --- a/tools/WebhookProcessor/secret.php +++ b/tools/WebhookProcessor/secret.php @@ -1,6 +1,6 @@ indentation detected" +# st=1 +# fi; nl=' ' nl=$'\n' @@ -45,9 +65,13 @@ 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 + st=1 fi; done < <(find . -type f -name '*.dm') +# if grep -P '^/[\w/]\S+\(.*(var/|, ?var/.*).*\)' code/**/*.dm; then +# echo "changed files contains proc argument starting with 'var'" +# st=1 # annoy the coders instead of causing it to fail +# fi; if grep -i 'centcomm' code/**/*.dm; then echo "ERROR: Misspelling(s) of CENTCOM detected in code, please remove the extra M(s)." st=1 @@ -56,6 +80,14 @@ if grep -i 'centcomm' _maps/**/*.dmm; then echo "ERROR: Misspelling(s) of CENTCOM detected in maps, please remove the extra M(s)." st=1 fi; +if grep -ni 'nanotransen' code/**/*.dm; then + echo "Misspelling(s) of nanotrasen detected in code, please remove the extra N(s)." + st=1 +fi; +if grep -ni 'nanotransen' _maps/**/*.dmm; then + echo "Misspelling(s) of nanotrasen detected in maps, please remove the extra N(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 diff --git a/tools/travis/travis_config.txt b/tools/ci/ci_config.txt similarity index 82% rename from tools/travis/travis_config.txt rename to tools/ci/ci_config.txt index ff6bf9a793..4925d781bb 100644 --- a/tools/travis/travis_config.txt +++ b/tools/ci/ci_config.txt @@ -1,7 +1,7 @@ SQL_ENABLED ADDRESS 127.0.0.1 PORT 3306 -FEEDBACK_DATABASE tg_travis +FEEDBACK_DATABASE tg_ci FEEDBACK_TABLEPREFIX FEEDBACK_LOGIN root FEEDBACK_PASSWORD diff --git a/tools/travis/dm.sh b/tools/ci/dm.sh similarity index 100% rename from tools/travis/dm.sh rename to tools/ci/dm.sh diff --git a/tools/appveyor/download_byond.sh b/tools/ci/download_byond.sh old mode 100644 new mode 100755 similarity index 100% rename from tools/appveyor/download_byond.sh rename to tools/ci/download_byond.sh diff --git a/tools/travis/install_build_tools.sh b/tools/ci/install_build_tools.sh similarity index 88% rename from tools/travis/install_build_tools.sh rename to tools/ci/install_build_tools.sh index c36cd571ba..6c3e267fca 100755 --- a/tools/travis/install_build_tools.sh +++ b/tools/ci/install_build_tools.sh @@ -10,5 +10,3 @@ npm install --global yarn pip3 install --user PyYaml pip3 install --user beautifulsoup4 - -phpenv global $PHP_VERSION diff --git a/tools/travis/install_byond.sh b/tools/ci/install_byond.sh similarity index 100% rename from tools/travis/install_byond.sh rename to tools/ci/install_byond.sh diff --git a/tools/ci/install_rust_g.sh b/tools/ci/install_rust_g.sh new file mode 100755 index 0000000000..2309f9d952 --- /dev/null +++ b/tools/ci/install_rust_g.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail + +source dependencies.sh + +mkdir -p ~/.byond/bin +wget -O ~/.byond/bin/librust_g.so "https://github.com/tgstation/rust-g/releases/download/$RUST_G_VERSION/librust_g.so" +chmod +x ~/.byond/bin/librust_g.so +ldd ~/.byond/bin/librust_g.so diff --git a/tools/ci/install_spaceman_dmm.sh b/tools/ci/install_spaceman_dmm.sh new file mode 100755 index 0000000000..d92dca4e95 --- /dev/null +++ b/tools/ci/install_spaceman_dmm.sh @@ -0,0 +1,19 @@ +#!/bin/bash +set -euo pipefail + +source dependencies.sh + +if [ ! -f ~/$1 ]; then + mkdir -p "$HOME/SpacemanDMM" + CACHEFILE="$HOME/SpacemanDMM/$1" + + if ! [ -f "$CACHEFILE.version" ] || ! grep -Fxq "$SPACEMAN_DMM_VERSION" "$CACHEFILE.version"; then + wget -O "$CACHEFILE" "https://github.com/SpaceManiac/SpacemanDMM/releases/download/$SPACEMAN_DMM_VERSION/$1" + chmod +x "$CACHEFILE" + echo "$SPACEMAN_DMM_VERSION" >"$CACHEFILE.version" + fi + + ln -s "$CACHEFILE" ~/$1 +fi + +~/$1 --version diff --git a/tools/ci/run_server.sh b/tools/ci/run_server.sh new file mode 100755 index 0000000000..46172abc66 --- /dev/null +++ b/tools/ci/run_server.sh @@ -0,0 +1,19 @@ +#!/bin/bash +set -euo pipefail + +tools/deploy.sh ci_test +rm ci_test/*.dll +mkdir ci_test/config + +#test config +cp tools/ci/ci_config.txt ci_test/config/config.txt + +#throw extools into ldd +cp libbyond-extools.so ~/.byond/bin/libbyond-extools.so +chmod +x ~/.byond/bin/libbyond-extools.so +ldd ~/.byond/bin/libbyond-extools.so + +cd ci_test +DreamDaemon tgstation.dmb -close -trusted -verbose -params "log-directory=ci" +cd .. +cat ci_test/data/logs/ci/clean_run.lk diff --git a/tools/travis/template_dm_generator.py b/tools/ci/template_dm_generator.py similarity index 100% rename from tools/travis/template_dm_generator.py rename to tools/ci/template_dm_generator.py diff --git a/tools/travis/build_bsql.sh b/tools/travis/build_bsql.sh deleted file mode 100755 index e2b281efc6..0000000000 --- a/tools/travis/build_bsql.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -source dependencies.sh - -mkdir -p BSQL -cd BSQL -git init -git remote add origin https://github.com/tgstation/BSQL -git fetch --depth 1 origin $BSQL_VERSION -git checkout FETCH_HEAD - -mkdir -p artifacts -cd artifacts -export CXX=g++-7 -# The -D will be unnecessary past BSQL v1.4.0.0 -cmake .. -DMARIA_LIBRARY=/usr/lib/i386-linux-gnu/libmariadb.so -make - -mkdir -p ~/.byond/bin -ln -s $PWD/src/BSQL/libBSQL.so ../../libBSQL.so diff --git a/tools/travis/check_line_endings.py b/tools/travis/check_line_endings.py deleted file mode 100644 index fbbbc41426..0000000000 --- a/tools/travis/check_line_endings.py +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env python - -import os -import sys -import glob - -WINDOWS_NEWLINE = b'\r\n' - -FILES_TO_READ = [] -FILES_TO_READ.extend(glob.glob(r"**/*.dm", recursive=True)) -FILES_TO_READ.extend(glob.glob(r"**/*.dmm", recursive=True)) -FILES_TO_READ.extend(glob.glob(r"*.dme")) -#for i in FILES_TO_READ: -# if os.path.isdir(i): -# FILES_TO_READ.remove(i) - -def _reader(filepath): - data = open(filepath, "rb") - return data - -def main(): - filelist = [] - foundfiles = False - - for file in FILES_TO_READ: - data = _reader(file) - lines = data.readlines() - for line in lines: - if line.endswith(WINDOWS_NEWLINE): - filelist.append(file) - foundfiles = True - break - data.close() - - if not foundfiles: - print("No CRLF files found.") - sys.exit(0) - else: - print("Found files with suspected CRLF type.") - for i in filelist: - print(i) - sys.exit(1) - - - -if __name__ == "__main__": - main() diff --git a/tools/travis/install_libmariadb.sh b/tools/travis/install_libmariadb.sh deleted file mode 100755 index d0ce4adc14..0000000000 --- a/tools/travis/install_libmariadb.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash -set -euo pipefail - -# get libmariadb, cache it so limmex doesn't get angery -if [ -f $HOME/libmariadb ]; then - #travis likes to interpret the cache command as it being a file for some reason - rm $HOME/libmariadb -fi -mkdir -p $HOME/libmariadb -if [ ! -f $HOME/libmariadb/libmariadb.so ]; then - wget http://www.byond.com/download/db/mariadb_client-2.0.0-linux.tgz - tar -xvf mariadb_client-2.0.0-linux.tgz - mv mariadb_client-2.0.0-linux/libmariadb.so $HOME/libmariadb/libmariadb.so - rm -rf mariadb_client-2.0.0-linux.tgz mariadb_client-2.0.0-linux -fi diff --git a/tools/travis/install_rust_g.sh b/tools/travis/install_rust_g.sh deleted file mode 100755 index 227034af66..0000000000 --- a/tools/travis/install_rust_g.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -source dependencies.sh - -mkdir -p ~/.byond/bin -wget -O ~/.byond/bin/rust_g "https://github.com/tgstation/rust-g/releases/download/$RUST_G_VERSION/librust_g.so" -chmod +x ~/.byond/bin/rust_g diff --git a/tools/travis/install_spaceman_dmm.sh b/tools/travis/install_spaceman_dmm.sh deleted file mode 100755 index 39464193f8..0000000000 --- a/tools/travis/install_spaceman_dmm.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/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 deleted file mode 100755 index 04c491cd5c..0000000000 --- a/tools/travis/run_server.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash -set -euo pipefail - -tools/deploy.sh travis_test -rm travis_test/*.dll -mkdir travis_test/config - -#test config -cp tools/travis/travis_config.txt travis_test/config/config.txt - -cd travis_test -ln -s $HOME/libmariadb/libmariadb.so libmariadb.so -DreamDaemon tgstation.dmb -close -trusted -verbose -params "test-run&log-directory=travis" -cd .. -cat travis_test/data/logs/travis/clean_run.lk