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 3fb2661cea..12c507c2bf 100644 --- a/_maps/map_files/PubbyStation/PubbyStation.dmm +++ b/_maps/map_files/PubbyStation/PubbyStation.dmm @@ -2337,9 +2337,12 @@ /turf/open/floor/plasteel/dark, /area/security/prison) "afJ" = ( -/obj/effect/landmark/carpspawn, -/turf/open/space/basic, -/area/space/nearstation) +/obj/effect/turf_decal/tile/neutral, +/obj/machinery/atmospherics/pipe/manifold/supply/hidden{ + dir = 8 + }, +/turf/open/floor/plasteel, +/area/hallway/primary/central) "afK" = ( /obj/machinery/atmospherics/components/unary/tank/air{ dir = 1 @@ -16527,6 +16530,9 @@ /obj/structure/cable{ icon_state = "4-8" }, +/obj/machinery/airalarm{ + pixel_y = 22 + }, /turf/open/floor/plasteel, /area/quartermaster/warehouse) "aMr" = ( @@ -20027,9 +20033,7 @@ /obj/structure/cable{ icon_state = "1-8" }, -/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{ - dir = 4 - }, +/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden, /turf/open/floor/plating, /area/maintenance/department/crew_quarters/bar) "aUQ" = ( @@ -20044,6 +20048,9 @@ /obj/effect/turf_decal/tile/neutral{ dir = 8 }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 10 + }, /turf/open/floor/plasteel/dark, /area/hydroponics) "aUR" = ( @@ -20485,8 +20492,16 @@ /turf/closed/wall, /area/janitor) "aVT" = ( -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, -/turf/closed/wall, +/obj/machinery/door/firedoor, +/obj/machinery/door/poddoor/shutters{ + id = "jangarage"; + name = "Custodial Closet Shutters" + }, +/obj/effect/turf_decal/delivery, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, +/turf/open/floor/plasteel, /area/janitor) "aVU" = ( /obj/machinery/door/window/eastright{ @@ -20510,6 +20525,7 @@ /obj/effect/turf_decal/tile/neutral{ dir = 8 }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/open/floor/plasteel/dark, /area/janitor) "aVV" = ( @@ -20892,9 +20908,6 @@ /obj/machinery/camera{ c_tag = "Custodial Quarters" }, -/obj/machinery/atmospherics/components/unary/vent_scrubber/on{ - dir = 1 - }, /obj/machinery/light/small{ dir = 1 }, @@ -20915,6 +20928,9 @@ /obj/effect/turf_decal/tile/neutral{ dir = 8 }, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on{ + dir = 4 + }, /turf/open/floor/plasteel/dark, /area/janitor) "aWO" = ( @@ -20934,6 +20950,9 @@ /obj/effect/turf_decal/tile/neutral{ dir = 8 }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 9 + }, /turf/open/floor/plasteel/dark, /area/janitor) "aWP" = ( @@ -23004,9 +23023,6 @@ /turf/open/floor/plasteel, /area/hallway/primary/central) "baW" = ( -/obj/machinery/atmospherics/pipe/manifold/supply/hidden{ - dir = 8 - }, /obj/machinery/button/door{ id = "jangarage"; name = "Custodial Closet Shutters Control"; @@ -23014,14 +23030,12 @@ req_access_txt = "26" }, /obj/effect/turf_decal/tile/neutral, +/obj/machinery/atmospherics/pipe/simple/supply/hidden, /turf/open/floor/plasteel, /area/hallway/primary/central) "baX" = ( /obj/vehicle/ridden/janicart, /obj/structure/disposalpipe/segment, -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 4 - }, /obj/machinery/light{ dir = 8 }, @@ -23034,6 +23048,9 @@ /obj/structure/cable{ icon_state = "2-4" }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 6 + }, /turf/open/floor/plasteel, /area/janitor) "baY" = ( @@ -23398,6 +23415,9 @@ /obj/structure/cable{ icon_state = "1-2" }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 9 + }, /turf/open/floor/plasteel, /area/janitor) "bbY" = ( @@ -31173,17 +31193,26 @@ "bup" = ( /obj/machinery/rnd/destructive_analyzer, /obj/effect/turf_decal/delivery, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, /turf/open/floor/plasteel, /area/science/lab) "buq" = ( /obj/structure/disposalpipe/segment, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /obj/effect/turf_decal/bot, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, /turf/open/floor/plasteel, /area/science/lab) "bur" = ( /obj/effect/turf_decal/delivery, /obj/machinery/rnd/production/protolathe/department/science, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, /turf/open/floor/plasteel, /area/science/lab) "bus" = ( @@ -31202,6 +31231,9 @@ /obj/machinery/light{ dir = 4 }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 10 + }, /turf/open/floor/plasteel/white, /area/science/lab) "but" = ( @@ -31664,6 +31696,7 @@ /obj/structure/cable{ icon_state = "1-2" }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden, /turf/open/floor/plasteel/white, /area/science/lab) "bvA" = ( @@ -32372,6 +32405,7 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 4 }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden, /turf/open/floor/plasteel/white, /area/science/lab) "bxh" = ( @@ -33056,12 +33090,6 @@ /turf/open/floor/plasteel, /area/hallway/primary/aft) "byD" = ( -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ - dir = 6 - }, -/obj/structure/cable{ - icon_state = "2-4" - }, /obj/machinery/door/airlock/research{ name = "R&D Lab"; req_one_access_txt = "7;29;30" @@ -33070,6 +33098,12 @@ /obj/structure/disposalpipe/segment{ dir = 6 }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 + }, /turf/open/floor/plasteel, /area/science/lab) "byE" = ( @@ -33091,7 +33125,6 @@ /turf/open/floor/plasteel/white, /area/science/lab) "byG" = ( -/obj/machinery/atmospherics/components/unary/vent_pump/on, /obj/structure/cable{ icon_state = "1-2" }, @@ -33919,10 +33952,6 @@ /area/hallway/primary/aft) "bAm" = ( /obj/structure/disposalpipe/segment, -/obj/structure/cable{ - icon_state = "1-2" - }, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/closed/wall/r_wall, /area/hallway/primary/aft) "bAo" = ( @@ -33952,7 +33981,6 @@ /obj/structure/cable{ icon_state = "1-4" }, -/obj/machinery/atmospherics/pipe/simple/supply/hidden, /obj/effect/turf_decal/tile/purple{ dir = 1 }, @@ -34404,17 +34432,14 @@ name = "RD Office APC"; pixel_x = -25 }, -/obj/structure/cable{ - icon_state = "0-4" - }, /obj/effect/turf_decal/tile/purple{ dir = 1 }, /obj/effect/turf_decal/tile/purple{ dir = 8 }, -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 4 +/obj/structure/cable{ + icon_state = "4-8" }, /turf/open/floor/plasteel/dark, /area/crew_quarters/heads/hor) @@ -34425,8 +34450,8 @@ /obj/structure/disposalpipe/segment{ dir = 5 }, -/obj/machinery/atmospherics/pipe/manifold/supply/hidden{ - dir = 4 +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 6 }, /turf/open/floor/plasteel/dark, /area/crew_quarters/heads/hor) @@ -34434,6 +34459,9 @@ /obj/structure/disposalpipe/segment{ dir = 4 }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, /turf/open/floor/plasteel/dark, /area/crew_quarters/heads/hor) "bBt" = ( @@ -34441,6 +34469,9 @@ /obj/structure/disposalpipe/segment{ dir = 4 }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, /turf/open/floor/plasteel/dark, /area/crew_quarters/heads/hor) "bBu" = ( @@ -34478,6 +34509,9 @@ /obj/effect/turf_decal/tile/purple{ dir = 4 }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 9 + }, /turf/open/floor/plasteel/dark, /area/crew_quarters/heads/hor) "bBw" = ( @@ -35240,6 +35274,7 @@ /obj/structure/cable{ icon_state = "0-8" }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden, /turf/open/floor/plating, /area/crew_quarters/heads/hor) "bCK" = ( @@ -44248,9 +44283,11 @@ /turf/open/floor/engine/co2, /area/engine/atmos) "bWh" = ( -/obj/effect/turf_decal/sand, +/obj/machinery/atmospherics/pipe/manifold/supply/hidden{ + dir = 8 + }, /turf/open/floor/plasteel, -/area/chapel/office) +/area/hallway/primary/aft) "bWi" = ( /obj/structure/flora/ausbushes/leafybush, /obj/structure/flora/ausbushes/reedbush, @@ -47597,6 +47634,9 @@ pixel_x = -25; specialfunctions = 4 }, +/obj/machinery/airalarm{ + pixel_y = 22 + }, /turf/open/floor/plasteel/grimy, /area/chapel/main/monastery) "cgM" = ( @@ -47945,6 +47985,9 @@ pixel_x = -25; specialfunctions = 4 }, +/obj/machinery/airalarm{ + pixel_y = 22 + }, /turf/open/floor/plasteel/grimy, /area/chapel/main/monastery) "cip" = ( @@ -51432,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" = ( @@ -52824,6 +52871,9 @@ /turf/closed/wall/r_wall, /area/science/lab) "cCt" = ( +/obj/machinery/atmospherics/pipe/manifold/supply/hidden{ + dir = 1 + }, /turf/open/floor/plasteel/white, /area/science/lab) "cCB" = ( @@ -53058,6 +53108,9 @@ freq = 1400; location = "Research Division" }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, /turf/open/floor/plasteel/dark, /area/science/lab) "cXW" = ( @@ -53151,10 +53204,6 @@ /area/maintenance/department/security/brig) "dhz" = ( /obj/structure/disposalpipe/segment, -/obj/structure/cable{ - icon_state = "1-2" - }, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /obj/structure/chair{ dir = 8; name = "Defense" @@ -53163,9 +53212,6 @@ /obj/effect/turf_decal/tile/purple{ dir = 8 }, -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 4 - }, /turf/open/floor/plasteel, /area/hallway/primary/aft) "dir" = ( @@ -53960,11 +54006,11 @@ /obj/structure/disposalpipe/segment{ dir = 4 }, -/obj/structure/cable{ - icon_state = "4-8" - }, /obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{ - dir = 1 + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-8" }, /turf/open/floor/plasteel, /area/hallway/primary/aft) @@ -55488,6 +55534,12 @@ /obj/effect/turf_decal/tile/purple{ dir = 4 }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 6 + }, +/obj/structure/cable{ + icon_state = "2-4" + }, /turf/open/floor/plasteel, /area/hallway/primary/aft) "ioj" = ( @@ -55591,6 +55643,9 @@ /obj/effect/turf_decal/tile/blue{ dir = 8 }, +/obj/structure/cable{ + icon_state = "4-8" + }, /turf/open/floor/plasteel, /area/hallway/primary/aft) "iyg" = ( @@ -56345,9 +56400,13 @@ /turf/open/floor/plasteel/white, /area/science/mixing) "koz" = ( -/obj/machinery/atmospherics/pipe/manifold/supply/hidden{ +/obj/effect/turf_decal/tile/purple, +/obj/effect/turf_decal/tile/purple{ dir = 8 }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, /turf/open/floor/plasteel, /area/hallway/primary/aft) "kpK" = ( @@ -56634,10 +56693,14 @@ /turf/open/floor/plasteel/dark, /area/science/xenobiology) "kSb" = ( -/obj/structure/lattice, -/obj/structure/grille, -/turf/open/space/basic, -/area/space) +/obj/structure/chair/office/light{ + dir = 8 + }, +/obj/machinery/atmospherics/components/unary/vent_pump/on{ + dir = 1 + }, +/turf/open/floor/plasteel/white, +/area/science/lab) "kSF" = ( /obj/structure/cable{ icon_state = "1-4" @@ -56711,6 +56774,10 @@ /obj/effect/turf_decal/tile/purple{ dir = 8 }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, +/obj/structure/cable{ + icon_state = "1-2" + }, /turf/open/floor/plasteel, /area/hallway/primary/aft) "lcU" = ( @@ -57121,6 +57188,7 @@ /obj/effect/turf_decal/tile/purple{ dir = 8 }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden, /turf/open/floor/plasteel/white, /area/science/lab) "meF" = ( @@ -57128,8 +57196,9 @@ /turf/closed/wall/r_wall, /area/engine/supermatter) "mfC" = ( -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 4 +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, +/obj/structure/cable{ + icon_state = "1-2" }, /turf/open/floor/plasteel, /area/hallway/primary/aft) @@ -59343,6 +59412,7 @@ /area/hallway/secondary/exit/departure_lounge) "qVk" = ( /obj/machinery/door/poddoor/incinerator_atmos_aux, +/obj/structure/lattice/catwalk, /turf/open/space/basic, /area/maintenance/disposal/incinerator) "qVP" = ( @@ -59377,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" = ( @@ -60493,6 +60567,9 @@ id = "research_shutters_2"; name = "research shutters" }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, /turf/open/floor/plasteel, /area/science/lab) "tLP" = ( @@ -60815,12 +60892,6 @@ /obj/structure/disposalpipe/segment{ dir = 9 }, -/obj/structure/cable{ - icon_state = "1-8" - }, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ - dir = 9 - }, /obj/structure/chair{ dir = 8; name = "Defense" @@ -61500,12 +61571,6 @@ }, /turf/open/floor/plasteel, /area/science/xenobiology) -"wfG" = ( -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 4 - }, -/turf/closed/wall/r_wall, -/area/crew_quarters/heads/hor) "wfO" = ( /mob/living/simple_animal/hostile/retaliate/poison/snake, /turf/open/floor/plating, @@ -76969,7 +77034,7 @@ aaa bOv bNs bNs -bWh +bQg bQg bQg bQg @@ -84176,7 +84241,7 @@ bIZ cbb bDi ccO -bIZ +bva cjm cjm xgh @@ -84436,8 +84501,8 @@ bva bva aht aht -kSb -kSb +fon +fon aht aht mau @@ -86691,7 +86756,7 @@ aXL aYL aZN baW -aKI +afJ aKI beb aKI @@ -86947,8 +87012,8 @@ aVS aXM aVS aVS -aXM -bbW +aVS +aVT bbW aVS aVS @@ -87149,7 +87214,7 @@ aaa aaa aaa aaa -afJ +cFB aby aaa agQ @@ -87456,7 +87521,7 @@ aRJ aSz aSz aUP -aVT +aVS aWN aXO aYM @@ -89468,7 +89533,7 @@ aaa aaa aaa aaa -afJ +cFB aaa aaa abI @@ -94932,12 +94997,12 @@ jcT xje tTl tTl -tTl +bWh gkS tTl tTl tTl -koz +tTl dgg phJ phJ @@ -95189,7 +95254,7 @@ bjm mhn cqi cqi -cqi +koz cqi cqi imE @@ -95708,7 +95773,7 @@ duF bxa byE bBp -wfG +bBp bBp bBp bBp @@ -95961,7 +96026,7 @@ cCl brq byF cCt -byF +kSb bxc nIU bAo 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/__DEFINES/vote.dm b/code/__DEFINES/vote.dm index a3617e21d0..88e70b884e 100644 --- a/code/__DEFINES/vote.dm +++ b/code/__DEFINES/vote.dm @@ -2,7 +2,7 @@ #define APPROVAL_VOTING "APPROVAL" #define SCHULZE_VOTING "SCHULZE" #define SCORE_VOTING "SCORE" -#define MAJORITY_JUDGEMENT_VOTING "MAJORITY_JUDGEMENT" +#define HIGHEST_MEDIAN_VOTING "HIGHEST_MEDIAN" #define INSTANT_RUNOFF_VOTING "IRV" #define SHOW_RESULTS (1<<0) @@ -18,7 +18,7 @@ GLOBAL_LIST_INIT(vote_type_names,list(\ "IRV (single winner ranked choice)" = INSTANT_RUNOFF_VOTING,\ "Schulze (ranked choice, higher result=better)" = SCHULZE_VOTING,\ "Raw Score (returns results from 0 to 1, winner is 1)" = SCORE_VOTING,\ -"Majority Judgement (single-winner score voting)" = MAJORITY_JUDGEMENT_VOTING,\ +"Highest Median (single-winner score voting)" = HIGHEST_MEDIAN_VOTING,\ )) GLOBAL_LIST_INIT(display_vote_settings, list(\ 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..71bbfe64fe 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -263,7 +263,7 @@ Turf and target are separate in case you want to teleport some distance from a t return . //Returns a list of all items of interest with their name -/proc/getpois(mobs_only=0,skip_mindless=0) +/proc/getpois(mobs_only = FALSE, skip_mindless = FALSE, specify_dead_role = TRUE) var/list/mobs = sortmobs() var/list/namecounts = list() var/list/pois = list() @@ -277,7 +277,7 @@ Turf and target are separate in case you want to teleport some distance from a t if(M.real_name && M.real_name != M.name) name += " \[[M.real_name]\]" - if(M.stat == DEAD) + if(M.stat == DEAD && specify_dead_role) if(isobserver(M)) name += " \[ghost\]" else @@ -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/lists/flavor_misc.dm b/code/_globalvars/lists/flavor_misc.dm index 7fad1690e6..41068048a1 100644 --- a/code/_globalvars/lists/flavor_misc.dm +++ b/code/_globalvars/lists/flavor_misc.dm @@ -274,7 +274,7 @@ GLOBAL_LIST_INIT(redacted_strings, list("\[REDACTED\]", "\[CLASSIFIED\]", "\[ARC GLOBAL_LIST_INIT(wisdoms, world.file2list("strings/wisdoms.txt")) //LANGUAGE CHARACTER CUSTOMIZATION -GLOBAL_LIST_INIT(speech_verbs, list("default","says","gibbers", "states", "chitters", "chimpers", "declares", "bellows", "buzzes" ,"beeps", "chirps", "clicks", "hisses" ,"poofs" , "puffs", "rattles", "mewls" ,"barks", "blorbles", "squeaks", "squawks", "flutters", "warbles")) +GLOBAL_LIST_INIT(speech_verbs, list("default","says","gibbers", "states", "chitters", "chimpers", "declares", "bellows", "buzzes" ,"beeps", "chirps", "clicks", "hisses" ,"poofs" , "puffs", "rattles", "mewls" ,"barks", "blorbles", "squeaks", "squawks", "flutters", "warbles", "caws", "gekkers", "clucks")) GLOBAL_LIST_INIT(roundstart_tongues, list("default","human tongue" = /obj/item/organ/tongue, "lizard tongue" = /obj/item/organ/tongue/lizard, "skeleton tongue" = /obj/item/organ/tongue/bone, "fly tongue" = /obj/item/organ/tongue/fly, "ipc tongue" = /obj/item/organ/tongue/robot/ipc, "xeno tongue" = /obj/item/organ/tongue/alien)) //SPECIES BODYPART LISTS 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/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index 880802fd5c..fb8299d108 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -141,8 +141,8 @@ SUBSYSTEM_DEF(vote) choices[choices[i]]++ // higher shortest path = better candidate, so we add to choices here // choices[choices[i]] is the schulze ranking, here, rather than raw vote numbers -/datum/controller/subsystem/vote/proc/calculate_majority_judgement_vote(var/blackbox_text) - // https://en.wikipedia.org/wiki/Majority_judgment +/datum/controller/subsystem/vote/proc/calculate_highest_median(var/blackbox_text) + // https://en.wikipedia.org/wiki/Highest_median_voting_rules var/list/scores_by_choice = list() for(var/choice in choices) scores_by_choice += "[choice]" @@ -161,33 +161,24 @@ SUBSYSTEM_DEF(vote) // END BALLOT GATHERING for(var/score_name in scores_by_choice) var/list/score = scores_by_choice[score_name] - for(var/indiv_score in score) - SSblackbox.record_feedback("nested tally","voting",1,list(blackbox_text,"Scores",score_name,GLOB.vote_score_options[indiv_score])) - if(score.len == 0) - scores_by_choice -= score_name - while(scores_by_choice.len > 1) - var/highest_median = 0 - for(var/score_name in scores_by_choice) // first get highest median - var/list/score = scores_by_choice[score_name] - if(!score.len) - scores_by_choice -= score_name - continue + if(!score.len) + choices[score_name] = 0 + else var/median = score[max(1,round(score.len/2))] - if(median >= highest_median) - highest_median = median - for(var/score_name in scores_by_choice) // then, remove - var/list/score = scores_by_choice[score_name] - var/median = score[max(1,round(score.len/2))] - if(median < highest_median) - scores_by_choice -= score_name - for(var/score_name in scores_by_choice) // after removals - var/list/score = scores_by_choice[score_name] - if(score.len == 0) - choices[score_name] += 100 // we're in a tie situation--just go with the first one - return - var/median_pos = max(1,round(score.len/2)) - score.Cut(median_pos,median_pos+1) - choices[score_name]++ + var/p = 0 // proponents (those with higher than median) + var/q = 0 // opponents (lower than median) + var/list/this_score_list = scores_by_choice[score_name] + for(var/indiv_score in score) + SSblackbox.record_feedback("nested tally","voting",1,list(blackbox_text,"Scores",score_name,GLOB.vote_score_options[indiv_score])) + if(indiv_score < median) // this is possible to do in O(logn) but n is never more than 200 so this is fine + q += 1 + else if(indiv_score > median) + p += 1 + p /= this_score_list.len + q /= this_score_list.len + choices[score_name] = median + (((p - q) / (1 - p - q)) * 0.5) // usual judgement + // choices[score_name] = median + p - q // typical judgement + // choices[score_name] = median + (((p - q) / (p + q)) * 0.5) // central judgement /datum/controller/subsystem/vote/proc/calculate_scores(var/blackbox_text) for(var/choice in choices) @@ -245,8 +236,8 @@ SUBSYSTEM_DEF(vote) calculate_condorcet_votes(vote_title_text) if(vote_system == SCORE_VOTING) calculate_scores(vote_title_text) - if(vote_system == MAJORITY_JUDGEMENT_VOTING) - calculate_majority_judgement_vote(vote_title_text) // nothing uses this at the moment + if(vote_system == HIGHEST_MEDIAN_VOTING) + calculate_highest_median(vote_title_text) // nothing uses this at the moment var/list/winners = vote_system == INSTANT_RUNOFF_VOTING ? get_runoff_results() : get_result() var/was_roundtype_vote = mode == "roundtype" || mode == "dynamic" if(winners.len > 0) @@ -255,8 +246,8 @@ SUBSYSTEM_DEF(vote) if(display_votes & SHOW_RESULTS) if(vote_system == SCHULZE_VOTING) text += "\nIt should be noted that this is not a raw tally of votes (impossible in ranked choice) but the score determined by the schulze method of voting, so the numbers will look weird!" - if(vote_system == MAJORITY_JUDGEMENT_VOTING) - text += "\nIt should be noted that this is not a raw tally of votes but the number of runoffs done by majority judgement!" + if(vote_system == HIGHEST_MEDIAN_VOTING) + text += "\nThis is the highest median score plus the tiebreaker!" for(var/i=1,i<=choices.len,i++) var/votes = choices[choices[i]] if(!votes) @@ -302,7 +293,7 @@ SUBSYSTEM_DEF(vote) if(vote_system != SCORE_VOTING) if(vote_system == SCHULZE_VOTING) admintext += "\nIt should be noted that this is not a raw tally of votes (impossible in ranked choice) but the score determined by the schulze method of voting, so the numbers will look weird!" - else if(vote_system == MAJORITY_JUDGEMENT_VOTING) + else if(vote_system == HIGHEST_MEDIAN_VOTING) admintext += "\nIt should be noted that this is not a raw tally of votes but the number of runoffs done by majority judgement!" for(var/i=1,i<=choices.len,i++) var/votes = choices[choices[i]] @@ -429,7 +420,7 @@ SUBSYSTEM_DEF(vote) voted[usr.ckey] = list() voted[usr.ckey] += vote saved -= usr.ckey - if(SCORE_VOTING,MAJORITY_JUDGEMENT_VOTING) + if(SCORE_VOTING,HIGHEST_MEDIAN_VOTING) if(!(usr.ckey in voted)) voted += usr.ckey voted[usr.ckey] = list() @@ -584,7 +575,7 @@ SUBSYSTEM_DEF(vote) . += "

Vote any number of choices.

" if(SCHULZE_VOTING,INSTANT_RUNOFF_VOTING) . += "

Vote by order of preference. Revoting will demote to the bottom. 1 is your favorite, and higher numbers are worse.

" - if(SCORE_VOTING,MAJORITY_JUDGEMENT_VOTING) + if(SCORE_VOTING,HIGHEST_MEDIAN_VOTING) . += "

Grade the candidates by how much you like them.

" . += "

No-votes have no power--your opinion is only heard if you vote!

" . += "Time Left: [DisplayTimeText(end_time-world.time)]