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..eb25c8a0cd 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/SpaceRuins/crashedship.dmm b/_maps/RandomRuins/SpaceRuins/crashedship.dmm
index 63e6770e42..beb93b319e 100644
--- a/_maps/RandomRuins/SpaceRuins/crashedship.dmm
+++ b/_maps/RandomRuins/SpaceRuins/crashedship.dmm
@@ -2372,7 +2372,7 @@
},
/area/awaymission/BMPship/Midship)
"hh" = (
-/obj/item/caution,
+/obj/item/clothing/suit/caution,
/turf/open/floor/plating/airless,
/area/awaymission/BMPship/Midship)
"hi" = (
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/RandomZLevels/away_mission/Academy.dmm b/_maps/RandomZLevels/away_mission/Academy.dmm
index 37b0098fd2..9b61f50600 100644
--- a/_maps/RandomZLevels/away_mission/Academy.dmm
+++ b/_maps/RandomZLevels/away_mission/Academy.dmm
@@ -2710,7 +2710,7 @@
/obj/structure/cable{
icon_state = "4-8"
},
-/obj/item/caution,
+/obj/item/clothing/suit/caution,
/obj/effect/turf_decal/tile/green,
/obj/effect/turf_decal/tile/green{
dir = 4
diff --git a/_maps/RandomZLevels/away_mission/SnowCabin.dmm b/_maps/RandomZLevels/away_mission/SnowCabin.dmm
index 844a134d27..fbb83899fd 100644
--- a/_maps/RandomZLevels/away_mission/SnowCabin.dmm
+++ b/_maps/RandomZLevels/away_mission/SnowCabin.dmm
@@ -312,7 +312,7 @@
/obj/structure/janitorialcart,
/obj/item/mop,
/obj/item/reagent_containers/glass/bucket,
-/obj/item/caution,
+/obj/item/clothing/suit/caution,
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/plating,
/area/awaymission/cabin)
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 bb372563cf..b81f55be21 100644
--- a/_maps/map_files/BoxStation/BoxStation.dmm
+++ b/_maps/map_files/BoxStation/BoxStation.dmm
@@ -69,35 +69,18 @@
/turf/closed/wall/r_wall,
/area/security/prison)
"aaj" = (
+/obj/structure/cable{
+ icon_state = "1-4"
+ },
/obj/structure/cable{
icon_state = "4-8"
},
-/turf/closed/wall/r_wall,
-/area/security/prison)
-"aak" = (
-/obj/structure/cable{
- icon_state = "0-4"
- },
-/obj/effect/spawner/structure/window/reinforced,
-/turf/open/floor/plating,
-/area/security/prison)
-"aal" = (
-/obj/structure/cable{
- icon_state = "0-4"
- },
-/obj/structure/cable{
- icon_state = "0-8"
- },
-/obj/effect/spawner/structure/window/reinforced,
-/turf/open/floor/plating,
+/turf/open/floor/plasteel,
/area/security/prison)
"aam" = (
/obj/structure/cable{
icon_state = "0-2"
},
-/obj/structure/cable{
- icon_state = "0-8"
- },
/obj/effect/spawner/structure/window/reinforced,
/turf/open/floor/plating,
/area/security/prison)
@@ -115,11 +98,17 @@
/obj/structure/sign/warning/electricshock{
pixel_y = 32
},
+/obj/structure/cable{
+ icon_state = "4-8"
+ },
/turf/open/floor/grass,
/area/security/prison)
"aap" = (
/obj/machinery/hydroponics/soil,
/obj/item/seeds/carrot,
+/obj/structure/cable{
+ icon_state = "1-4"
+ },
/turf/open/floor/grass,
/area/security/prison)
"aaq" = (
@@ -140,17 +129,29 @@
/obj/structure/sink{
pixel_y = 20
},
+/obj/structure/cable{
+ icon_state = "4-8"
+ },
/turf/open/floor/plasteel,
/area/security/prison)
"aar" = (
/obj/machinery/hydroponics/soil,
/obj/item/seeds/glowshroom,
+/obj/structure/cable{
+ icon_state = "1-4"
+ },
+/obj/structure/cable{
+ icon_state = "4-8"
+ },
/turf/open/floor/grass,
/area/security/prison)
"aas" = (
/obj/structure/sign/warning/electricshock{
pixel_y = 32
},
+/obj/structure/cable{
+ icon_state = "4-8"
+ },
/turf/open/floor/plasteel,
/area/security/prison)
"aat" = (
@@ -5666,6 +5667,9 @@
/obj/structure/disposalpipe/segment{
dir = 4
},
+/obj/structure/cable{
+ icon_state = "2-4"
+ },
/turf/open/floor/plasteel,
/area/security/brig)
"akw" = (
@@ -5845,10 +5849,13 @@
/area/science/xenobiology)
"akQ" = (
/obj/structure/cable{
- icon_state = "4-8"
+ icon_state = "1-2"
},
-/turf/closed/wall,
-/area/security/brig)
+/obj/structure/cable{
+ icon_state = "2-8"
+ },
+/turf/open/floor/plasteel,
+/area/security/prison)
"akR" = (
/obj/machinery/camera{
c_tag = "Security Office";
@@ -6108,7 +6115,7 @@
"alq" = (
/obj/machinery/door/airlock/security/glass{
name = "Evidence Storage";
- req_access_txt = "4"
+ req_one_access_txt = "4;1"
},
/obj/machinery/door/firedoor,
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
@@ -6142,25 +6149,11 @@
/turf/open/floor/plasteel,
/area/security/brig)
"alt" = (
-/obj/machinery/door/airlock/security/glass{
- id_tag = "innerbrig";
- name = "Brig";
- req_access_txt = "63"
- },
-/obj/machinery/door/firedoor,
-/obj/structure/cable{
- icon_state = "4-8"
- },
-/obj/effect/mapping_helpers/airlock/cyclelink_helper,
-/obj/effect/turf_decal/tile/red,
-/obj/effect/turf_decal/tile/red{
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
},
-/obj/effect/turf_decal/tile/red{
- dir = 8
- },
-/obj/effect/turf_decal/tile/red{
- dir = 1
+/obj/structure/cable{
+ icon_state = "1-2"
},
/turf/open/floor/plasteel,
/area/security/brig)
@@ -6180,16 +6173,11 @@
/area/ai_monitored/nuke_storage)
"alv" = (
/obj/effect/spawner/structure/window/reinforced,
-/obj/structure/cable{
- icon_state = "0-8"
- },
-/obj/structure/cable{
- icon_state = "0-4"
- },
/obj/machinery/door/poddoor/preopen{
id = "Secure Gate";
name = "brig shutters"
},
+/obj/structure/cable,
/turf/open/floor/plating,
/area/security/brig)
"alw" = (
@@ -6272,6 +6260,9 @@
/obj/effect/turf_decal/tile/red{
dir = 4
},
+/obj/structure/cable{
+ icon_state = "2-4"
+ },
/turf/open/floor/plasteel,
/area/security/brig)
"alB" = (
@@ -6572,9 +6563,6 @@
/turf/open/floor/engine,
/area/science/xenobiology)
"amm" = (
-/obj/structure/cable{
- icon_state = "0-8"
- },
/obj/structure/cable{
icon_state = "0-4"
},
@@ -6609,6 +6597,9 @@
/obj/effect/turf_decal/tile/red{
dir = 4
},
+/obj/structure/cable{
+ icon_state = "4-8"
+ },
/turf/open/floor/plasteel,
/area/security/brig)
"amq" = (
@@ -6661,9 +6652,6 @@
icon_state = "0-8"
},
/obj/effect/spawner/structure/window/reinforced,
-/obj/structure/cable{
- icon_state = "0-4"
- },
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/open/floor/plating,
/area/security/brig)
@@ -6763,6 +6751,12 @@
/obj/effect/turf_decal/tile/red{
dir = 1
},
+/obj/structure/cable{
+ icon_state = "1-8"
+ },
+/obj/structure/cable{
+ icon_state = "2-8"
+ },
/turf/open/floor/plasteel,
/area/security/brig)
"amJ" = (
@@ -6853,25 +6847,15 @@
},
/turf/open/floor/plasteel,
/area/science/xenobiology)
-"amR" = (
-/obj/structure/cable{
- icon_state = "0-4"
- },
-/obj/structure/cable{
- icon_state = "0-8"
- },
-/obj/machinery/door/poddoor/preopen{
- id = "Secure Gate";
- name = "brig shutters"
- },
-/obj/effect/spawner/structure/window/reinforced,
-/turf/open/floor/plating,
-/area/security/brig)
"amS" = (
-/obj/structure/cable{
- icon_state = "4-8"
+/obj/effect/turf_decal/tile/red,
+/obj/effect/turf_decal/tile/red{
+ dir = 8
},
-/turf/closed/wall/r_wall,
+/obj/structure/cable{
+ icon_state = "1-2"
+ },
+/turf/open/floor/plasteel,
/area/security/brig)
"amT" = (
/obj/structure/cable{
@@ -7271,9 +7255,11 @@
/obj/structure/cable{
icon_state = "0-4"
},
-/obj/structure/cable,
/obj/effect/spawner/structure/window/reinforced,
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/obj/structure/cable{
+ icon_state = "1-4"
+ },
/turf/open/floor/plating,
/area/security/brig)
"anQ" = (
@@ -7281,9 +7267,6 @@
/obj/effect/turf_decal/tile/yellow{
dir = 8
},
-/obj/structure/cable{
- icon_state = "1-2"
- },
/turf/open/floor/plasteel,
/area/security/brig)
"anR" = (
@@ -7514,14 +7497,13 @@
/obj/structure/cable{
icon_state = "0-4"
},
-/obj/structure/cable,
/obj/machinery/door/poddoor/preopen{
id = "Secure Gate";
name = "brig shutters"
},
/obj/effect/spawner/structure/window/reinforced,
/obj/structure/cable{
- icon_state = "1-8"
+ icon_state = "0-8"
},
/turf/open/floor/plating,
/area/security/brig)
@@ -7755,13 +7737,13 @@
/area/security/brig)
"aoZ" = (
/obj/effect/spawner/structure/window/reinforced,
-/obj/structure/cable{
- icon_state = "0-2"
- },
/obj/machinery/door/poddoor/preopen{
id = "Secure Brig Control";
name = "brig shutters"
},
+/obj/structure/cable{
+ icon_state = "0-4"
+ },
/turf/open/floor/plating,
/area/security/warden)
"apa" = (
@@ -7780,6 +7762,9 @@
/area/science/xenobiology)
"apc" = (
/obj/structure/chair/office/dark,
+/obj/structure/cable{
+ icon_state = "4-8"
+ },
/turf/open/floor/plasteel/showroomfloor,
/area/security/warden)
"apd" = (
@@ -7933,6 +7918,12 @@
pixel_x = 6;
pixel_y = 3
},
+/obj/structure/cable{
+ icon_state = "4-8"
+ },
+/obj/structure/cable{
+ icon_state = "2-4"
+ },
/turf/open/floor/plasteel/showroomfloor,
/area/security/warden)
"apw" = (
@@ -8052,6 +8043,12 @@
pixel_y = -24;
req_access_txt = "2"
},
+/obj/structure/cable{
+ icon_state = "2-4"
+ },
+/obj/structure/cable{
+ icon_state = "4-8"
+ },
/turf/open/floor/plasteel/showroomfloor,
/area/security/warden)
"apI" = (
@@ -8133,9 +8130,6 @@
req_access_txt = "63"
},
/obj/machinery/door/firedoor,
-/obj/structure/cable{
- icon_state = "4-8"
- },
/obj/effect/mapping_helpers/airlock/cyclelink_helper{
dir = 1
},
@@ -8158,14 +8152,19 @@
/turf/open/floor/plating,
/area/maintenance/fore)
"apT" = (
+/obj/machinery/door/poddoor/preopen{
+ id = "Cell Interior Shutters";
+ name = "brig shutters"
+ },
+/obj/effect/spawner/structure/window/reinforced,
/obj/structure/cable{
- icon_state = "4-8"
+ icon_state = "0-8"
},
/obj/structure/cable{
- icon_state = "1-8"
+ icon_state = "0-4"
},
-/turf/closed/wall/r_wall,
-/area/security/warden)
+/turf/open/floor/plating,
+/area/security/brig)
"apU" = (
/turf/open/floor/plating,
/area/security/vacantoffice/b)
@@ -8181,20 +8180,6 @@
},
/turf/open/floor/plating,
/area/maintenance/fore)
-"apX" = (
-/obj/effect/spawner/structure/window/reinforced,
-/obj/structure/cable{
- icon_state = "0-8"
- },
-/obj/structure/cable{
- icon_state = "0-4"
- },
-/obj/machinery/door/poddoor/preopen{
- id = "Secure Brig Control";
- name = "brig shutters"
- },
-/turf/open/floor/plating,
-/area/security/warden)
"apY" = (
/obj/machinery/light/small{
dir = 1
@@ -8406,13 +8391,11 @@
/area/crew_quarters/fitness/pool)
"aqt" = (
/obj/effect/spawner/structure/window/reinforced,
-/obj/structure/cable{
- icon_state = "0-8"
- },
/obj/machinery/door/poddoor/preopen{
id = "Secure Brig Control";
name = "brig shutters"
},
+/obj/structure/cable,
/turf/open/floor/plating,
/area/security/warden)
"aqu" = (
@@ -8858,6 +8841,9 @@
c_tag = "Brig Control";
dir = 1
},
+/obj/structure/cable{
+ icon_state = "1-8"
+ },
/turf/open/floor/plasteel/showroomfloor,
/area/security/warden)
"arz" = (
@@ -11044,18 +11030,12 @@
/obj/structure/closet/crate/coffin,
/turf/open/floor/plating,
/area/maintenance/port/fore)
-"axo" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 4
- },
-/turf/open/floor/plating,
-/area/maintenance/fore)
"axp" = (
/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
dir = 1
},
/turf/open/floor/plating,
-/area/maintenance/fore)
+/area/maintenance/port/fore)
"axq" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 4
@@ -11454,10 +11434,6 @@
},
/turf/open/floor/plating,
/area/maintenance/fore)
-"ayC" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/turf/closed/wall,
-/area/maintenance/fore)
"ayD" = (
/obj/effect/spawner/structure/window/reinforced,
/turf/open/floor/plasteel/dark,
@@ -14269,10 +14245,6 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/open/floor/plating,
/area/maintenance/fore)
-"aGh" = (
-/obj/effect/landmark/event_spawn,
-/turf/open/floor/plating,
-/area/maintenance/fore)
"aGi" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/open/floor/plasteel/dark,
@@ -29648,10 +29620,10 @@
/turf/open/floor/plasteel/white,
/area/science/robotics/lab)
"bsU" = (
-/mob/living/simple_animal/hostile/retaliate/ghost,
/obj/machinery/atmospherics/components/unary/vent_pump/on{
dir = 4
},
+/mob/living/simple_animal/hostile/retaliate/ghost,
/turf/open/floor/wood,
/area/maintenance/port/fore)
"bsV" = (
@@ -45293,7 +45265,7 @@
/area/maintenance/aft)
"cfq" = (
/obj/structure/mopbucket,
-/obj/item/caution,
+/obj/item/clothing/suit/caution,
/turf/open/floor/plating,
/area/maintenance/aft)
"cfr" = (
@@ -52616,9 +52588,6 @@
/obj/effect/turf_decal/tile/blue{
dir = 8
},
-/obj/structure/cable{
- icon_state = "1-2"
- },
/turf/open/floor/plasteel,
/area/security/brig)
"cLS" = (
@@ -53367,7 +53336,7 @@
},
/obj/structure/reagent_dispensers/fueltank,
/turf/open/floor/plating,
-/area/maintenance/fore)
+/area/maintenance/port/fore)
"ddM" = (
/obj/structure/sign/poster/official/the_owl{
pixel_x = 32
@@ -53519,11 +53488,23 @@
},
/turf/closed/wall,
/area/science/circuit)
+"dxF" = (
+/obj/machinery/gear_painter,
+/turf/open/floor/wood,
+/area/maintenance/bar)
"dyE" = (
/obj/structure/cable{
- icon_state = "1-2"
+ icon_state = "0-4"
},
-/turf/open/floor/plasteel,
+/obj/structure/cable{
+ icon_state = "0-8"
+ },
+/obj/machinery/door/poddoor/preopen{
+ id = "Secure Gate";
+ name = "brig shutters"
+ },
+/obj/effect/spawner/structure/window/reinforced,
+/turf/open/floor/plating,
/area/security/brig)
"dyS" = (
/obj/effect/turf_decal/tile/green{
@@ -53583,9 +53564,6 @@
/turf/open/space,
/area/space/nearstation)
"dCV" = (
-/obj/structure/cable{
- icon_state = "1-4"
- },
/obj/effect/turf_decal/tile/red{
dir = 1
},
@@ -53746,7 +53724,7 @@
dir = 1
},
/turf/open/floor/wood/wood_diagonal,
-/area/maintenance/fore)
+/area/maintenance/port/fore)
"edA" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 4
@@ -54942,7 +54920,7 @@
"gKG" = (
/obj/structure/bedsheetbin/towel,
/turf/open/floor/wood/wood_diagonal,
-/area/maintenance/fore)
+/area/maintenance/port/fore)
"gLz" = (
/obj/structure/cable{
icon_state = "1-2"
@@ -54994,11 +54972,11 @@
/obj/structure/cable{
icon_state = "0-8"
},
-/obj/structure/cable{
- icon_state = "0-4"
- },
/obj/effect/spawner/structure/window/reinforced,
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/obj/structure/cable{
+ icon_state = "2-8"
+ },
/turf/open/floor/plating,
/area/security/brig)
"gOZ" = (
@@ -56220,7 +56198,7 @@
},
/obj/effect/decal/cleanable/dirt/dust,
/turf/open/floor/plating,
-/area/maintenance/fore)
+/area/maintenance/port/fore)
"jJF" = (
/obj/machinery/door/airlock/maintenance,
/obj/structure/cable{
@@ -56342,15 +56320,15 @@
/obj/effect/turf_decal/tile/red{
dir = 8
},
-/obj/structure/cable{
- icon_state = "2-4"
- },
/obj/effect/turf_decal/tile/red{
dir = 1
},
/obj/effect/turf_decal/tile/red{
dir = 4
},
+/obj/structure/cable{
+ icon_state = "1-4"
+ },
/turf/open/floor/plasteel,
/area/security/brig)
"kcx" = (
@@ -56531,6 +56509,10 @@
},
/turf/open/floor/wood/wood_diagonal,
/area/maintenance/port/fore)
+"kqy" = (
+/obj/machinery/gear_painter,
+/turf/open/floor/plasteel,
+/area/crew_quarters/fitness)
"kqI" = (
/obj/structure/window,
/turf/open/floor/wood,
@@ -56869,9 +56851,6 @@
/turf/open/floor/plasteel,
/area/security/brig)
"laq" = (
-/obj/structure/cable{
- icon_state = "2-8"
- },
/obj/structure/cable{
icon_state = "2-4"
},
@@ -57013,7 +56992,7 @@
dir = 8
},
/turf/closed/wall,
-/area/maintenance/fore)
+/area/maintenance/port/fore)
"lzt" = (
/obj/machinery/portable_atmospherics/pump,
/obj/effect/turf_decal/stripes/line,
@@ -57160,7 +57139,7 @@
/area/maintenance/starboard/aft)
"lZn" = (
/obj/machinery/door/airlock/security/glass{
- id_tag = "innerbrig";
+ id_tag = null;
name = "Brig Infirmary";
req_access_txt = "2"
},
@@ -57605,7 +57584,7 @@
},
/obj/structure/reagent_dispensers/watertank,
/turf/open/floor/plating,
-/area/maintenance/fore)
+/area/maintenance/port/fore)
"nbT" = (
/obj/structure/cable{
icon_state = "0-8"
@@ -58195,9 +58174,6 @@
/area/hallway/primary/central)
"ovv" = (
/obj/structure/table,
-/obj/structure/cable{
- icon_state = "0-2"
- },
/obj/effect/turf_decal/tile/red{
dir = 1
},
@@ -58540,9 +58516,6 @@
/obj/effect/turf_decal/tile/red{
dir = 8
},
-/obj/structure/cable{
- icon_state = "2-4"
- },
/obj/effect/turf_decal/tile/red{
dir = 1
},
@@ -58586,6 +58559,7 @@
/obj/structure/disposalpipe/segment{
dir = 4
},
+/obj/machinery/gear_painter,
/turf/open/floor/plasteel,
/area/crew_quarters/locker)
"pqR" = (
@@ -58671,9 +58645,6 @@
/obj/effect/turf_decal/tile/red{
dir = 8
},
-/obj/structure/cable{
- icon_state = "2-8"
- },
/obj/effect/turf_decal/tile/red{
dir = 1
},
@@ -58681,7 +58652,10 @@
dir = 4
},
/obj/structure/cable{
- icon_state = "2-4"
+ icon_state = "4-8"
+ },
+/obj/structure/cable{
+ icon_state = "1-4"
},
/turf/open/floor/plasteel,
/area/security/brig)
@@ -58809,9 +58783,6 @@
/turf/open/floor/plating,
/area/crew_quarters/fitness)
"pQr" = (
-/obj/structure/cable{
- icon_state = "1-2"
- },
/obj/effect/turf_decal/tile/green,
/obj/effect/turf_decal/tile/green{
dir = 8
@@ -59081,7 +59052,7 @@
dir = 8
},
/turf/open/floor/wood/wood_diagonal,
-/area/maintenance/fore)
+/area/maintenance/port/fore)
"qIw" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 4
@@ -59498,9 +59469,6 @@
/area/maintenance/bar)
"rCl" = (
/obj/machinery/door/firedoor,
-/obj/structure/cable{
- icon_state = "4-8"
- },
/obj/effect/mapping_helpers/airlock/cyclelink_helper{
dir = 1
},
@@ -59544,20 +59512,6 @@
},
/turf/open/floor/plating,
/area/crew_quarters/abandoned_gambling_den)
-"rJv" = (
-/obj/effect/spawner/structure/window/reinforced,
-/obj/structure/cable{
- icon_state = "0-4"
- },
-/obj/structure/cable{
- icon_state = "0-8"
- },
-/obj/machinery/door/poddoor/preopen{
- id = "Secure Gate";
- name = "brig shutters"
- },
-/turf/open/floor/plating,
-/area/security/brig)
"rJw" = (
/obj/structure/table/glass,
/obj/item/hemostat,
@@ -59689,12 +59643,6 @@
},
/turf/open/floor/plasteel/dark,
/area/medical/paramedic)
-"rWw" = (
-/obj/machinery/atmospherics/pipe/heat_exchanging/simple{
- dir = 4
- },
-/turf/open/floor/wood/wood_diagonal,
-/area/maintenance/fore)
"rXl" = (
/obj/structure/chair/office/light,
/obj/machinery/firealarm{
@@ -59764,9 +59712,6 @@
},
/area/crew_quarters/fitness)
"seP" = (
-/obj/structure/cable{
- icon_state = "0-4"
- },
/obj/structure/cable{
icon_state = "0-8"
},
@@ -59817,7 +59762,7 @@
dir = 8
},
/turf/open/floor/wood/wood_diagonal,
-/area/maintenance/fore)
+/area/maintenance/port/fore)
"sqg" = (
/obj/structure/table/wood,
/obj/item/clothing/under/misc/pj/red,
@@ -60254,7 +60199,7 @@
dir = 8
},
/turf/open/floor/wood/wood_diagonal,
-/area/maintenance/fore)
+/area/maintenance/port/fore)
"trb" = (
/obj/machinery/light{
dir = 4
@@ -60672,7 +60617,7 @@
/obj/structure/girder,
/obj/structure/grille,
/turf/open/floor/plating,
-/area/maintenance/fore)
+/area/maintenance/port/fore)
"ugu" = (
/obj/structure/cable{
icon_state = "1-4"
@@ -61092,6 +61037,9 @@
/area/maintenance/starboard/aft)
"uXt" = (
/obj/machinery/atmospherics/pipe/manifold/supply/hidden,
+/obj/structure/cable{
+ icon_state = "1-2"
+ },
/turf/open/floor/plasteel,
/area/security/brig)
"vae" = (
@@ -61332,13 +61280,13 @@
/area/crew_quarters/dorms)
"vyK" = (
/obj/effect/spawner/structure/window/reinforced,
-/obj/structure/cable{
- icon_state = "0-8"
- },
/obj/machinery/door/poddoor/preopen{
id = "Secure Gate";
name = "brig shutters"
},
+/obj/structure/cable{
+ icon_state = "0-2"
+ },
/turf/open/floor/plating,
/area/security/brig)
"vzp" = (
@@ -82474,7 +82422,7 @@ lZN
amC
jIW
ddI
-arP
+alU
fgG
rqW
aGD
@@ -82725,13 +82673,13 @@ amC
htu
alU
edj
-rWw
+ygb
gKG
-arP
-aqR
-awb
+alU
+amC
+ntt
ugq
-arP
+alU
rPU
fne
aGr
@@ -82984,11 +82932,11 @@ alU
tqG
spR
qGw
-arP
-aGh
-awb
-axo
-arP
+alU
+aFJ
+ntt
+aAY
+alU
aCh
pIf
kCo
@@ -83238,14 +83186,14 @@ ali
ali
ali
alU
-arP
+alU
lzk
-arP
-arP
-arP
-avZ
+alU
+alU
+alU
+atO
axp
-ayC
+aue
azH
eEe
aGv
@@ -86395,7 +86343,7 @@ oKh
oKh
iiW
iiW
-iiW
+dxF
izv
nfm
bCq
@@ -88087,7 +88035,7 @@ aaa
aaa
aag
aaa
-aak
+aam
aap
saX
aaD
@@ -88344,7 +88292,7 @@ aaa
aaa
aag
aaf
-aaj
+aai
aao
aax
aaC
@@ -88370,7 +88318,7 @@ alz
cZe
alg
plS
-dyE
+afM
pQr
aou
aqC
@@ -88601,7 +88549,7 @@ aaa
aaa
aag
aaa
-aal
+aam
aar
uGI
aaF
@@ -88858,7 +88806,7 @@ aaa
aaa
aag
aaf
-aaj
+aai
aaq
dyS
aaE
@@ -88883,10 +88831,10 @@ agj
agM
sAk
akp
-akQ
+agj
amB
amn
-amS
+aiX
anz
anz
aov
@@ -89115,8 +89063,8 @@ aaa
aaa
aag
aaa
-aal
-aat
+aam
+aaj
aat
aat
aat
@@ -89143,7 +89091,7 @@ akM
amm
gyr
anM
-rJv
+xal
aqC
anz
aox
@@ -89372,7 +89320,7 @@ aaa
aaa
aag
aaf
-aaj
+aai
aas
aat
aat
@@ -89395,12 +89343,12 @@ akU
afM
lBz
alA
-ene
-alg
+alt
+amS
kbm
-dyE
+afM
cKC
-seP
+dyE
aqC
anR
aow
@@ -89630,7 +89578,7 @@ aaa
aag
aaa
aam
-aav
+akQ
aav
aav
aav
@@ -89657,7 +89605,7 @@ akT
gNE
gLz
anB
-amR
+seP
aqC
anz
aov
@@ -89911,10 +89859,10 @@ fxx
ako
ene
amj
-akQ
+agj
amB
amn
-amS
+aiX
anz
anz
aov
@@ -90171,7 +90119,7 @@ amk
amm
gyr
mos
-rJv
+xal
aqC
anz
aov
@@ -90424,11 +90372,11 @@ akF
aiy
akv
uXt
-alg
+amS
pAK
-dyE
+afM
anQ
-seP
+dyE
aqC
anz
aov
@@ -90685,7 +90633,7 @@ akT
amx
any
arD
-amR
+seP
aqC
anz
aov
@@ -90939,10 +90887,10 @@ ajc
akz
ene
als
-akQ
-amB
+agj
+apT
amn
-amS
+aiX
aqD
anz
aov
@@ -91196,7 +91144,7 @@ ajc
akz
ene
alg
-alt
+alw
amp
aot
apR
@@ -91455,7 +91403,7 @@ itD
alg
vyK
amI
-alg
+amS
alv
aqE
anS
@@ -91970,7 +91918,7 @@ agn
agn
amN
aoZ
-apT
+agn
anw
anz
cXU
@@ -92227,7 +92175,7 @@ akY
alE
amU
apH
-apX
+aqt
aqC
anz
gfC
@@ -98410,7 +98358,7 @@ awB
att
azh
fHG
-fHG
+kqy
kxf
ufD
alP
diff --git a/_maps/map_files/CogStation/CogStation.dmm b/_maps/map_files/CogStation/CogStation.dmm
index c690f7ea88..1c6fb96aea 100644
--- a/_maps/map_files/CogStation/CogStation.dmm
+++ b/_maps/map_files/CogStation/CogStation.dmm
@@ -3643,7 +3643,7 @@
lootcount = 2;
name = "2maintenance loot spawner"
},
-/obj/item/caution,
+/obj/item/clothing/suit/caution,
/turf/open/floor/plating,
/area/construction)
"ajb" = (
@@ -4579,7 +4579,7 @@
/turf/open/floor/plasteel,
/area/security/processing)
"alk" = (
-/obj/item/caution,
+/obj/item/clothing/suit/caution,
/turf/open/floor/plating,
/area/construction/secondary)
"all" = (
@@ -6034,12 +6034,15 @@
/obj/effect/turf_decal/tile/red{
dir = 1
},
-/obj/machinery/door/firedoor,
/obj/item/flashlight/lamp,
/obj/machinery/door/window/westright{
name = "Security Checkpoint";
req_access_txt = "1"
},
+/obj/machinery/door/firedoor/border_only{
+ dir = 8;
+ name = "west facing firelock"
+ },
/turf/open/floor/plasteel,
/area/security/checkpoint)
"aoB" = (
@@ -9593,12 +9596,15 @@
/obj/effect/turf_decal/tile/red{
dir = 1
},
-/obj/machinery/door/firedoor,
/obj/item/folder/red,
/obj/machinery/door/window/westleft{
name = "Security Checkpoint";
req_access_txt = "1"
},
+/obj/machinery/door/firedoor/border_only{
+ dir = 8;
+ name = "west facing firelock"
+ },
/turf/open/floor/plasteel,
/area/security/checkpoint)
"awu" = (
@@ -23201,7 +23207,25 @@
/area/hallway/primary/port/fore)
"aYW" = (
/obj/structure/table/reinforced,
-/obj/machinery/door/firedoor,
+/obj/item/pen/blue,
+/obj/machinery/camera{
+ c_tag = "Customs - Fore";
+ dir = 4
+ },
+/obj/structure/window/reinforced/spawner/north,
+/obj/machinery/door/poddoor/shutters/preopen{
+ id = "HoPFore";
+ name = "HoP Fore Desk Shutters"
+ },
+/obj/machinery/atmospherics/pipe/simple/orange/hidden,
+/obj/machinery/door/firedoor/border_only{
+ dir = 1;
+ name = "north facing firelock"
+ },
+/turf/open/floor/plasteel/dark,
+/area/security/checkpoint/customs)
+"aYX" = (
+/obj/structure/table/reinforced,
/obj/machinery/door/window/northright{
name = "Customs Desk";
req_access_txt = "57"
@@ -23210,16 +23234,9 @@
id = "HoPFore";
name = "HoP Fore Desk Shutters"
},
-/turf/open/floor/plasteel/dark,
-/area/security/checkpoint/customs)
-"aYX" = (
-/obj/structure/table/reinforced,
-/obj/machinery/door/firedoor,
-/obj/item/flashlight/lamp,
-/obj/structure/window/reinforced/spawner/north,
-/obj/machinery/door/poddoor/shutters/preopen{
- id = "HoPFore";
- name = "HoP Fore Desk Shutters"
+/obj/machinery/door/firedoor/border_only{
+ dir = 1;
+ name = "north facing firelock"
},
/turf/open/floor/plasteel/dark,
/area/security/checkpoint/customs)
@@ -23323,19 +23340,19 @@
/obj/effect/turf_decal/stripes/line{
dir = 8
},
-/obj/item/caution{
+/obj/item/clothing/suit/caution{
pixel_x = 6;
pixel_y = 3
},
-/obj/item/caution{
+/obj/item/clothing/suit/caution{
pixel_x = 6;
pixel_y = 3
},
-/obj/item/caution{
+/obj/item/clothing/suit/caution{
pixel_x = 6;
pixel_y = 3
},
-/obj/item/caution{
+/obj/item/clothing/suit/caution{
pixel_x = 6;
pixel_y = 3
},
@@ -25051,15 +25068,15 @@
/turf/open/floor/plating,
/area/ai_monitored/turret_protected/ai_upload_foyer)
"bcZ" = (
-/obj/machinery/power/terminal{
- dir = 8
- },
/obj/structure/cable{
icon_state = "1-2"
},
/obj/structure/cable{
icon_state = "0-2"
},
+/obj/machinery/power/smes{
+ charge = 5e+006
+ },
/turf/open/floor/plating,
/area/ai_monitored/turret_protected/ai_upload_foyer)
"bda" = (
@@ -25410,7 +25427,7 @@
dir = 4
},
/turf/open/floor/plasteel,
-/area/science/server)
+/area/science/server/compcore)
"bdM" = (
/turf/open/floor/plasteel,
/area/quartermaster/office)
@@ -25688,7 +25705,7 @@
/area/security/courtroom)
"bey" = (
/turf/closed/wall/r_wall,
-/area/science/server)
+/area/science/server/compcore)
"bez" = (
/obj/effect/spawner/structure/window/reinforced,
/turf/open/floor/plating,
@@ -25764,7 +25781,7 @@
},
/obj/machinery/atmospherics/pipe/simple/supplymain/hidden,
/turf/open/floor/plating,
-/area/science/server)
+/area/science/server/compcore)
"beI" = (
/obj/machinery/door/firedoor,
/obj/structure/disposalpipe/segment,
@@ -25778,7 +25795,7 @@
/obj/effect/turf_decal/delivery,
/obj/machinery/atmospherics/pipe/simple/orange/hidden,
/turf/open/floor/plasteel,
-/area/science/server)
+/area/science/server/compcore)
"beJ" = (
/turf/open/floor/plasteel,
/area/hallway/primary/central)
@@ -25967,7 +25984,7 @@
icon_state = "0-4"
},
/turf/open/floor/plating,
-/area/science/server)
+/area/science/server/compcore)
"bfi" = (
/obj/machinery/atmospherics/pipe/simple/cyan/hidden{
dir = 10
@@ -25985,13 +26002,13 @@
icon_state = "0-4"
},
/turf/open/floor/plating,
-/area/science/server)
+/area/science/server/compcore)
"bfk" = (
/obj/structure/cable{
icon_state = "2-8"
},
/turf/closed/wall/r_wall,
-/area/science/server)
+/area/science/server/compcore)
"bfl" = (
/obj/effect/turf_decal/tile/green,
/obj/effect/turf_decal/tile/green{
@@ -26793,7 +26810,7 @@
/area/quartermaster/sorting)
"bgP" = (
/obj/item/analyzer,
-/obj/item/caution,
+/obj/item/clothing/suit/caution,
/turf/open/floor/plating,
/area/maintenance/disposal)
"bgQ" = (
@@ -26841,9 +26858,6 @@
/turf/open/floor/plating,
/area/crew_quarters/heads/hor)
"bgY" = (
-/obj/structure/cable{
- icon_state = "1-2"
- },
/obj/machinery/status_display,
/turf/closed/wall/r_wall,
/area/hallway/primary/central)
@@ -26943,7 +26957,7 @@
icon_state = "2-4"
},
/turf/closed/wall/r_wall,
-/area/science/server)
+/area/science/server/compcore)
"bhm" = (
/obj/effect/landmark/event_spawn,
/turf/open/floor/engine,
@@ -27017,11 +27031,12 @@
/turf/open/floor/plasteel,
/area/engine/secure_construction)
"bht" = (
-/obj/structure/grille,
/obj/structure/cable,
/obj/structure/cable{
icon_state = "0-4"
},
+/obj/machinery/power/terminal,
+/obj/structure/grille,
/obj/structure/window/reinforced/spawner,
/turf/open/floor/plating,
/area/ai_monitored/turret_protected/ai)
@@ -27313,7 +27328,7 @@
icon_state = "4-8"
},
/turf/closed/wall/r_wall,
-/area/science/server)
+/area/science/server/compcore)
"bia" = (
/obj/effect/turf_decal/tile/yellow{
dir = 1
@@ -27399,7 +27414,7 @@
},
/obj/machinery/atmospherics/pipe/simple/supplymain/hidden,
/turf/closed/wall/r_wall,
-/area/science/server)
+/area/science/server/compcore)
"bik" = (
/obj/effect/spawner/structure/window/reinforced,
/obj/structure/cable,
@@ -27415,7 +27430,7 @@
"bil" = (
/obj/structure/window/reinforced/spawner,
/turf/open/floor/plasteel/dark,
-/area/science/server)
+/area/science/server/compcore)
"bim" = (
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/plating,
@@ -27513,7 +27528,7 @@
dir = 5
},
/turf/open/floor/plasteel/dark,
-/area/science/server)
+/area/science/server/compcore)
"bix" = (
/obj/machinery/door/firedoor,
/obj/effect/turf_decal/delivery,
@@ -27576,7 +27591,7 @@
dir = 10
},
/turf/open/floor/plasteel/dark,
-/area/science/server)
+/area/science/server/compcore)
"biF" = (
/obj/structure/cable{
icon_state = "4-8"
@@ -27615,7 +27630,7 @@
icon_state = "1-2"
},
/turf/closed/wall/r_wall,
-/area/science/server)
+/area/science/server/compcore)
"biI" = (
/obj/machinery/light{
dir = 4;
@@ -27638,6 +27653,9 @@
/area/quartermaster/office)
"biK" = (
/obj/structure/closet/firecloset,
+/obj/machinery/atmospherics/pipe/simple/cyan/hidden{
+ dir = 10
+ },
/turf/open/floor/plasteel,
/area/science/mixing)
"biL" = (
@@ -28416,7 +28434,7 @@
},
/obj/machinery/photocopier,
/turf/open/floor/plasteel,
-/area/science/server)
+/area/science/server/compcore)
"bku" = (
/obj/structure/closet,
/turf/open/floor/plasteel,
@@ -28455,7 +28473,7 @@
},
/obj/machinery/atmospherics/pipe/simple/supplymain/hidden,
/turf/open/floor/plasteel,
-/area/science/server)
+/area/science/server/compcore)
"bkA" = (
/obj/machinery/light_switch{
pixel_y = -24
@@ -28566,7 +28584,7 @@
pixel_y = 24
},
/turf/open/floor/plasteel,
-/area/science/server)
+/area/science/server/compcore)
"bkK" = (
/obj/structure/disposalpipe/segment,
/obj/structure/cable{
@@ -28674,7 +28692,7 @@
/area/maintenance/department/eva)
"bkW" = (
/turf/open/floor/plasteel,
-/area/science/server)
+/area/science/server/compcore)
"bkX" = (
/obj/effect/spawner/structure/window/reinforced,
/obj/structure/disposalpipe/segment,
@@ -28918,25 +28936,26 @@
"blv" = (
/obj/structure/disposalpipe/segment,
/turf/open/floor/plasteel,
-/area/science/server)
+/area/science/server/compcore)
"blw" = (
/obj/structure/cable{
icon_state = "1-4"
},
/obj/machinery/atmospherics/pipe/simple/orange/hidden,
/turf/open/floor/plasteel,
-/area/science/server)
+/area/science/server/compcore)
"blx" = (
/obj/structure/cable{
icon_state = "0-8"
},
/obj/machinery/power/apc{
+ areastring = "/area/science/server/compcore";
dir = 1;
name = "Computer Core APC";
pixel_y = 24
},
/turf/open/floor/plasteel,
-/area/science/server)
+/area/science/server/compcore)
"bly" = (
/obj/structure/disposalpipe/segment{
dir = 4
@@ -29001,7 +29020,7 @@
light_color = "#e8eaff"
},
/turf/open/floor/plasteel,
-/area/science/server)
+/area/science/server/compcore)
"blE" = (
/obj/machinery/light{
dir = 8
@@ -29216,7 +29235,7 @@
dir = 4
},
/turf/open/floor/plasteel,
-/area/science/server)
+/area/science/server/compcore)
"bma" = (
/obj/structure/chair{
dir = 8
@@ -29522,7 +29541,7 @@
icon_state = "1-2"
},
/turf/closed/wall/r_wall,
-/area/science/server)
+/area/science/server/compcore)
"bmG" = (
/turf/open/floor/engine,
/area/gateway)
@@ -29593,13 +29612,14 @@
/turf/open/floor/plasteel,
/area/hallway/primary/central)
"bmM" = (
-/obj/structure/grille,
/obj/structure/cable{
icon_state = "0-2"
},
/obj/structure/cable{
icon_state = "0-8"
},
+/obj/machinery/power/terminal,
+/obj/structure/grille,
/obj/structure/window/reinforced/spawner,
/turf/open/floor/plating,
/area/ai_monitored/turret_protected/ai)
@@ -30215,7 +30235,7 @@
pixel_y = 1
},
/turf/open/floor/plasteel,
-/area/science/server)
+/area/science/server/compcore)
"bnT" = (
/obj/effect/turf_decal/tile/green{
dir = 8
@@ -30228,7 +30248,7 @@
dir = 9
},
/turf/open/floor/plasteel,
-/area/science/server)
+/area/science/server/compcore)
"bnU" = (
/obj/structure/rack,
/obj/item/clothing/suit/space/fragile,
@@ -30280,18 +30300,16 @@
/area/engine/teg)
"bnZ" = (
/obj/structure/table/reinforced,
-/obj/machinery/door/firedoor,
-/obj/item/pen/blue,
-/obj/machinery/camera{
- c_tag = "Customs - Fore";
- dir = 4
- },
+/obj/item/flashlight/lamp,
/obj/structure/window/reinforced/spawner/north,
/obj/machinery/door/poddoor/shutters/preopen{
id = "HoPFore";
name = "HoP Fore Desk Shutters"
},
-/obj/machinery/atmospherics/pipe/simple/orange/hidden,
+/obj/machinery/door/firedoor/border_only{
+ dir = 1;
+ name = "north facing firelock"
+ },
/turf/open/floor/plasteel/dark,
/area/security/checkpoint/customs)
"boa" = (
@@ -30314,24 +30332,22 @@
/area/crew_quarters/heads/chief)
"bod" = (
/obj/structure/table/reinforced,
-/obj/effect/turf_decal/tile/yellow,
-/obj/effect/turf_decal/tile/yellow{
+/obj/item/stack/packageWrap,
+/obj/item/hand_labeler,
+/obj/machinery/camera{
+ c_tag = "Customs - Aft";
dir = 4
},
-/obj/effect/turf_decal/tile/yellow{
- dir = 1
+/obj/structure/window/reinforced/spawner,
+/obj/machinery/door/poddoor/shutters/preopen{
+ id = "HoPAft";
+ name = "HoP Aft Desk Shutters"
},
-/obj/effect/turf_decal/tile/yellow{
- dir = 8
+/obj/machinery/door/firedoor/border_only{
+ name = "south facing firelock"
},
-/obj/machinery/door/firedoor,
-/obj/machinery/door/window/southleft{
- name = "Primary Tool Storage Desk";
- req_access_txt = "11"
- },
-/obj/item/folder/yellow,
-/turf/open/floor/plasteel,
-/area/storage/primary)
+/turf/open/floor/plasteel/dark,
+/area/security/checkpoint/customs)
"boe" = (
/obj/machinery/door/airlock/vault{
name = "Vault Door";
@@ -30351,7 +30367,7 @@
req_access = list(16)
},
/turf/open/floor/plasteel,
-/area/science/server)
+/area/science/server/compcore)
"bog" = (
/obj/machinery/atmospherics/pipe/simple/supply/visible,
/obj/machinery/door/airlock/engineering/glass{
@@ -30380,7 +30396,7 @@
dir = 5
},
/turf/open/floor/plasteel,
-/area/science/server)
+/area/science/server/compcore)
"boj" = (
/obj/structure/disposalpipe/segment{
dir = 4
@@ -30451,7 +30467,7 @@
dir = 8
},
/turf/open/floor/plasteel,
-/area/science/server)
+/area/science/server/compcore)
"boq" = (
/obj/effect/turf_decal/tile/green,
/obj/effect/turf_decal/tile/green{
@@ -30464,7 +30480,7 @@
dir = 8
},
/turf/open/floor/plasteel,
-/area/science/server)
+/area/science/server/compcore)
"bor" = (
/obj/structure/closet/crate,
/obj/effect/spawner/lootdrop/maintenance,
@@ -30503,7 +30519,7 @@
dir = 8
},
/turf/open/floor/plasteel,
-/area/science/server)
+/area/science/server/compcore)
"bou" = (
/obj/effect/turf_decal/plaque{
icon_state = "L2"
@@ -30637,8 +30653,11 @@
/turf/open/floor/plating,
/area/quartermaster/miningoffice)
"boL" = (
-/obj/machinery/atmospherics/pipe/simple/cyan/hidden,
-/turf/open/floor/plasteel,
+/obj/effect/spawner/structure/window/reinforced,
+/obj/machinery/atmospherics/pipe/simple/cyan/hidden{
+ dir = 4
+ },
+/turf/open/floor/plating,
/area/science/mixing)
"boM" = (
/obj/machinery/mineral/ore_redemption{
@@ -30859,7 +30878,7 @@
},
/obj/item/book/manual/wiki/robotics_cyborgs,
/turf/open/floor/plasteel,
-/area/science/server)
+/area/science/server/compcore)
"bpi" = (
/obj/machinery/firealarm{
pixel_y = 26
@@ -31095,7 +31114,7 @@
dir = 4
},
/turf/open/floor/plasteel,
-/area/science/server)
+/area/science/server/compcore)
"bpL" = (
/obj/effect/turf_decal/tile/green{
dir = 8
@@ -31105,7 +31124,7 @@
dir = 1
},
/turf/open/floor/plasteel,
-/area/science/server)
+/area/science/server/compcore)
"bpM" = (
/obj/effect/turf_decal/stripes/corner,
/turf/open/floor/plasteel,
@@ -31116,7 +31135,7 @@
},
/obj/effect/turf_decal/tile/green,
/turf/open/floor/plasteel,
-/area/science/server)
+/area/science/server/compcore)
"bpO" = (
/obj/structure/disposalpipe/segment{
dir = 10
@@ -31164,7 +31183,7 @@
/obj/effect/turf_decal/tile/green,
/obj/structure/disposalpipe/segment,
/turf/open/floor/plasteel,
-/area/science/server)
+/area/science/server/compcore)
"bpW" = (
/obj/structure/cable{
icon_state = "1-2"
@@ -31350,7 +31369,7 @@
dir = 4
},
/turf/open/floor/plasteel,
-/area/science/server)
+/area/science/server/compcore)
"bqu" = (
/obj/structure/disposalpipe/segment,
/obj/structure/cable{
@@ -31546,7 +31565,7 @@
},
/obj/item/storage/box/disks,
/turf/open/floor/plasteel,
-/area/science/server)
+/area/science/server/compcore)
"bqP" = (
/obj/machinery/camera{
c_tag = "Engine Room - Port Quarter";
@@ -33585,6 +33604,10 @@
/obj/machinery/atmospherics/pipe/simple/cyan/hidden{
dir = 4
},
+/obj/item/kirbyplants{
+ icon_state = "plant-20";
+ pixel_y = 3
+ },
/turf/open/floor/plasteel,
/area/crew_quarters/locker)
"bvu" = (
@@ -33778,7 +33801,7 @@
/turf/open/floor/plasteel/dark,
/area/chapel/office)
"bvU" = (
-/obj/item/caution,
+/obj/item/clothing/suit/caution,
/obj/effect/decal/cleanable/dirt,
/obj/structure/sign/warning/biohazard{
pixel_x = -32
@@ -34882,7 +34905,7 @@
},
/obj/structure/window/reinforced/spawner,
/turf/open/floor/plasteel/dark,
-/area/science/server)
+/area/science/server/compcore)
"byf" = (
/obj/machinery/door/airlock/engineering/glass{
name = "Telecommunications Mainframe";
@@ -35576,7 +35599,7 @@
"bzN" = (
/obj/effect/spawner/structure/window/reinforced,
/turf/open/floor/plating,
-/area/science/server)
+/area/science/server/compcore)
"bzO" = (
/obj/machinery/conveyor_switch/oneway{
id = "recycler";
@@ -35605,7 +35628,7 @@
},
/obj/effect/turf_decal/stripes/line,
/turf/open/floor/plasteel,
-/area/science/server)
+/area/science/server/compcore)
"bzS" = (
/obj/structure/table,
/obj/machinery/light/small{
@@ -35651,7 +35674,9 @@
name = "Toxins Launch Room";
req_access_txt = "7;8"
},
-/obj/machinery/atmospherics/pipe/simple/cyan/hidden,
+/obj/machinery/atmospherics/pipe/simple/cyan/hidden{
+ dir = 5
+ },
/turf/open/floor/plasteel,
/area/science/mixing)
"bzY" = (
@@ -35785,7 +35810,6 @@
/obj/effect/turf_decal/tile/blue{
dir = 4
},
-/obj/machinery/atmospherics/pipe/simple/cyan/hidden,
/turf/open/floor/plasteel,
/area/science/mixing)
"bAm" = (
@@ -35924,7 +35948,7 @@
/obj/structure/disposalpipe/segment,
/obj/machinery/holopad,
/turf/open/floor/plasteel,
-/area/science/server)
+/area/science/server/compcore)
"bAz" = (
/obj/structure/disposalpipe/junction/flip{
dir = 1
@@ -36026,7 +36050,6 @@
/obj/effect/turf_decal/tile/red{
dir = 1
},
-/obj/machinery/atmospherics/pipe/simple/cyan/hidden,
/turf/open/floor/plasteel,
/area/science/mixing)
"bAH" = (
@@ -36037,7 +36060,7 @@
},
/obj/structure/window/reinforced/spawner,
/turf/open/floor/plasteel/dark,
-/area/science/server)
+/area/science/server/compcore)
"bAI" = (
/obj/machinery/photocopier,
/obj/machinery/requests_console{
@@ -36116,6 +36139,9 @@
/obj/effect/turf_decal/tile/blue{
dir = 4
},
+/obj/machinery/atmospherics/pipe/simple/cyan/hidden{
+ dir = 4
+ },
/turf/open/floor/plasteel,
/area/science/mixing)
"bAQ" = (
@@ -36143,10 +36169,16 @@
/obj/effect/turf_decal/stripes/line{
dir = 6
},
+/obj/machinery/atmospherics/pipe/simple/cyan/hidden{
+ dir = 4
+ },
/turf/open/floor/plasteel,
/area/science/mixing)
"bAV" = (
/obj/machinery/atmospherics/components/unary/portables_connector/visible,
+/obj/machinery/atmospherics/pipe/simple/cyan/hidden{
+ dir = 4
+ },
/turf/open/floor/plasteel/white,
/area/science/mixing)
"bAW" = (
@@ -36545,7 +36577,7 @@
/obj/effect/turf_decal/delivery,
/obj/machinery/rnd/server,
/turf/open/floor/plasteel,
-/area/science/server)
+/area/science/server/compcore)
"bBT" = (
/obj/structure/disposalpipe/segment,
/obj/structure/cable{
@@ -36623,10 +36655,10 @@
name = "RD Server Lockup"
},
/turf/open/floor/plasteel,
-/area/science/server)
+/area/science/server/compcore)
"bCb" = (
/turf/open/floor/circuit/green,
-/area/science/server)
+/area/science/server/compcore)
"bCc" = (
/obj/effect/turf_decal/delivery,
/obj/structure/cable{
@@ -36998,7 +37030,7 @@
"bCW" = (
/obj/structure/disposalpipe/segment,
/turf/open/floor/circuit/green,
-/area/science/server)
+/area/science/server/compcore)
"bCX" = (
/obj/machinery/rnd/production/circuit_imprinter/department/science,
/obj/item/reagent_containers/glass/beaker/sulphuric,
@@ -37355,10 +37387,11 @@
/turf/open/floor/plating,
/area/hallway/secondary/service)
"bDL" = (
+/obj/effect/spawner/structure/window/reinforced,
/obj/machinery/atmospherics/pipe/simple/cyan/hidden{
- dir = 4
+ dir = 10
},
-/turf/open/floor/plasteel,
+/turf/open/floor/plating,
/area/science/mixing)
"bDM" = (
/obj/structure/table/reinforced,
@@ -38170,12 +38203,7 @@
/turf/open/floor/plasteel,
/area/science/xenobiology)
"bFp" = (
-/obj/effect/turf_decal/stripes/line{
- dir = 4
- },
-/obj/machinery/atmospherics/pipe/simple/cyan/hidden{
- dir = 4
- },
+/obj/machinery/atmospherics/pipe/simple/cyan/hidden,
/turf/open/floor/plasteel,
/area/science/mixing)
"bFq" = (
@@ -38771,9 +38799,9 @@
/turf/open/floor/plasteel/freezer,
/area/crew_quarters/toilet/restrooms)
"bGv" = (
-/obj/item/caution,
+/obj/item/clothing/suit/caution,
/turf/open/floor/plasteel,
-/area/science/server)
+/area/science/server/compcore)
"bGw" = (
/obj/machinery/door/firedoor,
/obj/machinery/door/airlock/public/glass{
@@ -38897,7 +38925,7 @@
/obj/item/circuitboard/machine/rdserver,
/obj/item/disk/tech_disk,
/turf/open/floor/circuit/green,
-/area/science/server)
+/area/science/server/compcore)
"bGL" = (
/obj/structure/chair{
dir = 1
@@ -38912,10 +38940,7 @@
/obj/effect/turf_decal/tile/neutral{
dir = 1
},
-/obj/item/kirbyplants{
- icon_state = "plant-20";
- pixel_y = 3
- },
+/obj/machinery/gear_painter,
/turf/open/floor/plasteel,
/area/crew_quarters/locker)
"bGN" = (
@@ -38946,7 +38971,7 @@
/obj/machinery/light,
/obj/structure/disposalpipe/segment,
/turf/open/floor/circuit/green,
-/area/science/server)
+/area/science/server/compcore)
"bGQ" = (
/obj/structure/lattice/catwalk,
/obj/structure/disposalpipe/segment{
@@ -39522,7 +39547,7 @@
network = list("minisat")
},
/turf/open/floor/circuit/green,
-/area/science/server)
+/area/science/server/compcore)
"bIh" = (
/obj/machinery/disposal/bin,
/obj/effect/turf_decal/delivery/white,
@@ -40062,7 +40087,7 @@
icon_state = "1-4"
},
/turf/closed/wall/r_wall,
-/area/science/server)
+/area/science/server/compcore)
"bJo" = (
/obj/structure/disposalpipe/segment,
/turf/open/floor/plasteel,
@@ -40124,9 +40149,6 @@
/area/space/nearstation)
"bJw" = (
/obj/machinery/holopad,
-/obj/machinery/atmospherics/pipe/simple/cyan/hidden{
- dir = 4
- },
/turf/open/floor/plasteel/white,
/area/science/mixing)
"bJx" = (
@@ -40233,7 +40255,7 @@
icon_state = "0-4"
},
/turf/open/floor/plating,
-/area/science/server)
+/area/science/server/compcore)
"bJG" = (
/obj/structure/extinguisher_cabinet{
pixel_y = -32
@@ -40328,9 +40350,7 @@
/turf/open/floor/plating,
/area/maintenance/disposal)
"bJT" = (
-/obj/machinery/atmospherics/pipe/simple/cyan/hidden{
- dir = 10
- },
+/obj/machinery/atmospherics/pipe/simple/cyan/hidden,
/turf/open/floor/plasteel/white,
/area/science/mixing)
"bJU" = (
@@ -40574,7 +40594,7 @@
icon_state = "1-8"
},
/turf/closed/wall/r_wall,
-/area/science/server)
+/area/science/server/compcore)
"bKt" = (
/obj/structure/cable{
icon_state = "1-4"
@@ -40980,7 +41000,7 @@
dir = 1;
pixel_y = -26
},
-/obj/item/caution,
+/obj/item/clothing/suit/caution,
/obj/item/shovel,
/obj/item/stack/tile/plasteel{
pixel_x = 10;
@@ -42597,7 +42617,7 @@
icon_state = "0-2"
},
/turf/open/floor/plating,
-/area/science/server)
+/area/science/server/compcore)
"bOA" = (
/obj/effect/turf_decal/tile/green{
dir = 4
@@ -42646,9 +42666,6 @@
light_color = "#e8eaff"
},
/obj/machinery/atmospherics/pipe/simple/orange/hidden,
-/obj/machinery/atmospherics/pipe/simple/cyan/hidden{
- dir = 4
- },
/turf/open/floor/plasteel,
/area/science/mixing)
"bOF" = (
@@ -42830,18 +42847,23 @@
/area/science/xenobiology)
"bOY" = (
/obj/structure/table/reinforced,
-/obj/machinery/door/firedoor,
-/obj/item/stack/packageWrap,
-/obj/item/hand_labeler,
-/obj/machinery/camera{
- c_tag = "Customs - Aft";
- dir = 4
+/obj/item/clipboard,
+/obj/item/stamp/denied{
+ pixel_x = 4;
+ pixel_y = 4
+ },
+/obj/item/stamp,
+/obj/machinery/door/window/southright{
+ name = "Customs Desk";
+ req_access_txt = "57"
},
-/obj/structure/window/reinforced/spawner,
/obj/machinery/door/poddoor/shutters/preopen{
id = "HoPAft";
name = "HoP Aft Desk Shutters"
},
+/obj/machinery/door/firedoor/border_only{
+ name = "south facing firelock"
+ },
/turf/open/floor/plasteel/dark,
/area/security/checkpoint/customs)
"bOZ" = (
@@ -43300,9 +43322,6 @@
/obj/effect/turf_decal/stripes/line{
dir = 1
},
-/obj/structure/cable{
- icon_state = "2-4"
- },
/obj/machinery/camera/motion{
c_tag = "AI Foyer";
network = list("minisat");
@@ -43320,7 +43339,7 @@
dir = 6
},
/turf/open/floor/plasteel,
-/area/ai_monitored/turret_protected/ai)
+/area/ai_monitored/turret_protected/ai_upload_foyer)
"bQc" = (
/obj/structure/bodycontainer/morgue{
dir = 8
@@ -43383,9 +43402,6 @@
/obj/structure/cable{
icon_state = "1-4"
},
-/obj/structure/cable{
- icon_state = "4-8"
- },
/obj/machinery/atmospherics/pipe/manifold/supplymain/hidden,
/turf/open/floor/plasteel,
/area/ai_monitored/turret_protected/ai_upload_foyer)
@@ -43756,9 +43772,7 @@
/turf/open/floor/plating,
/area/router)
"bQX" = (
-/obj/machinery/atmospherics/pipe/simple/cyan/hidden{
- dir = 5
- },
+/obj/machinery/atmospherics/pipe/manifold/cyan/hidden,
/turf/open/floor/plasteel/white,
/area/science/mixing)
"bQY" = (
@@ -44254,9 +44268,6 @@
/area/science/robotics/lab)
"bRW" = (
/obj/effect/turf_decal/bot,
-/obj/structure/cable{
- icon_state = "2-4"
- },
/obj/machinery/status_display/ai{
pixel_y = 32
},
@@ -44384,9 +44395,6 @@
/area/science/xenobiology)
"bSk" = (
/obj/machinery/door/firedoor,
-/obj/structure/cable{
- icon_state = "4-8"
- },
/obj/effect/mapping_helpers/airlock/cyclelink_helper{
dir = 4
},
@@ -44439,7 +44447,7 @@
},
/obj/structure/cable,
/turf/open/floor/plating,
-/area/science/server)
+/area/science/server/compcore)
"bSp" = (
/obj/machinery/conveyor_switch/oneway{
id = "cargoload"
@@ -44473,9 +44481,6 @@
/turf/open/floor/plasteel,
/area/quartermaster/storage)
"bSr" = (
-/obj/structure/cable{
- icon_state = "4-8"
- },
/obj/machinery/light,
/obj/machinery/atmospherics/pipe/simple/supplymain/hidden{
dir = 4
@@ -44483,18 +44488,12 @@
/turf/open/floor/mineral/titanium/blue,
/area/ai_monitored/turret_protected/ai_upload_foyer)
"bSs" = (
-/obj/structure/cable{
- icon_state = "4-8"
- },
/obj/machinery/atmospherics/pipe/simple/supplymain/hidden{
dir = 4
},
/turf/open/floor/mineral/titanium/blue,
/area/ai_monitored/turret_protected/ai_upload_foyer)
"bSt" = (
-/obj/structure/cable{
- icon_state = "4-8"
- },
/obj/machinery/light{
dir = 1
},
@@ -44696,9 +44695,6 @@
/area/science/lab)
"bSO" = (
/obj/machinery/door/firedoor,
-/obj/structure/cable{
- icon_state = "4-8"
- },
/obj/effect/mapping_helpers/airlock/cyclelink_helper{
dir = 8
},
@@ -45219,9 +45215,6 @@
/obj/structure/cable{
icon_state = "1-2"
},
-/obj/structure/cable{
- icon_state = "4-8"
- },
/obj/machinery/status_display/ai{
pixel_y = 32
},
@@ -45319,9 +45312,6 @@
/obj/machinery/light_switch{
pixel_y = 24
},
-/obj/structure/cable{
- icon_state = "4-8"
- },
/obj/machinery/atmospherics/pipe/simple/supplymain/hidden{
dir = 4
},
@@ -46094,9 +46084,6 @@
/turf/open/floor/plasteel,
/area/engine/atmos)
"bVF" = (
-/obj/structure/cable{
- icon_state = "1-4"
- },
/obj/structure/cable{
icon_state = "1-2"
},
@@ -46307,26 +46294,17 @@
/area/engine/atmos)
"bVY" = (
/obj/structure/table/reinforced,
-/obj/effect/turf_decal/tile/yellow,
-/obj/effect/turf_decal/tile/yellow{
- dir = 4
+/obj/item/flashlight/lamp,
+/obj/structure/window/reinforced/spawner,
+/obj/machinery/door/poddoor/shutters/preopen{
+ id = "HoPAft";
+ name = "HoP Aft Desk Shutters"
},
-/obj/effect/turf_decal/tile/yellow{
- dir = 1
+/obj/machinery/door/firedoor/border_only{
+ name = "south facing firelock"
},
-/obj/effect/turf_decal/tile/yellow{
- dir = 8
- },
-/obj/machinery/door/firedoor,
-/obj/machinery/door/window/southright{
- name = "Primary Tool Storage Desk";
- req_access_txt = "11"
- },
-/obj/structure/cable{
- icon_state = "1-2"
- },
-/turf/open/floor/plasteel,
-/area/storage/primary)
+/turf/open/floor/plasteel/dark,
+/area/security/checkpoint/customs)
"bVZ" = (
/obj/machinery/power/apc{
name = "Cargo Bay APC";
@@ -46455,9 +46433,6 @@
/area/science/mixing)
"bWm" = (
/obj/machinery/door/firedoor,
-/obj/structure/cable{
- icon_state = "4-8"
- },
/obj/machinery/door/airlock/engineering{
name = "AI SMES Access";
req_one_access_txt = "10;24"
@@ -46559,9 +46534,6 @@
/turf/open/floor/plasteel/white,
/area/science/mixing)
"bWv" = (
-/obj/structure/cable{
- icon_state = "4-8"
- },
/obj/machinery/atmospherics/pipe/simple/orange/hidden{
dir = 8
},
@@ -48793,7 +48765,7 @@
/turf/open/floor/engine,
/area/science/storage)
"cbh" = (
-/obj/machinery/rnd/experimentor,
+/obj/effect/landmark/event_spawn,
/turf/open/floor/engine,
/area/science/explab)
"cbi" = (
@@ -49146,6 +49118,9 @@
/obj/effect/turf_decal/stripes/line{
dir = 8
},
+/obj/machinery/atmospherics/pipe/simple/cyan/hidden{
+ dir = 4
+ },
/turf/open/floor/plasteel,
/area/science/mixing)
"cbQ" = (
@@ -49637,13 +49612,11 @@
/turf/open/floor/plasteel,
/area/hallway/secondary/exit/departure_lounge)
"ccL" = (
-/obj/effect/landmark/event_spawn,
-/obj/machinery/light{
- dir = 8;
- light_color = "#e8eaff"
+/obj/effect/turf_decal/stripes/line,
+/obj/machinery/computer/rdconsole/experiment{
+ dir = 1
},
-/obj/machinery/rnd/bepis,
-/turf/open/floor/engine,
+/turf/open/floor/plasteel,
/area/science/explab)
"ccM" = (
/obj/structure/disposalpipe/segment{
@@ -51474,8 +51447,8 @@
/area/quartermaster/warehouse)
"cgt" = (
/obj/structure/rack,
-/obj/item/caution,
-/obj/item/caution,
+/obj/item/clothing/suit/caution,
+/obj/item/clothing/suit/caution,
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/plasteel,
/area/quartermaster/warehouse)
@@ -51557,7 +51530,6 @@
/obj/structure/disposalpipe/segment{
dir = 10
},
-/obj/structure/cable,
/obj/structure/cable{
icon_state = "0-2"
},
@@ -51950,9 +51922,6 @@
/turf/open/floor/plasteel,
/area/engine/atmos)
"chy" = (
-/obj/structure/cable{
- icon_state = "2-8"
- },
/obj/machinery/atmospherics/pipe/simple/orange/hidden{
dir = 10
},
@@ -52060,24 +52029,16 @@
/obj/structure/cable{
icon_state = "4-8"
},
-/obj/machinery/atmospherics/pipe/simple/cyan/visible{
- dir = 6
- },
/turf/open/floor/plasteel,
/area/engine/atmos)
"chM" = (
/obj/structure/cable{
icon_state = "1-8"
},
-/obj/machinery/atmospherics/pipe/manifold/cyan/visible{
- dir = 4
- },
+/obj/machinery/atmospherics/pipe/simple/cyan/visible,
/turf/open/floor/plasteel,
/area/engine/atmos)
"chN" = (
-/obj/structure/cable{
- icon_state = "1-2"
- },
/obj/machinery/atmospherics/pipe/simple/orange/hidden,
/turf/closed/wall/r_wall,
/area/engine/teg/hotloop)
@@ -52907,7 +52868,7 @@
dir = 4;
pixel_x = -28
},
-/obj/item/kirbyplants/random,
+/obj/machinery/gear_painter,
/turf/open/floor/plasteel,
/area/quartermaster/office)
"cjB" = (
@@ -54609,26 +54570,26 @@
/turf/open/floor/plasteel,
/area/science/robotics/lab)
"cmT" = (
-/obj/structure/table/reinforced,
-/obj/machinery/door/firedoor,
-/obj/effect/turf_decal/tile/red,
-/obj/effect/turf_decal/tile/red{
- dir = 8
- },
-/obj/effect/turf_decal/tile/red{
- dir = 4
- },
-/obj/effect/turf_decal/tile/red{
+/obj/machinery/disposal/bin,
+/obj/structure/disposalpipe/trunk,
+/obj/effect/turf_decal/tile/yellow,
+/obj/effect/turf_decal/tile/yellow{
dir = 1
},
-/obj/item/folder/red,
-/obj/machinery/atmospherics/pipe/simple/cyan/hidden,
-/obj/machinery/door/window/northright{
- name = "Security Checkpoint";
- req_access_txt = "1"
+/obj/effect/turf_decal/tile/yellow{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/yellow{
+ dir = 8
+ },
+/obj/effect/turf_decal/stripes/white/full,
+/obj/structure/window/reinforced/spawner/north,
+/obj/machinery/door/firedoor/border_only{
+ dir = 1;
+ name = "north facing firelock"
},
/turf/open/floor/plasteel,
-/area/security/checkpoint/supply)
+/area/engine/workshop)
"cmU" = (
/obj/structure/disposalpipe/segment,
/obj/structure/cable{
@@ -55042,6 +55003,9 @@
/obj/item/target/alien,
/obj/item/target,
/obj/item/target/clown,
+/obj/machinery/atmospherics/pipe/simple/cyan/hidden{
+ dir = 5
+ },
/turf/open/floor/plasteel,
/area/science/mixing)
"cnM" = (
@@ -55085,9 +55049,6 @@
/turf/open/space/basic,
/area/quartermaster/warehouse)
"cnR" = (
-/obj/structure/cable{
- icon_state = "1-8"
- },
/obj/machinery/atmospherics/components/unary/vent_scrubber/on{
dir = 4
},
@@ -55112,7 +55073,8 @@
/turf/open/floor/plating,
/area/maintenance/solars/starboard/aft)
"cnT" = (
-/obj/machinery/atmospherics/pipe/manifold/cyan/hidden,
+/obj/effect/turf_decal/stripes/line,
+/obj/machinery/atmospherics/pipe/simple/cyan/hidden,
/turf/open/floor/plasteel,
/area/science/mixing)
"cnU" = (
@@ -56727,9 +56689,6 @@
/turf/open/floor/plasteel,
/area/hallway/primary/aft)
"cqS" = (
-/obj/machinery/computer/rdconsole/experiment{
- dir = 4
- },
/obj/effect/turf_decal/stripes/line,
/obj/machinery/requests_console{
department = "Science";
@@ -56738,6 +56697,8 @@
pixel_x = -30;
receive_ore_updates = 1
},
+/obj/structure/table,
+/obj/item/book/manual/wiki/experimentor,
/turf/open/floor/plasteel,
/area/science/explab)
"cqT" = (
@@ -57988,20 +57949,25 @@
/turf/open/floor/plasteel,
/area/engine/atmos)
"ctl" = (
-/obj/machinery/disposal/bin,
-/obj/structure/disposalpipe/trunk,
-/obj/effect/turf_decal/tile/yellow,
/obj/effect/turf_decal/tile/yellow{
dir = 1
},
-/obj/effect/turf_decal/tile/yellow{
- dir = 4
- },
/obj/effect/turf_decal/tile/yellow{
dir = 8
},
-/obj/effect/turf_decal/stripes/white/full,
+/obj/effect/turf_decal/tile/yellow{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/yellow,
+/obj/machinery/modular_computer/console/preset/engineering,
+/obj/structure/cable{
+ icon_state = "1-2"
+ },
/obj/structure/window/reinforced/spawner/north,
+/obj/machinery/door/firedoor/border_only{
+ dir = 1;
+ name = "north facing firelock"
+ },
/turf/open/floor/plasteel,
/area/engine/workshop)
"ctm" = (
@@ -58202,21 +58168,17 @@
/turf/open/floor/plating,
/area/medical/virology)
"ctE" = (
-/obj/effect/turf_decal/tile/yellow{
- dir = 1
+/obj/structure/table/reinforced,
+/obj/machinery/door/window/southleft{
+ name = "Workshop Desk";
+ req_access_txt = "11"
},
-/obj/effect/turf_decal/tile/yellow{
- dir = 8
+/obj/item/paper_bin,
+/obj/item/pen,
+/obj/structure/disposalpipe/segment,
+/obj/machinery/door/firedoor/border_only{
+ name = "south facing firelock"
},
-/obj/effect/turf_decal/tile/yellow{
- dir = 4
- },
-/obj/effect/turf_decal/tile/yellow,
-/obj/machinery/modular_computer/console/preset/engineering,
-/obj/structure/cable{
- icon_state = "1-2"
- },
-/obj/structure/window/reinforced/spawner/north,
/turf/open/floor/plasteel,
/area/engine/workshop)
"ctF" = (
@@ -59567,34 +59529,38 @@
/area/science/xenobiology)
"cvZ" = (
/obj/structure/table/reinforced,
-/obj/machinery/door/firedoor,
-/obj/item/clipboard,
-/obj/item/stamp/denied{
- pixel_x = 4;
- pixel_y = 4
- },
-/obj/item/stamp,
/obj/machinery/door/window/southright{
- name = "Customs Desk";
- req_access_txt = "57"
+ name = "Workshop Desk";
+ req_access_txt = "11"
},
-/obj/machinery/door/poddoor/shutters/preopen{
- id = "HoPAft";
- name = "HoP Aft Desk Shutters"
+/obj/item/folder/yellow,
+/obj/machinery/door/firedoor/border_only{
+ name = "south facing firelock"
},
-/turf/open/floor/plasteel/dark,
-/area/security/checkpoint/customs)
+/turf/open/floor/plasteel,
+/area/engine/workshop)
"cwa" = (
/obj/structure/table/reinforced,
-/obj/machinery/door/firedoor,
-/obj/item/flashlight/lamp,
-/obj/structure/window/reinforced/spawner,
-/obj/machinery/door/poddoor/shutters/preopen{
- id = "HoPAft";
- name = "HoP Aft Desk Shutters"
+/obj/effect/turf_decal/tile/yellow,
+/obj/effect/turf_decal/tile/yellow{
+ dir = 4
},
-/turf/open/floor/plasteel/dark,
-/area/security/checkpoint/customs)
+/obj/effect/turf_decal/tile/yellow{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/yellow{
+ dir = 8
+ },
+/obj/machinery/door/window/southleft{
+ name = "Primary Tool Storage Desk";
+ req_access_txt = "11"
+ },
+/obj/item/folder/yellow,
+/obj/machinery/door/firedoor/border_only{
+ name = "south facing firelock"
+ },
+/turf/open/floor/plasteel,
+/area/storage/primary)
"cwb" = (
/obj/structure/disposalpipe/segment{
dir = 4
@@ -60704,6 +60670,7 @@
pixel_y = 24
},
/obj/machinery/power/apc{
+ areastring = "/area/crew_quarters/toilet/restrooms";
dir = 4;
name = "Restrooms APC";
pixel_x = 24
@@ -61860,7 +61827,7 @@
/obj/effect/turf_decal/tile/green{
dir = 8
},
-/obj/item/caution,
+/obj/item/clothing/suit/caution,
/obj/machinery/atmospherics/pipe/simple/cyan/hidden{
dir = 4
},
@@ -62959,7 +62926,7 @@
/obj/effect/turf_decal/tile/green{
dir = 4
},
-/obj/item/caution,
+/obj/item/clothing/suit/caution,
/obj/machinery/atmospherics/pipe/manifold4w/orange/hidden,
/obj/structure/cable{
icon_state = "4-8"
@@ -67102,8 +67069,8 @@
/turf/open/floor/plasteel,
/area/engine/gravity_generator)
"cJH" = (
-/obj/machinery/atmospherics/pipe/simple/orange/visible{
- dir = 9
+/obj/machinery/atmospherics/pipe/manifold/orange/visible{
+ dir = 4
},
/turf/open/floor/plasteel,
/area/engine/atmos)
@@ -67708,11 +67675,6 @@
/obj/machinery/atmospherics/pipe/simple/green/visible,
/turf/open/floor/plating,
/area/engine/atmos)
-"cLc" = (
-/obj/effect/spawner/structure/window/reinforced,
-/obj/machinery/atmospherics/pipe/simple/yellow/visible,
-/turf/open/floor/plating,
-/area/engine/atmos)
"cLd" = (
/obj/effect/turf_decal/tile/green{
dir = 4
@@ -68133,14 +68095,14 @@
/turf/open/floor/plating,
/area/engine/storage)
"cMa" = (
-/obj/machinery/light/small{
- dir = 1;
- light_color = "#ffc1c1"
- },
/obj/machinery/atmospherics/pipe/simple/orange/visible,
/obj/machinery/atmospherics/components/binary/pump/on{
dir = 4
},
+/obj/machinery/airlock_sensor/incinerator_atmos{
+ pixel_x = -8;
+ pixel_y = 24
+ },
/turf/open/floor/engine/vacuum,
/area/engine/atmos)
"cMb" = (
@@ -68280,17 +68242,22 @@
pixel_x = -40;
pixel_y = 8
},
-/obj/machinery/atmospherics/pipe/simple/cyan/visible,
/obj/machinery/atmospherics/pipe/simple/dark/visible{
dir = 4
},
+/obj/machinery/button/ignition/incinerator/atmos{
+ pixel_x = -24;
+ pixel_y = -9
+ },
/turf/open/floor/plasteel,
/area/engine/atmos)
"cMw" = (
-/obj/machinery/atmospherics/pipe/simple/orange/visible,
/obj/machinery/atmospherics/pipe/simple/dark/visible{
dir = 4
},
+/obj/machinery/atmospherics/components/binary/valve/digital{
+ name = "Waste Release"
+ },
/turf/open/floor/plasteel,
/area/engine/atmos)
"cMx" = (
@@ -68408,10 +68375,13 @@
/turf/open/floor/plasteel/dark,
/area/engine/atmos)
"cMI" = (
-/obj/machinery/atmospherics/pipe/simple/cyan/visible{
- dir = 9
+/obj/machinery/atmospherics/pipe/simple/supplymain/visible{
+ dir = 4
},
-/turf/closed/wall/r_wall,
+/obj/structure/extinguisher_cabinet{
+ pixel_x = 27
+ },
+/turf/open/floor/plasteel,
/area/engine/atmos)
"cMJ" = (
/obj/machinery/atmospherics/pipe/simple/cyan/visible{
@@ -68449,10 +68419,8 @@
/turf/open/floor/plating,
/area/engine/atmos)
"cMO" = (
+/obj/machinery/atmospherics/pipe/layer_manifold,
/obj/effect/spawner/structure/window/reinforced,
-/obj/machinery/atmospherics/pipe/manifold/cyan/visible{
- dir = 4
- },
/turf/open/floor/plating,
/area/engine/atmos)
"cMP" = (
@@ -68681,6 +68649,30 @@
/obj/machinery/light,
/turf/open/floor/plasteel,
/area/router/air)
+"cNm" = (
+/obj/structure/table/reinforced,
+/obj/effect/turf_decal/tile/yellow,
+/obj/effect/turf_decal/tile/yellow{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/yellow{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/yellow{
+ dir = 8
+ },
+/obj/machinery/door/window/southright{
+ name = "Primary Tool Storage Desk";
+ req_access_txt = "11"
+ },
+/obj/structure/cable{
+ icon_state = "1-2"
+ },
+/obj/machinery/door/firedoor/border_only{
+ name = "south facing firelock"
+ },
+/turf/open/floor/plasteel,
+/area/storage/primary)
"cNn" = (
/obj/machinery/conveyor/auto{
dir = 8;
@@ -68693,26 +68685,28 @@
/area/engine/workshop)
"cNp" = (
/obj/structure/table/reinforced,
-/obj/machinery/door/firedoor,
-/obj/machinery/door/window/southleft{
- name = "Workshop Desk";
- req_access_txt = "11"
+/obj/effect/turf_decal/tile/red,
+/obj/effect/turf_decal/tile/red{
+ dir = 8
},
-/obj/item/paper_bin,
-/obj/item/pen,
-/obj/structure/disposalpipe/segment,
-/turf/open/floor/plasteel,
-/area/engine/workshop)
-"cNq" = (
-/obj/structure/table/reinforced,
-/obj/machinery/door/firedoor,
-/obj/machinery/door/window/southright{
- name = "Workshop Desk";
- req_access_txt = "11"
+/obj/effect/turf_decal/tile/red{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/red{
+ dir = 1
+ },
+/obj/item/folder/red,
+/obj/machinery/atmospherics/pipe/simple/cyan/hidden,
+/obj/machinery/door/window/northright{
+ name = "Security Checkpoint";
+ req_access_txt = "1"
+ },
+/obj/machinery/door/firedoor/border_only{
+ dir = 1;
+ name = "north facing firelock"
},
-/obj/item/folder/yellow,
/turf/open/floor/plasteel,
-/area/engine/workshop)
+/area/security/checkpoint/supply)
"cNr" = (
/obj/effect/spawner/structure/window/reinforced,
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
@@ -70777,6 +70771,13 @@
/obj/effect/landmark/start/atmospheric_technician,
/turf/open/floor/plasteel,
/area/engine/atmos)
+"dnN" = (
+/obj/structure/lattice,
+/obj/machinery/atmospherics/pipe/simple/cyan/visible{
+ dir = 5
+ },
+/turf/open/space/basic,
+/area/space/nearstation)
"dpO" = (
/obj/machinery/atmospherics/components/unary/thermomachine/heater/on{
dir = 4
@@ -70796,6 +70797,14 @@
},
/turf/open/floor/plating,
/area/router)
+"dSZ" = (
+/obj/effect/spawner/structure/window/reinforced,
+/obj/machinery/atmospherics/pipe/simple/cyan/visible{
+ dir = 4
+ },
+/obj/machinery/atmospherics/pipe/layer_manifold,
+/turf/open/floor/plating,
+/area/engine/atmos)
"dVR" = (
/obj/machinery/atmospherics/pipe/simple/violet/visible,
/turf/open/floor/plasteel,
@@ -70807,13 +70816,19 @@
},
/turf/open/floor/engine,
/area/science/storage)
+"ebG" = (
+/obj/effect/spawner/structure/window/reinforced,
+/obj/machinery/atmospherics/pipe/simple/cyan/hidden,
+/turf/open/floor/plating,
+/area/science/mixing)
"eCy" = (
-/obj/structure/extinguisher_cabinet{
- pixel_x = -27
- },
/obj/machinery/atmospherics/pipe/simple/general/visible{
dir = 9
},
+/obj/machinery/embedded_controller/radio/airlock_controller/incinerator_atmos{
+ pixel_x = -25;
+ pixel_y = 7
+ },
/turf/open/floor/plasteel,
/area/engine/atmos)
"eIh" = (
@@ -70831,6 +70846,10 @@
dir = 1
},
/area/engine/atmos)
+"eJy" = (
+/obj/machinery/rnd/experimentor,
+/turf/open/floor/engine,
+/area/science/explab)
"eKM" = (
/obj/machinery/atmospherics/pipe/manifold/supplymain/visible,
/turf/open/floor/plasteel,
@@ -70991,6 +71010,13 @@
/obj/machinery/atmospherics/pipe/manifold/orange/visible,
/turf/open/space/basic,
/area/space/nearstation)
+"iCa" = (
+/obj/effect/spawner/structure/window/reinforced,
+/obj/machinery/atmospherics/pipe/simple/cyan/hidden{
+ dir = 5
+ },
+/turf/open/floor/plating,
+/area/science/mixing)
"iQY" = (
/obj/machinery/atmospherics/pipe/manifold/yellow/visible{
dir = 4
@@ -71016,6 +71042,13 @@
},
/turf/open/space/basic,
/area/space/nearstation)
+"jAv" = (
+/obj/structure/lattice,
+/obj/machinery/atmospherics/pipe/manifold/cyan/visible{
+ dir = 4
+ },
+/turf/open/space/basic,
+/area/space/nearstation)
"kzb" = (
/obj/machinery/atmospherics/pipe/manifold/orange/hidden{
dir = 4
@@ -71052,6 +71085,10 @@
},
/turf/open/floor/plasteel,
/area/engine/atmos)
+"mqE" = (
+/obj/machinery/atmospherics/pipe/manifold/cyan/visible,
+/turf/closed/wall/r_wall,
+/area/engine/atmos)
"mxW" = (
/obj/structure/lattice,
/obj/machinery/atmospherics/pipe/simple/supplymain/visible{
@@ -71059,6 +71096,13 @@
},
/turf/open/space/basic,
/area/space/nearstation)
+"mDW" = (
+/obj/machinery/atmospherics/pipe/simple/cyan/visible{
+ dir = 10
+ },
+/obj/effect/spawner/structure/window/reinforced,
+/turf/open/floor/plating,
+/area/engine/atmos)
"mEa" = (
/obj/machinery/atmospherics/components/binary/pump/on{
dir = 8;
@@ -71201,8 +71245,8 @@
/turf/open/space/basic,
/area/space/nearstation)
"rUl" = (
-/obj/machinery/atmospherics/pipe/manifold/orange/visible{
- dir = 8
+/obj/machinery/atmospherics/pipe/simple/orange/visible{
+ dir = 6
},
/turf/open/floor/plasteel,
/area/engine/atmos)
@@ -71213,6 +71257,13 @@
},
/turf/open/floor/plating/airless,
/area/router/aux)
+"stP" = (
+/obj/structure/disposalpipe/segment{
+ dir = 4
+ },
+/obj/item/kirbyplants/random,
+/turf/open/floor/plasteel,
+/area/quartermaster/office)
"sAm" = (
/obj/structure/plasticflaps,
/obj/machinery/door/poddoor{
@@ -71230,6 +71281,10 @@
/obj/machinery/portable_atmospherics/canister,
/turf/open/floor/plasteel,
/area/engine/atmos)
+"sSg" = (
+/obj/machinery/rnd/bepis,
+/turf/open/floor/engine,
+/area/science/explab)
"sVC" = (
/obj/structure/lattice/catwalk,
/obj/structure/cable{
@@ -71278,8 +71333,8 @@
/turf/open/floor/plasteel,
/area/engine/atmos)
"tZC" = (
-/obj/machinery/atmospherics/pipe/manifold/orange/visible{
- dir = 1
+/obj/machinery/atmospherics/pipe/simple/orange/visible{
+ dir = 4
},
/turf/open/floor/plasteel,
/area/engine/atmos)
@@ -71305,6 +71360,14 @@
},
/turf/open/floor/plasteel,
/area/engine/atmos)
+"uYy" = (
+/obj/structure/grille,
+/obj/structure/cable{
+ icon_state = "0-2"
+ },
+/obj/machinery/atmospherics/pipe/simple/orange/hidden,
+/turf/open/floor/plating/airless,
+/area/space/nearstation)
"vcb" = (
/obj/machinery/atmospherics/pipe/simple/brown/visible,
/obj/machinery/atmospherics/pipe/simple/green/visible{
@@ -90809,10 +90872,10 @@ bOv
bfo
blI
bfo
-bWS
-bcw
-bcw
-bcw
+bXg
+ebG
+ebG
+iCa
bcy
cbu
csR
@@ -91321,9 +91384,9 @@ boJ
fuR
bzX
bAl
-boL
+bdf
bAG
-cnT
+bdf
boQ
cKJ
bAP
@@ -91576,11 +91639,11 @@ bcy
bcy
bcy
bcy
-bcy
+bWS
bgC
bdf
boR
-bDL
+bdf
boQ
cKJ
bAP
@@ -91833,11 +91896,11 @@ bQe
aaU
aaU
aaU
-bcw
+boL
bdf
bdf
bpM
-bFp
+bvj
bvj
cKK
bAU
@@ -92090,7 +92153,7 @@ aye
aaU
aaU
aaU
-bcw
+bDL
cnL
bdf
bpR
@@ -92116,7 +92179,7 @@ cHj
cqS
cav
cav
-ccL
+ctb
caX
caX
caX
@@ -92349,8 +92412,8 @@ abp
abp
bcy
biK
-bdf
-bpR
+bFp
+cnT
bJT
bLl
cKM
@@ -92370,13 +92433,13 @@ aVF
caw
caA
cHk
-caP
+ccL
caT
caX
-caX
+eJy
caX
cbh
-caX
+sSg
caX
cbx
cav
@@ -94872,11 +94935,11 @@ aUV
aYB
bbg
bcH
-bnZ
+aYW
bqi
bIl
bcJ
-bOY
+bod
bdr
beJ
beJ
@@ -95129,11 +95192,11 @@ bcN
aYJ
aNL
aVJ
-aYW
+aYX
baF
bIr
bcx
-cvZ
+bOY
bdr
beJ
beT
@@ -95386,11 +95449,11 @@ bcQ
aUC
aNL
aVJ
-aYX
+bnZ
baD
bIV
bKg
-cwa
+bVY
bdr
beJ
bfd
@@ -105699,7 +105762,7 @@ cgD
cdV
chy
chN
-bWQ
+uYy
bWQ
cdo
aPg
@@ -107000,7 +107063,7 @@ cvb
cvd
cvd
cNa
-cNp
+ctE
ber
cIQ
cgB
@@ -107257,7 +107320,7 @@ cuV
cyv
cuV
cNb
-cNq
+cvZ
beW
cIM
cgB
@@ -108022,7 +108085,7 @@ cqs
cqG
crt
cdm
-ctl
+cmT
cuL
cvd
cAp
@@ -108279,7 +108342,7 @@ bxz
bwP
cBn
cBH
-ctE
+ctl
cuM
cvg
cBa
@@ -111626,7 +111689,7 @@ ciL
cLr
cwQ
bPx
-bod
+cwa
beW
bXX
cIM
@@ -111883,7 +111946,7 @@ con
coo
cwR
bPy
-bVY
+cNm
bWn
bYO
cJc
@@ -114200,7 +114263,7 @@ ckq
bgf
beB
cxC
-bgq
+stP
cjA
biy
bjN
@@ -117286,7 +117349,7 @@ bdM
cNA
bhb
ciE
-cmT
+cNp
cnB
csh
cHV
@@ -118800,7 +118863,7 @@ bNE
cww
cpO
bYP
-cRg
+cMI
cMH
cww
cMb
@@ -119577,7 +119640,7 @@ chn
eCy
chL
cMv
-cMI
+cMJ
anr
aaa
aaa
@@ -119834,7 +119897,7 @@ chp
chx
chM
gDY
-jiZ
+mqE
anr
aaa
aaa
@@ -120088,7 +120151,7 @@ uVD
mqB
dpO
tZC
-qWY
+cwB
rUl
cMw
cfs
@@ -120602,8 +120665,8 @@ sRD
nAF
cgz
cJH
-cwB
-cMl
+qWY
+cJH
cMx
cMJ
cxc
@@ -121366,7 +121429,7 @@ bSb
cKS
cKY
bQO
-cLc
+cMO
eIh
bYd
tXV
@@ -121376,7 +121439,7 @@ cwB
cMc
cMm
cMy
-cML
+dSZ
cLa
cKY
cLu
@@ -122394,7 +122457,7 @@ bTH
cKU
cKY
cLa
-cLc
+cMO
fgS
car
cwB
@@ -122404,7 +122467,7 @@ cwB
cMg
cMq
cMB
-cML
+dSZ
cMQ
cKY
cLw
@@ -123175,8 +123238,8 @@ cLs
cLs
cMs
cME
-cMN
-aaU
+mDW
+dnN
bZR
caJ
bpq
@@ -123422,7 +123485,7 @@ bTK
cKW
cKY
bQV
-cLc
+cMO
cLk
ctk
prx
@@ -123433,7 +123496,7 @@ prx
iQY
cMF
cMO
-cMS
+jAv
cMT
cLy
blM
diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm
index e907602d59..07902b28b1 100644
--- a/_maps/map_files/Deltastation/DeltaStation2.dmm
+++ b/_maps/map_files/Deltastation/DeltaStation2.dmm
@@ -3535,9 +3535,7 @@
dir = 4
},
/obj/effect/turf_decal/delivery,
-/obj/item/kirbyplants{
- icon_state = "plant-21"
- },
+/obj/machinery/gear_painter,
/turf/open/floor/plasteel,
/area/hallway/secondary/entry)
"ajL" = (
@@ -3823,6 +3821,9 @@
/obj/effect/turf_decal/tile/blue{
dir = 8
},
+/obj/item/kirbyplants{
+ icon_state = "plant-21"
+ },
/turf/open/floor/plasteel/white/corner,
/area/hallway/secondary/entry)
"akn" = (
@@ -79384,6 +79385,7 @@
/obj/effect/turf_decal/tile/neutral{
dir = 8
},
+/obj/machinery/gear_painter,
/turf/open/floor/plasteel{
heat_capacity = 1e+006
},
diff --git a/_maps/map_files/KiloStation/KiloStation.dmm b/_maps/map_files/KiloStation/KiloStation.dmm
index 3ff364fa5c..408efad32f 100644
--- a/_maps/map_files/KiloStation/KiloStation.dmm
+++ b/_maps/map_files/KiloStation/KiloStation.dmm
@@ -48007,8 +48007,9 @@
/obj/effect/turf_decal/tile/neutral{
dir = 4
},
-/obj/structure/closet/wardrobe/mixed,
/obj/machinery/light/small,
+/obj/effect/turf_decal/delivery,
+/obj/machinery/gear_painter,
/turf/open/floor/plasteel/dark,
/area/crew_quarters/locker)
"bzo" = (
@@ -48767,7 +48768,6 @@
/turf/open/floor/plasteel/dark,
/area/crew_quarters/fitness/recreation)
"bAA" = (
-/obj/structure/table,
/obj/effect/turf_decal/tile/neutral{
dir = 1
},
@@ -48777,11 +48777,6 @@
/obj/effect/turf_decal/tile/neutral{
dir = 8
},
-/obj/item/storage/backpack{
- pixel_x = 4;
- pixel_y = 4
- },
-/obj/item/storage/backpack,
/obj/machinery/firealarm{
dir = 8;
pixel_x = 26
@@ -49398,6 +49393,7 @@
dir = 1;
name = "recreation camera"
},
+/obj/structure/closet/wardrobe/mixed,
/turf/open/floor/plasteel,
/area/crew_quarters/fitness/recreation)
"bBy" = (
@@ -54797,11 +54793,6 @@
/area/hallway/secondary/exit/departure_lounge)
"bKn" = (
/obj/structure/table,
-/obj/item/paper_bin{
- pixel_x = -4;
- pixel_y = 4
- },
-/obj/item/pen,
/obj/effect/decal/cleanable/cobweb/cobweb2,
/obj/effect/turf_decal/tile/neutral{
dir = 8
@@ -54810,6 +54801,11 @@
/obj/machinery/airalarm{
pixel_y = 22
},
+/obj/item/storage/backpack{
+ pixel_x = 4;
+ pixel_y = 4
+ },
+/obj/item/storage/backpack,
/turf/open/floor/plasteel/dark,
/area/crew_quarters/fitness/recreation)
"bKo" = (
@@ -55425,6 +55421,12 @@
pixel_x = 28;
pixel_y = 22
},
+/obj/structure/table,
+/obj/item/paper_bin{
+ pixel_x = -4;
+ pixel_y = 4
+ },
+/obj/item/pen,
/turf/open/floor/plasteel,
/area/crew_quarters/fitness/recreation)
"bLd" = (
@@ -60844,6 +60846,11 @@
/obj/effect/turf_decal/tile/red{
dir = 1
},
+/obj/structure/table,
+/obj/item/toy/figure/assistant{
+ pixel_x = 8;
+ pixel_y = 6
+ },
/turf/open/floor/plasteel,
/area/hallway/secondary/entry)
"bTD" = (
@@ -61021,6 +61028,12 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer1{
dir = 10
},
+/obj/structure/table,
+/obj/item/paper_bin{
+ pixel_x = -4;
+ pixel_y = 4
+ },
+/obj/item/pen,
/turf/open/floor/plasteel,
/area/hallway/secondary/entry)
"bTO" = (
@@ -61259,19 +61272,8 @@
/obj/effect/turf_decal/tile/neutral{
dir = 1
},
-/obj/structure/table,
-/obj/item/paper_bin{
- pixel_x = -4;
- pixel_y = 4
- },
-/obj/item/pen,
-/obj/item/toy/figure/assistant{
- pixel_x = 8;
- pixel_y = 6
- },
-/obj/effect/turf_decal/loading_area{
- dir = 1
- },
+/obj/effect/turf_decal/delivery,
+/obj/machinery/gear_painter,
/turf/open/floor/plasteel/dark,
/area/hallway/secondary/entry)
"bUi" = (
@@ -71325,15 +71327,16 @@
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;
name = "Lia";
real_name = "Lia";
- response_help = "pets";
+ response_help_continuous = "pets";
+ response_help_simple = "pet";
turns_per_move = 10
},
/turf/open/floor/plasteel/dark,
diff --git a/_maps/map_files/LambdaStation/dorms.dmm b/_maps/map_files/LambdaStation/dorms.dmm
index a38d2b9e1d..0ed1b0203c 100644
--- a/_maps/map_files/LambdaStation/dorms.dmm
+++ b/_maps/map_files/LambdaStation/dorms.dmm
@@ -10679,7 +10679,7 @@
light_color = "#e8eaff"
},
/obj/machinery/vending/wardrobe/jani_wardrobe{
- products = list(/obj/item/clothing/under/rank/civilian/janitor = 2, /obj/item/cartridge/janitor = 2, /obj/item/clothing/gloves/color/black = 2, /obj/item/clothing/head/soft/purple = 2, /obj/item/paint/paint_remover = 2, /obj/item/melee/flyswatter = 2, /obj/item/flashlight = 2, /obj/item/caution = 10, /obj/item/holosign_creator = 2, /obj/item/lightreplacer = 2, /obj/item/soap/nanotrasen = 2, /obj/item/storage/bag/trash = 2, /obj/item/clothing/shoes/galoshes = 2, /obj/item/watertank/janitor = 2, /obj/item/storage/belt/janitor = 2)
+ products = list(/obj/item/clothing/under/rank/civilian/janitor = 2, /obj/item/cartridge/janitor = 2, /obj/item/clothing/gloves/color/black = 2, /obj/item/clothing/head/soft/purple = 2, /obj/item/paint/paint_remover = 2, /obj/item/melee/flyswatter = 2, /obj/item/flashlight = 2, /obj/item/clothing/suit/caution = 10, /obj/item/holosign_creator = 2, /obj/item/lightreplacer = 2, /obj/item/soap/nanotrasen = 2, /obj/item/storage/bag/trash = 2, /obj/item/clothing/shoes/galoshes = 2, /obj/item/watertank/janitor = 2, /obj/item/storage/belt/janitor = 2)
},
/turf/open/floor/plating,
/area/janitor)
@@ -13637,7 +13637,7 @@
/turf/open/floor/plasteel,
/area/hallway/primary/central)
"IX" = (
-/obj/item/caution,
+/obj/item/clothing/suit/caution,
/obj/effect/decal/cleanable/dirt,
/obj/effect/decal/cleanable/dirt,
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer3{
@@ -13764,6 +13764,7 @@
/obj/effect/turf_decal/trimline/neutral/filled/corner{
dir = 4
},
+/obj/machinery/gear_painter,
/turf/open/floor/plasteel,
/area/crew_quarters/locker)
"Jp" = (
diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm
index 3c160180da..958ab2dc5a 100644
--- a/_maps/map_files/MetaStation/MetaStation.dmm
+++ b/_maps/map_files/MetaStation/MetaStation.dmm
@@ -4826,6 +4826,7 @@
/obj/machinery/light{
dir = 4
},
+/obj/machinery/gear_painter,
/turf/open/floor/plasteel/white/corner,
/area/hallway/secondary/entry)
"aiU" = (
@@ -12681,7 +12682,7 @@
/turf/open/floor/wood,
/area/crew_quarters/dorms)
"axL" = (
-/obj/item/caution,
+/obj/item/clothing/suit/caution,
/obj/effect/turf_decal/stripes/line{
dir = 1
},
@@ -23177,6 +23178,9 @@
},
/obj/machinery/light,
/obj/effect/turf_decal/tile/neutral,
+/obj/machinery/newscaster{
+ pixel_y = -32
+ },
/turf/open/floor/plasteel,
/area/crew_quarters/locker)
"aTy" = (
@@ -23190,17 +23194,6 @@
/obj/effect/turf_decal/tile/neutral,
/turf/open/floor/plasteel,
/area/crew_quarters/locker)
-"aTz" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 4
- },
-/obj/machinery/light,
-/obj/machinery/newscaster{
- pixel_y = -32
- },
-/obj/effect/turf_decal/tile/neutral,
-/turf/open/floor/plasteel,
-/area/crew_quarters/locker)
"aTA" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 9
@@ -39921,9 +39914,6 @@
/turf/open/floor/plasteel/dark,
/area/bridge)
"bzU" = (
-/obj/structure/chair/comfy/teal{
- dir = 4
- },
/obj/structure/chair/comfy/black{
dir = 4
},
@@ -52010,19 +52000,23 @@
/turf/open/floor/plating,
/area/maintenance/port/aft)
"bZV" = (
-/obj/item/storage/toolbox/emergency,
-/obj/item/hand_labeler,
-/obj/effect/spawner/lootdrop/maintenance,
+/obj/item/storage/box/lights/mixed,
/turf/open/floor/plating,
/area/maintenance/port/aft)
"bZW" = (
-/obj/item/cigbutt,
+/obj/item/cigbutt{
+ pixel_x = 6;
+ pixel_y = -6
+ },
/obj/structure/disposalpipe/segment{
dir = 6
},
/obj/effect/turf_decal/stripes/line{
dir = 4
},
+/obj/item/storage/toolbox/emergency,
+/obj/item/hand_labeler,
+/obj/effect/spawner/lootdrop/maintenance,
/turf/open/floor/plating,
/area/maintenance/port/aft)
"bZX" = (
@@ -53085,7 +53079,6 @@
},
/area/maintenance/port/aft)
"cbG" = (
-/obj/item/storage/box/lights/mixed,
/obj/structure/disposalpipe/segment{
dir = 4
},
@@ -53178,8 +53171,6 @@
network = list("ss13","medbay")
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/obj/structure/closet/crate/freezer/surplus_limbs,
-/obj/item/reagent_containers/glass/beaker/synthflesh,
/obj/effect/turf_decal/tile/blue,
/obj/effect/turf_decal/tile/blue{
dir = 4
@@ -55173,7 +55164,7 @@
/obj/effect/turf_decal/tile/neutral{
dir = 8
},
-/obj/machinery/bloodbankgen,
+/obj/vehicle/ridden/wheelchair,
/turf/open/floor/plasteel/dark,
/area/medical/sleeper)
"cfL" = (
@@ -55715,7 +55706,6 @@
icon_state = "4-8"
},
/obj/machinery/atmospherics/pipe/manifold/supply/hidden,
-/obj/effect/turf_decal/stripes/line,
/turf/open/floor/plating,
/area/maintenance/port/aft)
"cgM" = (
@@ -56421,35 +56411,29 @@
/turf/closed/wall,
/area/medical/surgery)
"cib" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 6
- },
-/turf/closed/wall,
+/obj/structure/closet/secure_closet/medical2,
+/turf/open/floor/plasteel/white/corner,
/area/medical/surgery)
"cic" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 4
+ dir = 10
},
-/turf/closed/wall,
-/area/medical/surgery)
-"cid" = (
-/obj/machinery/door/airlock/maintenance{
- name = "Medbay Maintenance";
- req_access_txt = "5"
- },
-/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
+/turf/open/floor/plasteel/white/side{
dir = 1
},
-/turf/open/floor/plating,
-/area/maintenance/port/aft)
+/area/medical/surgery)
+"cid" = (
+/obj/structure/curtain{
+ icon_state = "closed"
+ },
+/obj/machinery/door/firedoor,
+/turf/open/floor/plasteel/white,
+/area/medical/surgery)
"cie" = (
/obj/machinery/firealarm{
dir = 4;
pixel_x = -24
},
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 10
- },
/obj/effect/turf_decal/tile/blue{
dir = 1
},
@@ -57093,56 +57077,65 @@
/turf/open/floor/plating,
/area/maintenance/port/aft)
"cjw" = (
-/obj/machinery/atmospherics/components/unary/vent_scrubber/on{
- dir = 4
+/obj/structure/table,
+/obj/item/storage/backpack/duffelbag/med/surgery{
+ pixel_y = 5
},
-/turf/open/floor/plasteel/dark,
-/area/medical/surgery)
-"cjx" = (
-/obj/structure/chair,
-/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
- dir = 4
+/obj/machinery/light_switch{
+ pixel_x = -26
},
-/turf/open/floor/plasteel/dark,
-/area/medical/surgery)
-"cjy" = (
-/obj/item/cigbutt,
-/obj/machinery/light/small{
- dir = 1
+/obj/machinery/vending/wallmed{
+ pixel_y = 29
},
-/turf/open/floor/plasteel/dark,
+/turf/open/floor/plasteel/white/corner,
/area/medical/surgery)
"cjz" = (
-/obj/structure/chair,
-/obj/machinery/airalarm{
- pixel_y = 23
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 6
- },
-/turf/open/floor/plasteel/dark,
-/area/medical/surgery)
-"cjA" = (
-/obj/machinery/atmospherics/components/unary/vent_pump/on{
+/obj/structure/closet/secure_closet/medical2,
+/turf/open/floor/plasteel/white/corner{
dir = 8
},
-/turf/open/floor/plasteel/dark,
+/area/medical/surgery)
+"cjA" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/turf/open/floor/plasteel/white/corner{
+ dir = 4
+ },
/area/medical/surgery)
"cjB" = (
-/obj/item/cigbutt,
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/turf/open/floor/plasteel/dark,
+/obj/machinery/iv_drip,
+/obj/machinery/atmospherics/components/unary/vent_pump/on,
+/obj/machinery/firealarm{
+ pixel_y = 28
+ },
+/turf/open/floor/plasteel/white/side,
/area/medical/surgery)
"cjC" = (
-/obj/structure/chair,
-/turf/open/floor/plasteel/dark,
+/obj/structure/table,
+/obj/item/radio/intercom{
+ broadcasting = 1;
+ frequency = 1485;
+ listening = 0;
+ name = "Station Intercom (Medbay)";
+ pixel_y = 22
+ },
+/obj/item/clothing/gloves/color/latex,
+/obj/item/clothing/suit/apron/surgical,
+/turf/open/floor/plasteel/white/side,
/area/medical/surgery)
"cjD" = (
-/obj/structure/chair,
-/obj/machinery/light/small{
- dir = 1
+/obj/structure/table,
+/obj/item/storage/backpack/duffelbag/med/surgery{
+ pixel_y = 5
+ },
+/obj/machinery/light_switch{
+ pixel_x = 28
+ },
+/obj/machinery/vending/wallmed{
+ pixel_y = 29
+ },
+/turf/open/floor/plasteel/white/corner{
+ dir = 8
},
-/turf/open/floor/plasteel/dark,
/area/medical/surgery)
"cjE" = (
/obj/structure/bed/roller,
@@ -57153,9 +57146,6 @@
name = "Station Intercom (Medbay)";
pixel_x = -30
},
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 5
- },
/obj/machinery/camera{
c_tag = "Medbay Sleepers";
dir = 4;
@@ -57171,12 +57161,7 @@
/turf/open/floor/plasteel/white,
/area/medical/sleeper)
"cjF" = (
-/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
- dir = 4
- },
-/obj/effect/turf_decal/tile/blue{
- dir = 8
- },
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/open/floor/plasteel/white,
/area/medical/sleeper)
"cjG" = (
@@ -57188,7 +57173,6 @@
/area/medical/sleeper)
"cjH" = (
/obj/machinery/atmospherics/pipe/manifold/supply/hidden,
-/obj/effect/turf_decal/tile/blue,
/turf/open/floor/plasteel/white,
/area/medical/sleeper)
"cjI" = (
@@ -57790,71 +57774,66 @@
/turf/open/floor/plasteel/dark,
/area/aisat)
"ckU" = (
-/obj/structure/chair,
-/obj/structure/sign/warning/nosmoking{
- pixel_x = -28
+/obj/machinery/computer/operating{
+ dir = 4
+ },
+/obj/machinery/light{
+ dir = 8
+ },
+/turf/open/floor/plasteel/white/side{
+ dir = 4
},
-/turf/open/floor/plasteel/dark,
-/area/medical/surgery)
-"ckV" = (
-/obj/structure/chair,
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/turf/open/floor/plasteel/dark,
-/area/medical/surgery)
-"ckW" = (
-/obj/machinery/holopad,
-/turf/open/floor/plasteel/dark,
/area/medical/surgery)
"ckX" = (
-/obj/structure/chair,
-/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
+/obj/structure/sink{
+ dir = 4;
+ pixel_x = 11
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 10
+ },
+/turf/open/floor/plasteel/white/side{
dir = 8
},
-/turf/open/floor/plasteel/dark,
/area/medical/surgery)
"ckY" = (
-/obj/structure/chair,
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 4
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 6
+ },
+/turf/open/floor/plasteel/white/side{
+ dir = 1
},
-/turf/open/floor/plasteel/dark,
/area/medical/surgery)
"ckZ" = (
-/obj/structure/disposalpipe/segment,
+/obj/structure/sink{
+ dir = 8;
+ pixel_x = -12;
+ pixel_y = 2
+ },
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 6
+ },
+/turf/open/floor/plasteel/white/side{
dir = 4
},
-/obj/machinery/door/firedoor,
-/obj/machinery/door/airlock/medical{
- name = "Observation"
- },
-/turf/open/floor/plasteel/dark,
/area/medical/surgery)
"cla" = (
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 4
- },
-/obj/machinery/atmospherics/components/unary/vent_scrubber/on{
- dir = 1
- },
-/turf/open/floor/plasteel/dark,
+/turf/open/floor/plasteel/white,
/area/medical/surgery)
"clb" = (
-/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
- dir = 1
- },
-/turf/open/floor/plasteel/dark,
+/obj/effect/landmark/start/medical_doctor,
+/turf/open/floor/plasteel/white,
/area/medical/surgery)
"clc" = (
-/obj/item/cigbutt,
-/obj/machinery/atmospherics/components/unary/vent_pump/on{
+/obj/machinery/computer/operating{
dir = 8
},
-/obj/structure/sign/warning/nosmoking{
- pixel_x = 28
+/obj/machinery/light{
+ dir = 4
+ },
+/turf/open/floor/plasteel/white/side{
+ dir = 8
},
-/obj/effect/landmark/blobstart,
-/turf/open/floor/plasteel/dark,
/area/medical/surgery)
"cld" = (
/obj/machinery/sleeper{
@@ -57894,6 +57873,7 @@
/obj/effect/turf_decal/tile/blue{
dir = 8
},
+/obj/effect/landmark/start/paramedic,
/turf/open/floor/plasteel/white,
/area/medical/sleeper)
"clg" = (
@@ -57974,6 +57954,9 @@
/area/medical/medbay/central)
"cln" = (
/obj/effect/turf_decal/tile/blue,
+/obj/vehicle/ridden/wheelchair{
+ dir = 1
+ },
/turf/open/floor/plasteel/white,
/area/medical/medbay/central)
"clo" = (
@@ -58441,26 +58424,32 @@
/turf/open/floor/wood,
/area/maintenance/port/aft)
"cmk" = (
-/obj/effect/spawner/structure/window,
-/turf/open/floor/plating,
+/obj/structure/table/optable,
+/turf/open/floor/plasteel/white/corner{
+ dir = 4
+ },
/area/medical/surgery)
"cml" = (
-/obj/effect/spawner/structure/window,
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/turf/open/floor/plating,
+/obj/machinery/atmospherics/components/unary/vent_scrubber/on{
+ dir = 4
+ },
+/turf/open/floor/plasteel/white/side{
+ dir = 1
+ },
/area/medical/surgery)
"cmm" = (
-/obj/effect/spawner/structure/window,
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/turf/open/floor/plating,
+/turf/open/floor/plasteel/white/corner{
+ dir = 1
+ },
/area/medical/surgery)
"cmn" = (
-/obj/machinery/door/firedoor,
-/obj/machinery/door/airlock/medical{
- name = "Observation"
+/obj/machinery/atmospherics/components/unary/vent_scrubber/on{
+ dir = 8
+ },
+/turf/open/floor/plasteel/white/side{
+ dir = 1
},
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/turf/open/floor/plasteel,
/area/medical/surgery)
"cmo" = (
/obj/effect/spawner/structure/window,
@@ -58903,78 +58892,30 @@
/turf/open/floor/wood,
/area/maintenance/port/aft)
"cnm" = (
-/obj/structure/table,
-/obj/item/hemostat,
-/obj/structure/extinguisher_cabinet{
- pixel_x = -27
- },
-/turf/open/floor/plasteel,
-/area/medical/surgery)
-"cnn" = (
-/obj/structure/table,
-/obj/item/surgicaldrill,
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/turf/open/floor/plasteel/white/side,
-/area/medical/surgery)
-"cno" = (
-/obj/structure/table,
-/obj/item/scalpel{
- pixel_y = 12
- },
-/obj/item/circular_saw,
-/turf/open/floor/plasteel/white/side,
+/obj/structure/sign/poster/official/cleanliness,
+/turf/closed/wall,
/area/medical/surgery)
"cnp" = (
-/obj/structure/table,
-/obj/item/cautery{
- pixel_x = 4
- },
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/obj/item/razor{
- pixel_y = 5
+/obj/machinery/door/firedoor,
+/obj/machinery/door/airlock/medical/glass{
+ name = "Operating Theatre";
+ req_access_txt = "45"
},
-/turf/open/floor/plasteel/white/side,
+/turf/open/floor/plasteel/white,
/area/medical/surgery)
"cnq" = (
-/obj/structure/table,
-/obj/item/retractor,
-/turf/open/floor/plasteel,
+/obj/machinery/smartfridge/organ/preloaded,
+/turf/closed/wall,
/area/medical/surgery)
"cnr" = (
-/obj/machinery/computer/med_data{
- dir = 4
- },
-/obj/structure/extinguisher_cabinet{
- pixel_x = -27
- },
-/turf/open/floor/plasteel/white/side,
-/area/medical/surgery)
-"cns" = (
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/turf/open/floor/plasteel/white/side,
+/obj/effect/spawner/structure/window,
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/turf/open/floor/plating,
/area/medical/surgery)
"cnt" = (
-/obj/structure/table/reinforced,
-/obj/item/radio/intercom{
- broadcasting = 1;
- frequency = 1485;
- listening = 0;
- name = "Station Intercom (Medbay)";
- pixel_x = 30
- },
-/obj/structure/bedsheetbin{
- pixel_x = 2
- },
-/obj/item/clothing/suit/straight_jacket,
-/obj/item/clothing/mask/muzzle,
-/obj/item/clothing/glasses/eyepatch,
-/obj/item/clothing/glasses/sunglasses/blindfold,
-/obj/item/clothing/ears/earmuffs,
-/obj/item/storage/belt/medical{
- pixel_y = 2
- },
-/obj/item/gun/syringe/dart,
-/turf/open/floor/plasteel/white/side,
+/obj/effect/spawner/structure/window,
+/turf/open/floor/plating,
/area/medical/surgery)
"cnu" = (
/obj/machinery/power/apc{
@@ -59637,89 +59578,96 @@
},
/area/maintenance/port/aft)
"coy" = (
-/obj/structure/table,
-/obj/item/clothing/gloves/color/latex,
-/obj/item/clothing/mask/surgical,
-/obj/item/clothing/suit/apron/surgical,
-/obj/machinery/airalarm{
- dir = 4;
- pixel_x = -22
- },
-/turf/open/floor/plasteel/white/side{
- dir = 4
+/obj/structure/chair{
+ dir = 1
},
+/turf/open/floor/plasteel/dark,
/area/medical/surgery)
"coz" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/turf/open/floor/plasteel/white,
+/obj/structure/chair{
+ dir = 1
+ },
+/obj/effect/decal/cleanable/vomit/old{
+ pixel_x = -2;
+ pixel_y = 7
+ },
+/turf/open/floor/plasteel/dark,
/area/medical/surgery)
"coA" = (
-/obj/effect/landmark/start/medical_doctor,
-/turf/open/floor/plasteel/white,
+/obj/structure/chair{
+ dir = 1
+ },
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 5
+ },
+/turf/open/floor/plasteel/dark,
/area/medical/surgery)
"coB" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/turf/open/floor/plasteel/white,
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/turf/open/floor/plasteel/dark,
/area/medical/surgery)
"coC" = (
-/obj/machinery/power/apc{
- areastring = "/area/medical/surgery";
- dir = 4;
- name = "Surgery APC";
- pixel_x = 26
- },
-/obj/structure/cable/yellow{
- icon_state = "0-2"
- },
-/obj/structure/table,
-/obj/item/surgical_drapes,
-/turf/open/floor/plasteel/white/side{
- dir = 8
+/obj/effect/landmark/start/medical_doctor,
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
},
+/turf/open/floor/plasteel/dark,
/area/medical/surgery)
"coD" = (
-/obj/structure/bed/roller,
-/obj/machinery/light/small{
- dir = 8
+/obj/item/cigbutt{
+ pixel_x = -8;
+ pixel_y = 12
},
-/obj/machinery/iv_drip,
-/turf/open/floor/plasteel/white,
+/obj/structure/chair{
+ dir = 1
+ },
+/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden,
+/turf/open/floor/plasteel/dark,
/area/medical/surgery)
"coE" = (
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/obj/machinery/atmospherics/components/unary/vent_scrubber/on{
- dir = 4
+/obj/structure/chair{
+ dir = 1
},
-/turf/open/floor/plasteel/white,
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 10
+ },
+/turf/open/floor/plasteel/dark,
/area/medical/surgery)
"coF" = (
-/obj/structure/bed,
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 4
+/obj/item/trash/popcorn{
+ pixel_x = -5;
+ pixel_y = -4
},
-/obj/item/bedsheet/medical,
-/turf/open/floor/plasteel/white,
+/obj/structure/chair{
+ dir = 1
+ },
+/obj/machinery/firealarm{
+ dir = 8;
+ pixel_x = 24
+ },
+/turf/open/floor/plasteel/dark,
/area/medical/surgery)
"coG" = (
-/obj/effect/spawner/structure/window,
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 4
+/obj/structure/table/optable,
+/obj/effect/decal/cleanable/blood/old,
+/turf/open/floor/plasteel/white/corner{
+ dir = 1
},
-/turf/open/floor/plating,
/area/medical/surgery)
"coH" = (
/obj/structure/cable/yellow{
icon_state = "1-2"
},
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 9
- },
/obj/effect/turf_decal/tile/blue{
dir = 1
},
/obj/effect/turf_decal/tile/blue{
dir = 8
},
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/open/floor/plasteel/white,
/area/medical/cryo)
"coI" = (
@@ -60439,96 +60387,90 @@
/obj/structure/cable/yellow{
icon_state = "1-2"
},
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/obj/structure/disposalpipe/segment,
/obj/effect/turf_decal/stripes/line{
dir = 4
},
-/turf/open/floor/plating,
-/area/maintenance/port/aft)
-"cpT" = (
-/obj/machinery/door/airlock/maintenance{
- name = "Surgery Maintenance";
- req_access_txt = "45"
- },
-/turf/open/floor/plating,
-/area/maintenance/port/aft)
-"cpU" = (
-/turf/open/floor/plasteel/white,
-/area/medical/surgery)
-"cpW" = (
-/obj/structure/cable/yellow{
- icon_state = "1-4"
- },
-/turf/open/floor/plasteel/white,
-/area/medical/surgery)
-"cpX" = (
-/obj/structure/cable/yellow{
- icon_state = "4-8"
- },
-/obj/machinery/door/firedoor,
-/obj/machinery/door/airlock/medical{
- name = "Operating Theatre";
- req_access_txt = "45"
- },
-/turf/open/floor/plasteel/white,
-/area/medical/surgery)
-"cpY" = (
-/obj/structure/cable/yellow{
- icon_state = "4-8"
- },
-/obj/effect/landmark/event_spawn,
-/turf/open/floor/plasteel/white,
-/area/medical/surgery)
-"cpZ" = (
-/obj/structure/cable/yellow{
- icon_state = "4-8"
- },
/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
dir = 8
},
-/obj/effect/landmark/start/medical_doctor,
-/obj/machinery/holopad,
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
+"cpT" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 5
+ },
/turf/open/floor/plasteel/white,
/area/medical/surgery)
+"cpW" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
+ },
+/obj/machinery/holopad,
+/turf/open/floor/plasteel/dark/side{
+ dir = 1
+ },
+/area/medical/surgery)
+"cpX" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 9
+ },
+/obj/structure/extinguisher_cabinet{
+ pixel_y = -30
+ },
+/turf/open/floor/plasteel/dark/side{
+ dir = 1
+ },
+/area/medical/surgery)
+"cpZ" = (
+/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
+ dir = 8
+ },
+/turf/open/floor/plasteel/dark/side{
+ dir = 1
+ },
+/area/medical/surgery)
"cqa" = (
-/obj/structure/cable/yellow{
- icon_state = "4-8"
+/turf/open/floor/plasteel/dark/side{
+ dir = 1
},
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 4
- },
-/turf/open/floor/plasteel/white,
/area/medical/surgery)
"cqb" = (
-/obj/structure/cable/yellow{
- icon_state = "4-8"
+/obj/machinery/door/firedoor,
+/obj/effect/turf_decal/tile/blue{
+ dir = 8
},
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+/obj/effect/turf_decal/tile/blue{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/blue,
+/obj/effect/turf_decal/tile/blue{
dir = 4
},
-/obj/machinery/door/firedoor,
-/obj/machinery/door/airlock/medical/glass{
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/obj/machinery/door/airlock/medical{
name = "Surgery Observation"
},
/turf/open/floor/plasteel/white,
/area/medical/surgery)
"cqc" = (
-/obj/structure/cable/yellow{
- icon_state = "4-8"
- },
/obj/structure/cable/yellow{
icon_state = "1-4"
},
-/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
- dir = 1
- },
/obj/effect/turf_decal/tile/blue{
dir = 1
},
/obj/effect/turf_decal/tile/blue{
dir = 8
},
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 6
+ },
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 9
+ },
/turf/open/floor/plasteel/white,
/area/medical/cryo)
"cqd" = (
@@ -61165,66 +61107,36 @@
},
/area/maintenance/port/aft)
"crj" = (
-/obj/machinery/atmospherics/components/unary/vent_scrubber/on{
- dir = 4
- },
-/obj/structure/sink{
- dir = 8;
- pixel_x = -12;
- pixel_y = 2
- },
/obj/machinery/light_switch{
- pixel_x = -28
+ pixel_x = -26
},
-/turf/open/floor/plasteel/white/side{
+/turf/open/floor/plasteel/white/corner,
+/area/medical/surgery)
+"crl" = (
+/turf/open/floor/plasteel/white/side,
+/area/medical/surgery)
+"crm" = (
+/obj/machinery/atmospherics/components/unary/vent_pump/on{
+ dir = 1
+ },
+/turf/open/floor/plasteel/white/side,
+/area/medical/surgery)
+"crn" = (
+/obj/machinery/light{
dir = 4
},
+/turf/open/floor/plasteel/white/side,
/area/medical/surgery)
-"crk" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+"cro" = (
+/obj/effect/landmark/blobstart,
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 9
},
/turf/open/floor/plasteel/white,
/area/medical/surgery)
-"crl" = (
-/obj/machinery/computer/operating{
- dir = 1
- },
-/turf/open/floor/plasteel/white,
-/area/medical/surgery)
-"crm" = (
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 5
- },
-/turf/open/floor/plasteel/white,
-/area/medical/surgery)
-"crn" = (
-/obj/machinery/atmospherics/components/unary/vent_pump/on{
- dir = 8
- },
-/obj/machinery/firealarm{
- dir = 8;
- pixel_x = 24
- },
-/turf/open/floor/plasteel/white/side{
- dir = 8
- },
-/area/medical/surgery)
-"cro" = (
-/obj/structure/bed/roller,
-/obj/machinery/iv_drip,
-/obj/structure/sign/warning/nosmoking{
- pixel_x = -28
- },
-/turf/open/floor/plasteel/white,
-/area/medical/surgery)
"crq" = (
-/obj/structure/bed,
-/obj/item/bedsheet/medical,
-/obj/machinery/light_switch{
- pixel_x = 26
- },
-/turf/open/floor/plasteel/white,
+/obj/effect/landmark/event_spawn,
+/turf/open/floor/plasteel/white/side,
/area/medical/surgery)
"crr" = (
/obj/machinery/airalarm{
@@ -61669,23 +61581,46 @@
/turf/open/floor/plating,
/area/maintenance/port/aft)
"csj" = (
-/obj/structure/closet/secure_closet/medical2,
/obj/structure/sign/warning/nosmoking{
pixel_x = -28
},
-/turf/open/floor/plasteel,
+/obj/machinery/limbgrower,
+/turf/open/floor/plasteel/white/side{
+ dir = 4
+ },
/area/medical/surgery)
"csk" = (
+/obj/machinery/light,
+/obj/machinery/bloodbankgen,
+/turf/open/floor/plasteel/white,
+/area/medical/surgery)
+"csl" = (
/obj/machinery/airalarm{
dir = 1;
pixel_y = -22
},
-/turf/open/floor/plasteel/white/side{
- dir = 1
+/obj/structure/window/reinforced{
+ dir = 8
},
+/obj/structure/closet/crate/freezer/blood,
+/obj/machinery/door/window/northleft{
+ name = "Surgery Supplies";
+ red_alert_access = 1;
+ req_access_txt = "5"
+ },
+/turf/open/floor/plasteel/white,
/area/medical/surgery)
-"csl" = (
-/obj/machinery/light,
+"csm" = (
+/obj/structure/window/reinforced{
+ dir = 4
+ },
+/obj/structure/closet/crate/freezer/surplus_limbs,
+/obj/item/reagent_containers/glass/beaker/synthflesh,
+/obj/machinery/door/window/northright{
+ name = "Surgery Supplies";
+ red_alert_access = 1;
+ req_access_txt = "5"
+ },
/obj/machinery/camera{
c_tag = "Medbay Surgery";
dir = 1;
@@ -61693,72 +61628,38 @@
},
/turf/open/floor/plasteel/white,
/area/medical/surgery)
-"csm" = (
-/obj/machinery/firealarm{
- dir = 1;
- pixel_y = -24
- },
-/turf/open/floor/plasteel/white/side{
- dir = 1
- },
-/area/medical/surgery)
"csn" = (
-/obj/item/radio/intercom{
- broadcasting = 1;
- frequency = 1485;
- listening = 0;
- name = "Station Intercom (Medbay)";
- pixel_y = -30
- },
-/obj/structure/closet/crate/freezer/blood,
-/turf/open/floor/plasteel,
-/area/medical/surgery)
-"cso" = (
-/obj/structure/bed/roller,
-/obj/machinery/light/small{
- dir = 8
- },
-/obj/machinery/airalarm{
- dir = 1;
- pixel_y = -22
- },
-/obj/machinery/iv_drip,
-/obj/effect/turf_decal/tile/blue,
-/obj/effect/turf_decal/tile/blue{
- dir = 8
+/obj/structure/chair/office/light{
+ dir = 4
},
/turf/open/floor/plasteel/white,
/area/medical/surgery)
-"csp" = (
-/obj/machinery/atmospherics/components/unary/vent_pump/on{
+"cso" = (
+/obj/item/bedsheet/medical{
dir = 1
},
-/obj/effect/turf_decal/tile/blue,
-/obj/effect/turf_decal/tile/blue{
- dir = 8
+/obj/structure/bed{
+ dir = 1
+ },
+/turf/open/floor/plasteel/white/side{
+ dir = 4
+ },
+/area/medical/surgery)
+"csp" = (
+/obj/machinery/atmospherics/components/unary/vent_scrubber/on{
+ dir = 1
},
/turf/open/floor/plasteel/white,
/area/medical/surgery)
"csq" = (
/obj/structure/bed,
-/obj/machinery/firealarm{
- dir = 8;
- pixel_x = 24
- },
/obj/item/bedsheet/medical,
-/obj/machinery/newscaster{
- pixel_y = -32
+/obj/structure/sign/warning/nosmoking{
+ pixel_x = 28
},
-/obj/machinery/camera{
- c_tag = "Medbay Recovery Room";
- dir = 1;
- network = list("ss13","medbay")
- },
-/obj/effect/turf_decal/tile/blue,
-/obj/effect/turf_decal/tile/blue{
+/turf/open/floor/plasteel/white/side{
dir = 8
},
-/turf/open/floor/plasteel/white,
/area/medical/surgery)
"csr" = (
/obj/machinery/door/airlock/maintenance{
@@ -62325,8 +62226,12 @@
/turf/open/floor/plating,
/area/maintenance/aft)
"ctr" = (
-/obj/structure/bed,
-/obj/item/bedsheet/medical,
+/obj/structure/bed{
+ dir = 1
+ },
+/obj/item/bedsheet/medical{
+ dir = 1
+ },
/obj/machinery/atmospherics/components/unary/vent_scrubber/on,
/obj/machinery/airalarm{
dir = 4;
@@ -62376,6 +62281,16 @@
/obj/structure/cable/yellow{
icon_state = "4-8"
},
+/obj/effect/turf_decal/tile/blue{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/blue,
/turf/open/floor/plasteel/white,
/area/medical/patients_rooms/room_a)
"ctv" = (
@@ -62458,7 +62373,7 @@
"ctD" = (
/obj/structure/sign/directions/evac,
/turf/closed/wall,
-/area/medical/genetics)
+/area/medical/paramedic)
"ctE" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/obj/machinery/door/firedoor,
@@ -62728,29 +62643,38 @@
/turf/open/floor/plating,
/area/maintenance/port/aft)
"cui" = (
-/obj/structure/closet/crate,
-/obj/item/coin/silver,
-/obj/item/reagent_containers/spray/weedspray,
-/obj/item/paper,
-/obj/effect/spawner/lootdrop/maintenance{
- lootcount = 2;
- name = "2maintenance loot spawner"
+/obj/structure/table/reinforced,
+/obj/structure/bedsheetbin{
+ pixel_x = 2
},
-/turf/open/floor/plating,
-/area/maintenance/port/aft)
+/obj/item/clothing/suit/straight_jacket,
+/obj/item/clothing/ears/earmuffs,
+/obj/item/clothing/glasses/sunglasses/blindfold,
+/obj/item/clothing/mask/muzzle,
+/obj/item/clothing/glasses/eyepatch,
+/obj/item/gun/syringe/dart,
+/obj/item/storage/belt/medical{
+ pixel_y = 2
+ },
+/turf/open/floor/plasteel/white/side{
+ dir = 1
+ },
+/area/medical/surgery)
"cuj" = (
-/obj/effect/decal/cleanable/cobweb,
-/obj/structure/cable/yellow{
- icon_state = "0-2"
+/obj/structure/sign/poster/official/medical_green_cross{
+ pixel_y = -32
},
-/obj/machinery/power/apc{
- areastring = "/area/maintenance/port/aft";
- dir = 1;
- name = "Port Quarter Maintenance APC";
- pixel_y = 24
+/obj/structure/bed{
+ dir = 1
},
-/turf/open/floor/plating,
-/area/maintenance/port/aft)
+/obj/item/bedsheet/medical{
+ dir = 1
+ },
+/obj/machinery/light/small,
+/turf/open/floor/plasteel/white/corner{
+ dir = 4
+ },
+/area/medical/surgery)
"cuk" = (
/obj/structure/table,
/obj/item/folder/white{
@@ -62936,14 +62860,16 @@
},
/obj/item/folder/white{
pixel_x = 4;
- pixel_y = -3
+ pixel_y = 4
},
/obj/item/folder/white{
pixel_x = 4;
- pixel_y = -3
+ pixel_y = 4
},
/obj/item/storage/pill_bottle/mutadone,
-/obj/item/storage/pill_bottle/mannitol,
+/obj/item/storage/pill_bottle/mannitol{
+ pixel_x = 5
+ },
/obj/structure/table/glass,
/obj/effect/turf_decal/tile/neutral{
dir = 1
@@ -62981,10 +62907,12 @@
/obj/effect/turf_decal/tile/neutral{
dir = 8
},
+/obj/item/reagent_containers/spray/cleaner{
+ pixel_x = -5
+ },
/turf/open/floor/plasteel/dark,
/area/medical/genetics)
"cuw" = (
-/obj/structure/filingcabinet/chestdrawer,
/obj/effect/turf_decal/tile/blue{
dir = 1
},
@@ -62994,51 +62922,41 @@
/obj/effect/turf_decal/tile/blue{
dir = 8
},
-/turf/open/floor/plasteel,
-/area/medical/genetics)
-"cux" = (
-/obj/structure/noticeboard{
- desc = "A board for pinning important notices upon. Probably helpful for keeping track of requests.";
- name = "requests board";
- pixel_x = -32;
- pixel_y = 32
+/obj/machinery/computer/crew,
+/obj/machinery/vending/wallmed{
+ pixel_x = -25
},
+/turf/open/floor/plasteel,
+/area/medical/paramedic)
+"cux" = (
/obj/structure/disposalpipe/segment,
/obj/effect/turf_decal/tile/blue{
dir = 1
},
-/obj/effect/turf_decal/tile/blue,
/obj/effect/turf_decal/tile/blue{
dir = 4
},
/turf/open/floor/plasteel,
-/area/medical/genetics)
+/area/medical/paramedic)
"cuy" = (
-/obj/effect/spawner/structure/window/reinforced,
-/obj/machinery/door/poddoor/shutters/preopen{
- id = "genetics_shutters";
- name = "genetics shutters"
+/obj/structure/table/glass,
+/obj/item/flashlight/lamp{
+ pixel_x = -1;
+ pixel_y = 11
},
-/turf/open/floor/plating,
-/area/medical/genetics)
-"cuz" = (
-/obj/structure/table/reinforced,
-/obj/item/paper_bin{
- pixel_x = -2;
- pixel_y = 6
+/obj/effect/spawner/lootdrop/cig_packs{
+ pixel_x = 5;
+ pixel_y = -4
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 4
},
/obj/effect/turf_decal/tile/blue{
dir = 1
},
/obj/effect/turf_decal/tile/blue,
-/obj/effect/turf_decal/tile/blue{
- dir = 4
- },
-/obj/effect/turf_decal/tile/blue{
- dir = 8
- },
/turf/open/floor/plasteel,
-/area/medical/genetics)
+/area/medical/paramedic)
"cuA" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/obj/effect/turf_decal/tile/blue{
@@ -63047,6 +62965,9 @@
/obj/effect/turf_decal/tile/blue{
dir = 8
},
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
/turf/open/floor/plasteel,
/area/hallway/primary/aft)
"cuB" = (
@@ -63346,8 +63267,8 @@
/turf/open/floor/plating,
/area/maintenance/port/aft)
"cvn" = (
-/obj/structure/chair{
- dir = 8
+/obj/structure/sign/poster/contraband/random{
+ pixel_x = 32
},
/turf/open/floor/plating,
/area/maintenance/port/aft)
@@ -63528,72 +63449,61 @@
/turf/open/floor/plasteel/white,
/area/medical/genetics)
"cvC" = (
-/obj/machinery/firealarm{
- dir = 4;
+/obj/effect/turf_decal/tile/blue{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 8
+ },
+/obj/structure/chair/office/light{
+ dir = 1
+ },
+/obj/machinery/power/apc{
+ areastring = "/area/medical/paramedic";
+ dir = 8;
+ name = "Paramedic Station APC";
pixel_x = -24
},
-/obj/item/storage/box/syringes,
-/obj/item/storage/box/beakers{
- pixel_x = 2;
- pixel_y = 2
- },
-/obj/structure/table/glass,
-/obj/effect/turf_decal/tile/blue{
- dir = 1
- },
-/obj/effect/turf_decal/tile/blue{
- dir = 8
+/obj/structure/cable/yellow{
+ icon_state = "0-4"
},
/turf/open/floor/plasteel,
-/area/medical/genetics)
+/area/medical/paramedic)
"cvD" = (
-/obj/structure/chair/office/light{
- dir = 4
- },
/obj/structure/disposalpipe/segment,
-/obj/effect/landmark/start/geneticist,
-/obj/effect/turf_decal/tile/blue,
-/obj/effect/turf_decal/tile/blue{
- dir = 4
+/obj/structure/cable/yellow{
+ icon_state = "2-8"
},
+/obj/item/cigbutt{
+ pixel_x = -15;
+ pixel_y = 14
+ },
+/obj/effect/landmark/start/paramedic,
/turf/open/floor/plasteel,
-/area/medical/genetics)
+/area/medical/paramedic)
"cvE" = (
-/obj/structure/table/reinforced,
+/obj/structure/table/glass,
/obj/item/folder/white{
pixel_x = 4;
- pixel_y = -3
+ pixel_y = 4
},
-/obj/item/pen,
-/obj/machinery/door/firedoor,
-/obj/machinery/door/window/eastright{
- dir = 8;
- name = "Genetics Desk";
- req_access_txt = "5;9"
+/obj/item/pen/blue{
+ pixel_x = 5;
+ pixel_y = 3
},
-/obj/machinery/door/window/southleft{
- dir = 4;
- name = "Outer Window"
- },
-/obj/machinery/door/poddoor/shutters/preopen{
- id = "genetics_shutters";
- name = "genetics shutters"
- },
-/turf/open/floor/plating,
-/area/medical/genetics)
-"cvF" = (
-/obj/effect/turf_decal/tile/blue{
- dir = 1
- },
-/obj/effect/turf_decal/tile/blue,
/obj/effect/turf_decal/tile/blue{
dir = 4
},
-/obj/effect/turf_decal/tile/blue{
- dir = 8
+/obj/effect/turf_decal/tile/blue,
+/obj/machinery/atmospherics/components/unary/vent_scrubber/on{
+ dir = 4
},
/turf/open/floor/plasteel,
-/area/medical/genetics)
+/area/medical/paramedic)
+"cvF" = (
+/obj/effect/spawner/structure/window/reinforced,
+/turf/open/floor/plating,
+/area/medical/paramedic)
"cvG" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/obj/structure/extinguisher_cabinet{
@@ -63853,7 +63763,14 @@
/turf/open/floor/plating,
/area/maintenance/port/aft)
"cwj" = (
-/obj/item/cigbutt,
+/obj/structure/closet/crate,
+/obj/item/coin/silver,
+/obj/item/reagent_containers/spray/weedspray,
+/obj/item/paper,
+/obj/effect/spawner/lootdrop/maintenance{
+ lootcount = 2;
+ name = "2maintenance loot spawner"
+ },
/turf/open/floor/plating,
/area/maintenance/port/aft)
"cwm" = (
@@ -63865,12 +63782,10 @@
/turf/open/floor/plating,
/area/maintenance/port/aft)
"cwn" = (
-/obj/structure/rack,
-/obj/item/clothing/glasses/sunglasses,
-/obj/item/flashlight/pen,
-/obj/effect/spawner/lootdrop/maintenance,
-/turf/open/floor/plating,
-/area/maintenance/port/aft)
+/turf/open/floor/plasteel/white/side{
+ dir = 1
+ },
+/area/medical/surgery)
"cwo" = (
/obj/machinery/light/small{
dir = 8
@@ -64061,20 +63976,15 @@
/turf/open/floor/plasteel/white,
/area/medical/genetics)
"cwD" = (
-/obj/item/storage/box/disks{
- pixel_x = 2;
- pixel_y = 2
- },
/obj/item/radio/intercom{
name = "Station Intercom (General)";
pixel_x = -29
},
/obj/machinery/camera{
- c_tag = "Genetics Desk";
+ c_tag = "Paramedics Office";
dir = 4;
network = list("ss13","medbay")
},
-/obj/structure/table/glass,
/obj/effect/turf_decal/tile/blue{
dir = 1
},
@@ -64082,26 +63992,15 @@
dir = 8
},
/turf/open/floor/plasteel,
-/area/medical/genetics)
+/area/medical/paramedic)
"cwE" = (
-/obj/machinery/light{
- dir = 4
- },
/obj/structure/disposalpipe/segment,
-/obj/machinery/button/door{
- id = "genetics_shutters";
- name = "genetics shutters control";
- pixel_x = 28;
- req_access_txt = "9"
- },
-/obj/effect/turf_decal/tile/blue,
-/obj/effect/turf_decal/tile/blue{
- dir = 4
+/obj/structure/cable/yellow{
+ icon_state = "1-2"
},
/turf/open/floor/plasteel,
-/area/medical/genetics)
+/area/medical/paramedic)
"cwF" = (
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/obj/machinery/firealarm{
dir = 4;
pixel_x = -24
@@ -64109,6 +64008,7 @@
/obj/effect/turf_decal/tile/blue{
dir = 1
},
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/turf/open/floor/plasteel,
/area/hallway/primary/aft)
"cwG" = (
@@ -64333,11 +64233,28 @@
},
/area/maintenance/port/aft)
"cxc" = (
-/obj/item/trash/chips,
-/turf/open/floor/plating,
-/area/maintenance/port/aft)
+/obj/machinery/newscaster{
+ pixel_y = -32
+ },
+/obj/machinery/camera{
+ c_tag = "Medbay Recovery Room";
+ dir = 1;
+ network = list("ss13","medbay")
+ },
+/obj/structure/bed,
+/obj/item/bedsheet/medical,
+/obj/structure/sign/poster/official/love_ian{
+ pixel_x = 32
+ },
+/turf/open/floor/plasteel/white/corner{
+ dir = 1
+ },
+/area/medical/surgery)
"cxd" = (
-/obj/structure/reagent_dispensers/watertank,
+/obj/structure/rack,
+/obj/item/clothing/glasses/sunglasses,
+/obj/item/flashlight/pen,
+/obj/effect/spawner/lootdrop/maintenance,
/obj/effect/landmark/blobstart,
/turf/open/floor/plating,
/area/maintenance/port/aft)
@@ -64383,6 +64300,16 @@
req_access_txt = "5"
},
/obj/machinery/door/firedoor,
+/obj/effect/turf_decal/tile/blue{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/blue,
+/obj/effect/turf_decal/tile/blue{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 4
+ },
/turf/open/floor/plasteel/white,
/area/medical/medbay/aft)
"cxi" = (
@@ -64491,12 +64418,12 @@
/obj/structure/cable/yellow{
icon_state = "1-2"
},
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 4
- },
/obj/effect/turf_decal/tile/blue{
dir = 4
},
+/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
+ dir = 1
+ },
/turf/open/floor/plasteel/white,
/area/medical/genetics)
"cxu" = (
@@ -64513,57 +64440,62 @@
/turf/open/floor/plasteel/white,
/area/medical/genetics)
"cxv" = (
-/obj/effect/spawner/structure/window,
-/turf/open/floor/plating,
-/area/medical/genetics)
-"cxw" = (
-/obj/item/folder/white{
- pixel_x = 4;
- pixel_y = -3
- },
-/obj/item/stack/packageWrap,
-/obj/item/pen,
-/obj/item/reagent_containers/spray/cleaner,
-/obj/structure/table/glass,
-/obj/effect/turf_decal/tile/blue{
- dir = 1
- },
-/obj/effect/turf_decal/tile/blue{
- dir = 8
- },
-/turf/open/floor/plasteel,
-/area/medical/genetics)
-"cxx" = (
-/obj/structure/disposalpipe/segment{
- dir = 5
+/obj/machinery/firealarm{
+ dir = 8;
+ pixel_x = 24
},
+/obj/effect/landmark/start/paramedic,
/obj/effect/turf_decal/tile/blue{
dir = 4
},
+/obj/effect/turf_decal/tile/blue,
/turf/open/floor/plasteel,
-/area/medical/genetics)
-"cxy" = (
-/obj/structure/sign/warning/nosmoking{
- pixel_x = 28
- },
-/obj/machinery/disposal/bin,
-/obj/structure/disposalpipe/trunk{
- dir = 8
- },
+/area/medical/paramedic)
+"cxw" = (
/obj/effect/turf_decal/tile/blue{
dir = 1
},
+/obj/effect/turf_decal/tile/blue{
+ dir = 8
+ },
+/obj/machinery/suit_storage_unit/paramedic,
+/obj/effect/turf_decal/tile/blue,
+/turf/open/floor/plasteel,
+/area/medical/paramedic)
+"cxx" = (
+/obj/structure/disposalpipe/segment,
+/obj/machinery/light,
+/obj/structure/closet/secure_closet/paramedic,
+/obj/structure/cable/yellow{
+ icon_state = "1-4"
+ },
+/obj/effect/turf_decal/tile/blue,
+/obj/effect/turf_decal/tile/blue{
+ dir = 8
+ },
+/turf/open/floor/plasteel,
+/area/medical/paramedic)
+"cxy" = (
/obj/effect/turf_decal/tile/blue,
/obj/effect/turf_decal/tile/blue{
dir = 4
},
-/turf/open/floor/plasteel,
-/area/medical/genetics)
-"cxz" = (
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/obj/machinery/light{
+/obj/structure/cable/yellow{
+ icon_state = "4-8"
+ },
+/obj/machinery/airalarm{
+ dir = 1;
+ pixel_y = -22
+ },
+/obj/machinery/atmospherics/components/unary/vent_pump/on{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/blue{
dir = 8
},
+/turf/open/floor/plasteel,
+/area/medical/paramedic)
+"cxz" = (
/obj/machinery/navbeacon{
codes_txt = "patrol;next_patrol=10.1-Central-from-Aft";
location = "10-Aft-To-Central"
@@ -64571,6 +64503,12 @@
/obj/effect/turf_decal/tile/neutral{
dir = 8
},
+/obj/structure/cable/yellow{
+ icon_state = "4-8"
+ },
+/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
+ dir = 4
+ },
/turf/open/floor/plasteel,
/area/hallway/primary/aft)
"cxA" = (
@@ -64580,6 +64518,9 @@
/obj/machinery/atmospherics/components/unary/vent_scrubber/on{
dir = 4
},
+/obj/structure/cable/yellow{
+ icon_state = "1-8"
+ },
/turf/open/floor/plasteel,
/area/hallway/primary/aft)
"cxB" = (
@@ -64710,17 +64651,36 @@
},
/area/maintenance/port/aft)
"cxR" = (
-/obj/structure/rack,
-/obj/item/clothing/mask/gas,
-/obj/effect/spawner/lootdrop/maintenance,
+/obj/item/trash/chips,
/turf/open/floor/plating,
/area/maintenance/port/aft)
"cxS" = (
-/obj/item/latexballon,
+/obj/structure/disposalpipe/segment{
+ dir = 6
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 6
+ },
+/obj/structure/cable/yellow{
+ icon_state = "2-4"
+ },
+/obj/structure/reagent_dispensers/fueltank,
+/obj/effect/decal/cleanable/oil/streak,
/turf/open/floor/plating,
/area/maintenance/port/aft)
"cxT" = (
-/obj/item/clothing/suit/ianshirt,
+/obj/structure/cable/yellow{
+ icon_state = "4-8"
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
+ },
+/obj/structure/disposalpipe/segment{
+ dir = 4
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
/turf/open/floor/plating,
/area/maintenance/port/aft)
"cxU" = (
@@ -64885,6 +64845,7 @@
/obj/structure/cable/yellow{
icon_state = "1-8"
},
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/open/floor/plasteel/white,
/area/medical/genetics)
"cyh" = (
@@ -64892,67 +64853,74 @@
/obj/effect/turf_decal/tile/blue{
dir = 4
},
+/obj/structure/sink{
+ dir = 4;
+ pixel_x = 11
+ },
+/obj/structure/mirror{
+ pixel_x = 28
+ },
/turf/open/floor/plasteel/white,
/area/medical/genetics)
"cyi" = (
-/obj/machinery/door/firedoor,
-/obj/machinery/door/airlock/research{
- id_tag = "AuxGenetics";
- name = "Genetics Lab";
- req_access_txt = "9"
+/obj/machinery/door/airlock/medical/glass{
+ id_tag = "MedbayFoyer";
+ name = "Medbay";
+ req_access_txt = "5"
},
+/obj/machinery/door/firedoor,
+/obj/structure/cable/yellow{
+ icon_state = "4-8"
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
+ },
+/turf/open/floor/plasteel,
+/area/medical/paramedic)
+"cyk" = (
+/obj/structure/disposalpipe/segment,
+/turf/closed/wall,
+/area/medical/paramedic)
+"cyl" = (
+/turf/closed/wall,
+/area/medical/paramedic)
+"cym" = (
+/obj/machinery/door/firedoor,
/obj/effect/mapping_helpers/airlock/cyclelink_helper{
dir = 4
},
-/turf/open/floor/plasteel,
-/area/medical/genetics)
-"cyj" = (
-/obj/effect/turf_decal/tile/blue{
- dir = 1
- },
-/obj/effect/turf_decal/tile/blue{
- dir = 8
- },
-/turf/open/floor/plasteel,
-/area/medical/genetics)
-"cyk" = (
-/obj/machinery/atmospherics/components/unary/vent_pump/on{
- dir = 4
- },
-/turf/open/floor/plasteel,
-/area/medical/genetics)
-"cyl" = (
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 4
- },
-/obj/effect/turf_decal/tile/blue,
-/obj/effect/turf_decal/tile/blue{
- dir = 4
- },
-/turf/open/floor/plasteel,
-/area/medical/genetics)
-"cym" = (
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 4
- },
-/obj/machinery/door/firedoor,
/obj/machinery/door/airlock/research{
id_tag = "AuxGenetics";
name = "Genetics Access";
req_access_txt = "9"
},
-/obj/effect/mapping_helpers/airlock/cyclelink_helper{
+/obj/effect/turf_decal/tile/blue{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/blue,
+/obj/effect/turf_decal/tile/blue{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/blue{
dir = 8
},
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
/turf/open/floor/plasteel,
/area/medical/genetics)
"cyn" = (
-/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
- dir = 4
- },
/obj/effect/turf_decal/tile/neutral{
dir = 8
},
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/obj/machinery/light{
+ dir = 8
+ },
+/obj/item/radio/intercom{
+ name = "Station Intercom (General)";
+ pixel_x = -26
+ },
/turf/open/floor/plasteel,
/area/hallway/primary/aft)
"cyo" = (
@@ -65278,13 +65246,6 @@
/turf/open/floor/plasteel/white,
/area/medical/genetics)
"cza" = (
-/obj/structure/sink{
- dir = 4;
- pixel_x = 11
- },
-/obj/structure/mirror{
- pixel_x = 28
- },
/obj/effect/turf_decal/tile/blue,
/obj/effect/turf_decal/tile/blue{
dir = 4
@@ -65292,65 +65253,66 @@
/obj/effect/turf_decal/tile/blue{
dir = 8
},
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
/turf/open/floor/plasteel/white,
/area/medical/genetics)
"czb" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 6
- },
/obj/effect/turf_decal/tile/blue{
dir = 1
},
-/obj/effect/turf_decal/tile/blue,
/obj/effect/turf_decal/tile/blue{
dir = 8
},
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 10
+ },
+/obj/machinery/camera{
+ c_tag = "Genetics Lab";
+ dir = 6;
+ network = list("ss13","medbay")
+ },
/turf/open/floor/plasteel,
/area/medical/genetics)
"czc" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+/obj/structure/disposalpipe/segment,
+/obj/machinery/atmospherics/components/unary/vent_pump/on{
dir = 4
},
-/obj/effect/turf_decal/tile/blue,
-/obj/effect/turf_decal/tile/blue{
- dir = 8
+/obj/machinery/light/small{
+ dir = 1
},
/turf/open/floor/plasteel,
/area/medical/genetics)
"czd" = (
-/obj/machinery/light_switch{
- pixel_x = 23
- },
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
},
-/obj/effect/turf_decal/tile/blue,
-/obj/effect/turf_decal/tile/blue{
- dir = 4
- },
-/obj/effect/turf_decal/tile/blue{
- dir = 8
- },
/turf/open/floor/plasteel,
/area/medical/genetics)
"cze" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+/obj/machinery/door/firedoor,
+/obj/effect/mapping_helpers/airlock/cyclelink_helper{
+ dir = 8
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
},
-/turf/closed/wall,
+/obj/machinery/door/airlock/research{
+ id_tag = "AuxGenetics";
+ name = "Genetics Access";
+ req_access_txt = "9"
+ },
+/turf/open/floor/plasteel,
/area/medical/genetics)
"czf" = (
-/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/obj/item/radio/intercom{
- name = "Station Intercom (General)";
- pixel_x = -26
- },
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 4
- },
/obj/effect/turf_decal/tile/neutral{
dir = 8
},
+/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
+ dir = 4
+ },
/turf/open/floor/plasteel,
/area/hallway/primary/aft)
"czg" = (
@@ -65363,9 +65325,6 @@
/turf/open/floor/plasteel,
/area/hallway/primary/aft)
"czh" = (
-/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
- dir = 4
- },
/obj/machinery/button/door{
id = "Skynet_launch";
name = "Mech Bay Door Control";
@@ -65374,6 +65333,7 @@
req_one_access_txt = "29"
},
/obj/effect/turf_decal/tile/neutral,
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/open/floor/plasteel,
/area/hallway/primary/aft)
"czi" = (
@@ -65928,6 +65888,9 @@
/obj/effect/turf_decal/tile/neutral{
dir = 8
},
+/obj/structure/disposalpipe/segment{
+ dir = 5
+ },
/turf/open/floor/plasteel/dark,
/area/medical/genetics)
"cAh" = (
@@ -67855,9 +67818,7 @@
/obj/structure/cable/yellow{
icon_state = "4-8"
},
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 5
- },
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/open/floor/plasteel/dark,
/area/medical/morgue)
"cEd" = (
@@ -67876,28 +67837,21 @@
pixel_y = -3
},
/obj/item/clothing/gloves/color/latex,
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 4
- },
/turf/open/floor/plasteel/dark,
/area/medical/morgue)
"cEe" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 4
},
-/turf/closed/wall,
-/area/medical/morgue)
-"cEf" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 4
+/turf/open/floor/plasteel/dark/side{
+ dir = 1
},
+/area/medical/surgery)
+"cEf" = (
/turf/closed/wall,
/area/hallway/primary/aft)
"cEg" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 4
- },
/obj/machinery/firealarm{
dir = 4;
pixel_x = -24
@@ -67908,13 +67862,11 @@
/turf/open/floor/plasteel,
/area/hallway/primary/aft)
"cEh" = (
-/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
- dir = 4
- },
/obj/effect/turf_decal/tile/purple,
/obj/effect/turf_decal/tile/purple{
dir = 4
},
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/open/floor/plasteel,
/area/hallway/primary/aft)
"cEi" = (
@@ -68343,12 +68295,18 @@
/obj/structure/disposalpipe/segment{
dir = 4
},
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 5
+ },
/turf/open/floor/plasteel/dark,
/area/medical/morgue)
"cEX" = (
/obj/structure/disposalpipe/segment{
dir = 10
},
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
/turf/open/floor/plasteel/dark,
/area/medical/morgue)
"cEY" = (
@@ -68357,9 +68315,15 @@
name = "Morgue";
req_access_txt = "6"
},
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
/turf/open/floor/plasteel/dark,
/area/medical/morgue)
"cEZ" = (
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 10
+ },
/turf/open/floor/plasteel/dark,
/area/hallway/primary/aft)
"cFa" = (
@@ -68840,6 +68804,9 @@
/area/medical/morgue)
"cFY" = (
/obj/structure/closet,
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 5
+ },
/turf/open/floor/plasteel/dark,
/area/hallway/primary/aft)
"cFZ" = (
@@ -68848,6 +68815,9 @@
/obj/effect/turf_decal/tile/neutral{
dir = 1
},
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
/turf/open/floor/plasteel,
/area/hallway/primary/aft)
"cGa" = (
@@ -72322,17 +72292,14 @@
/turf/open/floor/plating,
/area/maintenance/port/aft)
"cMo" = (
-/obj/structure/disposalpipe/segment{
- dir = 9
+/obj/machinery/power/apc{
+ areastring = "/area/maintenance/port/aft";
+ dir = 1;
+ name = "Port Quarter Maintenance APC";
+ pixel_y = 24
},
/obj/structure/cable/yellow{
- icon_state = "1-8"
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 9
- },
-/obj/structure/extinguisher_cabinet{
- pixel_y = -30
+ icon_state = "0-8"
},
/turf/open/floor/plating,
/area/maintenance/port/aft)
@@ -72899,10 +72866,16 @@
/turf/open/floor/plating,
/area/maintenance/port/aft)
"cNg" = (
-/obj/structure/rack,
-/obj/item/flashlight,
-/obj/effect/spawner/lootdrop/maintenance,
-/obj/machinery/light/small,
+/obj/structure/cable/yellow{
+ icon_state = "4-8"
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
+ },
+/obj/structure/disposalpipe/segment{
+ dir = 4
+ },
+/obj/item/cigbutt,
/turf/open/floor/plating,
/area/maintenance/port/aft)
"cNh" = (
@@ -75895,8 +75868,12 @@
/turf/closed/wall/r_wall,
/area/science/xenobiology)
"cUH" = (
-/obj/structure/table/optable,
-/turf/open/floor/plasteel/white,
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
+ },
+/turf/open/floor/plasteel/dark/side{
+ dir = 1
+ },
/area/medical/surgery)
"cUL" = (
/obj/docking_port/stationary/random{
@@ -79639,9 +79616,6 @@
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 10
},
-/obj/structure/sign/poster/contraband/random{
- pixel_y = 32
- },
/obj/structure/cable/yellow{
icon_state = "2-4"
},
@@ -80246,6 +80220,14 @@
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
},
+/obj/machinery/power/apc{
+ areastring = "/area/medical/surgery";
+ name = "Surgery APC";
+ pixel_y = -26
+ },
+/obj/structure/cable/yellow{
+ icon_state = "0-8"
+ },
/turf/open/floor/plating,
/area/maintenance/port/aft)
"dwj" = (
@@ -81359,6 +81341,27 @@
/obj/structure/closet/firecloset,
/turf/open/floor/plating,
/area/engine/engineering)
+"foN" = (
+/obj/effect/turf_decal/tile/neutral{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/neutral,
+/obj/effect/turf_decal/tile/neutral{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 8
+ },
+/obj/machinery/light,
+/obj/machinery/gear_painter,
+/turf/open/floor/plasteel/dark,
+/area/crew_quarters/locker)
+"fpa" = (
+/obj/structure/extinguisher_cabinet{
+ pixel_y = -30
+ },
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
"fpY" = (
/turf/closed/wall,
/area/crew_quarters/cryopod)
@@ -81457,6 +81460,32 @@
},
/turf/open/floor/plating,
/area/maintenance/starboard/aft)
+"gtn" = (
+/obj/effect/turf_decal/tile/neutral{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/neutral,
+/obj/effect/turf_decal/tile/neutral{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 8
+ },
+/obj/machinery/disposal/bin,
+/obj/structure/disposalpipe/trunk{
+ dir = 8
+ },
+/obj/structure/sign/warning/nosmoking{
+ pixel_x = 28
+ },
+/turf/open/floor/plasteel/dark,
+/area/medical/genetics)
+"gwW" = (
+/obj/structure/chair{
+ dir = 1
+ },
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
"gEk" = (
/obj/structure/cable/yellow{
icon_state = "2-8"
@@ -81519,6 +81548,11 @@
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/turf/open/floor/wood,
/area/security/vacantoffice)
+"hny" = (
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/obj/structure/curtain,
+/turf/open/floor/plasteel/white/side,
+/area/medical/surgery)
"hyP" = (
/obj/machinery/door/airlock/external{
name = "Escape Pod Two"
@@ -81766,6 +81800,15 @@
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/turf/open/floor/plasteel/white,
/area/science/circuit)
+"kgN" = (
+/obj/machinery/door/firedoor,
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/obj/machinery/door/airlock/medical/glass{
+ name = "Operating Theatre";
+ req_access_txt = "45"
+ },
+/turf/open/floor/plasteel/white,
+/area/medical/surgery)
"krD" = (
/turf/closed/wall,
/area/science/circuit)
@@ -81939,6 +81982,16 @@
},
/turf/open/floor/plasteel/dark,
/area/crew_quarters/cryopod)
+"lFR" = (
+/obj/effect/turf_decal/tile/blue{
+ dir = 4
+ },
+/obj/machinery/light{
+ dir = 4
+ },
+/obj/machinery/vending/clothing,
+/turf/open/floor/plasteel/white/corner,
+/area/hallway/secondary/entry)
"lGS" = (
/obj/docking_port/stationary/public_mining_dock,
/turf/open/floor/plating,
@@ -81982,8 +82035,22 @@
/turf/open/floor/plasteel/white,
/area/science/circuit)
"lWL" = (
-/obj/machinery/smartfridge/organ/preloaded,
-/turf/closed/wall,
+/obj/machinery/computer/med_data{
+ dir = 8
+ },
+/obj/structure/window{
+ dir = 4
+ },
+/obj/item/radio/intercom{
+ broadcasting = 1;
+ frequency = 1485;
+ listening = 0;
+ name = "Station Intercom (Medbay)";
+ pixel_y = -30
+ },
+/turf/open/floor/plasteel/white/side{
+ dir = 8
+ },
/area/medical/surgery)
"lWY" = (
/obj/machinery/door/airlock/hatch{
@@ -82057,6 +82124,10 @@
},
/turf/open/floor/wood,
/area/security/vacantoffice)
+"mqC" = (
+/obj/structure/lattice,
+/turf/closed/wall,
+/area/maintenance/port/aft)
"mvj" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
@@ -82110,6 +82181,10 @@
icon_state = "panelscorched"
},
/area/maintenance/port/aft)
+"nho" = (
+/obj/item/latexballon,
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
"nhy" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 4
@@ -82265,6 +82340,12 @@
},
/turf/open/floor/plasteel/white,
/area/science/circuit)
+"oeQ" = (
+/obj/structure/rack,
+/obj/item/clothing/mask/gas,
+/obj/effect/spawner/lootdrop/maintenance,
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
"ohj" = (
/obj/item/integrated_electronics/analyzer,
/obj/item/integrated_electronics/debugger,
@@ -82519,6 +82600,16 @@
},
/turf/open/floor/plasteel/white,
/area/science/circuit)
+"qee" = (
+/obj/structure/extinguisher_cabinet{
+ pixel_x = 27
+ },
+/obj/effect/turf_decal/tile/neutral,
+/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
+ dir = 4
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/aft)
"qhe" = (
/obj/effect/turf_decal/stripes/line{
dir = 8
@@ -82627,6 +82718,16 @@
/obj/effect/turf_decal/tile/neutral,
/turf/open/floor/plasteel,
/area/hallway/primary/port)
+"reM" = (
+/obj/effect/turf_decal/tile/blue,
+/obj/effect/turf_decal/tile/blue{
+ dir = 8
+ },
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 5
+ },
+/turf/open/floor/plasteel/white,
+/area/medical/genetics)
"roa" = (
/obj/structure/chair/stool,
/obj/machinery/light/small{
@@ -82650,6 +82751,13 @@
},
/turf/open/floor/plating,
/area/hallway/secondary/entry)
+"rvd" = (
+/obj/structure/rack,
+/obj/item/flashlight,
+/obj/effect/spawner/lootdrop/maintenance,
+/obj/machinery/light/small,
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
"rzX" = (
/obj/structure/chair/office/light{
dir = 1;
@@ -82759,6 +82867,10 @@
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/turf/open/floor/plasteel,
/area/crew_quarters/fitness/recreation)
+"sos" = (
+/obj/structure/mirror,
+/turf/closed/wall,
+/area/medical/surgery)
"sqe" = (
/obj/machinery/atmospherics/pipe/heat_exchanging/simple,
/turf/open/space/basic,
@@ -82780,6 +82892,17 @@
/obj/effect/turf_decal/tile/neutral,
/turf/open/floor/plasteel,
/area/hallway/primary/port)
+"sBC" = (
+/obj/effect/spawner/structure/window/reinforced,
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/turf/open/floor/plating,
+/area/medical/paramedic)
+"sCN" = (
+/obj/item/clothing/suit/ianshirt,
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
"sFv" = (
/obj/structure/cable/yellow{
icon_state = "4-8"
@@ -82954,6 +83077,13 @@
/obj/item/flashlight,
/turf/open/floor/plasteel,
/area/hallway/secondary/entry)
+"umv" = (
+/obj/effect/turf_decal/tile/neutral,
+/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
+ dir = 4
+ },
+/turf/open/floor/plasteel,
+/area/hallway/primary/aft)
"upN" = (
/obj/effect/turf_decal/stripes/line{
dir = 5
@@ -83074,6 +83204,14 @@
},
/turf/open/floor/wood,
/area/security/vacantoffice)
+"vwZ" = (
+/obj/machinery/atmospherics/pipe/manifold4w/general{
+ color = "#0000ff"
+ },
+/turf/open/floor/plasteel/dark/side{
+ dir = 1
+ },
+/area/medical/surgery)
"vxG" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
@@ -97423,7 +97561,7 @@ blU
aiT
bEs
bHJ
-aiT
+lFR
iSt
mcS
alK
@@ -100807,7 +100945,7 @@ cwi
dux
dux
dux
-aaa
+dux
aaa
cBR
cCK
@@ -101062,10 +101200,10 @@ cuf
cvk
cwh
bXE
+bXE
dvq
dux
aaa
-aaa
cBR
cBR
cDE
@@ -101318,10 +101456,10 @@ chZ
chZ
cvl
cbx
+cfD
ceu
dux
-dux
-aaf
+mqC
aaa
aaa
cBR
@@ -101568,7 +101706,7 @@ cia
cia
cia
cia
-cpT
+cDP
cia
cia
cia
@@ -101576,11 +101714,11 @@ ceu
dyg
dvt
bXE
+bXE
dvE
dux
aaf
aaf
-aaf
dBN
cDG
cEJ
@@ -101823,21 +101961,21 @@ cia
cjw
ckU
cmk
-cnm
+cnt
coy
-cpU
+cUH
crj
csj
cia
cug
dyg
+bXE
dDw
bXE
-cNg
+rvd
dux
aaa
aaa
-aaa
cBR
cDH
cEK
@@ -102076,25 +102214,25 @@ bXE
cer
dux
dwb
-cib
-cjx
-ckV
+cia
+cjC
+cla
cml
-cnn
+cnt
coz
-coz
-crk
+cUH
+crq
csk
cia
cuh
cvm
cDK
-cxc
+ceu
cxR
+oeQ
dux
aaa
aaa
-aaa
dBN
cDI
cEL
@@ -102333,11 +102471,11 @@ bXE
bYJ
dux
dwe
+cia
+cjB
+cpT
cic
-cjy
-ckW
-cmk
-cno
+cnr
coA
cUH
crl
@@ -102346,12 +102484,12 @@ cia
ceu
ceu
dyg
+ceu
dux
dux
dux
aaa
aaa
-aaa
cBR
cDJ
cEM
@@ -102590,25 +102728,25 @@ dvt
dux
dux
dwb
-cic
+cia
cjz
ckX
cmm
cnp
coB
-coB
+vwZ
crm
csm
cia
-cui
+dux
cwj
-dyg
+cNg
+ceu
dux
-cxS
+nho
dux
aaf
aaf
-aaf
cBR
cBR
cBR
@@ -102847,23 +102985,23 @@ cdi
dux
cdl
dwb
-cic
-cjA
-ckY
-cmk
+cia
+cnm
+sos
+cid
cnq
coC
cpW
crn
csn
-cia
-cdl
-cMm
-cMo
+cui
dux
-cxT
+cxS
+cNf
+fpa
+dux
+sCN
dux
-aaa
aaa
aaa
aaf
@@ -103104,25 +103242,25 @@ dux
dux
cfD
dwb
-cic
cia
+cib
ckZ
-cia
-cia
-cia
+cjA
+kgN
+coB
cpX
cia
lWL
cia
-ceu
+cia
dyg
+bXE
dyw
dux
-cxS
+nho
dux
aaa
aaa
-aaa
aaf
aaa
aaa
@@ -103361,20 +103499,20 @@ cdj
cse
cdj
cgL
-cid
+cia
cjB
-cla
-cmk
+cro
+ckY
cnr
coD
-cpY
-cro
+cqa
+cnt
cso
+cuj
cia
-cfD
dyj
ceu
-dux
+ceu
dux
dux
dux
@@ -103618,18 +103756,18 @@ cdk
ceu
cfE
dwi
-cic
+cia
cjC
clb
cmn
-cns
+cnt
coE
cpZ
-coB
+hny
csp
+cwn
csr
-duH
-dyg
+cxT
ceu
cMm
cwm
@@ -103875,17 +104013,17 @@ dux
dux
cfF
dwj
-cic
+cia
cjD
clc
-cmk
+coG
cnt
coF
-cqa
-crq
+cEe
+cnt
csq
+cxc
cia
-dux
diM
cwm
cNf
@@ -104132,20 +104270,20 @@ cdl
cev
cev
cgO
-cic
cia
cia
cia
cia
-coG
+cia
+cia
cqb
cia
cia
cia
-cuj
-cbx
+cia
+cMo
dDw
-bXE
+gwW
cxU
cxU
czN
@@ -104401,7 +104539,7 @@ csr
duH
bXE
cvn
-cwn
+dvE
cxd
cxU
cyN
@@ -104655,9 +104793,9 @@ coI
cqd
crs
css
-dux
-dux
-dux
+cvp
+cvp
+cvp
cxU
cxU
cxU
@@ -108773,7 +108911,7 @@ cvA
cwB
cxt
cyg
-cyZ
+reM
cAd
ctA
dbr
@@ -109285,10 +109423,10 @@ ctA
ctA
ctA
ctA
-cxv
-cyi
ctA
ctA
+cym
+ctA
ctA
cCi
cCW
@@ -109538,12 +109676,12 @@ coV
cqt
cga
cKJ
-ctB
+cyl
cuw
cvC
cwD
cxw
-cyj
+cyl
czb
cAf
cBc
@@ -110052,18 +110190,18 @@ coX
cnL
cga
cbC
-ctB
+cyl
cuy
cvE
-ctB
+cxv
cxy
cyl
czd
-cAg
+gtn
ctB
cCe
cCe
-cEe
+cCe
cEY
cCe
cCe
@@ -110310,11 +110448,11 @@ coY
cga
csI
ctD
-cuz
cvF
-ctB
-ctB
-cym
+sBC
+cyl
+cyi
+cyl
cze
ctB
cBd
@@ -110825,18 +110963,18 @@ crG
csK
ctF
car
-car
+czg
car
cxA
car
-czg
+car
cAi
ctF
car
car
-czg
-cFb
car
+cFb
+czg
car
cHO
cIF
@@ -111082,7 +111220,7 @@ crH
csL
ctG
cgc
-cvG
+qee
chh
cxB
cyo
@@ -111093,7 +111231,7 @@ cCm
cpa
cEh
cFc
-chh
+umv
chh
cvG
cIG
@@ -118481,8 +118619,8 @@ aOD
aPK
aQV
aOu
-aTz
-aUM
+aTt
+foN
aUM
aYe
dnh
diff --git a/_maps/map_files/OmegaStation/OmegaStation.dmm b/_maps/map_files/OmegaStation/OmegaStation.dmm
index 74f7f95c2c..f4d798511f 100644
--- a/_maps/map_files/OmegaStation/OmegaStation.dmm
+++ b/_maps/map_files/OmegaStation/OmegaStation.dmm
@@ -15268,6 +15268,9 @@
/obj/effect/turf_decal/tile/neutral{
dir = 8
},
+/obj/item/kirbyplants{
+ icon_state = "plant-21"
+ },
/turf/open/floor/plasteel/dark,
/area/crew_quarters/dorms)
"axG" = (
@@ -19618,9 +19621,6 @@
/turf/open/floor/plasteel/dark,
/area/crew_quarters/dorms)
"aEL" = (
-/obj/item/kirbyplants{
- icon_state = "plant-21"
- },
/obj/machinery/status_display{
pixel_y = -32
},
@@ -19635,6 +19635,7 @@
/obj/effect/turf_decal/tile/neutral{
dir = 8
},
+/obj/machinery/gear_painter,
/turf/open/floor/plasteel/dark,
/area/crew_quarters/dorms)
"aEM" = (
diff --git a/_maps/map_files/PubbyStation/PubbyStation.dmm b/_maps/map_files/PubbyStation/PubbyStation.dmm
index 0356dd1d07..12ae0092f0 100644
--- a/_maps/map_files/PubbyStation/PubbyStation.dmm
+++ b/_maps/map_files/PubbyStation/PubbyStation.dmm
@@ -511,10 +511,10 @@
/turf/open/floor/plasteel,
/area/crew_quarters/fitness/recreation)
"abi" = (
-/obj/machinery/disposal/bin,
-/obj/structure/disposalpipe/trunk{
- dir = 8
+/obj/structure/disposalpipe/segment{
+ dir = 10
},
+/obj/machinery/gear_painter,
/turf/open/floor/plasteel,
/area/crew_quarters/fitness/recreation)
"abj" = (
@@ -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
@@ -20027,9 +20030,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 +20045,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 +20489,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 +20522,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 +20905,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 +20925,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 +20947,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 +23020,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 +23027,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 +23045,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 +23412,9 @@
/obj/structure/cable{
icon_state = "1-2"
},
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 9
+ },
/turf/open/floor/plasteel,
/area/janitor)
"bbY" = (
@@ -24603,7 +24620,7 @@
/turf/open/floor/plating,
/area/maintenance/department/cargo)
"beS" = (
-/obj/item/caution,
+/obj/item/clothing/suit/caution,
/turf/open/floor/plating,
/area/maintenance/department/cargo)
"beU" = (
@@ -31173,17 +31190,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 +31228,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 +31693,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 +32402,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 +33087,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 +33095,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 +33122,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 +33949,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 +33978,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 +34429,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 +34447,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 +34456,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 +34466,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 +34506,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 +35271,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 +44280,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,
@@ -52824,6 +52858,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 +53095,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 +53191,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 +53199,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 +53993,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 +55521,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 +55630,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 +56387,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 +56680,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 +56761,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 +57175,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 +57183,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)
@@ -59138,6 +59194,13 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/open/floor/plating,
/area/maintenance/department/engine)
+"qAx" = (
+/obj/structure/disposalpipe/trunk{
+ dir = 1
+ },
+/obj/machinery/disposal/bin,
+/turf/open/floor/plasteel,
+/area/crew_quarters/fitness/recreation)
"qAM" = (
/obj/effect/spawner/lootdrop/maintenance,
/obj/item/cigbutt,
@@ -59336,6 +59399,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" = (
@@ -60486,6 +60550,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" = (
@@ -60808,12 +60875,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"
@@ -60933,6 +60994,10 @@
/obj/effect/turf_decal/plaque,
/turf/open/floor/plating,
/area/maintenance/department/engine)
+"uNA" = (
+/obj/structure/disposalpipe/segment,
+/turf/open/floor/plasteel,
+/area/crew_quarters/fitness/recreation)
"uQR" = (
/obj/item/ammo_casing/shotgun/beanbag,
/turf/open/floor/plating,
@@ -61489,12 +61554,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,
@@ -76958,7 +77017,7 @@ aaa
bOv
bNs
bNs
-bWh
+bQg
bQg
bQg
bQg
@@ -84165,7 +84224,7 @@ bIZ
cbb
bDi
ccO
-bIZ
+bva
cjm
cjm
xgh
@@ -84425,8 +84484,8 @@ bva
bva
aht
aht
-kSb
-kSb
+fon
+fon
aht
aht
mau
@@ -86680,7 +86739,7 @@ aXL
aYL
aZN
baW
-aKI
+afJ
aKI
beb
aKI
@@ -86936,8 +86995,8 @@ aVS
aXM
aVS
aVS
-aXM
-bbW
+aVS
+aVT
bbW
aVS
aVS
@@ -87138,7 +87197,7 @@ aaa
aaa
aaa
aaa
-afJ
+cFB
aby
aaa
agQ
@@ -87445,7 +87504,7 @@ aRJ
aSz
aSz
aUP
-aVT
+aVS
aWN
aXO
aYM
@@ -89457,7 +89516,7 @@ aaa
aaa
aaa
aaa
-afJ
+cFB
aaa
aaa
abI
@@ -94921,12 +94980,12 @@ jcT
xje
tTl
tTl
-tTl
+bWh
gkS
tTl
tTl
tTl
-koz
+tTl
dgg
phJ
phJ
@@ -95178,7 +95237,7 @@ bjm
mhn
cqi
cqi
-cqi
+koz
cqi
cqi
imE
@@ -95697,7 +95756,7 @@ duF
bxa
byE
bBp
-wfG
+bBp
bBp
bBp
bBp
@@ -95950,7 +96009,7 @@ cCl
brq
byF
cCt
-byF
+kSb
bxc
nIU
bAo
@@ -104126,8 +104185,8 @@ aaY
awB
abe
abi
-axw
-axw
+uNA
+qAx
axw
axw
aBX
diff --git a/_maps/map_files/generic/CentCom.dmm b/_maps/map_files/generic/CentCom.dmm
index bf0e1dc797..7506fbdca3 100644
--- a/_maps/map_files/generic/CentCom.dmm
+++ b/_maps/map_files/generic/CentCom.dmm
@@ -10524,6 +10524,10 @@
},
/turf/open/floor/plasteel,
/area/centcom/control)
+"yl" = (
+/obj/machinery/gear_painter,
+/turf/open/indestructible/hotelwood,
+/area/centcom/holding)
"yn" = (
/obj/effect/spawner/structure/window/reinforced,
/obj/structure/sign/warning/vacuum,
@@ -43992,7 +43996,7 @@ NS
Nd
ZL
NS
-NS
+yl
Nd
CU
NS
diff --git a/_maps/shuttles/emergency_nature.dmm b/_maps/shuttles/emergency_nature.dmm
index 9639e37852..51a14594fb 100644
--- a/_maps/shuttles/emergency_nature.dmm
+++ b/_maps/shuttles/emergency_nature.dmm
@@ -33,8 +33,8 @@
"bg" = (
/obj/structure/table/reinforced,
/obj/item/storage/toolbox/mechanical{
- pixel_y = 8;
- pixel_x = -2
+ pixel_x = -2;
+ pixel_y = 8
},
/obj/item/storage/toolbox/electrical,
/obj/effect/turf_decal/stripes/line,
@@ -43,8 +43,8 @@
"bS" = (
/obj/structure/table/reinforced,
/obj/item/storage/box/lights/mixed{
- pixel_y = 9;
- pixel_x = -5
+ pixel_x = -5;
+ pixel_y = 9
},
/obj/item/storage/box/matches{
pixel_y = 5
@@ -413,8 +413,8 @@
pixel_y = 4
},
/obj/item/reagent_containers/food/drinks/soda_cans/monkey_energy{
- pixel_y = 5;
- pixel_x = 6
+ pixel_x = 6;
+ pixel_y = 5
},
/turf/open/floor/plasteel/white,
/area/shuttle/escape)
@@ -494,8 +494,8 @@
/area/shuttle/escape)
"rg" = (
/obj/item/clothing/glasses/welding{
- pixel_y = 8;
- pixel_x = 3
+ pixel_x = 3;
+ pixel_y = 8
},
/obj/item/weldingtool/largetank{
pixel_x = -3
@@ -882,8 +882,8 @@
},
/obj/structure/table/glass,
/obj/item/storage/box/monkeycubes{
- pixel_y = 10;
- pixel_x = 5
+ pixel_x = 5;
+ pixel_y = 10
},
/obj/item/reagent_containers/food/snacks/cube/monkey{
pixel_x = 5
@@ -1156,8 +1156,8 @@
},
/obj/structure/table/glass,
/obj/item/clothing/suit/monkeysuit{
- pixel_y = 4;
- pixel_x = -2
+ pixel_x = -2;
+ pixel_y = 4
},
/obj/item/clothing/mask/gas/monkeymask{
pixel_x = 5;
@@ -1169,6 +1169,7 @@
/obj/machinery/door/airlock/titanium{
name = "Emergency Shuttle Airlock"
},
+/obj/structure/fans/tiny,
/turf/open/floor/plasteel/white,
/area/shuttle/escape)
"ST" = (
@@ -1319,6 +1320,7 @@
name = "Emergency Shuttle Airlock"
},
/obj/docking_port/mobile/emergency,
+/obj/structure/fans/tiny,
/turf/open/floor/plasteel/white,
/area/shuttle/escape)
"Yu" = (
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/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 51a5fb3ece..a084f2ae34 100644
--- a/code/__DEFINES/dcs/signals.dm
+++ b/code/__DEFINES/dcs/signals.dm
@@ -136,11 +136,15 @@
#define COMSIG_ATOM_ATTACK_HAND "atom_attack_hand" //from base of atom/attack_hand(): (mob/user)
#define COMSIG_ATOM_ATTACK_PAW "atom_attack_paw" //from base of atom/attack_paw(): (mob/user)
#define COMPONENT_NO_ATTACK_HAND 1 //works on all 3.
+/////////////////
+
//This signal return value bitflags can be found in __DEFINES/misc.dm
#define COMSIG_ATOM_INTERCEPT_Z_FALL "movable_intercept_z_impact" //called for each movable in a turf contents on /turf/zImpact(): (atom/movable/A, levels)
-
-/////////////////
+/// Called from orbit component: (atom/movable/orbiter, radius, clockwise, rotation_speed, rotation_segments, pre_rotation)
+#define COMSIG_ATOM_ORBIT_BEGIN "atom_orbit_begin"
+/// Called from orbit component: (atom/movable/orbiter, refreshing)
+#define COMSIG_ATOM_ORBIT_END "atom_orbit_end"
#define COMSIG_ENTER_AREA "enter_area" //from base of area/Entered(): (/area)
#define COMSIG_EXIT_AREA "exit_area" //from base of area/Exited(): (/area)
@@ -536,3 +540,7 @@
#define COMSIG_XENO_TURF_CLICK_SHIFT "xeno_turf_click_shift" //from turf ShiftClickOn(): (/mob)
#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)
+
+// 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 7fe5fa4876..ecd043a66a 100644
--- a/code/__DEFINES/loadout.dm
+++ b/code/__DEFINES/loadout.dm
@@ -55,6 +55,9 @@
//donator items
#define LOADOUT_CATEGORY_DONATOR "Donator"
+//unlockable items
+#define LOADOUT_CATEGORY_UNLOCKABLE "Unlockable"
+
//how many prosthetics can we have
#define MAXIMUM_LOADOUT_PROSTHETICS 2
diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm
index 153a82ad5e..8e7cf8763b 100644
--- a/code/__DEFINES/mobs.dm
+++ b/code/__DEFINES/mobs.dm
@@ -61,7 +61,7 @@
#define BODYPART_NANITES 4
#define HYBRID_BODYPART_DAMAGE_THRESHHOLD 25 //How much damage has to be suffered until the damage threshhold counts as passed
-#define HYBRID_BODYPART_THESHHOLD_MINDAMAGE 15 //Which damage value this limb cannot be healed out of via easy nonsurgical means if the threshhold has been passed, state resets if damage value goes below mindamage.
+#define HYBRID_BODYPART_THESHHOLD_MINDAMAGE 10 //Which damage value this limb cannot be healed out of via easy nonsurgical means if the threshhold has been passed, state resets if damage value goes below mindamage.
#define BODYPART_NOT_DISABLED 0
#define BODYPART_DISABLED_DAMAGE 1
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/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/species.dm b/code/__DEFINES/species.dm
index efd715b85a..74ca459fa1 100644
--- a/code/__DEFINES/species.dm
+++ b/code/__DEFINES/species.dm
@@ -5,6 +5,7 @@
#define SPECIES_ANDROID "android"
#define SPECIES_ANGEL "angel"
#define SPECIES_MAMMAL "mammal"
+ #define SPECIES_MAMMAL_SYNTHETIC "mammal_synthetic"
#define SPECIES_ARACHNID "arachnid"
#define SPECIES_INSECT "insect"
#define SPECIES_DULLAHAN "dullahan"
diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm
index d6db35e68d..e2ace84156 100644
--- a/code/__DEFINES/status_effects.dm
+++ b/code/__DEFINES/status_effects.dm
@@ -40,6 +40,9 @@
#define STATUS_EFFECT_DETERMINED /datum/status_effect/determined //currently in a combat high from being seriously wounded
+#define STATUS_EFFECT_MANTRA /datum/status_effect/mantra // a toggled self buff that makes you stronger and more resilient, but drains stamina over time
+#define STATUS_EFFECT_ASURA /datum/status_effect/asura // like a weaker version of mantra, drains HP instead of stamina and has no armor
+
/////////////
// DEBUFFS //
/////////////
@@ -102,10 +105,6 @@
#define STATUS_EFFECT_FAKE_VIRUS /datum/status_effect/fake_virus //gives you fluff messages for cough, sneeze, headache, etc but without an actual virus
-#define STATUS_EFFECT_BREASTS_ENLARGEMENT /datum/status_effect/chem/breast_enlarger //Applied slowdown due to the ominous bulk.
-
-#define STATUS_EFFECT_PENIS_ENLARGEMENT /datum/status_effect/chem/penis_enlarger //More applied slowdown, just like the above.
-
#define STATUS_EFFECT_NO_COMBAT_MODE /datum/status_effect/no_combat_mode //Wont allow combat mode and will disable it
#define STATUS_EFFECT_MESMERIZE /datum/status_effect/mesmerize //Just reskinned no_combat_mode
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/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..8d25fb8e03 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) {\
diff --git a/code/__HELPERS/_logging.dm b/code/__HELPERS/_logging.dm
index 583427cab7..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)
@@ -86,10 +86,6 @@
if (CONFIG_GET(flag/log_attack))
WRITE_LOG(GLOB.world_attack_log, "ATTACK: [text]")
-/proc/log_wounded(text)
- if (CONFIG_GET(flag/log_attack))
- WRITE_LOG(GLOB.world_attack_log, "WOUND: [text]")
-
/proc/log_manifest(ckey, datum/mind/mind,mob/body, latejoin = FALSE)
if (CONFIG_GET(flag/log_manifest))
WRITE_LOG(GLOB.world_manifest_log, "[ckey] \\ [body.real_name] \\ [mind.assigned_role] \\ [mind.special_role ? mind.special_role : "NONE"] \\ [latejoin ? "LATEJOIN":"ROUNDSTART"]")
@@ -195,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/roundend.dm b/code/__HELPERS/roundend.dm
index 2263ac2e27..40ae43b281 100644
--- a/code/__HELPERS/roundend.dm
+++ b/code/__HELPERS/roundend.dm
@@ -238,8 +238,11 @@
CHECK_TICK
SSdbcore.SetRoundEnd()
//Collects persistence features
- if(mode.allow_persistence_save)
- SSpersistence.CollectData()
+ if(mode.station_was_nuked)
+ SSpersistence.station_was_destroyed = TRUE
+ if(!mode.allow_persistence_save)
+ SSpersistence.station_persistence_save_disabled = TRUE
+ SSpersistence.CollectData()
//stop collecting feedback during grifftime
SSblackbox.Seal()
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index babcd5de54..08bf5e709a 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -271,7 +271,7 @@ Turf and target are separate in case you want to teleport some distance from a t
if(skip_mindless && (!M.mind && !M.ckey))
if(!isbot(M) && !iscameramob(M) && !ismegafauna(M))
continue
- if(M.client && M.client.holder && M.client.holder.fakekey) //stealthmins
+ if(M.client?.holder?.fakekey && isobserver(M))
continue
var/name = avoid_assoc_duplicate_keys(M.name, namecounts)
@@ -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 0444e42e91..7fad1690e6 100644
--- a/code/_globalvars/lists/flavor_misc.dm
+++ b/code/_globalvars/lists/flavor_misc.dm
@@ -275,7 +275,7 @@ 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(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))
+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
//locked parts are those that your picked species requires to have
diff --git a/code/_globalvars/lists/loadout_categories.dm b/code/_globalvars/lists/loadout_categories.dm
index 0f0ac52214..4a61a94dc7 100644
--- a/code/_globalvars/lists/loadout_categories.dm
+++ b/code/_globalvars/lists/loadout_categories.dm
@@ -9,5 +9,6 @@ GLOBAL_LIST_INIT(loadout_categories, list(
LOADOUT_CATEGORY_SHOES = LOADOUT_SUBCATEGORIES_NONE,
LOADOUT_CATEGORY_GLOVES = LOADOUT_SUBCATEGORIES_NONE,
LOADOUT_CATEGORY_GLASSES = LOADOUT_SUBCATEGORIES_NONE,
- LOADOUT_CATEGORY_DONATOR = LOADOUT_SUBCATEGORIES_NONE
+ LOADOUT_CATEGORY_DONATOR = LOADOUT_SUBCATEGORIES_NONE,
+ LOADOUT_CATEGORY_UNLOCKABLE = LOADOUT_SUBCATEGORIES_NONE
))
diff --git a/code/_globalvars/lists/maintenance_loot.dm b/code/_globalvars/lists/maintenance_loot.dm
index 694e913d53..b41b7356a8 100644
--- a/code/_globalvars/lists/maintenance_loot.dm
+++ b/code/_globalvars/lists/maintenance_loot.dm
@@ -89,7 +89,7 @@ GLOBAL_LIST_INIT(maintenance_loot, list(
/obj/effect/spawner/lootdrop/welder_tools = 3,
/obj/effect/spawner/lootdrop/low_tools = 5,
/obj/item/relic = 3,
- /obj/item/weaponcrafting/improvised_parts/shotgun_receiver = 2,
+ /obj/item/weaponcrafting/receiver = 2,
/obj/item/clothing/head/cone = 2,
/obj/item/grenade/smokebomb = 2,
/obj/item/geiger_counter = 3,
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/_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/configuration/entries/game_options.dm b/code/controllers/configuration/entries/game_options.dm
index 67e4a97894..dc8e9e1859 100644
--- a/code/controllers/configuration/entries/game_options.dm
+++ b/code/controllers/configuration/entries/game_options.dm
@@ -566,3 +566,20 @@
config_entry_value = 0.333
min_val = 0
integer = FALSE
+
+/// Amount of dirtyness tiles need to spawn dirt.
+/datum/config_entry/number/turf_dirt_threshold
+ config_entry_value = 100
+ min_val = 1
+ integer = TRUE
+
+/// Alpha dirt starts at
+/datum/config_entry/number/dirt_alpha_starting
+ config_entry_value = 127
+ max_val = 255
+ min_val = 0
+ integer = TRUE
+
+/// Dirtyness multiplier for making turfs dirty
+/datum/config_entry/number/turf_dirty_multiplier
+ config_entry_value = 1
diff --git a/code/controllers/configuration/entries/persistence.dm b/code/controllers/configuration/entries/persistence.dm
new file mode 100644
index 0000000000..2444034b86
--- /dev/null
+++ b/code/controllers/configuration/entries/persistence.dm
@@ -0,0 +1,20 @@
+/// Whether or not to use the persistence system for cleanable objects
+/datum/config_entry/flag/persistent_debris
+ config_entry_value = FALSE
+
+/// Whether or not to nuke all roundstart debris that isn't due to persistence if the above is true
+/datum/config_entry/flag/persistent_debris_only
+ config_entry_value = TRUE
+
+/// Max amount of objects to store, total
+/datum/config_entry/number/persistent_debris_global_max
+ config_entry_value = 10000
+ integer = TRUE
+
+/// Max amount of objects to store per type
+/datum/config_entry/number/persistent_debris_type_max
+ config_entry_value = 2000
+ integer = TRUE
+
+/// Wipe dirty stuff on nuke
+/datum/config_entry/flag/persistent_debris_wipe_on_nuke
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 a343f4c578..84f63cf47d 100644
--- a/code/controllers/subsystem/blackbox.dm
+++ b/code/controllers/subsystem/blackbox.dm
@@ -115,7 +115,6 @@ SUBSYSTEM_DEF(blackbox)
SSdbcore.MassInsert(format_table_name("feedback"), sqlrowlist, ignore_errors = TRUE, delayed = TRUE, special_columns = special_columns)
-
/datum/controller/subsystem/blackbox/proc/Seal()
if(sealed)
return FALSE
@@ -285,6 +284,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/LogAhelp(ticket, action, message, recipient, sender)
if(!SSdbcore.Connect())
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 b6b750fbf4..c298460b2c 100644
--- a/code/controllers/subsystem/dbcore.dm
+++ b/code/controllers/subsystem/dbcore.dm
@@ -202,6 +202,25 @@ SUBSYSTEM_DEF(dbcore)
+/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
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 51d56545b6..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
@@ -115,18 +139,22 @@ SUBSYSTEM_DEF(garbage)
lastlevel = level
- for (var/refID in queue)
- if (!refID)
+ //We do this rather then for(var/refID in queue) because that sort of for loop copies the whole list.
+ //Normally this isn't expensive, but the gc queue can grow to 40k items, and that gets costly/causes overrun.
+ for (var/i in 1 to length(queue))
+ var/list/L = queue[i]
+ if (length(L) < 2)
count++
if (MC_TICK_CHECK)
return
continue
- var/GCd_at_time = queue[refID]
+ var/GCd_at_time = L[1]
if(GCd_at_time > cut_off_time)
break // Everything else is newer, skip them
count++
+ var/refID = L[2]
var/datum/D
D = locate(refID)
@@ -135,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
@@ -149,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
@@ -186,27 +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]
- if (queue[refid])
- queue -= refid // Removing any previous references that were GC'd so that the current object will be at the end of the list.
-
- queue[refid] = gctime
-
#ifdef LEGACY_REFERENCE_TRACKING
/datum/controller/subsystem/garbage/proc/add_type_to_findref(type)
if(!ispath(type))
@@ -222,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
@@ -274,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)
@@ -330,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 4963e33cc3..779ee2fbac 100644
--- a/code/controllers/subsystem/job.dm
+++ b/code/controllers/subsystem/job.dm
@@ -698,6 +698,8 @@ SUBSYSTEM_DEF(job)
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
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/mapping.dm b/code/controllers/subsystem/mapping.dm
index 36347c9a43..b5dfec3c44 100644
--- a/code/controllers/subsystem/mapping.dm
+++ b/code/controllers/subsystem/mapping.dm
@@ -41,6 +41,8 @@ SUBSYSTEM_DEF(mapping)
var/datum/space_level/transit
var/datum/space_level/empty_space
var/num_of_res_levels = 1
+ /// Lookup for zlevel to station z. text = num.
+ var/list/z_to_station_z_index
var/stat_map_name = "Loading..."
@@ -259,6 +261,16 @@ SUBSYSTEM_DEF(mapping)
INIT_ANNOUNCE("Loaded [name] in [(REALTIMEOFDAY - start_time)/10]s!")
return parsed_maps
+/datum/controller/subsystem/mapping/proc/setup_station_z_index()
+ z_to_station_z_index = list()
+ var/sz = 1
+ var/cz = station_start
+ if(islist(config.map_file))
+ for(var/map in config.map_file)
+ z_to_station_z_index["[cz++]"] = sz++
+ else
+ z_to_station_z_index["[station_start]"] = 1
+
/datum/controller/subsystem/mapping/proc/loadWorld()
//if any of these fail, something has gone horribly, HORRIBLY, wrong
var/list/FailedZs = list()
@@ -271,6 +283,8 @@ SUBSYSTEM_DEF(mapping)
INIT_ANNOUNCE("Loading [config.map_name]...")
LoadGroup(FailedZs, "Station", config.map_path, config.map_file, config.traits, ZTRAITS_STATION, FALSE, config.orientation)
+ setup_station_z_index()
+
if(SSdbcore.Connect())
var/datum/db_query/query_round_map_name = SSdbcore.NewQuery({"
UPDATE [format_table_name("round")] SET map_name = :map_name WHERE id = :round_id
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.dm b/code/controllers/subsystem/persistence/_persistence.dm
similarity index 51%
rename from code/controllers/subsystem/persistence.dm
rename to code/controllers/subsystem/persistence/_persistence.dm
index e39242aac3..e8faf80e5d 100644
--- a/code/controllers/subsystem/persistence.dm
+++ b/code/controllers/subsystem/persistence/_persistence.dm
@@ -5,18 +5,14 @@ SUBSYSTEM_DEF(persistence)
name = "Persistence"
init_order = INIT_ORDER_PERSISTENCE
flags = SS_NO_FIRE
- var/list/satchel_blacklist = list() //this is a typecache
- var/list/new_secret_satchels = list() //these are objects
- var/list/old_secret_satchels = list()
+
+ /// Marks if the station got horribly destroyed
+ var/station_was_destroyed = FALSE
+ /// Marks if persistence save should be disabled
+ var/station_persistence_save_disabled = FALSE
var/list/obj/structure/chisel_message/chisel_messages = list()
var/list/saved_messages = list()
- var/list/saved_modes = list(1,2,3)
- var/list/saved_dynamic_rules = list(list(),list(),list())
- var/list/saved_storytellers = list("foo","bar","baz")
- var/list/average_dynamic_threat = 50
- var/list/saved_maps
- var/list/saved_trophies = list()
var/list/spawned_objects = list()
var/list/antag_rep = list()
var/list/antag_rep_change = list()
@@ -28,62 +24,82 @@ SUBSYSTEM_DEF(persistence)
var/list/paintings = list()
/datum/controller/subsystem/persistence/Initialize()
- LoadSatchels()
- LoadPoly()
- LoadChiselMessages()
- LoadTrophies()
- LoadRecentModes()
- LoadRecentStorytellers()
- LoadRecentRulesets()
- LoadRecentMaps()
- LoadPhotoPersistence()
+ LoadServerPersistence()
+ LoadGamePersistence()
+ var/map_persistence_path = get_map_persistence_path()
+ if(map_persistence_path)
+ LoadMapPersistence()
+ return ..()
+
+/**
+ * Gets the persistence path of the current map.
+ */
+/datum/controller/subsystem/persistence/proc/get_map_persistence_path()
+ ASSERT(SSmapping.config)
+ if(!SSmapping.config.persistence_key || (SSmapping.config.persistence_key == "NO_PERSIST"))
+ return null
+ return "data/persistence/[ckey(SSmapping.config.persistence_key)]"
+
+/datum/controller/subsystem/persistence/proc/CollectData()
+ SaveServerPersistence()
+ if(station_persistence_save_disabled)
+ return
+ SaveGamePersistence()
+ var/map_persistence_path = get_map_persistence_path()
+ if(map_persistence_path)
+ SaveMapPersistence()
+
+/**
+ * Loads persistent data relevant to the server: Configurations, past gamemodes, votes, antag rep, etc
+ */
+/datum/controller/subsystem/persistence/proc/LoadServerPersistence()
for(var/client/C in GLOB.clients)
LoadSavedVote(C.ckey)
if(CONFIG_GET(flag/use_antag_rep))
LoadAntagReputation()
LoadRandomizedRecipes()
- LoadPanicBunker()
- return ..()
+ LoadPaintings()
-/datum/controller/subsystem/persistence/proc/LoadSatchels()
- var/placed_satchel = 0
- var/path
+/**
+ * Saves persistent data relevant to the server: Configurations, past gamemodes, votes, antag rep, etc
+ */
+/datum/controller/subsystem/persistence/proc/SaveServerPersistence()
+ if(CONFIG_GET(flag/use_antag_rep))
+ CollectAntagReputation()
+ SaveRandomizedRecipes()
- var/json_file = file("data/npc_saves/SecretSatchels[SSmapping.config.map_name].json")
- var/list/json = list()
- if(fexists(json_file))
- json = json_decode(file2text(json_file))
+/**
+ * Loads persistent data relevant to the game in general: Photos, etc
+ *
+ * Legacy map persistence systems also use this.
+ */
+/datum/controller/subsystem/persistence/proc/LoadGamePersistence()
+ LoadChiselMessages()
+ LoadPhotoPersistence()
+ LoadPaintings()
- old_secret_satchels = json["data"]
- var/obj/item/storage/backpack/satchel/flat/F
- if(old_secret_satchels && old_secret_satchels.len >= 10) //guards against low drop pools assuring that one player cannot reliably find his own gear.
- var/pos = rand(1, old_secret_satchels.len)
- F = new()
- old_secret_satchels.Cut(pos, pos+1 % old_secret_satchels.len)
- F.x = old_secret_satchels[pos]["x"]
- F.y = old_secret_satchels[pos]["y"]
- F.z = SSmapping.station_start
- path = text2path(old_secret_satchels[pos]["saved_obj"])
+/**
+ * Saves persistent data relevant to the game in general: Photos, etc
+ *
+ * Legacy map persistence systems also use this.
+ */
+/datum/controller/subsystem/persistence/proc/SaveGamePersistence()
+ CollectChiselMessages()
+ SavePhotoPersistence() //THIS IS PERSISTENCE, NOT THE LOGGING PORTION.
+ SavePaintings()
+ SaveScars()
- if(F)
- if(isfloorturf(F.loc) && !isplatingturf(F.loc))
- F.hide(1)
- if(ispath(path))
- var/spawned_item = new path(F)
- spawned_objects[spawned_item] = TRUE
- placed_satchel++
- var/free_satchels = 0
- for(var/turf/T in shuffle(block(locate(TRANSITIONEDGE,TRANSITIONEDGE,SSmapping.station_start), locate(world.maxx-TRANSITIONEDGE,world.maxy-TRANSITIONEDGE,SSmapping.station_start)))) //Nontrivially expensive but it's roundstart only
- if(isfloorturf(T) && !isplatingturf(T))
- new /obj/item/storage/backpack/satchel/flat/secret(T)
- free_satchels++
- if((free_satchels + placed_satchel) == 10) //ten tiles, more than enough to kill anything that moves
- break
+/**
+ * Loads persistent data relevant to the current map: Objects, etc.
+ */
+/datum/controller/subsystem/persistence/proc/LoadMapPersistence()
+ return
-/datum/controller/subsystem/persistence/proc/LoadPoly()
- for(var/mob/living/simple_animal/parrot/Poly/P in GLOB.alive_mob_list)
- twitterize(P.speech_buffer, "polytalk")
- break //Who's been duping the bird?!
+/**
+ * Saves persistent data relevant to the current map: Objects, etc.
+ */
+/datum/controller/subsystem/persistence/proc/SaveMapPersistence()
+ return
/datum/controller/subsystem/persistence/proc/LoadChiselMessages()
var/list/saved_messages = list()
@@ -130,63 +146,6 @@ SUBSYSTEM_DEF(persistence)
log_world("Loaded [saved_messages.len] engraved messages on map [SSmapping.config.map_name]")
-/datum/controller/subsystem/persistence/proc/LoadTrophies()
- if(fexists("data/npc_saves/TrophyItems.sav")) //legacy compatability to convert old format to new
- var/savefile/S = new /savefile("data/npc_saves/TrophyItems.sav")
- var/saved_json
- S >> saved_json
- if(!saved_json)
- return
- saved_trophies = json_decode(saved_json)
- fdel("data/npc_saves/TrophyItems.sav")
- else
- var/json_file = file("data/npc_saves/TrophyItems.json")
- if(!fexists(json_file))
- return
- var/list/json = json_decode(file2text(json_file))
- if(!json)
- return
- saved_trophies = json["data"]
- SetUpTrophies(saved_trophies.Copy())
-
-/datum/controller/subsystem/persistence/proc/LoadRecentModes()
- var/json_file = file("data/RecentModes.json")
- if(!fexists(json_file))
- return
- var/list/json = json_decode(file2text(json_file))
- if(!json)
- return
- saved_modes = json["data"]
-
-/datum/controller/subsystem/persistence/proc/LoadRecentRulesets()
- var/json_file = file("data/RecentRulesets.json")
- if(!fexists(json_file))
- return
- var/list/json = json_decode(file2text(json_file))
- if(!json)
- return
- saved_dynamic_rules = json["data"]
-
-/datum/controller/subsystem/persistence/proc/LoadRecentStorytellers()
- var/json_file = file("data/RecentStorytellers.json")
- if(!fexists(json_file))
- return
- var/list/json = json_decode(file2text(json_file))
- if(!json)
- return
- saved_storytellers = json["data"]
- if(saved_storytellers.len > 3)
- average_dynamic_threat = saved_storytellers[4]
- saved_storytellers.len = 3
-
-/datum/controller/subsystem/persistence/proc/LoadRecentMaps()
- var/json_file = file("data/RecentMaps.json")
- if(!fexists(json_file))
- return
- var/list/json = json_decode(file2text(json_file))
- if(!json)
- return
- saved_maps = json["maps"]
/datum/controller/subsystem/persistence/proc/LoadAntagReputation()
var/json = file2text(FILE_ANTAG_REP)
@@ -207,59 +166,6 @@ SUBSYSTEM_DEF(persistence)
return
saved_votes[ckey] = json["data"]
-/datum/controller/subsystem/persistence/proc/SetUpTrophies(list/trophy_items)
- for(var/A in GLOB.trophy_cases)
- var/obj/structure/displaycase/trophy/T = A
- if (T.showpiece)
- continue
- T.added_roundstart = TRUE
-
- var/trophy_data = pick_n_take(trophy_items)
-
- if(!islist(trophy_data))
- continue
-
- var/list/chosen_trophy = trophy_data
-
- if(!chosen_trophy || isemptylist(chosen_trophy)) //Malformed
- continue
-
- var/path = text2path(chosen_trophy["path"]) //If the item no longer exist, this returns null
- if(!path)
- continue
-
- T.showpiece = new /obj/item/showpiece_dummy(T, path)
- T.trophy_message = chosen_trophy["message"]
- T.placer_key = chosen_trophy["placer_key"]
- T.update_icon()
-
-/datum/controller/subsystem/persistence/proc/CollectData()
- CollectChiselMessages()
- CollectSecretSatchels()
- CollectTrophies()
- CollectRoundtype()
- if(istype(SSticker.mode, /datum/game_mode/dynamic))
- var/datum/game_mode/dynamic/mode = SSticker.mode
- CollectStoryteller(mode)
- CollectRulesets(mode)
- RecordMaps()
- SavePhotoPersistence() //THIS IS PERSISTENCE, NOT THE LOGGING PORTION.
- if(CONFIG_GET(flag/use_antag_rep))
- CollectAntagReputation()
- SaveRandomizedRecipes()
- SavePanicBunker()
- SavePaintings()
- SaveScars()
-
-/datum/controller/subsystem/persistence/proc/LoadPanicBunker()
- var/bunker_path = file("data/bunker_passthrough.json")
- if(fexists(bunker_path))
- var/list/json = json_decode(file2text(bunker_path))
- GLOB.bunker_passthrough = json["data"]
- for(var/ckey in GLOB.bunker_passthrough)
- if(daysSince(GLOB.bunker_passthrough[ckey]) >= CONFIG_GET(number/max_bunker_days))
- GLOB.bunker_passthrough -= ckey
-
/datum/controller/subsystem/persistence/proc/GetPhotoAlbums()
var/album_path = file("data/photo_albums.json")
if(fexists(album_path))
@@ -329,35 +235,6 @@ SUBSYSTEM_DEF(persistence)
WRITE_FILE(frame_path, frame_json)
-/datum/controller/subsystem/persistence/proc/CollectSecretSatchels()
- satchel_blacklist = typecacheof(list(/obj/item/stack/tile/plasteel, /obj/item/crowbar))
- var/list/satchels_to_add = list()
- for(var/A in new_secret_satchels)
- var/obj/item/storage/backpack/satchel/flat/F = A
- if(QDELETED(F) || F.z != SSmapping.station_start || F.invisibility != INVISIBILITY_MAXIMUM)
- continue
- var/list/savable_obj = list()
- for(var/obj/O in F)
- if(is_type_in_typecache(O, satchel_blacklist) || (O.flags_1 & ADMIN_SPAWNED_1))
- continue
- if(O.persistence_replacement)
- savable_obj += O.persistence_replacement
- else
- savable_obj += O.type
- if(isemptylist(savable_obj))
- continue
- var/list/data = list()
- data["x"] = F.x
- data["y"] = F.y
- data["saved_obj"] = pick(savable_obj)
- satchels_to_add += list(data)
-
- var/json_file = file("data/npc_saves/SecretSatchels[SSmapping.config.map_name].json")
- var/list/file_data = list()
- fdel(json_file)
- file_data["data"] = old_secret_satchels + satchels_to_add
- WRITE_FILE(json_file, json_encode(file_data))
-
/datum/controller/subsystem/persistence/proc/CollectChiselMessages()
var/json_file = file("data/npc_saves/ChiselMessages[SSmapping.config.map_name].json")
@@ -373,84 +250,6 @@ SUBSYSTEM_DEF(persistence)
/datum/controller/subsystem/persistence/proc/SaveChiselMessage(obj/structure/chisel_message/M)
saved_messages += list(M.pack()) // dm eats one list
-
-/datum/controller/subsystem/persistence/proc/CollectTrophies()
- var/json_file = file("data/npc_saves/TrophyItems.json")
- var/list/file_data = list()
- file_data["data"] = remove_duplicate_trophies(saved_trophies)
- fdel(json_file)
- WRITE_FILE(json_file, json_encode(file_data))
-
-/datum/controller/subsystem/persistence/proc/SavePanicBunker()
- var/json_file = file("data/bunker_passthrough.json")
- var/list/file_data = list()
- file_data["data"] = GLOB.bunker_passthrough
- fdel(json_file)
- WRITE_FILE(json_file,json_encode(file_data))
-
-/datum/controller/subsystem/persistence/proc/remove_duplicate_trophies(list/trophies)
- var/list/ukeys = list()
- . = list()
- for(var/trophy in trophies)
- var/tkey = "[trophy["path"]]-[trophy["message"]]"
- if(ukeys[tkey])
- continue
- else
- . += list(trophy)
- ukeys[tkey] = TRUE
-
-/datum/controller/subsystem/persistence/proc/SaveTrophy(obj/structure/displaycase/trophy/T)
- if(!T.added_roundstart && T.showpiece)
- var/list/data = list()
- data["path"] = T.showpiece.type
- data["message"] = T.trophy_message
- data["placer_key"] = T.placer_key
- saved_trophies += list(data)
-
-/datum/controller/subsystem/persistence/proc/CollectRoundtype()
- saved_modes[3] = saved_modes[2]
- saved_modes[2] = saved_modes[1]
- saved_modes[1] = SSticker.mode.config_tag
- var/json_file = file("data/RecentModes.json")
- var/list/file_data = list()
- file_data["data"] = saved_modes
- fdel(json_file)
- WRITE_FILE(json_file, json_encode(file_data))
-
-/datum/controller/subsystem/persistence/proc/CollectStoryteller(var/datum/game_mode/dynamic/mode)
- saved_storytellers.len = 3
- saved_storytellers[3] = saved_storytellers[2]
- saved_storytellers[2] = saved_storytellers[1]
- saved_storytellers[1] = mode.storyteller.name
- average_dynamic_threat = (mode.max_threat + average_dynamic_threat) / 2
- var/json_file = file("data/RecentStorytellers.json")
- var/list/file_data = list()
- file_data["data"] = saved_storytellers + average_dynamic_threat
- fdel(json_file)
- WRITE_FILE(json_file, json_encode(file_data))
-
-/datum/controller/subsystem/persistence/proc/CollectRulesets(var/datum/game_mode/dynamic/mode)
- saved_dynamic_rules[3] = saved_dynamic_rules[2]
- saved_dynamic_rules[2] = saved_dynamic_rules[1]
- saved_dynamic_rules[1] = list()
- for(var/r in mode.executed_rules)
- var/datum/dynamic_ruleset/rule = r
- saved_dynamic_rules[1] += rule.config_tag
- var/json_file = file("data/RecentRulesets.json")
- var/list/file_data = list()
- file_data["data"] = saved_dynamic_rules
- fdel(json_file)
- WRITE_FILE(json_file, json_encode(file_data))
-
-/datum/controller/subsystem/persistence/proc/RecordMaps()
- saved_maps = saved_maps?.len ? list("[SSmapping.config.map_name]") | saved_maps : list("[SSmapping.config.map_name]")
- var/json_file = file("data/RecentMaps.json")
- var/list/file_data = list()
- file_data["maps"] = saved_maps
- fdel(json_file)
- WRITE_FILE(json_file, json_encode(file_data))
-
-
/datum/controller/subsystem/persistence/proc/CollectAntagReputation()
var/ANTAG_REP_MAXIMUM = CONFIG_GET(number/antag_rep_maximum)
diff --git a/code/controllers/subsystem/persistence/cleanable_debris.dm b/code/controllers/subsystem/persistence/cleanable_debris.dm
new file mode 100644
index 0000000000..a0817c460b
--- /dev/null
+++ b/code/controllers/subsystem/persistence/cleanable_debris.dm
@@ -0,0 +1,177 @@
+/**
+ * Persistence for cleanable debris.
+ */
+/datum/controller/subsystem/persistence
+ /// tracks if we already loaded debris. Unlike everything else, this can actually be a major problem if some badmin procs it twice.
+ var/loaded_debris = FALSE
+
+/datum/controller/subsystem/persistence/LoadMapPersistence()
+ . = ..()
+ if(CONFIG_GET(flag/persistent_debris))
+ LoadMapDebris()
+
+/datum/controller/subsystem/persistence/SaveMapPersistence()
+ . = ..()
+ if(CONFIG_GET(flag/persistent_debris))
+ SaveMapDebris()
+
+/datum/controller/subsystem/persistence/proc/LoadMapDebris()
+ if(CONFIG_GET(flag/persistent_debris_only))
+ wipe_existing_debris()
+ if(!fexists("[get_map_persistence_path()]/debris.json"))
+ return
+ if(loaded_debris)
+ return
+ loaded_debris = TRUE
+ var/list/allowed_turf_typecache = typecacheof(/turf/open) - typecacheof(/turf/open/space)
+ var/list/allowed_z_cache = list()
+ for(var/z in SSmapping.levels_by_trait(ZTRAIT_STATION))
+ allowed_z_cache[num2text(z)] = TRUE
+ var/list/data = json_decode(file2text("[get_map_persistence_path()]/debris.json"))
+ var/list/z_lookup = list()
+ var/loaded = 0
+ var/list/loaded_by_type = list()
+ var/nopath = 0
+ var/badloc = 0
+ var/noturf = 0
+ /// reverse it
+ for(var/z in SSmapping.z_to_station_z_index)
+ var/sz = SSmapping.z_to_station_z_index[z]
+ z_lookup[num2text(sz)] = text2num(z)
+ for(var/z in data)
+ var/actual_z = z_lookup[z]
+ var/list/L1 = data[z]
+ for(var/x in L1)
+ var/list/L2 = data[z][x]
+ for(var/y in L2)
+ var/turf/tile = locate(text2num(x), text2num(y), actual_z)
+ if(!tile)
+ noturf++
+ continue
+ var/list/objects = data[z][x][y]
+ for(var/_L in objects)
+ var/list/objdata
+ var/path
+ if(islist(_L))
+ objdata = _L
+ path = text2path(objdata["__PATH__"])
+ else
+ path = text2path(_L)
+ objdata = objects[_L]
+ if(!path)
+ nopath++
+ continue
+ if(!IsValidDebrisLocation(tile, allowed_turf_typecache, allowed_z_cache, path, TRUE))
+ badloc++
+ continue
+ var/obj/effect/decal/cleanable/instantiated = new path(tile)
+ loaded_by_type[path] += 1
+ loaded++
+ if(objdata)
+ instantiated.PersistenceLoad(objdata)
+ var/list/bytype = list()
+ for(var/path in loaded_by_type)
+ bytype += "[path] - [loaded_by_type[path]]"
+ subsystem_log(
+ {"Debris loading completed:
+ Errors:
+ No path: [nopath]
+ Invalid location: [badloc]
+ No turf on map: [noturf]
+ Total loaded: [loaded]
+ By type:
+ [bytype.Join("\n")]"}
+ )
+
+/datum/controller/subsystem/persistence/proc/SaveMapDebris()
+ if(fexists("[get_map_persistence_path()]/debris.json"))
+ fdel("[get_map_persistence_path()]/debris.json")
+ if(CONFIG_GET(flag/persistent_debris_wipe_on_nuke) && station_was_destroyed)
+ return // local janitor cheers on nukeop team to save some work
+ var/list/data = list()
+ var/list/z_lookup = SSmapping.z_to_station_z_index
+ var/list/debris = RelevantPersistentDebris()
+ var/obj/effect/decal/cleanable/saving
+ var/global_max = CONFIG_GET(number/persistent_debris_global_max)
+ var/type_max = CONFIG_GET(number/persistent_debris_type_max)
+ var/stored = 0
+ var/list/stored_by_type = list()
+ for(var/i in debris)
+ saving = i
+ var/list/serializing = list()
+ var/path = saving.PersistenceSave(serializing)
+ if(!path)
+ continue
+ if(stored_by_type[path] > type_max)
+ continue
+ var/text_z = num2text(z_lookup[num2text(saving.z)])
+ var/text_y = num2text(saving.y)
+ var/text_x = num2text(saving.x)
+ LAZYINITLIST(data[text_z])
+ LAZYINITLIST(data[text_z][text_x])
+ LAZYINITLIST(data[text_z][text_x][text_y])
+ if(saving.persistence_allow_stacking)
+ serializing["__PATH__"] = path
+ data[text_z][text_x][text_y] += list(serializing)
+ else
+ data[text_z][text_x][text_y][path] = serializing
+ stored++
+ if(stored > global_max)
+ var/w = "Persistent debris saving globally aborted due to global max >= [global_max]. Either janitors never do their jobs or something is wrong."
+ message_admins(w)
+ subsystem_log(w)
+ return
+ stored_by_type[path] = stored_by_type[path]? stored_by_type[path] + 1 : 1
+ if(stored_by_type[path] > type_max)
+ var/w = "Persistent debris saving aborted for type [path] due to type max >= [global_max]. Either janitors never do their jobs or something is wrong."
+ message_admins(w)
+ subsystem_log(w)
+
+ var/list/bytype = list()
+ for(var/path in stored_by_type)
+ bytype += "[path] - [stored_by_type[path]]"
+ subsystem_log(
+ {"Debris saving completed:
+ Total: [stored]
+ By type:
+ [bytype.Join("\n")]"}
+ )
+ WRITE_FILE(file("[get_map_persistence_path()]/debris.json"), json_encode(data))
+
+/datum/controller/subsystem/persistence/proc/IsValidDebrisLocation(turf/tile, list/allowed_typecache, list/allowed_zcache, obj/effect/decal/cleanable/type, loading = FALSE)
+ if(!allowed_typecache[tile.type])
+ return FALSE
+ var/area/A = tile.loc
+ if(!A.persistent_debris_allowed)
+ return FALSE
+ if(!allowed_zcache[num2text(tile.z)])
+ return FALSE
+ if(loading)
+ if(!initial(type.persistence_allow_stacking))
+ var/obj/effect/decal/cleanable/C = locate(type) in tile
+ if(!QDELETED(C))
+ return FALSE
+ // Saving verifies allow stacking in the save proc.
+ for(var/obj/structure/window/W in tile)
+ if(W.fulltile)
+ return FALSE
+ return TRUE
+
+/datum/controller/subsystem/persistence/proc/wipe_existing_debris()
+ var/list/existing = RelevantPersistentDebris()
+ QDEL_LIST(existing)
+
+/datum/controller/subsystem/persistence/proc/RelevantPersistentDebris()
+ var/list/allowed_turf_typecache = typecacheof(/turf/open) - typecacheof(/turf/open/space)
+ var/list/allowed_z_cache = list()
+ for(var/z in SSmapping.levels_by_trait(ZTRAIT_STATION))
+ allowed_z_cache[num2text(z)] = TRUE
+ . = list()
+ for(var/obj/effect/decal/cleanable/C in world)
+ if(!C.loc || QDELETED(C))
+ continue
+ if(!C.persistent)
+ continue
+ if(!IsValidDebrisLocation(C.loc, allowed_turf_typecache, allowed_z_cache, C.type, FALSE))
+ continue
+ . += C
diff --git a/code/controllers/subsystem/persistence/panic_bunker.dm b/code/controllers/subsystem/persistence/panic_bunker.dm
new file mode 100644
index 0000000000..93ada2835c
--- /dev/null
+++ b/code/controllers/subsystem/persistence/panic_bunker.dm
@@ -0,0 +1,26 @@
+/**
+ * Persists panic bunker whitelisting for a configured period of time
+ */
+/datum/controller/subsystem/persistence/LoadServerPersistence()
+ . = ..()
+ LoadPanicBunker()
+
+/datum/controller/subsystem/persistence/SaveServerPersistence()
+ . = ..()
+ SavePanicBunker()
+
+/datum/controller/subsystem/persistence/proc/LoadPanicBunker()
+ var/bunker_path = file("data/bunker_passthrough.json")
+ if(fexists(bunker_path))
+ var/list/json = json_decode(file2text(bunker_path))
+ GLOB.bunker_passthrough = json["data"]
+ for(var/ckey in GLOB.bunker_passthrough)
+ if(daysSince(GLOB.bunker_passthrough[ckey]) >= CONFIG_GET(number/max_bunker_days))
+ GLOB.bunker_passthrough -= ckey
+
+/datum/controller/subsystem/persistence/proc/SavePanicBunker()
+ var/json_file = file("data/bunker_passthrough.json")
+ var/list/file_data = list()
+ file_data["data"] = GLOB.bunker_passthrough
+ fdel(json_file)
+ WRITE_FILE(json_file,json_encode(file_data))
diff --git a/code/controllers/subsystem/persistence/poly_parrot.dm b/code/controllers/subsystem/persistence/poly_parrot.dm
new file mode 100644
index 0000000000..64743e9623
--- /dev/null
+++ b/code/controllers/subsystem/persistence/poly_parrot.dm
@@ -0,0 +1,11 @@
+/**
+ * Persists poly messages across rounds
+ */
+/datum/controller/subsystem/persistence/LoadGamePersistence()
+ . = ..()
+ LoadPoly()
+
+/datum/controller/subsystem/persistence/proc/LoadPoly()
+ for(var/mob/living/simple_animal/parrot/Poly/P in GLOB.alive_mob_list)
+ twitterize(P.speech_buffer, "polytalk")
+ break //Who's been duping the bird?!
diff --git a/code/controllers/subsystem/persistence/recent_votes_etc.dm b/code/controllers/subsystem/persistence/recent_votes_etc.dm
new file mode 100644
index 0000000000..f1b902d6ab
--- /dev/null
+++ b/code/controllers/subsystem/persistence/recent_votes_etc.dm
@@ -0,0 +1,107 @@
+/**
+ * Stores recently played gamemodes, maps, etc.
+ */
+/datum/controller/subsystem/persistence
+ var/list/saved_modes = list(1,2,3)
+ var/list/saved_dynamic_rules = list(list(),list(),list())
+ var/list/saved_storytellers = list("foo","bar","baz")
+ var/list/average_dynamic_threat = 50
+ var/list/saved_maps
+
+/datum/controller/subsystem/persistence/SaveServerPersistence()
+ . = ..()
+ CollectRoundtype()
+ if(istype(SSticker.mode, /datum/game_mode/dynamic))
+ var/datum/game_mode/dynamic/mode = SSticker.mode
+ CollectStoryteller(mode)
+ CollectRulesets(mode)
+ RecordMaps()
+
+/datum/controller/subsystem/persistence/LoadServerPersistence()
+ . = ..()
+ LoadRecentModes()
+ LoadRecentStorytellers()
+ LoadRecentRulesets()
+ LoadRecentMaps()
+
+/datum/controller/subsystem/persistence/proc/CollectRoundtype()
+ saved_modes[3] = saved_modes[2]
+ saved_modes[2] = saved_modes[1]
+ saved_modes[1] = SSticker.mode.config_tag
+ var/json_file = file("data/RecentModes.json")
+ var/list/file_data = list()
+ file_data["data"] = saved_modes
+ fdel(json_file)
+ WRITE_FILE(json_file, json_encode(file_data))
+
+/datum/controller/subsystem/persistence/proc/CollectStoryteller(var/datum/game_mode/dynamic/mode)
+ saved_storytellers.len = 3
+ saved_storytellers[3] = saved_storytellers[2]
+ saved_storytellers[2] = saved_storytellers[1]
+ saved_storytellers[1] = mode.storyteller.name
+ average_dynamic_threat = (mode.max_threat + average_dynamic_threat) / 2
+ var/json_file = file("data/RecentStorytellers.json")
+ var/list/file_data = list()
+ file_data["data"] = saved_storytellers + average_dynamic_threat
+ fdel(json_file)
+ WRITE_FILE(json_file, json_encode(file_data))
+
+/datum/controller/subsystem/persistence/proc/CollectRulesets(var/datum/game_mode/dynamic/mode)
+ saved_dynamic_rules[3] = saved_dynamic_rules[2]
+ saved_dynamic_rules[2] = saved_dynamic_rules[1]
+ saved_dynamic_rules[1] = list()
+ for(var/r in mode.executed_rules)
+ var/datum/dynamic_ruleset/rule = r
+ saved_dynamic_rules[1] += rule.config_tag
+ var/json_file = file("data/RecentRulesets.json")
+ var/list/file_data = list()
+ file_data["data"] = saved_dynamic_rules
+ fdel(json_file)
+ WRITE_FILE(json_file, json_encode(file_data))
+
+/datum/controller/subsystem/persistence/proc/RecordMaps()
+ saved_maps = saved_maps?.len ? list("[SSmapping.config.map_name]") | saved_maps : list("[SSmapping.config.map_name]")
+ var/json_file = file("data/RecentMaps.json")
+ var/list/file_data = list()
+ file_data["maps"] = saved_maps
+ fdel(json_file)
+ WRITE_FILE(json_file, json_encode(file_data))
+
+/datum/controller/subsystem/persistence/proc/LoadRecentModes()
+ var/json_file = file("data/RecentModes.json")
+ if(!fexists(json_file))
+ return
+ var/list/json = json_decode(file2text(json_file))
+ if(!json)
+ return
+ saved_modes = json["data"]
+
+/datum/controller/subsystem/persistence/proc/LoadRecentRulesets()
+ var/json_file = file("data/RecentRulesets.json")
+ if(!fexists(json_file))
+ return
+ var/list/json = json_decode(file2text(json_file))
+ if(!json)
+ return
+ saved_dynamic_rules = json["data"]
+
+/datum/controller/subsystem/persistence/proc/LoadRecentStorytellers()
+ var/json_file = file("data/RecentStorytellers.json")
+ if(!fexists(json_file))
+ return
+ var/list/json = json_decode(file2text(json_file))
+ if(!json)
+ return
+ saved_storytellers = json["data"]
+ if(saved_storytellers.len > 3)
+ average_dynamic_threat = saved_storytellers[4]
+ saved_storytellers.len = 3
+
+/datum/controller/subsystem/persistence/proc/LoadRecentMaps()
+ var/json_file = file("data/RecentMaps.json")
+ if(!fexists(json_file))
+ return
+ var/list/json = json_decode(file2text(json_file))
+ if(!json)
+ return
+ saved_maps = json["maps"]
diff --git a/code/controllers/subsystem/persistence/secret_satchels.dm b/code/controllers/subsystem/persistence/secret_satchels.dm
new file mode 100644
index 0000000000..fa2a445317
--- /dev/null
+++ b/code/controllers/subsystem/persistence/secret_satchels.dm
@@ -0,0 +1,79 @@
+/**
+ * Secret satchel persistence - allows storing of items in underfloor satchels that's loaded later.
+ */
+/datum/controller/subsystem/persistence
+ var/list/satchel_blacklist = list() //this is a typecache
+ var/list/new_secret_satchels = list() //these are objects
+ var/list/old_secret_satchels = list()
+
+/datum/controller/subsystem/persistence/LoadGamePersistence()
+ . = ..()
+ LoadSatchels()
+
+/datum/controller/subsystem/persistence/SaveGamePersistence()
+ . = ..()
+ CollectSecretSatchels()
+
+/datum/controller/subsystem/persistence/proc/LoadSatchels()
+ var/placed_satchel = 0
+ var/path
+
+ var/json_file = file("data/npc_saves/SecretSatchels[SSmapping.config.map_name].json")
+ var/list/json = list()
+ if(fexists(json_file))
+ json = json_decode(file2text(json_file))
+
+ old_secret_satchels = json["data"]
+ var/obj/item/storage/backpack/satchel/flat/F
+ if(old_secret_satchels && old_secret_satchels.len >= 10) //guards against low drop pools assuring that one player cannot reliably find his own gear.
+ var/pos = rand(1, old_secret_satchels.len)
+ F = new()
+ old_secret_satchels.Cut(pos, pos+1 % old_secret_satchels.len)
+ F.x = old_secret_satchels[pos]["x"]
+ F.y = old_secret_satchels[pos]["y"]
+ F.z = SSmapping.station_start
+ path = text2path(old_secret_satchels[pos]["saved_obj"])
+
+ if(F)
+ if(isfloorturf(F.loc) && !isplatingturf(F.loc))
+ F.hide(1)
+ if(ispath(path))
+ var/spawned_item = new path(F)
+ spawned_objects[spawned_item] = TRUE
+ placed_satchel++
+ var/free_satchels = 0
+ for(var/turf/T in shuffle(block(locate(TRANSITIONEDGE,TRANSITIONEDGE,SSmapping.station_start), locate(world.maxx-TRANSITIONEDGE,world.maxy-TRANSITIONEDGE,SSmapping.station_start)))) //Nontrivially expensive but it's roundstart only
+ if(isfloorturf(T) && !isplatingturf(T))
+ new /obj/item/storage/backpack/satchel/flat/secret(T)
+ free_satchels++
+ if((free_satchels + placed_satchel) == 10) //ten tiles, more than enough to kill anything that moves
+ break
+
+/datum/controller/subsystem/persistence/proc/CollectSecretSatchels()
+ satchel_blacklist = typecacheof(list(/obj/item/stack/tile/plasteel, /obj/item/crowbar))
+ var/list/satchels_to_add = list()
+ for(var/A in new_secret_satchels)
+ var/obj/item/storage/backpack/satchel/flat/F = A
+ if(QDELETED(F) || F.z != SSmapping.station_start || F.invisibility != INVISIBILITY_MAXIMUM)
+ continue
+ var/list/savable_obj = list()
+ for(var/obj/O in F)
+ if(is_type_in_typecache(O, satchel_blacklist) || (O.flags_1 & ADMIN_SPAWNED_1))
+ continue
+ if(O.persistence_replacement)
+ savable_obj += O.persistence_replacement
+ else
+ savable_obj += O.type
+ if(isemptylist(savable_obj))
+ continue
+ var/list/data = list()
+ data["x"] = F.x
+ data["y"] = F.y
+ data["saved_obj"] = pick(savable_obj)
+ satchels_to_add += list(data)
+
+ var/json_file = file("data/npc_saves/SecretSatchels[SSmapping.config.map_name].json")
+ var/list/file_data = list()
+ fdel(json_file)
+ file_data["data"] = old_secret_satchels + satchels_to_add
+ WRITE_FILE(json_file, json_encode(file_data))
diff --git a/code/controllers/subsystem/persistence/trophies.dm b/code/controllers/subsystem/persistence/trophies.dm
new file mode 100644
index 0000000000..770ca99125
--- /dev/null
+++ b/code/controllers/subsystem/persistence/trophies.dm
@@ -0,0 +1,84 @@
+/**
+ * Stores trophies in curator display cases
+ */
+/datum/controller/subsystem/persistence
+ var/list/saved_trophies = list()
+
+/datum/controller/subsystem/persistence/LoadGamePersistence()
+ . = ..()
+ LoadTrophies()
+
+/datum/controller/subsystem/persistence/SaveGamePersistence()
+ . = ..()
+ CollectTrophies()
+
+/datum/controller/subsystem/persistence/proc/LoadTrophies()
+ if(fexists("data/npc_saves/TrophyItems.sav")) //legacy compatability to convert old format to new
+ var/savefile/S = new /savefile("data/npc_saves/TrophyItems.sav")
+ var/saved_json
+ S >> saved_json
+ if(!saved_json)
+ return
+ saved_trophies = json_decode(saved_json)
+ fdel("data/npc_saves/TrophyItems.sav")
+ else
+ var/json_file = file("data/npc_saves/TrophyItems.json")
+ if(!fexists(json_file))
+ return
+ var/list/json = json_decode(file2text(json_file))
+ if(!json)
+ return
+ saved_trophies = json["data"]
+ SetUpTrophies(saved_trophies.Copy())
+
+/datum/controller/subsystem/persistence/proc/SetUpTrophies(list/trophy_items)
+ for(var/A in GLOB.trophy_cases)
+ var/obj/structure/displaycase/trophy/T = A
+ if (T.showpiece)
+ continue
+ T.added_roundstart = TRUE
+
+ var/trophy_data = pick_n_take(trophy_items)
+
+ if(!islist(trophy_data))
+ continue
+
+ var/list/chosen_trophy = trophy_data
+
+ if(!chosen_trophy || isemptylist(chosen_trophy)) //Malformed
+ continue
+
+ var/path = text2path(chosen_trophy["path"]) //If the item no longer exist, this returns null
+ if(!path)
+ continue
+
+ T.showpiece = new /obj/item/showpiece_dummy(T, path)
+ T.trophy_message = chosen_trophy["message"]
+ T.placer_key = chosen_trophy["placer_key"]
+ T.update_icon()
+
+/datum/controller/subsystem/persistence/proc/CollectTrophies()
+ var/json_file = file("data/npc_saves/TrophyItems.json")
+ var/list/file_data = list()
+ file_data["data"] = remove_duplicate_trophies(saved_trophies)
+ fdel(json_file)
+ WRITE_FILE(json_file, json_encode(file_data))
+
+/datum/controller/subsystem/persistence/proc/remove_duplicate_trophies(list/trophies)
+ var/list/ukeys = list()
+ . = list()
+ for(var/trophy in trophies)
+ var/tkey = "[trophy["path"]]-[trophy["message"]]"
+ if(ukeys[tkey])
+ continue
+ else
+ . += list(trophy)
+ ukeys[tkey] = TRUE
+
+/datum/controller/subsystem/persistence/proc/SaveTrophy(obj/structure/displaycase/trophy/T)
+ if(!T.added_roundstart && T.showpiece)
+ var/list/data = list()
+ data["path"] = T.showpiece.type
+ data["message"] = T.trophy_message
+ data["placer_key"] = T.placer_key
+ saved_trophies += list(data)
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..e5d6b0bbd0 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,42 @@ 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()
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 +140,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 +164,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)
. += "
| " @@ -2677,6 +2689,9 @@ GLOBAL_LIST_EMPTY(preferences_datums) if(G.donoritem && !G.donator_ckey_check(user.ckey)) to_chat(user, "This is an item intended for donator use only. You are not authorized to use this item.") return + if(istype(G, /datum/gear/unlockable) && !can_use_unlockable(G)) + to_chat(user, "To use this item, you need to meet the defined requirements!") + return if(gear_points >= initial(G.cost)) var/list/new_loadout_data = list(LOADOUT_ITEM = "[G.type]") if(length(G.loadout_initial_colors)) @@ -2962,6 +2977,11 @@ GLOBAL_LIST_EMPTY(preferences_datums) if(find_gear) loadout_data["SAVE_[save_slot]"] -= list(find_gear) +/datum/preferences/proc/can_use_unlockable(datum/gear/unlockable/unlockable_gear) + if(unlockable_loadout_data[unlockable_gear.progress_key] >= unlockable_gear.progress_required) + return TRUE + return FALSE + #undef DEFAULT_SLOT_AMT #undef HANDS_SLOT_AMT #undef BACKPACK_SLOT_AMT diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index 86f7622a93..0db9fbb66c 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -5,7 +5,7 @@ // You do not need to raise this if you are adding new values that have sane defaults. // Only raise this value when changing the meaning/format/name/layout of an existing value // where you would want the updater procs below to run -#define SAVEFILE_VERSION_MAX 47 +#define SAVEFILE_VERSION_MAX 48 /* SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Carn @@ -285,6 +285,9 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car S["loadout"] = safe_json_encode(loadout_data) + if(current_version < 48) //unlockable loadout items but we need to clear bad data from a mistake + S["unlockable_loadout"] = list() + /datum/preferences/proc/load_path(ckey,filename="preferences.sav") if(!ckey) return @@ -427,6 +430,11 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car verify_keybindings_valid() // one of these days this will runtime and you'll be glad that i put it in a different proc so no one gets their saves wiped + if(S["unlockable_loadout"]) + unlockable_loadout_data = safe_json_decode(S["unlockable_loadout"]) + else + unlockable_loadout_data = list() + if(needs_update >= 0) //save the updated version var/old_default_slot = default_slot var/old_max_save_slots = max_save_slots @@ -532,6 +540,11 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car WRITE_FILE(S["auto_ooc"], auto_ooc) WRITE_FILE(S["no_tetris_storage"], no_tetris_storage) + if(length(unlockable_loadout_data)) + WRITE_FILE(S["unlockable_loadout"], safe_json_encode(unlockable_loadout_data)) + else + WRITE_FILE(S["unlockable_loadout"], safe_json_encode(list())) + return 1 /datum/preferences/proc/load_character(slot, bypass_cooldown = FALSE) @@ -736,7 +749,10 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car belly_prefs = json_from_file["belly_prefs"] //gear loadout - loadout_data = safe_json_decode(S["loadout"]) + if(S["loadout"]) + loadout_data = safe_json_decode(S["loadout"]) + else + loadout_data = list() //try to fix any outdated data if necessary //preference updating will handle saving the updated data for us. diff --git a/code/modules/client/verbs/looc.dm b/code/modules/client/verbs/looc.dm index 67563b99e5..e6e62280e2 100644 --- a/code/modules/client/verbs/looc.dm +++ b/code/modules/client/verbs/looc.dm @@ -17,7 +17,7 @@ GLOBAL_VAR_INIT(normal_looc_colour, "#6699CC") if(!msg) return - if(!(prefs.toggles & CHAT_OOC)) + if(!(prefs.chat_toggles & CHAT_OOC)) to_chat(src, " You have OOC muted.") return if(jobban_isbanned(mob, "OOC")) @@ -63,14 +63,14 @@ GLOBAL_VAR_INIT(normal_looc_colour, "#6699CC") if (isobserver(M)) continue //Also handled later. - if(C.prefs.toggles & CHAT_OOC) + if(C.prefs.chat_toggles & CHAT_OOC) if(GLOB.LOOC_COLOR) to_chat(C, "LOOC: [src.mob.name]: ") else to_chat(C, "LOOC: [src.mob.name]: ") for(var/client/C in GLOB.admins) - if(C.prefs.toggles & CHAT_OOC) + if(C.prefs.chat_toggles & CHAT_OOC) var/prefix = "(R)LOOC" if (C.mob in heard) prefix = "LOOC" diff --git a/code/modules/clothing/gloves/miscellaneous.dm b/code/modules/clothing/gloves/miscellaneous.dm index af55c6b9d7..c069649848 100644 --- a/code/modules/clothing/gloves/miscellaneous.dm +++ b/code/modules/clothing/gloves/miscellaneous.dm @@ -36,7 +36,7 @@ /obj/item/clothing/gloves/fingerless/pugilist/equipped(mob/user, slot) . = ..() - if(current_equipped_slot == SLOT_GLOVES) + if(slot == SLOT_GLOVES) use_buffs(user, TRUE) wornonce = TRUE diff --git a/code/modules/clothing/spacesuits/miscellaneous.dm b/code/modules/clothing/spacesuits/miscellaneous.dm index 2ffe85b6c4..c944b2aa1f 100644 --- a/code/modules/clothing/spacesuits/miscellaneous.dm +++ b/code/modules/clothing/spacesuits/miscellaneous.dm @@ -510,12 +510,12 @@ Contains: name = "paramedic EVA suit" icon_state = "paramedic-eva" item_state = "paramedic-eva" - desc = "A deep blue space suit decorated with red and white crosses to indicate that the wearer is trained emergency medical personnel." + desc = "A deep blue space suit decorated with medical insignia to indicate that the wearer is trained emergency medical personnel." allowed = list(/obj/item/flashlight, /obj/item/tank/internals, /obj/item/roller) /obj/item/clothing/head/helmet/space/eva/paramedic name = "paramedic EVA helmet" - desc = "A deep blue space helmet with a large red cross on the faceplate to designate the wearer as trained emergency medical personnel." + desc = "A deep blue space helmet decorated with medical insignia to designate the wearer as trained emergency medical personnel." icon_state = "paramedic-eva-helmet" item_state = "paramedic-eva-helmet" diff --git a/code/modules/clothing/suits/labcoat.dm b/code/modules/clothing/suits/labcoat.dm index c7d5a4ea56..a27d82a544 100644 --- a/code/modules/clothing/suits/labcoat.dm +++ b/code/modules/clothing/suits/labcoat.dm @@ -55,7 +55,7 @@ /obj/item/clothing/suit/toggle/labcoat/virologist name = "virologist labcoat" - desc = "A suit that protects against minor chemical spills. Offers slightly more protection against biohazards than the standard model. Has a green stripe on the shoulder." + desc = "A suit that protects against minor chemical spills. Has a green stripe on the shoulder." icon_state = "labcoat_vir" /obj/item/clothing/suit/toggle/labcoat/science @@ -63,6 +63,11 @@ desc = "A suit that protects against minor chemical spills. Has a purple stripe on the shoulder." icon_state = "labcoat_tox" +/obj/item/clothing/suit/toggle/labcoat/roboticist + name = "roboticist labcoat" + desc = "More like an eccentric coat than a labcoat. Helps pass off bloodstains as part of the aesthetic. Comes with red shoulder pads." + icon_state = "labcoat_robo" + // Departmental Jackets /obj/item/clothing/suit/toggle/labcoat/depjacket mutantrace_variation = STYLE_DIGITIGRADE|STYLE_NO_ANTHRO_ICON diff --git a/code/modules/clothing/suits/miscellaneous.dm b/code/modules/clothing/suits/miscellaneous.dm index 149f17f4d6..6dfcd72c10 100644 --- a/code/modules/clothing/suits/miscellaneous.dm +++ b/code/modules/clothing/suits/miscellaneous.dm @@ -541,6 +541,21 @@ flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT allowed = list(/obj/item/clothing/mask/facehugger/toy) +/obj/item/clothing/suit/caution + name = "wet floor sign" + desc = "Caution! Wet Floor!" + icon_state = "caution" + lefthand_file = 'icons/mob/inhands/equipment/custodial_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/custodial_righthand.dmi' + force = 1 + throwforce = 3 + throw_speed = 2 + throw_range = 5 + w_class = WEIGHT_CLASS_SMALL + body_parts_covered = CHEST|GROIN + attack_verb = list("warned", "cautioned", "smashed") + armor = list("melee" = 5, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0) + // WINTER COATS /obj/item/clothing/suit/hooded/wintercoat diff --git a/code/modules/clothing/suits/toggles.dm b/code/modules/clothing/suits/toggles.dm index f496468371..16a6c06799 100644 --- a/code/modules/clothing/suits/toggles.dm +++ b/code/modules/clothing/suits/toggles.dm @@ -58,6 +58,11 @@ RemoveHood() /obj/item/clothing/suit/hooded/proc/ToggleHood() + if(!hood) + to_chat(loc, "[src] seems to be missing its hood..") + return + hood.atom_colours = atom_colours.Copy() + hood.update_atom_colour() if(!suittoggled) if(ishuman(src.loc)) var/mob/living/carbon/human/H = src.loc @@ -191,7 +196,10 @@ if(!helmettype) return if(!helmet) + to_chat(H, "[src] seems to be missing its helmet..") return + helmet.atom_colours = atom_colours.Copy() + helmet.update_atom_colour() if(!suittoggled) if(ishuman(src.loc)) if(H.wear_suit != src) diff --git a/code/modules/clothing/under/_under.dm b/code/modules/clothing/under/_under.dm index 23cb2b1c15..e617d2d57b 100644 --- a/code/modules/clothing/under/_under.dm +++ b/code/modules/clothing/under/_under.dm @@ -244,35 +244,33 @@ /obj/item/clothing/under/proc/rolldown() if(!can_use(usr)) return - if(!can_adjust) - to_chat(usr, "You cannot wear this suit any differently!") - return - if(toggle_jumpsuit_adjust()) - to_chat(usr, "You adjust the suit to wear it more casually.") - else - to_chat(usr, "You adjust the suit back to normal.") - if(ishuman(usr)) + if(toggle_jumpsuit_adjust() && ishuman(usr)) var/mob/living/carbon/human/H = usr H.update_inv_w_uniform() H.update_body() /obj/item/clothing/under/proc/toggle_jumpsuit_adjust() + if(!can_adjust) + to_chat(usr, "You cannot wear this suit any differently!") + return FALSE adjusted = !adjusted if(adjusted) + to_chat(usr, "You adjust the suit to wear it more casually.") if(fitted != FEMALE_UNIFORM_TOP) fitted = NO_FEMALE_UNIFORM if(!alt_covers_chest) // for the special snowflake suits that expose the chest when adjusted body_parts_covered &= ~CHEST mutantrace_variation &= ~USE_TAUR_CLIP_MASK //How are we supposed to see the uniform otherwise? else + to_chat(usr, "You adjust the suit back to normal.") fitted = initial(fitted) if(!alt_covers_chest) body_parts_covered |= CHEST if(initial(mutantrace_variation) & USE_TAUR_CLIP_MASK) mutantrace_variation |= USE_TAUR_CLIP_MASK - return adjusted + return TRUE /obj/item/clothing/under/rank dying_key = DYE_REGISTRY_UNDER diff --git a/code/modules/clothing/under/jobs/civilian/civilian.dm b/code/modules/clothing/under/jobs/civilian/civilian.dm index 505aa91775..2eabb0ce35 100644 --- a/code/modules/clothing/under/jobs/civilian/civilian.dm +++ b/code/modules/clothing/under/jobs/civilian/civilian.dm @@ -24,7 +24,7 @@ mutantrace_variation = STYLE_DIGITIGRADE|STYLE_NO_ANTHRO_ICON /obj/item/clothing/under/rank/civilian/util - name = "generic utility uniform" + name = "utility uniform" desc = "A utility uniform worn by various crew." icon_state = "utilgen" item_state = "utilgen" diff --git a/code/modules/clothing/under/jobs/command.dm b/code/modules/clothing/under/jobs/command.dm index 8a6c372272..cc07665063 100644 --- a/code/modules/clothing/under/jobs/command.dm +++ b/code/modules/clothing/under/jobs/command.dm @@ -3,11 +3,12 @@ name = "captain's jumpsuit" icon_state = "captain" item_state = "b_suit" + armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0, "wound" = 15) sensor_mode = SENSOR_COORDS random_sensor = FALSE /obj/item/clothing/under/rank/captain/util - name = "Command Utiltiy Uniform" + name = "command utility uniform" desc = "A utility uniform for command personnel." icon_state = "utilcom" item_state = "utilcom" @@ -26,7 +27,6 @@ /obj/item/clothing/under/rank/captain/suit name = "captain's suit" desc = "A green suit and yellow necktie. Exemplifies authority." - armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0, "wound" = 15) icon_state = "green_suit" item_state = "dg_suit" can_adjust = FALSE diff --git a/code/modules/clothing/under/jobs/medical.dm b/code/modules/clothing/under/jobs/medical.dm index de285b0470..20fd34f4a0 100644 --- a/code/modules/clothing/under/jobs/medical.dm +++ b/code/modules/clothing/under/jobs/medical.dm @@ -131,7 +131,7 @@ armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 10, "rad" = 0, "fire" = 0, "acid" = 0, "wound" = 5) /obj/item/clothing/under/rank/medical/doctor/util - name = "Medical Utility Uniform" + name = "medical utility uniform" desc = "Utility jumpsuit for medical personnel" icon_state = "utilmed" item_state = "utilmed" diff --git a/code/modules/clothing/under/jobs/rnd.dm b/code/modules/clothing/under/jobs/rnd.dm index 7443cd9d39..d63e81a0a3 100644 --- a/code/modules/clothing/under/jobs/rnd.dm +++ b/code/modules/clothing/under/jobs/rnd.dm @@ -62,7 +62,7 @@ armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 10, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0, "wound" = 5) /obj/item/clothing/under/rank/rnd/scientist/util - name = "Science Utility Uniform" + name = "science utility uniform" desc = "A utility uniform for science personnel" icon_state = "utilsci" item_state = "utilsci" diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm index 2a5d6974ef..59e0832fef 100644 --- a/code/modules/clothing/under/miscellaneous.dm +++ b/code/modules/clothing/under/miscellaneous.dm @@ -172,11 +172,13 @@ body_parts_covered = CHEST|GROIN /obj/item/clothing/under/misc/gear_harness/toggle_jumpsuit_adjust() - adjusted = !adjusted - if(adjusted) - body_parts_covered = NONE - else + if(!body_parts_covered) + to_chat(usr, "Your gear harness is now covering your chest and groin.") body_parts_covered = CHEST|GROIN + else + to_chat(usr, "Your gear harness is no longer covering anything.") + body_parts_covered = NONE + return TRUE /obj/item/clothing/under/misc/durathread name = "durathread jumpsuit" diff --git a/code/modules/events/_event.dm b/code/modules/events/_event.dm index 40ce543d31..10f8c60386 100644 --- a/code/modules/events/_event.dm +++ b/code/modules/events/_event.dm @@ -92,7 +92,7 @@ log_admin_private("[key_name(usr)] cancelled event [name].") SSblackbox.record_feedback("tally", "event_admin_cancelled", 1, typepath) -/datum/round_event_control/proc/runEvent() +/datum/round_event_control/proc/runEvent(random = FALSE) var/datum/round_event/E = new typepath() E.current_players = get_active_player_count(alive_check = 1, afk_check = 1, human_check = 1) E.control = src diff --git a/code/modules/events/spacevine.dm b/code/modules/events/spacevine.dm index 7cf11848e8..edc062f78f 100644 --- a/code/modules/events/spacevine.dm +++ b/code/modules/events/spacevine.dm @@ -340,6 +340,7 @@ playsound(src.loc, 'sound/items/welder.ogg', 100, TRUE) /obj/structure/spacevine/Crossed(atom/movable/AM) + . = ..() if(!isliving(AM)) return for(var/datum/spacevine_mutation/SM in mutations) diff --git a/code/modules/events/travelling_trader.dm b/code/modules/events/travelling_trader.dm index eeb1acdba5..1f9c69a9f0 100644 --- a/code/modules/events/travelling_trader.dm +++ b/code/modules/events/travelling_trader.dm @@ -99,7 +99,7 @@ new reward(get_turf(src)) /mob/living/carbon/human/dummy/travelling_trader/Initialize() - ..() + . = ..() // return a hint you fuck add_atom_colour("#570d6b", FIXED_COLOUR_PRIORITY) //make them purple (otherworldly!) set_light(1, -0.7, "#AAD84B") ADD_TRAIT(src,TRAIT_PIERCEIMMUNE, "trader_pierce_immune") //don't let people take their blood diff --git a/code/modules/fields/fields.dm b/code/modules/fields/fields.dm index 8710282021..cb8d3e8dcf 100644 --- a/code/modules/fields/fields.dm +++ b/code/modules/fields/fields.dm @@ -16,7 +16,7 @@ if(!F.check_variables() && !override_checks) QDEL_NULL(F) if(start_field && (F || override_checks)) - F.Initialize() + F.begin_field() return F /datum/proximity_monitor/advanced @@ -78,11 +78,11 @@ /datum/proximity_monitor/advanced/proc/process_edge_turf(turf/T) -/datum/proximity_monitor/advanced/New() +/datum/proximity_monitor/advanced/New(atom/_host, range, _ignore_if_not_on_turf = TRUE) if(requires_processing) START_PROCESSING(SSfields, src) -/datum/proximity_monitor/advanced/proc/Initialize() +/datum/proximity_monitor/advanced/proc/begin_field() setup_field() post_setup_field() @@ -154,7 +154,7 @@ var/atom/_host = host var/atom/new_host_loc = _host.loc if(last_host_loc != new_host_loc) - recalculate_field() + INVOKE_ASYNC(src, .proc/recalculate_field) /datum/proximity_monitor/advanced/proc/post_setup_field() @@ -302,7 +302,7 @@ /obj/item/multitool/field_debug/attack_self(mob/user) operating = !operating - to_chat(user, "You turn [src] [operating? "on":"off"].") + to_chat(user, "You turn [src] [operating? "on":"off"].") UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED) listeningTo = null if(!istype(current) && operating) @@ -312,13 +312,15 @@ else if(!operating) QDEL_NULL(current) -/obj/item/multitool/field_debug/dropped(mob/user) +/obj/item/multitool/field_debug/dropped() . = ..() if(listeningTo) UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED) listeningTo = null /obj/item/multitool/field_debug/proc/on_mob_move() + SIGNAL_HANDLER + check_turf(get_turf(src)) /obj/item/multitool/field_debug/process() diff --git a/code/modules/fields/timestop.dm b/code/modules/fields/timestop.dm index 56abef8cd6..a96a44a789 100644 --- a/code/modules/fields/timestop.dm +++ b/code/modules/fields/timestop.dm @@ -33,7 +33,7 @@ if(G.summoner && locate(/obj/effect/proc_holder/spell/aoe_turf/timestop) in G.summoner.mind.spell_list) //It would only make sense that a person's stand would also be immune. immune[G] = TRUE if(start) - timestop() + INVOKE_ASYNC(src, .proc/timestop) /obj/effect/timestop/Destroy() qdel(chronofield) @@ -42,7 +42,7 @@ /obj/effect/timestop/proc/timestop() target = get_turf(src) - playsound(src, 'sound/magic/timeparadox2.ogg', 75, 1, -1) + playsound(src, 'sound/magic/timeparadox2.ogg', 75, TRUE, -1) chronofield = make_field(/datum/proximity_monitor/advanced/timestop, list("current_range" = freezerange, "host" = src, "immune" = immune, "check_anti_magic" = check_anti_magic, "check_holy" = check_holy)) QDEL_IN(src, duration) @@ -112,6 +112,8 @@ unfreeze_turf(T) /datum/proximity_monitor/advanced/timestop/proc/unfreeze_atom(atom/movable/A) + SIGNAL_HANDLER + if(A.throwing) unfreeze_throwing(A) if(isliving(A)) @@ -128,12 +130,14 @@ frozen_things -= A global_frozen_atoms -= A + /datum/proximity_monitor/advanced/timestop/proc/freeze_mecha(obj/mecha/M) M.completely_disabled = TRUE /datum/proximity_monitor/advanced/timestop/proc/unfreeze_mecha(obj/mecha/M) M.completely_disabled = FALSE + /datum/proximity_monitor/advanced/timestop/proc/freeze_throwing(atom/movable/AM) var/datum/thrownthing/T = AM.throwing T.paused = TRUE @@ -160,7 +164,7 @@ /datum/proximity_monitor/advanced/timestop/process() for(var/i in frozen_mobs) var/mob/living/m = i - m.Stun(20, 1, 1) + m.Stun(20, ignore_canstun = TRUE) /datum/proximity_monitor/advanced/timestop/setup_field_turf(turf/T) for(var/i in T.contents) @@ -168,6 +172,7 @@ freeze_turf(T) return ..() + /datum/proximity_monitor/advanced/timestop/proc/freeze_projectile(obj/item/projectile/P) P.paused = TRUE @@ -176,18 +181,18 @@ /datum/proximity_monitor/advanced/timestop/proc/freeze_mob(mob/living/L) frozen_mobs += L - L.Stun(20, 1, 1) + L.Stun(20, ignore_canstun = TRUE) ADD_TRAIT(L, TRAIT_MUTE, TIMESTOP_TRAIT) walk(L, 0) //stops them mid pathing even if they're stunimmune if(isanimal(L)) var/mob/living/simple_animal/S = L S.toggle_ai(AI_OFF) - if(ishostile(L)) - var/mob/living/simple_animal/hostile/H = L - H.LoseTarget() + if(ishostile(L)) + var/mob/living/simple_animal/hostile/H = L + H.LoseTarget() /datum/proximity_monitor/advanced/timestop/proc/unfreeze_mob(mob/living/L) - L.AdjustStun(-20, 1, 1) + L.AdjustStun(-20, ignore_canstun = TRUE) REMOVE_TRAIT(L, TRAIT_MUTE, TIMESTOP_TRAIT) frozen_mobs -= L if(isanimal(L)) diff --git a/code/modules/fields/turf_objects.dm b/code/modules/fields/turf_objects.dm index d37036d83c..1af924294a 100644 --- a/code/modules/fields/turf_objects.dm +++ b/code/modules/fields/turf_objects.dm @@ -24,11 +24,12 @@ desc = "Get off my turf!" /obj/effect/abstract/proximity_checker/advanced/field_turf/CanPass(atom/movable/AM, turf/target) + . = ..() if(parent) return parent.field_turf_canpass(AM, src, target) - return TRUE /obj/effect/abstract/proximity_checker/advanced/field_turf/Crossed(atom/movable/AM) + . = ..() if(parent) return parent.field_turf_crossed(AM, src) return TRUE @@ -48,11 +49,12 @@ desc = "Edgy description here." /obj/effect/abstract/proximity_checker/advanced/field_edge/CanPass(atom/movable/AM, turf/target) + . = ..() if(parent) return parent.field_edge_canpass(AM, src, target) - return TRUE /obj/effect/abstract/proximity_checker/advanced/field_edge/Crossed(atom/movable/AM) + . = ..() if(parent) return parent.field_edge_crossed(AM, src) return TRUE diff --git a/code/modules/flufftext/Hallucination.dm b/code/modules/flufftext/Hallucination.dm index 56c96c3559..cc18207a29 100644 --- a/code/modules/flufftext/Hallucination.dm +++ b/code/modules/flufftext/Hallucination.dm @@ -139,10 +139,11 @@ GLOBAL_LIST_INIT(hallucination_list, list( Show() /obj/effect/hallucination/simple/Moved(atom/OldLoc, Dir) + . = ..() Show() /obj/effect/hallucination/simple/Destroy() - if(target && target.client) + if(target?.client) target.client.images.Remove(current_image) active = FALSE return ..() @@ -1093,6 +1094,7 @@ GLOBAL_LIST_INIT(hallucination_list, list( target.client.images += image /obj/effect/hallucination/danger/lava/Crossed(atom/movable/AM) + . = ..() if(AM == target) target.adjustStaminaLoss(20) new /datum/hallucination/fire(target) diff --git a/code/modules/food_and_drinks/drinks/drinks.dm b/code/modules/food_and_drinks/drinks/drinks.dm index 140923c1ef..07039139bf 100644 --- a/code/modules/food_and_drinks/drinks/drinks.dm +++ b/code/modules/food_and_drinks/drinks/drinks.dm @@ -48,7 +48,7 @@ var/fraction = min(gulp_size/reagents.total_volume, 1) checkLiked(fraction, M) reagents.reaction(M, INGEST, fraction) - reagents.trans_to(M, gulp_size) + reagents.trans_to(M, gulp_size, log = TRUE) playsound(M.loc,'sound/items/drink.ogg', rand(10,50), 1) return 1 @@ -71,7 +71,7 @@ return var/refill = reagents.get_master_reagent_id() - var/trans = src.reagents.trans_to(target, amount_per_transfer_from_this) + var/trans = src.reagents.trans_to(target, amount_per_transfer_from_this, log = TRUE) to_chat(user, "You transfer [trans] units of the solution to [target].") if(iscyborg(user)) //Cyborg modules that include drinks automatically refill themselves, but drain the borg's cell @@ -92,7 +92,7 @@ to_chat(user, "[src] is full.") return - var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this) + var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this, log = TRUE) to_chat(user, "You fill [src] with [trans] units of the contents of [target].") /obj/item/reagent_containers/food/drinks/attackby(obj/item/I, mob/user, params) @@ -596,7 +596,7 @@ name = "Buzz Fuzz" desc = "The sister drink of Shambler's Juice! Uses real honey, making it a sweet tooth's dream drink. The slogan reads ''A Hive of Flavour'', there's also a label about how it is adddicting." icon_state = "honeysoda_can" - list_reagents = list(/datum/reagent/consumable/buzz_fuzz = 25, /datum/reagent/consumable/honey = 5) + list_reagents = list(/datum/reagent/consumable/buzz_fuzz = 30) foodtype = SUGAR | JUNKFOOD /obj/item/reagent_containers/food/drinks/soda_cans/grey_bull diff --git a/code/modules/food_and_drinks/food/condiment.dm b/code/modules/food_and_drinks/food/condiment.dm index 95e5c9fb56..dca12aa4f8 100644 --- a/code/modules/food_and_drinks/food/condiment.dm +++ b/code/modules/food_and_drinks/food/condiment.dm @@ -55,7 +55,7 @@ var/fraction = min(10/reagents.total_volume, 1) reagents.reaction(M, INGEST, fraction) - reagents.trans_to(M, 10) + reagents.trans_to(M, 10, log = TRUE) playsound(M.loc,'sound/items/drink.ogg', rand(10,50), 1) return 1 @@ -73,7 +73,7 @@ to_chat(user, "[src] is full!") return - var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this) + var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this, log = TRUE) to_chat(user, "You fill [src] with [trans] units of the contents of [target].") //Something like a glass or a food item. Player probably wants to transfer TO it. @@ -84,7 +84,7 @@ if(target.reagents.total_volume >= target.reagents.maximum_volume) to_chat(user, "you can't add anymore to [target]!") return - var/trans = src.reagents.trans_to(target, amount_per_transfer_from_this) + var/trans = src.reagents.trans_to(target, amount_per_transfer_from_this, log = TRUE) to_chat(user, "You transfer [trans] units of the condiment to [target].") /obj/item/reagent_containers/food/condiment/on_reagent_change(changetype) @@ -270,7 +270,7 @@ return else to_chat(user, "You tear open [src] above [target] and the condiments drip onto it.") - src.reagents.trans_to(target, amount_per_transfer_from_this) + src.reagents.trans_to(target, amount_per_transfer_from_this, log = TRUE) qdel(src) /obj/item/reagent_containers/food/condiment/pack/on_reagent_change(changetype) diff --git a/code/modules/food_and_drinks/food/snacks.dm b/code/modules/food_and_drinks/food/snacks.dm index 4d5f4e2dd0..cb1ed628c4 100644 --- a/code/modules/food_and_drinks/food/snacks.dm +++ b/code/modules/food_and_drinks/food/snacks.dm @@ -160,7 +160,7 @@ All foods are distributed among various categories. Use common sense. SEND_SIGNAL(src, COMSIG_FOOD_EATEN, M, user) var/fraction = min(bitesize / reagents.total_volume, 1) reagents.reaction(M, INGEST, fraction) - reagents.trans_to(M, bitesize) + reagents.trans_to(M, bitesize, log = TRUE) bitecount++ On_Consume(M) checkLiked(fraction, M) @@ -359,7 +359,7 @@ All foods are distributed among various categories. Use common sense. if(!M.is_drainable()) to_chat(user, "[M] is unable to be dunked in!") return - if(M.reagents.trans_to(src, dunk_amount)) //if reagents were transfered, show the message + if(M.reagents.trans_to(src, dunk_amount, log = TRUE)) //if reagents were transfered, show the message to_chat(user, "You dunk the [M].") return if(!M.reagents.total_volume) diff --git a/code/modules/food_and_drinks/food/snacks_bread.dm b/code/modules/food_and_drinks/food/snacks_bread.dm index 0d7c715654..f30d955b00 100644 --- a/code/modules/food_and_drinks/food/snacks_bread.dm +++ b/code/modules/food_and_drinks/food/snacks_bread.dm @@ -7,6 +7,12 @@ foodtype = GRAIN dunkable = TRUE +/obj/item/reagent_containers/food/snacks/store/bread/proc/bread_teleport() + // you did WHAT? + new /mob/living/simple_animal/hostile/bread(get_turf(src)) + visible_message("[src] begins to deform and grow grotesque tumors!") + qdel(src) + /obj/item/reagent_containers/food/snacks/breadslice icon = 'icons/obj/food/burgerbread.dmi' bitesize = 2 @@ -228,3 +234,25 @@ /obj/item/reagent_containers/food/snacks/butterdog/ComponentInitialize() . = ..() AddComponent(/datum/component/slippery, 80) + +/obj/item/reagent_containers/food/snacks/store/bread/tumor_bread + name = "dead tumor bread" + desc = "It's still within its expiration date, right?" + icon_state = "tumorbread" + slice_path = /obj/item/reagent_containers/food/snacks/breadslice/tumor_bread + list_reagents = list(/datum/reagent/consumable/nutriment = 10, /datum/reagent/toxin = 10) + foodtype = GROSS | GRAIN + tastes = list("wheat and tumors" = 10) + +//teleporting tumor bread kills it +/obj/item/reagent_containers/food/snacks/store/bread/tumor_bread/bread_teleport() + visible_message(src, "[src] explodes in a horrible mess of tumor and flour!") + qdel(src) + +/obj/item/reagent_containers/food/snacks/breadslice/tumor_bread + name = "tumor bread slice" + desc = "A slice of bread filled with tumors!" + icon_state = "tumorbreadslice" + filling_color = "#B2D72C" + list_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/toxin = 2) + foodtype = GROSS | GRAIN diff --git a/code/modules/food_and_drinks/food/snacks_pie.dm b/code/modules/food_and_drinks/food/snacks_pie.dm index 24522503c1..a4287d3d19 100644 --- a/code/modules/food_and_drinks/food/snacks_pie.dm +++ b/code/modules/food_and_drinks/food/snacks_pie.dm @@ -54,7 +54,7 @@ H.visible_message("[H] is creamed by [src]!", "You've been creamed by [src]!") playsound(H, "desceration", 50, TRUE) if(!H.is_mouth_covered()) - reagents.trans_to(H,15) //Cream pie combat + reagents.trans_to(H, 15, log = TRUE) //Cream pie combat if(!H.creamed) // one layer at a time H.add_overlay(creamoverlay) H.creamed = TRUE diff --git a/code/modules/food_and_drinks/kitchen_machinery/microwave.dm b/code/modules/food_and_drinks/kitchen_machinery/microwave.dm index d9e3bc6165..6bdf3cff8e 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/microwave.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/microwave.dm @@ -195,7 +195,7 @@ /obj/machinery/microwave/AltClick(mob/user) . = ..() if(user.canUseTopic(src, !hasSiliconAccessInArea(user))) - cook() + cook(user) return TRUE /obj/machinery/microwave/ui_interact(mob/user) @@ -226,7 +226,7 @@ if("eject") eject() if("use") - cook() + cook(user) if("examine") examine(user) @@ -236,7 +236,7 @@ AM.forceMove(drop_location()) ingredients.Cut() -/obj/machinery/microwave/proc/cook() +/obj/machinery/microwave/proc/cook(mob/user) if(stat & (NOPOWER|BROKEN)) return if(operating || broken > 0 || panel_open || !anchored || dirty == 100) @@ -257,7 +257,7 @@ start_can_fail() return break - start() + start(user) /obj/machinery/microwave/proc/turn_on() visible_message("\The [src] turns on.", "You hear a microwave humming.") @@ -277,9 +277,9 @@ #define MICROWAVE_MUCK 1 #define MICROWAVE_PRE 2 -/obj/machinery/microwave/proc/start() +/obj/machinery/microwave/proc/start(mob/user) turn_on() - loop(MICROWAVE_NORMAL, 10) + loop(MICROWAVE_NORMAL, 10, user = user) /obj/machinery/microwave/proc/start_can_fail() turn_on() @@ -292,7 +292,7 @@ update_icon() loop(MICROWAVE_MUCK, 4) -/obj/machinery/microwave/proc/loop(type, time, wait = max(12 - 2 * productivity, 2)) // standard wait is 10 +/obj/machinery/microwave/proc/loop(type, time, wait = max(12 - 2 * productivity, 2), mob/user) // standard wait is 10 if(stat & (NOPOWER|BROKEN)) if(type == MICROWAVE_PRE) pre_fail() @@ -300,7 +300,7 @@ if(!time) switch(type) if(MICROWAVE_NORMAL) - loop_finish() + loop_finish(user) if(MICROWAVE_MUCK) muck_finish() if(MICROWAVE_PRE) @@ -308,16 +308,21 @@ return time-- use_power(500) - addtimer(CALLBACK(src, .proc/loop, type, time, wait), wait) + addtimer(CALLBACK(src, .proc/loop, type, time, wait, user), wait) -/obj/machinery/microwave/proc/loop_finish() +/obj/machinery/microwave/proc/loop_finish(mob/user) operating = FALSE var/metal = 0 + var/cooked_food = 0 for(var/obj/item/O in ingredients) - O.microwave_act(src) + var/cooked_result = O.microwave_act(src) + if(!istype(cooked_result, /obj/item/reagent_containers/food/snacks/badrecipe)) + cooked_food += 1 if(O.custom_materials?.len) metal += O.custom_materials[SSmaterials.GetMaterialRef(/datum/material/iron)] + if(cooked_food && user.client) + user.client.increment_progress("cook", cooked_food) if(metal) spark() @@ -336,8 +341,8 @@ spark() after_finish_loop() -/obj/machinery/microwave/proc/pre_success() - loop(MICROWAVE_NORMAL, 10) +/obj/machinery/microwave/proc/pre_success(mob/user) + loop(MICROWAVE_NORMAL, 10, user) /obj/machinery/microwave/proc/muck_finish() visible_message("\The [src] gets covered in muck!") diff --git a/code/modules/holiday/halloween/bartholomew.dm b/code/modules/holiday/halloween/bartholomew.dm index 117e03c357..31cfb1f26a 100644 --- a/code/modules/holiday/halloween/bartholomew.dm +++ b/code/modules/holiday/halloween/bartholomew.dm @@ -117,7 +117,7 @@ /obj/item/weldingtool = 3, /obj/item/wirecutters = 2, /obj/item/wrench = 4, - /obj/item/weaponcrafting/improvised_parts/shotgun_receiver = 1, + /obj/item/weaponcrafting/receiver = 1, /obj/item/geiger_counter = 3, /obj/item/reagent_containers/food/snacks/grown/citrus/orange = 5, /obj/item/assembly/infra = 1, diff --git a/code/modules/holiday/halloween/jacqueen.dm b/code/modules/holiday/halloween/jacqueen.dm index 90016954fc..4212a2e296 100644 --- a/code/modules/holiday/halloween/jacqueen.dm +++ b/code/modules/holiday/halloween/jacqueen.dm @@ -50,16 +50,18 @@ var/cached_z /// I'm busy, don't move. var/busy = FALSE + var/static/blacklisted_items = typecacheof(list( - /obj/effect, - /obj/belly, - /obj/mafia_game_board, - /obj/docking_port, - /obj/shapeshift_holder, - /obj/screen)) + /obj/effect, + /obj/belly, + /obj/mafia_game_board, + /obj/docking_port, + /obj/shapeshift_holder, + /obj/screen + )) /mob/living/simple_animal/jacq/Initialize() - ..() + . = ..() //fuck you jacq, return a hint you shit cached_z = z poof() @@ -158,23 +160,18 @@ return FALSE /mob/living/simple_animal/jacq/proc/gender_check(mob/living/carbon/C) - var/gender = "lamb" - if(C) - if(C.gender == MALE) - gender = "laddie" - if(C.gender == FEMALE) - gender = "lassie" - return gender + . = "lamb" + switch(C) + if(MALE) + . = "laddie" + if(FEMALE) + . = "lassie" //Ye wee bugger, gerrout of it. Ye've nae tae enjoy reading the code fer mae secrets like. /mob/living/simple_animal/jacq/proc/chit_chat(mob/living/carbon/C) //Very important var/gender = gender_check(C) - if(C) - if(C.gender == MALE) - gender = "laddie" - if(C.gender == FEMALE) - gender = "lassie" + // it physicaly cannot fail*. Why is there a fucking dupe if(!progression["[C.real_name]"] || !(progression["[C.real_name]"] & JACQ_HELLO)) visible_message("[src] smiles ominously at [C], \"Well halo there [gender]! Ah'm Jacqueline, tae great Pumpqueen, great tae meet ye.\"") diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm index a1a177c028..8467d00124 100644 --- a/code/modules/hydroponics/hydroponics.dm +++ b/code/modules/hydroponics/hydroponics.dm @@ -130,7 +130,7 @@ reagents.remove_any(min(0.5, nutridrain)) else reagents.remove_any(nutridrain) - + // Lack of nutrients hurts non-weeds if(reagents.total_volume <= 0 && !myseed.get_gene(/datum/plant_gene/trait/plant_type/weed_hardy)) adjustHealth(-rand(1,3)) @@ -501,7 +501,7 @@ if(visi_msg) visible_message("[visi_msg].") - + for(var/obj/machinery/hydroponics/H in trays) //cause I don't want to feel like im juggling 15 tamagotchis and I can get to my real work of ripping flooring apart in hopes of validating my life choices of becoming a space-gardener //This was originally in apply_chemicals, but due to apply_chemicals only holding nutrients, we handle it here now. @@ -675,7 +675,7 @@ idle_power_usage = 0 self_sustaining = FALSE update_icon() - + /// Tray Setters - The following procs adjust the tray or plants variables, and make sure that the stat doesn't go out of bounds./// /obj/machinery/hydroponics/proc/adjustWater(adjustamt) waterlevel = clamp(waterlevel + adjustamt, 0, maxwater) diff --git a/code/modules/instruments/songs/play_legacy.dm b/code/modules/instruments/songs/play_legacy.dm index eee9be3cc7..c4d86e2013 100644 --- a/code/modules/instruments/songs/play_legacy.dm +++ b/code/modules/instruments/songs/play_legacy.dm @@ -82,5 +82,5 @@ var/sound/music_played = sound(soundfile) for(var/i in hearing_mobs) var/mob/M = i - M.playsound_local(source, null, volume * using_instrument.volume_multiplier, falloff = 5, S = music_played) + M.playsound_local(source, null, volume * using_instrument.volume_multiplier, S = music_played) // Could do environment and echo later but not for now diff --git a/code/modules/integrated_electronics/core/assemblies.dm b/code/modules/integrated_electronics/core/assemblies.dm index 7c9f811c34..6cb578dfb1 100644 --- a/code/modules/integrated_electronics/core/assemblies.dm +++ b/code/modules/integrated_electronics/core/assemblies.dm @@ -578,6 +578,7 @@ return FALSE /obj/item/electronic_assembly/Moved(oldLoc, dir) + . = ..() for(var/I in assembly_components) var/obj/item/integrated_circuit/IC = I IC.ext_moved(oldLoc, dir) diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm index 64ab4791d3..855e2ccbd7 100644 --- a/code/modules/jobs/job_types/_job.dm +++ b/code/modules/jobs/job_types/_job.dm @@ -187,7 +187,7 @@ /datum/job/proc/announce_head(var/mob/living/carbon/human/H, var/channels) //tells the given channel that the given mob is the new department head. See communications.dm for valid channels. if(H && GLOB.announcement_systems.len) //timer because these should come after the captain announcement - SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/addtimer, CALLBACK(pick(GLOB.announcement_systems), /obj/machinery/announcement_system/proc/announce, "NEWHEAD", H.real_name, H.job, channels), 1)) + SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/_addtimer, CALLBACK(pick(GLOB.announcement_systems), /obj/machinery/announcement_system/proc/announce, "NEWHEAD", H.real_name, H.job, channels), 1)) //If the configuration option is set to require players to be logged as old enough to play certain jobs, then this proc checks that they are, otherwise it just returns 1 /datum/job/proc/player_old_enough(client/C) diff --git a/code/modules/jobs/job_types/roboticist.dm b/code/modules/jobs/job_types/roboticist.dm index aa52b353df..b44d536cd2 100644 --- a/code/modules/jobs/job_types/roboticist.dm +++ b/code/modules/jobs/job_types/roboticist.dm @@ -32,7 +32,7 @@ l_pocket = /obj/item/pda/roboticist ears = /obj/item/radio/headset/headset_sci uniform = /obj/item/clothing/under/rank/rnd/roboticist - suit = /obj/item/clothing/suit/toggle/labcoat + suit = /obj/item/clothing/suit/toggle/labcoat/roboticist backpack = /obj/item/storage/backpack/science satchel = /obj/item/storage/backpack/satchel/tox diff --git a/code/modules/mapping/map_config.dm b/code/modules/mapping/map_config.dm index d18ca1e1e3..1f4b558e21 100644 --- a/code/modules/mapping/map_config.dm +++ b/code/modules/mapping/map_config.dm @@ -18,6 +18,8 @@ var/map_name = "Box Station" var/map_path = "map_files/BoxStation" var/map_file = "BoxStation.dmm" + /// Persistence key: Defaults to ckey(map_name). If set to "NO_PERSIST", this map will have NO persistence. + var/persistence_key var/traits = null var/space_ruin_levels = 4 @@ -99,6 +101,16 @@ map_path = json["map_path"] map_file = json["map_file"] + + persistence_key = ckey(map_name) + + var/json_persistence_key = json["persistence_key"] + if(json_persistence_key) + if(json_persistence_key == "NO_PERSIST") + persistence_key = null + else + persistence_key = json_persistence_key + // "map_file": "BoxStation.dmm" if (istext(map_file)) if (!fexists("_maps/[map_path]/[map_file]")) diff --git a/code/modules/mapping/reader.dm b/code/modules/mapping/reader.dm index 11bcc0ffcf..a3e0653678 100644 --- a/code/modules/mapping/reader.dm +++ b/code/modules/mapping/reader.dm @@ -135,7 +135,7 @@ var/curr_z = text2num(dmmRegex.group[5]) if(curr_z < z_lower || curr_z > z_upper) continue - + var/curr_x = text2num(dmmRegex.group[3]) var/curr_y = text2num(dmmRegex.group[4]) @@ -171,7 +171,7 @@ if(width > right_width) for(var/i in 1 to lines) gridLines[i] = copytext(gridLines[i], 1, key_len * right_width) - + // during the actual load we're starting at the top and working our way down gridSet.ycrd += lines - 1 @@ -300,14 +300,14 @@ //we do this after we load everything in. if we don't; we'll have weird atmos bugs regarding atmos adjacent turfs T.AfterChange(CHANGETURF_IGNORE_AIR) + if(did_expand) + world.refresh_atmos_grid() + #ifdef TESTING if(turfsSkipped) testing("Skipped loading [turfsSkipped] default turfs") #endif - if(did_expand) - world.refresh_atmos_grid() - return TRUE /datum/parsed_map/proc/build_cache(no_changeturf, bad_paths=null) diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm index 0953ea138d..9c39601b4e 100644 --- a/code/modules/mining/lavaland/necropolis_chests.dm +++ b/code/modules/mining/lavaland/necropolis_chests.dm @@ -1104,7 +1104,7 @@ if(1) new /obj/item/mayhem(src) if(2) - new /obj/item/gun/ballistic/revolver/doublebarrel/super(src) + new /obj/item/book/granter/spell/asura(src) if(3) new /obj/item/guardiancreator(src) @@ -1187,6 +1187,13 @@ unique_reskin = null sawn_off = TRUE +/obj/item/book/granter/spell/asura + spell = /obj/effect/proc_holder/spell/self/asura + spellname = "asuras wrath" + icon_state = "bookasura" + desc = "This crimson novel emanates rage incarnate." + remarks = list("Kaio-What?", "It can only be sustained for a short time...", "It's like a massive upsurge of energy...", "Takes a heavy toll on the user's body...?", "Extra arms not included...", "There's stronger levels? Why aren't they in the book...") + //Colossus /obj/structure/closet/crate/necropolis/colossus name = "colossus chest" diff --git a/code/modules/mining/ores_coins.dm b/code/modules/mining/ores_coins.dm index 8bc9cc4512..26a3ca1b70 100644 --- a/code/modules/mining/ores_coins.dm +++ b/code/modules/mining/ores_coins.dm @@ -397,6 +397,17 @@ GLOBAL_LIST_INIT(sand_recipes, list(\ else to_chat(user, "You need one length of cable to attach a string to the coin!") return + else if(istype(W, /obj/item/card/id)) + var/obj/item/card/id/ID = W + if(!ID.registered_account) + to_chat(user, "[ID] doesn't have a linked account to deposit into!") + return + for(var/obj/item/holochip/money in src.loc.contents) + ID.attackby(money, user) + for(var/obj/item/stack/spacecash/money in src.loc.contents) + ID.attackby(money, user) + for(var/obj/item/coin/money in src.loc.contents) + ID.attackby(money, user) else ..() diff --git a/code/modules/mining/point_bank.dm b/code/modules/mining/point_bank.dm index 11f23a5d7c..f18b62635f 100644 --- a/code/modules/mining/point_bank.dm +++ b/code/modules/mining/point_bank.dm @@ -30,6 +30,8 @@ if(points) if(I) I.mining_points += points + if(usr.client) + usr.client.increment_progress("miner", points) points = 0 else to_chat(usr, "No ID detected.") diff --git a/code/modules/mob/dead/dead.dm b/code/modules/mob/dead/dead.dm index 87f9d716bd..223366c7ab 100644 --- a/code/modules/mob/dead/dead.dm +++ b/code/modules/mob/dead/dead.dm @@ -8,6 +8,7 @@ INITIALIZE_IMMEDIATE(/mob/dead) throwforce = 0 /mob/dead/Initialize() + SHOULD_CALL_PARENT(FALSE) if(flags_1 & INITIALIZED_1) stack_trace("Warning: [src]([type]) initialized multiple times!") flags_1 |= INITIALIZED_1 @@ -68,14 +69,15 @@ INITIALIZE_IMMEDIATE(/mob/dead) set desc= "Jump to the other server" if(mob_transforming) return - var/list/csa = CONFIG_GET(keyed_list/cross_server) + var/list/our_id = CONFIG_GET(string/cross_comms_name) + var/list/csa = CONFIG_GET(keyed_list/cross_server) - our_id var/pick switch(csa.len) if(0) remove_verb(src, /mob/dead/proc/server_hop) to_chat(src, "Server Hop has been disabled.") if(1) - pick = csa[0] + pick = csa[1] else pick = input(src, "Pick a server to jump to", "Server Hop") as null|anything in csa @@ -100,7 +102,7 @@ INITIALIZE_IMMEDIATE(/mob/dead) winset(src, null, "command=.options") //other wise the user never knows if byond is downloading resources - C << link("[addr]?server_hop=[key]") + C << link("[addr]") /mob/dead/proc/update_z(new_z) // 1+ to register, null to unregister if (registered_z != new_z) diff --git a/code/modules/mob/dead/new_player/sprite_accessories/body_markings.dm b/code/modules/mob/dead/new_player/sprite_accessories/body_markings.dm index 6c510807b4..bc6c4899dd 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/body_markings.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/body_markings.dm @@ -243,6 +243,10 @@ icon_state = "none" relevant_layers = null +/datum/sprite_accessory/insect_fluff/brown + name = "Brown" + icon_state = "brown" + /datum/sprite_accessory/insect_fluff/punished name = "Burnt Off" icon_state = "punished" @@ -271,6 +275,10 @@ name = "Deathshead" icon_state = "deathhead" +/datum/sprite_accessory/insect_fluff/featherymoth + name = "Feathery Moth" + icon_state = "featherymoth" + /datum/sprite_accessory/insect_fluff/firewatch name = "Firewatch" icon_state = "firewatch" @@ -291,18 +299,22 @@ name = "Moon Fly" icon_state = "moonfly" -/datum/sprite_accessory/insect_fluff/oakworm - name = "Oak Worm" - icon_state = "oakworm" - /datum/sprite_accessory/insect_fluff/plain name = "Plain" icon_state = "plain" +/datum/sprite_accessory/insect_fluff/plasmafire + name = "Plasma Fire" + icon_state = "plasmafire" + /datum/sprite_accessory/insect_fluff/poison name = "Poison" icon_state = "poison" +/datum/sprite_accessory/insect_fluff/oakworm + name = "Oak Worm" + icon_state = "oakworm" + /datum/sprite_accessory/insect_fluff/ragged name = "Ragged" icon_state = "ragged" @@ -311,6 +323,10 @@ name = "Reddish" icon_state = "redish" +/datum/sprite_accessory/insect_fluff/rosy + name = "Rosy" + icon_state = "rosy" + /datum/sprite_accessory/insect_fluff/royal name = "Royal" icon_state = "royal" diff --git a/code/modules/mob/dead/new_player/sprite_accessories/wings.dm b/code/modules/mob/dead/new_player/sprite_accessories/wings.dm index fb71bb483d..800682b8cf 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/wings.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/wings.dm @@ -58,9 +58,7 @@ dimension_y = 34 relevant_layers = list(BODY_BEHIND_LAYER, BODY_ADJ_LAYER, BODY_FRONT_LAYER) -/datum/sprite_accessory/deco_wings/atlas - name = "Atlas" - icon_state = "atlas" +//nonmoth wings /datum/sprite_accessory/deco_wings/bat name = "Bat" @@ -70,18 +68,76 @@ name = "Bee" icon_state = "bee" -/datum/sprite_accessory/deco_wings/deathhead - name = "Deathshead" - icon_state = "deathhead" +/datum/sprite_accessory/deco_wings/bee2 + name = "Small Bee" + icon_state = "beewings" + +/datum/sprite_accessory/deco_wings/dragon + name = "Dragon" + icon_state = "dragon" + +/datum/sprite_accessory/deco_wings/dragonfly + name = "Dragonfly" + icon_state = "dragonfly" /datum/sprite_accessory/deco_wings/fairy name = "Fairy" icon_state = "fairy" -/datum/sprite_accessory/deco_wings/feathery +/datum/sprite_accessory/deco_wings/featheredwing name = "Feathery" icon_state = "feathery" +/datum/sprite_accessory/deco_wings/featheredwingmedium + name = "Medium Feathered" + icon_state = "feathered3" + +/datum/sprite_accessory/deco_wings/featheredwinglarge + name = "Large Feathered" + icon_state = "feathered2" + +/datum/sprite_accessory/deco_wings/harpywings + name = "Harpy" + icon_state = "harpywings" + +/datum/sprite_accessory/deco_wings/roboticwing + name = "Robotic" + icon_state = "drago" + +/datum/sprite_accessory/deco_wings/succubusblack + name = "Succubus Black" + icon_state = "succubusblack" + +/datum/sprite_accessory/deco_wings/succubuspurple + name = "Succubus Purple" + icon_state = "succubuspurple" + +/datum/sprite_accessory/deco_wings/succubusred + name = "Succubus Red" + icon_state = "succubusred" + +/datum/sprite_accessory/deco_wings/xenobackplate + name = "Xenomorph Backplate" + icon_state = "snagbackplate" + +//moth wings + +/datum/sprite_accessory/deco_wings/atlas + name = "Atlas" + icon_state = "atlas" + +/datum/sprite_accessory/deco_wings/brown + name = "Brown" + icon_state = "brown" + +/datum/sprite_accessory/deco_wings/deathhead + name = "Deathshead" + icon_state = "deathhead" + +/datum/sprite_accessory/deco_wings/featherymoth + name = "Feathery Moth Wings" + icon_state = "featherymoth" + /datum/sprite_accessory/deco_wings/firewatch name = "Firewatch" icon_state = "firewatch" @@ -90,6 +146,10 @@ name = "Gothic" icon_state = "gothic" +/datum/sprite_accessory/deco_wings/jungle + name = "Jungle" + icon_state = "jungle" + /datum/sprite_accessory/deco_wings/lovers name = "Lovers" icon_state = "lovers" @@ -106,10 +166,18 @@ name = "Moon Fly" icon_state = "moonfly" +/datum/sprite_accessory/deco_wings/oakworm + name = "Oak Worm" + icon_state = "oakworm" + /datum/sprite_accessory/deco_wings/plain name = "Plain" icon_state = "plain" +/datum/sprite_accessory/deco_wings/plasmafire + name = "Plasma Fire" + icon_state = "plasmafire" + /datum/sprite_accessory/deco_wings/poison name = "Poison" icon_state = "poison" @@ -126,6 +194,10 @@ name = "Reddish" icon_state = "redish" +/datum/sprite_accessory/deco_wings/rosy + name = "Rosy" + icon_state = "rosy" + /datum/sprite_accessory/deco_wings/royal name = "Royal" icon_state = "royal" @@ -138,6 +210,10 @@ name = "White Fly" icon_state = "whitefly" +/datum/sprite_accessory/deco_wings/witchwing + name = "Witch Wing" + icon_state = "witchwing" + //INSECT WINGS /datum/sprite_accessory/insect_wings @@ -145,6 +221,69 @@ color_src = WINGCOLOR relevant_layers = list(BODY_BEHIND_LAYER, BODY_FRONT_LAYER) +//non insect wings +/datum/sprite_accessory/deco_wings/bat + name = "Bat" + icon_state = "bat" + +/datum/sprite_accessory/insect_wings/bee + name = "Bee" + icon_state = "bee" + +/datum/sprite_accessory/insect_wings/bee2 + name = "Small Bee" + icon_state = "beewings" + +/datum/sprite_accessory/insect_wings/dragon + name = "Dragon" + icon_state = "dragon" + +/datum/sprite_accessory/insect_wings/dragonfly + name = "Dragonfly" + icon_state = "dragonfly" + +/datum/sprite_accessory/insect_wings/fairy + name = "Fairy" + icon_state = "fairy" + +/datum/sprite_accessory/insect_wings/featheredwing + name = "Feathery" + icon_state = "feathery" + +/datum/sprite_accessory/insect_wings/featheredwingmedium + name = "Medium Feathered" + icon_state = "feathered3" + +/datum/sprite_accessory/insect_wings/featheredwinglarge + name = "Large Feathered" + icon_state = "feathered2" + +/datum/sprite_accessory/insect_wings/harpywings + name = "Harpy" + icon_state = "harpywings" + +/datum/sprite_accessory/insect_wings/roboticwing + name = "Robotic" + icon_state = "drago" + +/datum/sprite_accessory/insect_wings/succubusblack + name = "Succubus Black" + icon_state = "succubusblack" + +/datum/sprite_accessory/insect_wings/succubuspurple + name = "Succubus Purple" + icon_state = "succubuspurple" + +/datum/sprite_accessory/insect_wings/succubusred + name = "Succubus Red" + icon_state = "succubusred" + +/datum/sprite_accessory/insect_wings/xenobackplate + name = "Xenomorph Backplate" + icon_state = "snagbackplate" + +//moth wings + /datum/sprite_accessory/insect_wings/none name = "None" icon_state = "none" @@ -154,25 +293,17 @@ name = "Atlas" icon_state = "atlas" -/datum/sprite_accessory/insect_wings/bat - name = "Bat" - icon_state = "bat" - -/datum/sprite_accessory/insect_wings/bee - name = "Bee" - icon_state = "bee" +/datum/sprite_accessory/insect_wings/brown + name = "Brown" + icon_state = "brown" /datum/sprite_accessory/insect_wings/deathhead name = "Deathshead" icon_state = "deathhead" -/datum/sprite_accessory/insect_wings/fairy - name = "Fairy" - icon_state = "fairy" - -/datum/sprite_accessory/insect_wings/feathery - name = "Feathery" - icon_state = "feathery" +/datum/sprite_accessory/insect_wings/featherymoth + name = "Feathery Moth Wings" + icon_state = "featherymoth" /datum/sprite_accessory/insect_wings/firewatch name = "Firewatch" @@ -210,6 +341,10 @@ name = "Plain" icon_state = "plain" +/datum/sprite_accessory/insect_wings/plasmafire + name = "Plasma Fire" + icon_state = "plasmafire" + /datum/sprite_accessory/insect_wings/poison name = "Poison" icon_state = "poison" @@ -226,6 +361,10 @@ name = "Reddish" icon_state = "redish" +/datum/sprite_accessory/insect_wings/rosy + name = "Rosy" + icon_state = "rosy" + /datum/sprite_accessory/insect_wings/royal name = "Royal" icon_state = "royal" @@ -253,45 +392,25 @@ icon_state = "none" relevant_layers = null -/datum/sprite_accessory/insect_markings/reddish - name = "Reddish" - icon_state = "reddish" - -/datum/sprite_accessory/insect_markings/royal - name = "Royal" - icon_state = "royal" - -/datum/sprite_accessory/insect_markings/gothic - name = "Gothic" - icon_state = "gothic" - -/datum/sprite_accessory/insect_markings/whitefly - name = "White Fly" - icon_state = "whitefly" - -/datum/sprite_accessory/insect_markings/lovers - name = "Lovers" - icon_state = "lovers" - -/datum/sprite_accessory/insect_markings/punished - name = "Punished" - icon_state = "punished" +/datum/sprite_accessory/insect_markings/deathhead + name = "Deathshead" + icon_state = "deathhead" /datum/sprite_accessory/insect_markings/firewatch name = "Firewatch" icon_state = "firewatch" -/datum/sprite_accessory/insect_markings/deathhead - name = "Deathshead" - icon_state = "deathhead" +/datum/sprite_accessory/insect_markings/gothic + name = "Gothic" + icon_state = "gothic" -/datum/sprite_accessory/insect_markings/poison - name = "Poison" - icon_state = "poison" +/datum/sprite_accessory/insect_markings/jungle + name = "Jungle" + icon_state = "jungle" -/datum/sprite_accessory/insect_markings/ragged - name = "Ragged" - icon_state = "ragged" +/datum/sprite_accessory/insect_markings/lovers + name = "Lovers" + icon_state = "lovers" /datum/sprite_accessory/insect_markings/moonfly name = "Moon Fly" @@ -301,10 +420,42 @@ name = "Oak Worm" icon_state = "oakworm" -/datum/sprite_accessory/insect_markings/jungle - name = "Jungle" - icon_state = "jungle" +/datum/sprite_accessory/insect_markings/poison + name = "Poison" + icon_state = "poison" + +/datum/sprite_accessory/insect_markings/punished + name = "Punished" + icon_state = "punished" + +/datum/sprite_accessory/insect_markings/ragged + name = "Ragged" + icon_state = "ragged" + +/datum/sprite_accessory/insect_markings/reddish + name = "Reddish" + icon_state = "reddish" + +/datum/sprite_accessory/insect_markings/royal + name = "Royal" + icon_state = "royal" + +/datum/sprite_accessory/insect_markings/whitefly + name = "White Fly" + icon_state = "whitefly" /datum/sprite_accessory/insect_markings/witchwing name = "Witch Wing" icon_state = "witchwing" + +//DONATOR WINGS + +/datum/sprite_accessory/deco_wings/eyestalks + name = "gazer eyestalks" + icon_state = "eyestalks" + //ckeys_allowed = list("liquidfirefly","seiga") //At request. + +/datum/sprite_accessory/insect_wings/eyestalks + name = "gazer eyestalks" + icon_state = "eyestalks" + //ckeys_allowed = list("liquidfirefly","seiga") //At request. diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 9493d11792..dc53f9487f 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -380,6 +380,8 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp /mob/dead/observer/Move(NewLoc, direct) + if (SEND_SIGNAL(src, COMSIG_MOVABLE_PRE_MOVE, NewLoc) & COMPONENT_MOVABLE_BLOCK_PRE_MOVE) + return if(updatedir) setDir(direct)//only update dir if we actually need it, so overlays won't spin on base sprites that don't have directions of their own var/oldloc = loc diff --git a/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm b/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm index 399efc4b29..28d311b034 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm @@ -68,7 +68,7 @@ Doesn't work on other aliens/AI.*/ /obj/effect/proc_holder/alien/plant name = "Plant Weeds" - desc = "Plants some alien weeds." + desc = "Plants Alien weeds which spread resin which heals any alien. These weeds also regenerate plasma faster. Costs 50 Plasma." plasma_cost = 50 check_turf = TRUE action_icon_state = "alien_plant" @@ -83,7 +83,7 @@ Doesn't work on other aliens/AI.*/ /obj/effect/proc_holder/alien/whisper name = "Whisper" - desc = "Whisper to someone." + desc = "Whisper to someone through the hivemind. Costs 10 Plasma." plasma_cost = 10 action_icon_state = "alien_whisper" @@ -143,7 +143,7 @@ Doesn't work on other aliens/AI.*/ /obj/effect/proc_holder/alien/acid name = "Corrosive Acid" - desc = "Drench an object in acid, destroying it over time." + desc = "Drench an object in acid, destroying it over time. Costs 200 Plasma." plasma_cost = 200 action_icon_state = "alien_acid" @@ -189,7 +189,7 @@ Doesn't work on other aliens/AI.*/ /obj/effect/proc_holder/alien/neurotoxin name = "Spit Neurotoxin" - desc = "Spits neurotoxin at someone, paralyzing them for a short time." + desc = "Activates your Neurotoxin glands. You can shoot paralyzing shots. Each shot costs 50 Plasma." action_icon_state = "alien_neurotoxin_0" active = FALSE @@ -254,7 +254,7 @@ Doesn't work on other aliens/AI.*/ /obj/effect/proc_holder/alien/resin name = "Secrete Resin" - desc = "Secrete tough malleable resin." + desc = "Secrete tough malleable resin. Costs 55 Plasma." plasma_cost = 55 check_turf = TRUE var/list/structures = list( diff --git a/code/modules/mob/living/carbon/alien/humanoid/caste/praetorian.dm b/code/modules/mob/living/carbon/alien/humanoid/caste/praetorian.dm index 4ec5780838..796a78d566 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/caste/praetorian.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/caste/praetorian.dm @@ -20,7 +20,7 @@ /obj/effect/proc_holder/alien/royal/praetorian/evolve name = "Evolve" - desc = "Produce an internal egg sac capable of spawning children. Only one queen can exist at a time." + desc = "Produce an internal egg sac capable of spawning children. Only one queen can exist at a time. Costs 500 Plasma." plasma_cost = 500 action_icon_state = "alien_evolve_praetorian" diff --git a/code/modules/mob/living/carbon/alien/humanoid/queen.dm b/code/modules/mob/living/carbon/alien/humanoid/queen.dm index 1200220ce4..91a61efea6 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/queen.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/queen.dm @@ -57,7 +57,7 @@ //Queen verbs /obj/effect/proc_holder/alien/lay_egg name = "Lay Egg" - desc = "Lay an egg to produce huggers to impregnate prey with." + desc = "Lay an egg to produce huggers to impregnate prey with. Costs 75 Plasma." plasma_cost = 75 check_turf = TRUE action_icon_state = "alien_egg" @@ -77,7 +77,7 @@ //Button to let queen choose her praetorian. /obj/effect/proc_holder/alien/royal/queen/promote name = "Create Royal Parasite" - desc = "Produce a royal parasite to grant one of your children the honor of being your Praetorian." + desc = "Produce a royal parasite to grant one of your children the honor of being your Praetorian. Costs 500 Plasma." plasma_cost = 500 //Plasma cost used on promotion, not spawning the parasite. action_icon_state = "alien_queen_promote" diff --git a/code/modules/mob/living/carbon/alien/special/facehugger.dm b/code/modules/mob/living/carbon/alien/special/facehugger.dm index 5392e7b2d5..ca2946fd8a 100644 --- a/code/modules/mob/living/carbon/alien/special/facehugger.dm +++ b/code/modules/mob/living/carbon/alien/special/facehugger.dm @@ -91,8 +91,8 @@ Attach(M) /obj/item/clothing/mask/facehugger/Crossed(atom/target) + . = ..() HasProximity(target) - return /obj/item/clothing/mask/facehugger/on_found(mob/finder) if(stat == CONSCIOUS) diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index 7a16d5c352..b2c14c30fe 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -304,10 +304,16 @@ emote("wag") else if(check_zone(M.zone_selected) == BODY_ZONE_R_ARM || check_zone(M.zone_selected) == BODY_ZONE_L_ARM) - M.visible_message( \ - "[M] shakes [src]'s hand.", \ - "You shake [src]'s hand.", target = src, - target_message = "[M] shakes your hand.") + if((pulling == M) && (grab_state == GRAB_PASSIVE)) + M.visible_message( \ + "[M] squeezes [src]'s hand.", \ + "You squeeze [src]'s hand.", target = src, + target_message = "[M] squeezes your hand.") + else + M.visible_message( \ + "[M] shakes [src]'s hand.", \ + "You shake [src]'s hand.", target = src, + target_message = "[M] shakes your hand.") else M.visible_message("[M] hugs [src] to make [p_them()] feel better!", \ diff --git a/code/modules/mob/living/carbon/damage_procs.dm b/code/modules/mob/living/carbon/damage_procs.dm index a866049d65..1f3a174d0f 100644 --- a/code/modules/mob/living/carbon/damage_procs.dm +++ b/code/modules/mob/living/carbon/damage_procs.dm @@ -62,8 +62,8 @@ amount += BP.burn_dam return amount - -/mob/living/carbon/adjustBruteLoss(amount, updating_health = TRUE, forced = FALSE) +//In both these procs, only_organic / only_robotic are only used for healing, not for damaging. For now at least. +/mob/living/carbon/adjustBruteLoss(amount, updating_health = TRUE, forced = FALSE, only_robotic = FALSE, only_organic = TRUE) if(!forced && amount < 0 && HAS_TRAIT(src,TRAIT_NONATURALHEAL)) return FALSE if(!forced && (status_flags & GODMODE)) @@ -71,10 +71,10 @@ if(amount > 0) take_overall_damage(amount, 0, 0, updating_health) else - heal_overall_damage(abs(amount), 0, 0, FALSE, TRUE, updating_health) + heal_overall_damage(abs(amount), 0, 0, only_robotic, only_organic, updating_health) return amount -/mob/living/carbon/adjustFireLoss(amount, updating_health = TRUE, forced = FALSE) +/mob/living/carbon/adjustFireLoss(amount, updating_health = TRUE, forced = FALSE, only_robotic = FALSE, only_organic = TRUE) if(!forced && amount < 0 && HAS_TRAIT(src,TRAIT_NONATURALHEAL)) //Vamps don't heal naturally. return FALSE if(!forced && (status_flags & GODMODE)) @@ -82,7 +82,7 @@ if(amount > 0) take_overall_damage(0, amount, 0, updating_health) else - heal_overall_damage(0, abs(amount), 0, FALSE, TRUE, updating_health) + heal_overall_damage(0, abs(amount), 0, only_robotic, only_organic, updating_health) return amount diff --git a/code/modules/mob/living/carbon/handle_corruption.dm b/code/modules/mob/living/carbon/handle_corruption.dm index 7b84c41e27..5ac2a2f616 100644 --- a/code/modules/mob/living/carbon/handle_corruption.dm +++ b/code/modules/mob/living/carbon/handle_corruption.dm @@ -80,10 +80,11 @@ if("shortlimbdisable") var/disabled_type = pick(list(TRAIT_PARALYSIS_L_ARM, TRAIT_PARALYSIS_R_ARM, TRAIT_PARALYSIS_L_LEG, TRAIT_PARALYSIS_R_LEG)) ADD_TRAIT(src, disabled_type, CORRUPTED_SYSTEM) + update_disabled_bodyparts() addtimer(CALLBACK(src, .proc/reenable_limb, disabled_type), 5 SECONDS) to_chat(src, "Error - Limb control subsystem partially shutdown, rebooting.") if("shortblind") - ADD_TRAIT(src, TRAIT_BLIND, CORRUPTED_SYSTEM) + become_blind(CORRUPTED_SYSTEM) addtimer(CALLBACK(src, .proc/reenable_vision), 5 SECONDS) to_chat(src, "Visual receptor shutdown detected - Initiating reboot.") if("shortstun") @@ -105,10 +106,11 @@ if("longlimbdisable") var/disabled_type = pick(list(TRAIT_PARALYSIS_L_ARM, TRAIT_PARALYSIS_R_ARM, TRAIT_PARALYSIS_L_LEG, TRAIT_PARALYSIS_R_LEG)) ADD_TRAIT(src, disabled_type, CORRUPTED_SYSTEM) + update_disabled_bodyparts() addtimer(CALLBACK(src, .proc/reenable_limb, disabled_type), 25 SECONDS) to_chat(src, "Fatal error in limb control subsystem - rebooting.") if("blindmutedeaf") - ADD_TRAIT(src, TRAIT_BLIND, CORRUPTED_SYSTEM) + become_blind(CORRUPTED_SYSTEM) addtimer(CALLBACK(src, .proc/reenable_vision), (rand(10, 25)) SECONDS) ADD_TRAIT(src, TRAIT_DEAF, CORRUPTED_SYSTEM) addtimer(CALLBACK(src, .proc/reenable_hearing), (rand(15, 35)) SECONDS) @@ -140,6 +142,7 @@ /mob/living/carbon/proc/reenable_limb(disabled_limb) REMOVE_TRAIT(src, disabled_limb, CORRUPTED_SYSTEM) + update_disabled_bodyparts() to_chat(src, "Limb control subsystem successfully rebooted.") /mob/living/carbon/proc/reenable_hearing() @@ -147,7 +150,7 @@ to_chat(src, "Hearing restored.") /mob/living/carbon/proc/reenable_vision() - REMOVE_TRAIT(src, TRAIT_BLIND, CORRUPTED_SYSTEM) + cure_blind(CORRUPTED_SYSTEM) to_chat(src, "Visual receptors back online.") /mob/living/carbon/proc/reenable_speech() diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 03816555b3..df7ed66169 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -3,7 +3,7 @@ real_name = "Unknown" icon = 'icons/mob/human.dmi' icon_state = "caucasian_m" - appearance_flags = KEEP_TOGETHER|TILE_BOUND|PIXEL_SCALE + SET_APPEARANCE_FLAGS(KEEP_TOGETHER|TILE_BOUND|PIXEL_SCALE) /mob/living/carbon/human/Initialize() add_verb(src, /mob/living/proc/mob_sleep) @@ -1028,7 +1028,7 @@ return stop_pulling() - riding_datum.handle_vehicle_layer() + riding_datum.handle_vehicle_layer(dir) riding_datum.fireman_carrying = fireman . = ..(target, force, check_loc) diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 1b140af672..a74afc10f5 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -411,15 +411,18 @@ if(isrobotic(src)) apply_status_effect(/datum/status_effect/no_combat_mode/robotic_emp, severity / 20) severity *= 0.5 + var/do_not_stun = FALSE if(HAS_TRAIT(src, TRAIT_ROBOTIC_ORGANISM)) severity *= 0.5 //Robotpeople take less limb damage, but instead suffer system corruption (see carbon emp_act) + do_not_stun = TRUE for(var/obj/item/bodypart/L in src.bodyparts) if(L.is_robotic_limb()) if(!informed) to_chat(src, "You feel a sharp pain as your robotic limbs overload.") informed = TRUE L.receive_damage(0,severity/10) - Stun(severity*2) + if(!do_not_stun) //Tiny bit better than checking for the trait another six times in succession + Stun(severity*2) /mob/living/carbon/human/acid_act(acidpwr, acid_volume, bodyzone_hit) var/list/damaged = list() diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index 341aa6a30f..a82151cc1d 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -15,6 +15,7 @@ block_parry_data = /datum/block_parry_data/unarmed/human default_block_parry_data = /datum/block_parry_data/unarmed/human + causes_dirt_buildup_on_floor = TRUE //Hair colour and style var/hair_color = "000" diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm index 509633c0d5..1619d0f6de 100644 --- a/code/modules/mob/living/carbon/human/human_movement.dm +++ b/code/modules/mob/living/carbon/human/human_movement.dm @@ -9,11 +9,6 @@ return return considering -/mob/living/carbon/human/movement_delay() - . = ..() - if (m_intent == MOVE_INTENT_WALK && HAS_TRAIT(src, TRAIT_SPEEDY_STEP)) - . -= 1.5 - /mob/living/carbon/human/slip(knockdown_amount, obj/O, lube) if(HAS_TRAIT(src, TRAIT_NOSLIPALL)) return 0 @@ -100,3 +95,8 @@ if(dna.species.space_move(src)) return TRUE return ..() + +/mob/living/carbon/human/dirt_buildup(strength) + if(!shoes || !(shoes.body_parts_covered & FEET)) + return // barefoot advantage + return ..() diff --git a/code/modules/mob/living/carbon/human/species_types/anthromorph.dm b/code/modules/mob/living/carbon/human/species_types/anthromorph.dm index 95aec26d9f..d718db818c 100644 --- a/code/modules/mob/living/carbon/human/species_types/anthromorph.dm +++ b/code/modules/mob/living/carbon/human/species_types/anthromorph.dm @@ -18,3 +18,33 @@ species_category = SPECIES_CATEGORY_FURRY allowed_limb_ids = list("mammal","aquatic","avian") + +/datum/species/mammal/synthetic + name = "Synthetic Anthromorph" + id = SPECIES_MAMMAL_SYNTHETIC + + species_traits = list(MUTCOLORS,NOTRANSSTING,EYECOLOR,LIPS,HAIR,ROBOTIC_LIMBS,HAS_FLESH,HAS_BONE,WINGCOLOR,HORNCOLOR) + inherent_traits = list(TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_NO_PROCESS_FOOD, TRAIT_ROBOTIC_ORGANISM) + inherent_biotypes = MOB_ROBOTIC|MOB_HUMANOID|MOB_BEAST + + meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/ipc + gib_types = list(/obj/effect/gibspawner/ipc, /obj/effect/gibspawner/ipc/bodypartless) + //Just robo looking parts. + mutant_heart = /obj/item/organ/heart/ipc + mutantlungs = /obj/item/organ/lungs/ipc + mutantliver = /obj/item/organ/liver/ipc + mutantstomach = /obj/item/organ/stomach/ipc + mutanteyes = /obj/item/organ/eyes/ipc + mutantears = /obj/item/organ/ears/ipc + mutanttongue = /obj/item/organ/tongue/robot/ipc + mutant_brain = /obj/item/organ/brain/ipc + + //special cybernetic organ for getting power from apcs + mutant_organs = list(/obj/item/organ/cyberimp/arm/power_cord) + + + attack_verb = "claw" + attack_sound = 'sound/weapons/slash.ogg' + miss_sound = 'sound/weapons/slashmiss.ogg' + + allowed_limb_ids = list("mammal","aquatic","avian", "human") diff --git a/code/modules/mob/living/carbon/human/species_types/arachnid.dm b/code/modules/mob/living/carbon/human/species_types/arachnid.dm index a44177ced1..454625cf36 100644 --- a/code/modules/mob/living/carbon/human/species_types/arachnid.dm +++ b/code/modules/mob/living/carbon/human/species_types/arachnid.dm @@ -4,7 +4,7 @@ override_bp_icon = 'icons/mob/arachnid_parts.dmi' say_mod = "chitters" default_color = "00FF00" - species_traits = list(LIPS, NOEYES, NO_UNDERWEAR) + species_traits = list(LIPS, NOEYES, NO_UNDERWEAR, HAS_FLESH, HAS_BONE) inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_BUG mutant_bodyparts = list("arachnid_legs" = "Plain", "arachnid_spinneret" = "Plain", "arachnid_mandibles" = "Plain") attack_verb = "slash" diff --git a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm index 803d3ec245..dc2269e19b 100644 --- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm @@ -94,7 +94,7 @@ name = "Xenobiological Slime Entity" id = SPECIES_SLIME default_color = "00FFFF" - species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR) + species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,HAS_FLESH) say_mod = "says" hair_color = "mutcolor" hair_alpha = 150 @@ -404,7 +404,7 @@ id = SPECIES_SLIME_HYBRID limbs_id = SPECIES_SLIME default_color = "00FFFF" - species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR) + species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,HAS_FLESH) inherent_traits = list(TRAIT_TOXINLOVER) mutant_bodyparts = list("mcolor" = "FFFFFF", "mcolor2" = "FFFFFF","mcolor3" = "FFFFFF", "mam_tail" = "None", "mam_ears" = "None", "mam_body_markings" = "Plain", "mam_snouts" = "None", "taur" = "None", "legs" = "Plantigrade") say_mod = "says" diff --git a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm index e02d15303f..4d0f88754f 100644 --- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm @@ -4,7 +4,7 @@ id = SPECIES_LIZARD say_mod = "hisses" default_color = "00FF00" - species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,LIPS,HORNCOLOR,WINGCOLOR,HAS_FLESH,HAS_BONE) + species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,LIPS,HORNCOLOR,WINGCOLOR,CAN_SCAR,HAS_FLESH,HAS_BONE) inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_REPTILE mutanttongue = /obj/item/organ/tongue/lizard mutanttail = /obj/item/organ/tail/lizard @@ -48,7 +48,7 @@ name = "Ash Walker" id = SPECIES_ASHWALKER limbs_id = SPECIES_LIZARD - species_traits = list(MUTCOLORS,EYECOLOR,LIPS,DIGITIGRADE) + species_traits = list(MUTCOLORS,EYECOLOR,LIPS,DIGITIGRADE,CAN_SCAR,HAS_FLESH,HAS_BONE) inherent_traits = list(TRAIT_CHUNKYFINGERS) mutantlungs = /obj/item/organ/lungs/ashwalker mutanteyes = /obj/item/organ/eyes/night_vision diff --git a/code/modules/mob/living/carbon/human/species_types/podpeople.dm b/code/modules/mob/living/carbon/human/species_types/podpeople.dm index 45a1870ae8..c25c5efb6c 100644 --- a/code/modules/mob/living/carbon/human/species_types/podpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/podpeople.dm @@ -68,7 +68,7 @@ /datum/species/pod/pseudo_weak name = "Anthromorphic Plant" id = SPECIES_POD_WEAK - species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,MUTCOLORS) + species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,MUTCOLORS,CAN_SCAR,HAS_FLESH,HAS_BONE) mutant_bodyparts = list("mcolor" = "FFFFFF","mcolor2" = "FFFFFF","mcolor3" = "FFFFFF", "mam_snouts" = "Husky", "mam_tail" = "Husky", "mam_ears" = "Husky", "mam_body_markings" = "Husky", "taur" = "None", "legs" = "Normal Legs") limbs_id = SPECIES_POD light_nutrition_gain_factor = 3 diff --git a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm index 4806813c04..33a2a09b70 100644 --- a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm @@ -203,6 +203,15 @@ var/obj/item/I = AM if(I.light_range && I.light_power) disintegrate(I) + else if (isstructure(AM)) + var/obj/structure/S = AM + if(istype(S, /obj/structure/glowshroom) || istype(S, /obj/structure/marker_beacon)) + qdel(S) + visible_message("[S] is disintegrated by [src]!") + else if(AM.light_range && AM.light_power && !(istype(AM, /obj/machinery/power/apc) || istype(AM, /obj/machinery/airalarm))) + var/obj/target_object = AM + target_object.take_damage(force * 5, BRUTE, "melee", 0) + /obj/item/light_eater/proc/disintegrate(obj/item/O) if(istype(O, /obj/item/pda)) diff --git a/code/modules/mob/living/carbon/human/species_types/xeno.dm b/code/modules/mob/living/carbon/human/species_types/xeno.dm index 2757c624e7..9d5a700417 100644 --- a/code/modules/mob/living/carbon/human/species_types/xeno.dm +++ b/code/modules/mob/living/carbon/human/species_types/xeno.dm @@ -4,8 +4,8 @@ id = SPECIES_XENOHYBRID say_mod = "hisses" default_color = "00FF00" - species_traits = list(MUTCOLORS,EYECOLOR,LIPS,CAN_SCAR) - mutant_bodyparts = list("xenotail"="Xenomorph Tail","xenohead"="Standard","xenodorsal"="Standard", "mam_body_markings" = "Xeno","mcolor" = "0F0","mcolor2" = "0F0","mcolor3" = "0F0","taur" = "None", "legs" = "Digitigrade") + species_traits = list(MUTCOLORS,EYECOLOR,LIPS,CAN_SCAR,HAS_FLESH,HAS_BONE) + mutant_bodyparts = list("xenotail"="Xenomorph Tail","xenohead"="Standard","xenodorsal"="Standard", "mam_body_markings" = "Xeno","mcolor" = "0F0","mcolor2" = "0F0","mcolor3" = "0F0","taur" = "None", "legs" = "Digitigrade","deco_wings"= "None") attack_verb = "slash" attack_sound = 'sound/weapons/slash.ogg' miss_sound = 'sound/weapons/slashmiss.ogg' diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index e0fab331a6..9885efd7c7 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -594,10 +594,18 @@ GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put drunkenness = max(drunkenness - (drunkenness * 0.04), 0) if(drunkenness >= 6) SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "drunk", /datum/mood_event/drunk) + if(prob(25)) + slurring += 2 jitteriness = max(jitteriness - 3, 0) + // throw_alert("drunk", /atom/movable/screen/alert/drunk) if(HAS_TRAIT(src, TRAIT_DRUNK_HEALING)) adjustBruteLoss(-0.12, FALSE) adjustFireLoss(-0.06, FALSE) + sound_environment_override = SOUND_ENVIRONMENT_PSYCHOTIC + else + SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "drunk") + clear_alert("drunk") + sound_environment_override = SOUND_ENVIRONMENT_NONE if(mind && (mind.assigned_role == "Scientist" || mind.assigned_role == "Research Director")) if(SSresearch.science_tech) diff --git a/code/modules/mob/living/carbon/status_procs.dm b/code/modules/mob/living/carbon/status_procs.dm index a47bb7fb4a..d602c25331 100644 --- a/code/modules/mob/living/carbon/status_procs.dm +++ b/code/modules/mob/living/carbon/status_procs.dm @@ -8,10 +8,12 @@ overlay_fullscreen("high", /obj/screen/fullscreen/high) throw_alert("high", /obj/screen/alert/high) SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "high", /datum/mood_event/high) + sound_environment_override = SOUND_ENVIRONMENT_DRUGGED else clear_fullscreen("high") clear_alert("high") SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "high") + sound_environment_override = SOUND_ENVIRONMENT_NONE /mob/living/carbon/set_drugginess(amount) druggy = max(amount, 0) diff --git a/code/modules/mob/living/damage_procs.dm b/code/modules/mob/living/damage_procs.dm index 44701a26b2..e7426aa1fa 100644 --- a/code/modules/mob/living/damage_procs.dm +++ b/code/modules/mob/living/damage_procs.dm @@ -141,7 +141,8 @@ /mob/living/proc/getBruteLoss() return bruteloss -/mob/living/proc/adjustBruteLoss(amount, updating_health = TRUE, forced = FALSE) +//only_robotic and only_organic arg only relevant for carbons +/mob/living/proc/adjustBruteLoss(amount, updating_health = TRUE, forced = FALSE, only_robotic = FALSE, only_organic = TRUE) if(!forced && (status_flags & GODMODE)) return FALSE bruteloss = clamp((bruteloss + (amount * CONFIG_GET(number/damage_multiplier))), 0, maxHealth * 2) @@ -215,7 +216,8 @@ /mob/living/proc/getFireLoss() return fireloss -/mob/living/proc/adjustFireLoss(amount, updating_health = TRUE, forced = FALSE) +//only_robotic and only_organic arg only relevant for carbons +/mob/living/proc/adjustFireLoss(amount, updating_health = TRUE, forced = FALSE, only_robotic = FALSE, only_organic = TRUE) if(!forced && (status_flags & GODMODE)) return FALSE fireloss = clamp((fireloss + (amount * CONFIG_GET(number/damage_multiplier))), 0, maxHealth * 2) diff --git a/code/modules/mob/living/living_active_parry.dm b/code/modules/mob/living/living_active_parry.dm index 16855d6f22..8d1ee38de6 100644 --- a/code/modules/mob/living/living_active_parry.dm +++ b/code/modules/mob/living/living_active_parry.dm @@ -17,6 +17,9 @@ /mob/living/proc/initiate_parry_sequence() if(parrying) return // already parrying + if(!(mobility_flags & MOBILITY_USE)) + to_chat(src, "You can't move your arms!") + return if(!(combat_flags & COMBAT_FLAG_PARRY_CAPABLE)) to_chat(src, "You are not something that can parry attacks.") return diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm index d4ccc63b34..742d4d8624 100644 --- a/code/modules/mob/living/living_defines.dm +++ b/code/modules/mob/living/living_defines.dm @@ -63,6 +63,8 @@ //Allows mobs to move through dense areas without restriction. For instance, in space or out of holder objects. var/incorporeal_move = FALSE //FALSE is off, INCORPOREAL_MOVE_BASIC is normal, INCORPOREAL_MOVE_SHADOW is for ninjas //and INCORPOREAL_MOVE_JAUNT is blocked by holy water/salt + /// Do we make floors dirty as we move? + var/causes_dirt_buildup_on_floor = FALSE var/list/roundstart_quirks = list() diff --git a/code/modules/mob/living/living_movement.dm b/code/modules/mob/living/living_movement.dm index 0cdfe9dbf2..bafa38ec5e 100644 --- a/code/modules/mob/living/living_movement.dm +++ b/code/modules/mob/living/living_movement.dm @@ -102,6 +102,30 @@ if(lying && !buckled && prob(getBruteLoss()*200/maxHealth)) makeTrail(newloc, T, old_direction) + if(causes_dirt_buildup_on_floor && (movement_type & GROUND)) + dirt_buildup() + +/** + * Attempts to make the floor dirty. + */ +/mob/living/proc/dirt_buildup(strength = 1) + var/turf/open/T = loc + if(!istype(T) || !T.dirt_buildup_allowed) + return + var/area/A = T.loc + if(!A.dirt_buildup_allowed) + return + var/multiplier = CONFIG_GET(number/turf_dirty_multiplier) + strength *= multiplier + var/obj/effect/decal/cleanable/dirt/D = locate() in T + if(D) + D.dirty(strength) + else + T.dirtyness += strength + if(T.dirtyness >= (isnull(T.dirt_spawn_threshold)? CONFIG_GET(number/turf_dirt_threshold) : T.dirt_spawn_threshold)) + D = new /obj/effect/decal/cleanable/dirt(T) + D.dirty(T.dirt_spawn_threshold - T.dirtyness) + T.dirtyness = 0 // reset. /mob/living/Move_Pulled(atom/A) . = ..() diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index fbf2d27c31..823f759e67 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -911,10 +911,10 @@ if(!istype(apc) || QDELETED(apc) || apc.stat & BROKEN) to_chat(src, "Hack aborted. The designated APC no longer exists on the power network.") - playsound(get_turf(src), 'sound/machines/buzz-two.ogg', 50, 1) + playsound(get_turf(src), 'sound/machines/buzz-two.ogg', 50, TRUE, ignore_walls = FALSE) else if(apc.aidisabled) to_chat(src, "Hack aborted. \The [apc] is no longer responding to our systems.") - playsound(get_turf(src), 'sound/machines/buzz-sigh.ogg', 50, 1) + playsound(get_turf(src), 'sound/machines/buzz-sigh.ogg', 50, TRUE, ignore_walls = FALSE) else malf_picker.processing_time += 10 @@ -923,7 +923,7 @@ apc.locked = TRUE apc.coverlocked = TRUE - playsound(get_turf(src), 'sound/machines/ding.ogg', 50, 1) + playsound(get_turf(src), 'sound/machines/ding.ogg', 50, TRUE, ignore_walls = FALSE) to_chat(src, "Hack complete. \The [apc] is now under your exclusive control.") apc.update_icon() diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index 786c121ad6..2ab74664a3 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -426,6 +426,10 @@ //Misc .["Cyborg - Misc (dog - blade)"] = process_holoform_icon_filter(icon('modular_citadel/icons/mob/widerobot.dmi', "blade"), HOLOFORM_FILTER_PAI, FALSE) + // Gorillas + .["Gorilla (standing)"] = process_holoform_icon_filter(icon('icons/mob/gorilla.dmi', "standing"), HOLOFORM_FILTER_PAI, FALSE) + .["Gorilla (crawling)"] = process_holoform_icon_filter(icon('icons/mob/gorilla.dmi', "crawling"), HOLOFORM_FILTER_PAI, FALSE) + /mob/living/silicon/pai/proc/default_chassis_pixel_offsets_x() . = list() //Engi diff --git a/code/modules/mob/living/silicon/pai/pai_defense.dm b/code/modules/mob/living/silicon/pai/pai_defense.dm index c5fa5ece1f..c339aa920f 100644 --- a/code/modules/mob/living/silicon/pai/pai_defense.dm +++ b/code/modules/mob/living/silicon/pai/pai_defense.dm @@ -81,10 +81,10 @@ to_chat(src, "The impact degrades your holochassis!") return amount -/mob/living/silicon/pai/adjustBruteLoss(amount, updating_health = TRUE, forced = FALSE) +/mob/living/silicon/pai/adjustBruteLoss(amount, updating_health = TRUE, forced = FALSE, only_robotic = FALSE, only_organic = TRUE) return take_holo_damage(amount) -/mob/living/silicon/pai/adjustFireLoss(amount, updating_health = TRUE, forced = FALSE) +/mob/living/silicon/pai/adjustFireLoss(amount, updating_health = TRUE, forced = FALSE, only_robotic = FALSE, only_organic = TRUE) return take_holo_damage(amount) /mob/living/silicon/pai/adjustToxLoss(amount, updating_health = TRUE, forced = FALSE, toxins_type = TOX_DEFAULT) diff --git a/code/modules/mob/living/simple_animal/damage_procs.dm b/code/modules/mob/living/simple_animal/damage_procs.dm index 9a2921cc0e..f478458829 100644 --- a/code/modules/mob/living/simple_animal/damage_procs.dm +++ b/code/modules/mob/living/simple_animal/damage_procs.dm @@ -7,13 +7,13 @@ updatehealth() return amount -/mob/living/simple_animal/adjustBruteLoss(amount, updating_health = TRUE, forced = FALSE) +/mob/living/simple_animal/adjustBruteLoss(amount, updating_health = TRUE, forced = FALSE, only_robotic = FALSE, only_organic = TRUE) if(forced) . = adjustHealth(amount * CONFIG_GET(number/damage_multiplier), updating_health, forced) else if(damage_coeff[BRUTE]) . = adjustHealth(amount * damage_coeff[BRUTE] * CONFIG_GET(number/damage_multiplier), updating_health, forced) -/mob/living/simple_animal/adjustFireLoss(amount, updating_health = TRUE, forced = FALSE) +/mob/living/simple_animal/adjustFireLoss(amount, updating_health = TRUE, forced = FALSE, only_robotic = FALSE, only_organic = TRUE) if(forced) . = adjustHealth(amount * CONFIG_GET(number/damage_multiplier), updating_health, forced) else if(damage_coeff[BURN]) diff --git a/code/modules/mob/living/simple_animal/friendly/cockroach.dm b/code/modules/mob/living/simple_animal/friendly/cockroach.dm index 384fa8146f..f33c179911 100644 --- a/code/modules/mob/living/simple_animal/friendly/cockroach.dm +++ b/code/modules/mob/living/simple_animal/friendly/cockroach.dm @@ -37,23 +37,25 @@ return ..() -/mob/living/simple_animal/cockroach/Crossed(var/atom/movable/AM) - if(ismob(AM)) - if(isliving(AM)) - var/mob/living/A = AM - if(A.mob_size > MOB_SIZE_SMALL && !(A.movement_type & FLYING)) - if(prob(squish_chance)) - A.visible_message("[A] squashed [src].", "You squashed [src].") - adjustBruteLoss(1) //kills a normal cockroach - else - visible_message("[src] avoids getting crushed.") - else - if(isstructure(AM)) +/mob/living/simple_animal/cockroach/Crossed(atom/movable/AM) + . = ..() + if(isliving(AM)) + var/mob/living/A = AM + if(A.mob_size > MOB_SIZE_SMALL && !(A.movement_type & FLYING)) + if(HAS_TRAIT(A, TRAIT_PACIFISM)) + A.visible_message("[A] carefully steps over [src].", "You carefully step over [src] to avoid hurting it.") + return if(prob(squish_chance)) - AM.visible_message("[src] was crushed under [AM].") - adjustBruteLoss(1) + A.visible_message("[A] squashed [src].", "You squashed [src].") + adjustBruteLoss(1) //kills a normal cockroach else visible_message("[src] avoids getting crushed.") + else if(isstructure(AM)) + if(prob(squish_chance)) + AM.visible_message("[src] is crushed under [AM].") + adjustBruteLoss(1) + else + visible_message("[src] avoids getting crushed.") /mob/living/simple_animal/cockroach/ex_act() //Explosions are a terrible way to handle a cockroach. return diff --git a/code/modules/mob/living/simple_animal/friendly/dog.dm b/code/modules/mob/living/simple_animal/friendly/dog.dm index 0584995583..49581b91a7 100644 --- a/code/modules/mob/living/simple_animal/friendly/dog.dm +++ b/code/modules/mob/living/simple_animal/friendly/dog.dm @@ -263,7 +263,7 @@ /mob/living/simple_animal/pet/dog/corgi/proc/place_on_head(obj/item/item_to_add, mob/user) if(istype(item_to_add, /obj/item/grenade/plastic)) // last thing he ever wears, I guess - item_to_add.afterattack(src,user,1) + INVOKE_ASYNC(item_to_add, /obj/item.proc/afterattack, src, user, 1) return if(inventory_head) @@ -271,13 +271,15 @@ to_chat(user, "You can't put more than one hat on [src]!") return if(!item_to_add) - user.visible_message("[user] pets [src].","You rest your hand on [src]'s head for a moment.") + user.visible_message("[user] pets [src].", "You rest your hand on [src]'s head for a moment.") + if(flags_1 & HOLOGRAM_1) + return SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, src, /datum/mood_event/pet_animal, src) return if(user && !user.temporarilyRemoveItemFromInventory(item_to_add)) to_chat(user, "\The [item_to_add] is stuck to your hand, you cannot put it on [src]'s head!") - return 0 + return var/valid = FALSE if(ispath(item_to_add.dog_fashion, /datum/dog_fashion/head)) @@ -287,11 +289,11 @@ if(valid) if(health <= 0) - to_chat(user, "There is merely a dull, lifeless look in [real_name]'s eyes as you put the [item_to_add] on [p_them()].") + to_chat(user, "There is merely a dull, lifeless look in [real_name]'s eyes as you put the [item_to_add] on [p_them()].") else if(user) - user.visible_message("[user] puts [item_to_add] on [real_name]'s head. [src] looks at [user] and barks once.", - "You put [item_to_add] on [real_name]'s head. [src] gives you a peculiar look, then wags [p_their()] tail once and barks.", - "You hear a friendly-sounding bark.") + user.visible_message("[user] puts [item_to_add] on [real_name]'s head. [src] looks at [user] and barks once.", + "You put [item_to_add] on [real_name]'s head. [src] gives you a peculiar look, then wags [p_their()] tail once and barks.", + "You hear a friendly-sounding bark.") item_to_add.forceMove(src) src.inventory_head = item_to_add update_corgi_fluff() @@ -361,7 +363,7 @@ icon_state = "old_corgi" icon_living = "old_corgi" icon_dead = "old_corgi_dead" - desc = "At a ripe old age of [record_age] Ian's not as spry as he used to be, but he'll always be the HoP's beloved corgi." //RIP + desc = "At a ripe old age of [record_age], Ian's not as spry as he used to be, but he'll always be the HoP's beloved corgi." //RIP turns_per_move = 20 RemoveElement(/datum/element/mob_holder, held_icon) AddElement(/datum/element/mob_holder, "old_corgi") diff --git a/code/modules/mob/living/simple_animal/guardian/guardian.dm b/code/modules/mob/living/simple_animal/guardian/guardian.dm index ae045dbd26..012515d0e9 100644 --- a/code/modules/mob/living/simple_animal/guardian/guardian.dm +++ b/code/modules/mob/living/simple_animal/guardian/guardian.dm @@ -9,6 +9,7 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians real_name = "Guardian Spirit" desc = "A mysterious being that stands by its charge, ever vigilant." speak_emote = list("hisses") + rad_flags = RAD_NO_CONTAMINATE | RAD_PROTECT_CONTENTS gender = NEUTER mob_biotypes = NONE bubble_icon = "guardian" diff --git a/code/modules/mob/living/simple_animal/guardian/types/ranged.dm b/code/modules/mob/living/simple_animal/guardian/types/ranged.dm index e7c4e2f352..e2bcdd5684 100644 --- a/code/modules/mob/living/simple_animal/guardian/types/ranged.dm +++ b/code/modules/mob/living/simple_animal/guardian/types/ranged.dm @@ -110,6 +110,7 @@ /obj/effect/snare/Crossed(AM as mob|obj) + . = ..() if(isliving(AM) && spawner && spawner.summoner && AM != spawner && !spawner.hasmatchingsummoner(AM)) to_chat(spawner.summoner, "[AM] has crossed surveillance snare, [name].") var/list/guardians = spawner.summoner.hasparasites() diff --git a/code/modules/mob/living/simple_animal/hostile/bread.dm b/code/modules/mob/living/simple_animal/hostile/bread.dm new file mode 100644 index 0000000000..317827028d --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/bread.dm @@ -0,0 +1,69 @@ +//funny reference to the video 'Expiration Date' + +/mob/living/simple_animal/hostile/bread + name = "tumor bread" + desc = "I have done nothing but teleport bread for three days." + icon_state = "tumorbread" + health = 1 + maxHealth = 1 + turns_per_move = 5 //this isn't player speed =| + speed = 2 //this is player speed + melee_damage_lower = 1 + melee_damage_upper = 2 + obj_damage = 0 + loot = list(/obj/item/reagent_containers/food/snacks/store/bread/tumor_bread) + atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) + minbodytemp = 270 + maxbodytemp = INFINITY + pass_flags = PASSTABLE | PASSGRILLE | PASSMOB + mob_size = MOB_SIZE_TINY + response_help_continuous = "pokes" + response_help_simple = "poke" + response_disarm_continuous = "shoos" + response_disarm_simple = "shoo" + response_harm_continuous = "punches" + response_harm_simple = "punch" + speak_emote = list("growls") + mouse_opacity = 2 + density = TRUE + ventcrawler = VENTCRAWLER_ALWAYS + verb_say = "growls" + verb_ask = "growls inquisitively" + verb_exclaim = "growls loudly" + verb_yell = "growls loudly" + del_on_death = TRUE + +/mob/living/simple_animal/bread/hostile/Initialize() + . = ..() + var/area/A = get_area(src) + if(A) + notify_ghosts("A tumor bread has been created in \the [A.name].", source = src, action=NOTIFY_ATTACK, flashwindow = FALSE, ignore_dnr_observers = TRUE) + +/mob/living/simple_animal/hostile/bread/attack_ghost(mob/user) + if(key) //please stop using src. without a good reason. + return + if(CONFIG_GET(flag/use_age_restriction_for_jobs)) + if(!isnum(user.client.player_age)) + return + if(isobserver(user)) + var/mob/dead/observer/O = user + if(!O.can_reenter_round()) + return + if(!SSticker.mode) + to_chat(user, "Can't become a tumor bread before the game has started.") + return + var/be_bread = alert("Become a tumor bread? (Warning, You can no longer be cloned!)",,"Yes","No") + if(be_bread == "No" || QDELETED(src) || !isobserver(user)) + return + if(key) + to_chat(user, "Someone else already took this tumor bread.") + return + sentience_act() + user.transfer_ckey(src, FALSE) + density = TRUE + +/mob/living/simple_animal/hostile/bread/ex_act() + return + +/mob/living/simple_animal/hostile/bread/start_pulling() + return FALSE diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm index 61be1f6287..cee7e2979d 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm @@ -94,16 +94,17 @@ consume_bait() /mob/living/simple_animal/hostile/asteroid/basilisk/watcher/proc/consume_bait() - var/obj/item/stack/ore/diamond/diamonds = locate(/obj/item/stack/ore/diamond) in oview(src, 9) - var/obj/item/pen/survival/bait = locate(/obj/item/pen/survival) in oview(src, 9) - if(!diamonds && !bait) - return + var/list/L = list() + for(var/obj/O in view(src, 9)) + L += O + var/obj/item/stack/ore/diamond/diamonds = locate(/obj/item/stack/ore/diamond) in L if(diamonds) var/distanced = 0 distanced = get_dist(loc,diamonds.loc) if(distanced <= 1 && diamonds) qdel(diamonds) src.visible_message("[src] consumes [diamonds], and it disappears! ...At least, you think.") + var/obj/item/pen/survival/bait = locate(/obj/item/pen/survival) in L if(bait) var/distanceb = 0 distanceb = get_dist(loc,bait.loc) diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm index 4e8f4f6160..ef51dc572f 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm @@ -219,6 +219,9 @@ /obj/effect/temp_visual/goliath_tentacle/broodmother/patch/Initialize(mapload, new_spawner) . = ..() + INVOKE_ASYNC(src, .proc/createpatch) + +/obj/effect/temp_visual/goliath_tentacle/broodmother/patch/proc/createpatch() var/tentacle_locs = spiral_range_turfs(1, get_turf(src)) for(var/T in tentacle_locs) new /obj/effect/temp_visual/goliath_tentacle/broodmother(T, spawner) diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/frog.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/frog.dm index 8424a0a576..f0fe85008a 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/frog.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/frog.dm @@ -42,7 +42,8 @@ butcher_results = list(/obj/item/reagent_containers/food/snacks/nugget = 5) /mob/living/simple_animal/hostile/retaliate/frog/Crossed(AM as mob|obj) + . = ..() if(!stat && isliving(AM)) var/mob/living/L = AM if(L.mob_size > MOB_SIZE_TINY) - playsound(src, stepped_sound, 50, 1) + playsound(src, stepped_sound, 50, TRUE) diff --git a/code/modules/mob/living/simple_animal/parrot.dm b/code/modules/mob/living/simple_animal/parrot.dm index 6e02944885..06e336875a 100644 --- a/code/modules/mob/living/simple_animal/parrot.dm +++ b/code/modules/mob/living/simple_animal/parrot.dm @@ -1189,4 +1189,4 @@ icon_state = "mtoo-flap" icon_living = "mtoo-flap" icon_dead = "mtoo-dead" - icon_sit = "mtoo_sit" \ No newline at end of file + icon_sit = "mtoo_sit" diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm index 1f45e57718..ab59441572 100644 --- a/code/modules/mob/living/simple_animal/slime/slime.dm +++ b/code/modules/mob/living/simple_animal/slime/slime.dm @@ -225,7 +225,7 @@ . += "Power Level: [powerlevel]" -/mob/living/simple_animal/slime/adjustFireLoss(amount, updating_health = TRUE, forced = FALSE) +/mob/living/simple_animal/slime/adjustFireLoss(amount, updating_health = TRUE, forced = FALSE, only_robotic = FALSE, only_organic = TRUE) if(!forced) amount = -abs(amount) return ..() //Heals them diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index dc81b3cfbf..ba2399b831 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -177,3 +177,6 @@ var/list/ability_actions /// ability = list(data). see __DEFINES/mobs/innate_abilities.dm var/list/ability_properties + + ///Override for sound_environments. If this is set the user will always hear a specific type of reverb (Instead of the area defined reverb) + var/sound_environment_override = SOUND_ENVIRONMENT_NONE diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 7a69026922..605f0a2d55 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -508,7 +508,7 @@ It's fairly easy to fix if dealing with single letters but not so much with comp if(LOG_EMOTE) colored_message = "(EMOTE) [colored_message]" - var/list/timestamped_message = list("\[[TIME_STAMP("hh:mm:ss", FALSE)]\] [key_name(src)] [loc_name(src)]" = colored_message) + var/list/timestamped_message = list("\[[TIME_STAMP("hh:mm:ss", FALSE)]\] [key_name(src)] [loc_name(src)] (Event #[LAZYLEN(logging[smessage_type])])" = colored_message) logging[smessage_type] += timestamped_message diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index e977c397c9..c467605f37 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -73,6 +73,7 @@ return FALSE //We are now going to move var/add_delay = mob.movement_delay() + mob.set_glide_size(DELAY_TO_GLIDE_SIZE(add_delay * ( (NSCOMPONENT(direction) && EWCOMPONENT(direction)) ? 2 : 1 ) ), FALSE) // set it now in case of pulled objects if(old_move_delay + (add_delay*MOVEMENT_DELAY_BUFFER_DELTA) + MOVEMENT_DELAY_BUFFER > world.time) move_delay = old_move_delay else @@ -95,6 +96,7 @@ if((direction & (direction - 1)) && mob.loc == n) //moved diagonally successfully add_delay *= 2 + mob.set_glide_size(DELAY_TO_GLIDE_SIZE(add_delay), FALSE) move_delay += add_delay if(.) // If mob is null here, we deserve the runtime if(mob.throwing) @@ -104,6 +106,8 @@ if(AM && AM.density && !SEND_SIGNAL(L, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_ACTIVE) && !ismob(AM)) L.setDir(turn(L.dir, 180)) + last_move = world.time + SEND_SIGNAL(mob, COMSIG_MOB_CLIENT_MOVE, src, direction, n, oldloc, add_delay) /// Process_Grab(): checks for grab, attempts to break if so. Return TRUE to prevent movement. diff --git a/code/modules/mob/say_vr.dm b/code/modules/mob/say_vr.dm index 658d7e5874..c5c53dc876 100644 --- a/code/modules/mob/say_vr.dm +++ b/code/modules/mob/say_vr.dm @@ -148,8 +148,8 @@ proc/get_top_level_mob(var/mob/S) var/safety = 25 for(var/obj/structure/table/T in range(user, 1)) processing |= T - for(var/i in processing) - var/obj/structure/table/T = i + for(var/i = 1; i <= processing.len; ++i) + var/obj/structure/table/T = processing[i] if(safety-- <= 0) to_chat(user, "Table scan aborted early, some people might have not received the message (max 25)") break diff --git a/code/modules/modular_computers/file_system/programs/arcade.dm b/code/modules/modular_computers/file_system/programs/arcade.dm index 87a3f1ec94..002cf20801 100644 --- a/code/modules/modular_computers/file_system/programs/arcade.dm +++ b/code/modules/modular_computers/file_system/programs/arcade.dm @@ -27,7 +27,7 @@ // user?.mind?.adjust_experience(/datum/skill/gaming, 1) if(boss_hp <= 0) heads_up = "You have crushed [boss_name]! Rejoice!" - playsound(computer.loc, 'sound/arcade/win.ogg', 50, TRUE, extrarange = -3, falloff = 10) + playsound(computer.loc, 'sound/arcade/win.ogg', 50, TRUE, extrarange = -3) game_active = FALSE program_icon_state = "arcade_off" if(istype(computer)) @@ -37,7 +37,7 @@ sleep(10) else if(player_hp <= 0 || player_mp <= 0) heads_up = "You have been defeated... how will the station survive?" - playsound(computer.loc, 'sound/arcade/lose.ogg', 50, TRUE, extrarange = -3, falloff = 10) + playsound(computer.loc, 'sound/arcade/lose.ogg', 50, TRUE, extrarange = -3) game_active = FALSE program_icon_state = "arcade_off" if(istype(computer)) @@ -57,17 +57,17 @@ return if (boss_mp <= 5) heads_up = "[boss_mpamt] magic power has been stolen from you!" - playsound(computer.loc, 'sound/arcade/steal.ogg', 50, TRUE, extrarange = -3, falloff = 10) + playsound(computer.loc, 'sound/arcade/steal.ogg', 50, TRUE, extrarange = -3) player_mp -= boss_mpamt boss_mp += boss_mpamt else if(boss_mp > 5 && boss_hp <12) heads_up = "[boss_name] heals for [bossheal] health!" - playsound(computer.loc, 'sound/arcade/heal.ogg', 50, TRUE, extrarange = -3, falloff = 10) + playsound(computer.loc, 'sound/arcade/heal.ogg', 50, TRUE, extrarange = -3) boss_hp += bossheal boss_mp -= boss_mpamt else heads_up = "[boss_name] attacks you for [boss_attackamt] damage!" - playsound(computer.loc, 'sound/arcade/hit.ogg', 50, TRUE, extrarange = -3, falloff = 10) + playsound(computer.loc, 'sound/arcade/hit.ogg', 50, TRUE, extrarange = -3) player_hp -= boss_attackamt pause_state = FALSE @@ -106,7 +106,7 @@ attackamt = rand(2,6)// + rand(0, gamerSkill) pause_state = TRUE heads_up = "You attack for [attackamt] damage." - playsound(computer.loc, 'sound/arcade/hit.ogg', 50, TRUE, extrarange = -3, falloff = 10) + playsound(computer.loc, 'sound/arcade/hit.ogg', 50, TRUE, extrarange = -3) boss_hp -= attackamt sleep(10) game_check() @@ -123,7 +123,7 @@ healcost = rand(1, maxPointCost) pause_state = TRUE heads_up = "You heal for [healamt] damage." - playsound(computer.loc, 'sound/arcade/heal.ogg', 50, TRUE, extrarange = -3, falloff = 10) + playsound(computer.loc, 'sound/arcade/heal.ogg', 50, TRUE, extrarange = -3) player_hp += healamt player_mp -= healcost sleep(10) @@ -136,7 +136,7 @@ rechargeamt = rand(4,7)// + rand(0, gamerSkill) pause_state = TRUE heads_up = "You regain [rechargeamt] magic power." - playsound(computer.loc, 'sound/arcade/mana.ogg', 50, TRUE, extrarange = -3, falloff = 10) + playsound(computer.loc, 'sound/arcade/mana.ogg', 50, TRUE, extrarange = -3) player_mp += rechargeamt sleep(10) game_check() @@ -153,7 +153,7 @@ computer.visible_message("\The [computer] prints out paper.") if(ticket_count >= 1) new /obj/item/stack/arcadeticket((get_turf(computer)), 1) - to_chat(usr, "[src] dispenses a ticket!") + to_chat(usr, "[computer] dispenses a ticket!") ticket_count -= 1 printer.stored_paper -= 1 else diff --git a/code/modules/movespeed/_movespeed_modifier.dm b/code/modules/movespeed/_movespeed_modifier.dm index 9c8036bd55..46d10afe7f 100644 --- a/code/modules/movespeed/_movespeed_modifier.dm +++ b/code/modules/movespeed/_movespeed_modifier.dm @@ -96,7 +96,7 @@ GLOBAL_LIST_EMPTY(movespeed_modification_cache) return TRUE remove_movespeed_modifier(existing, FALSE) if(length(movespeed_modification)) - BINARY_INSERT(type_or_datum.id, movespeed_modification, datum/movespeed_modifier, type_or_datum, priority, COMPARE_VALUE) + BINARY_INSERT(type_or_datum.id, movespeed_modification, /datum/movespeed_modifier, type_or_datum, priority, COMPARE_VALUE) LAZYSET(movespeed_modification, type_or_datum.id, type_or_datum) if(update) update_movespeed() @@ -217,13 +217,25 @@ GLOBAL_LIST_EMPTY(movespeed_modification_cache) else continue . = M.apply_multiplicative(., src) - var/old = cached_multiplicative_slowdown // CITAEDL EDIT - To make things a bit less jarring, when in situations where // your delay decreases, "give" the delay back to the client cached_multiplicative_slowdown = . - var/diff = old - cached_multiplicative_slowdown - if((diff > 0) && client) + if(!client) + return + var/diff = (client.last_move - client.move_delay) - cached_multiplicative_slowdown + if(diff > 0) if(client.move_delay > world.time + 1.5) client.move_delay -= diff + var/timeleft = world.time - client.move_delay + var/elapsed = world.time - client.last_move + var/glide_size_current = glide_size + if((timeleft <= 0) || (elapsed > 20)) + set_glide_size(16, TRUE) + return + var/pixels_moved = glide_size_current * elapsed * (1 / world.tick_lag) + // calculate glidesize needed to move to the next tile within timeleft deciseconds + var/ticks_allowed = timeleft / world.tick_lag + var/pixels_per_tick = pixels_moved / ticks_allowed + set_glide_size(pixels_per_tick * GLOB.glide_size_multiplier, TRUE) /// Get the move speed modifiers list of the mob /mob/proc/get_movespeed_modifiers() diff --git a/code/modules/movespeed/modifiers/mobs.dm b/code/modules/movespeed/modifiers/mobs.dm index f6cf84eb83..cdfb275418 100644 --- a/code/modules/movespeed/modifiers/mobs.dm +++ b/code/modules/movespeed/modifiers/mobs.dm @@ -62,6 +62,11 @@ var/mod = CONFIG_GET(number/movedelay/walk_delay) multiplicative_slowdown = isnum(mod)? mod : initial(multiplicative_slowdown) +/datum/movespeed_modifier/config_wak_run/walk/apply_multiplicative(existing, mob/target) + . = ..() + if(HAS_TRAIT(target, TRAIT_SPEEDY_STEP)) + . -= 1.25 + /datum/movespeed_modifier/config_walk_run/run/sync() var/mod = CONFIG_GET(number/movedelay/run_delay) multiplicative_slowdown = isnum(mod)? mod : initial(multiplicative_slowdown) @@ -141,6 +146,8 @@ var/mob/living/L = target if(!(L.mobility_flags & MOBILITY_STAND)) return + if(iscyborg(target)) + return max(1, existing - 1) var/static/datum/config_entry/number/movedelay/sprint_max_tiles_increase/SMTI if(!SMTI) SMTI = CONFIG_GET_ENTRY(number/movedelay/sprint_max_tiles_increase) diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm index 13890ae69e..8863a098fc 100644 --- a/code/modules/paperwork/pen.dm +++ b/code/modules/paperwork/pen.dm @@ -182,8 +182,9 @@ if(..()) if(reagents.total_volume) if(M.reagents) + log_combat(user, M, "injected with sleepypen", src, reagents.log_list()) reagents.reaction(M, INJECT) - reagents.trans_to(M, reagents.total_volume) + reagents.trans_to(M, reagents.total_volume, log = "sleepypen inject") /obj/item/pen/sleepy/Initialize() diff --git a/code/modules/pool/pool_main.dm b/code/modules/pool/pool_main.dm index 98189cc8a4..088c991ca0 100644 --- a/code/modules/pool/pool_main.dm +++ b/code/modules/pool/pool_main.dm @@ -150,7 +150,8 @@ H.DefaultCombatKnockdown(40) playsound(src, 'sound/effects/woodhit.ogg', 60, TRUE, 1) else if(filled) - victim.adjustStaminaLoss(1) + if(iscarbon(victim)) + victim.adjustStaminaLoss(1) playsound(src, "water_wade", 20, TRUE) return ..() diff --git a/code/modules/power/singularity/containment_field.dm b/code/modules/power/singularity/containment_field.dm index dfb51df9cf..2ca9b7513c 100644 --- a/code/modules/power/singularity/containment_field.dm +++ b/code/modules/power/singularity/containment_field.dm @@ -56,12 +56,14 @@ else ..() -/obj/machinery/field/containment/Crossed(mob/mover) - if(isliving(mover)) - shock(mover) +/obj/machinery/field/containment/Crossed(atom/movable/AM) + . = ..() + if(isliving(AM)) + shock(AM) + + if(ismachinery(AM) || isstructure(AM) || ismecha(AM)) + bump_field(AM) - if(ismachinery(mover) || isstructure(mover) || ismecha(mover)) - bump_field(mover) /obj/machinery/field/containment/proc/set_master(master1,master2) if(!master1 || !master2) diff --git a/code/modules/power/singularity/narsie.dm b/code/modules/power/singularity/narsie.dm index 8bf20fddc6..5b5292a020 100644 --- a/code/modules/power/singularity/narsie.dm +++ b/code/modules/power/singularity/narsie.dm @@ -78,6 +78,7 @@ set_security_level("delta") SSshuttle.registerHostileEnvironment(src) SSshuttle.lockdown = TRUE + SSpersistence.station_was_destroyed = TRUE sleep(600) if(resolved == FALSE) resolved = TRUE diff --git a/code/modules/power/singularity/particle_accelerator/particle.dm b/code/modules/power/singularity/particle_accelerator/particle.dm index 9e098446d1..7ecde364ae 100644 --- a/code/modules/power/singularity/particle_accelerator/particle.dm +++ b/code/modules/power/singularity/particle_accelerator/particle.dm @@ -44,6 +44,7 @@ movement_range = 0 /obj/effect/accelerated_particle/Crossed(atom/A) + . = ..() if(isliving(A)) toxmob(A) diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm index f385b640aa..1e82a601ea 100644 --- a/code/modules/power/supermatter/supermatter.dm +++ b/code/modules/power/supermatter/supermatter.dm @@ -348,11 +348,11 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) /obj/machinery/power/supermatter_crystal/proc/alarm() switch(get_status()) if(SUPERMATTER_DELAMINATING) - playsound(src, 'sound/misc/bloblarm.ogg', 100) + playsound(src, 'sound/misc/bloblarm.ogg', 100, FALSE, 40, 30, falloff_distance = 10) if(SUPERMATTER_EMERGENCY) - playsound(src, 'sound/machines/engine_alert1.ogg', 100) + playsound(src, 'sound/machines/engine_alert1.ogg', 100, FALSE, 30, 30, falloff_distance = 10) if(SUPERMATTER_DANGER) - playsound(src, 'sound/machines/engine_alert2.ogg', 100) + playsound(src, 'sound/machines/engine_alert2.ogg', 100, FALSE, 30, 30, falloff_distance = 10) if(SUPERMATTER_WARNING) playsound(src, 'sound/machines/terminal_alert.ogg', 75) diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 1c3a0d230f..e3a2da68da 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -18,6 +18,8 @@ item_flags = NEEDS_PERMIT attack_verb = list("struck", "hit", "bashed") attack_speed = CLICK_CD_RANGE + var/ranged_attack_speed = CLICK_CD_RANGE + var/melee_attack_speed = CLICK_CD_MELEE var/fire_sound = "gunshot" var/suppressed = null //whether or not a message is displayed when fired @@ -158,7 +160,7 @@ user.UseStaminaBuffer(safe_cost) if(suppressed) - playsound(user, fire_sound, 10, 1) + playsound(user, fire_sound, 10, TRUE, ignore_walls = FALSE, extrarange = SILENCED_SOUND_EXTRARANGE, falloff_distance = 0) else playsound(user, fire_sound, 50, 1) if(message) @@ -173,12 +175,25 @@ for(var/obj/O in contents) O.emp_act(severity) +/obj/item/gun/attack(mob/living/M, mob/user) + . = ..() + if(!(. & DISCARD_LAST_ACTION)) + user.DelayNextAction(melee_attack_speed) + +/obj/item/gun/attack_obj(obj/O, mob/user) + . = ..() + if(!(. & DISCARD_LAST_ACTION)) + user.DelayNextAction(melee_attack_speed) + /obj/item/gun/afterattack(atom/target, mob/living/user, flag, params) . = ..() - if(!CheckAttackCooldown(user, target)) + if(!CheckAttackCooldown(user, target, TRUE)) return process_afterattack(target, user, flag, params) +/obj/item/gun/CheckAttackCooldown(mob/user, atom/target, shooting = FALSE) + return user.CheckActionCooldown(shooting? ranged_attack_speed : attack_speed, clickdelay_from_next_action, clickdelay_mod_bypass, clickdelay_ignores_next_action) + /obj/item/gun/proc/process_afterattack(atom/target, mob/living/user, flag, params) if(!target) return diff --git a/code/modules/projectiles/guns/ballistic/revolver.dm b/code/modules/projectiles/guns/ballistic/revolver.dm index 37b23402f1..3e564a9ace 100644 --- a/code/modules/projectiles/guns/ballistic/revolver.dm +++ b/code/modules/projectiles/guns/ballistic/revolver.dm @@ -373,7 +373,6 @@ sawn_off = TRUE slot_flags = ITEM_SLOT_BELT - /obj/item/gun/ballistic/revolver/reverse //Fires directly at its user... unless the user is a clown, of course. clumsy_check = 0 diff --git a/code/modules/projectiles/guns/ballistic/shotgun.dm b/code/modules/projectiles/guns/ballistic/shotgun.dm index 7b3ac36ef6..796e544603 100644 --- a/code/modules/projectiles/guns/ballistic/shotgun.dm +++ b/code/modules/projectiles/guns/ballistic/shotgun.dm @@ -318,7 +318,7 @@ pump() return TRUE -// DOUBLE BARRELED SHOTGUN and IMPROVISED SHOTGUN are in revolver.dm +//due to code weirdness, and the fact that a refactor is coming soon anyway, the barman's shotgun and maint shotgun are in revolver.dm /obj/item/gun/ballistic/shotgun/doublebarrel/hook name = "hook modified sawn-off shotgun" diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm index a08e570dd7..ae6050a68e 100644 --- a/code/modules/projectiles/guns/energy/special.dm +++ b/code/modules/projectiles/guns/energy/special.dm @@ -173,18 +173,60 @@ force = 15 ammo_type = list(/obj/item/ammo_casing/energy/plasma/adv) +//Sci guns + +/obj/item/gun/energy/gravity_gun + name = "one-point gravitational manipulator" + desc = "An experimental, multi-mode device that fires bolts of Zero-Point Energy, causing local distortions in gravity. Requires an anomaly core to function." + ammo_type = list(/obj/item/ammo_casing/energy/gravity/repulse, /obj/item/ammo_casing/energy/gravity/attract, /obj/item/ammo_casing/energy/gravity/chaos) + item_state = "gravity_gun" + icon_state = "gravity_gun" + var/power = 4 + var/firing_core = FALSE + +/obj/item/gun/energy/gravity_gun/attackby(obj/item/C, mob/user) + if(istype(C, /obj/item/assembly/signaler/anomaly)) + to_chat(user, "You insert [C] into the gravitational manipulator and the weapon gently hums to life.") + firing_core = TRUE + playsound(src.loc, 'sound/machines/click.ogg', 50, TRUE) + qdel(C) + return + return ..() + +/obj/item/gun/energy/gravity_gun/can_shoot() + if(!firing_core) + return FALSE + return ..() + /obj/item/gun/energy/wormhole_projector name = "bluespace wormhole projector" - desc = "A projector that emits high density quantum-coupled bluespace beams." + desc = "A projector that emits high density quantum-coupled bluespace beams. Requires an anomaly core to function." ammo_type = list(/obj/item/ammo_casing/energy/wormhole, /obj/item/ammo_casing/energy/wormhole/orange) item_state = null icon_state = "wormhole_projector" - pin = null inaccuracy_modifier = 0.25 automatic_charge_overlays = FALSE var/obj/effect/portal/p_blue var/obj/effect/portal/p_orange var/atmos_link = FALSE + var/firing_core = FALSE + +/obj/item/gun/energy/wormhole_projector/attackby(obj/item/C, mob/user) + if(istype(C, /obj/item/assembly/signaler/anomaly)) + to_chat(user, "You insert [C] into the wormhole projector and the weapon gently hums to life.") + firing_core = TRUE + playsound(src.loc, 'sound/machines/click.ogg', 50, TRUE) + qdel(C) + return + +/obj/item/gun/energy/wormhole_projector/can_shoot() + if(!firing_core) + return FALSE + return ..() + +/obj/item/gun/energy/wormhole_projector/shoot_with_empty_chamber(mob/living/user) + . = ..() + to_chat(user, "The display says, 'NO CORE INSTALLED'.") /obj/item/gun/energy/wormhole_projector/update_icon_state() icon_state = "[initial(icon_state)][current_firemode_index]" @@ -243,6 +285,9 @@ p_blue = P crosslink() +/obj/item/gun/energy/wormhole_projector/core_inserted + firing_core = TRUE + /* 3d printer 'pseudo guns' for borgs */ /obj/item/gun/energy/printer @@ -298,18 +343,6 @@ /obj/item/gun/energy/laser/instakill/emp_act() //implying you could stop the instagib return -/obj/item/gun/energy/gravity_gun - name = "one-point bluespace-gravitational manipulator" - desc = "An experimental, multi-mode device that fires bolts of Zero-Point Energy, causing local distortions in gravity." - ammo_type = list(/obj/item/ammo_casing/energy/gravity/repulse, /obj/item/ammo_casing/energy/gravity/attract, /obj/item/ammo_casing/energy/gravity/chaos) - item_state = "gravity_gun" - icon_state = "gravity_gun" - pin = null - var/power = 4 - -/obj/item/gun/energy/gravity_gun/security - pin = /obj/item/firing_pin - //Emitter Gun /obj/item/gun/energy/emitter diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index fb9e6ff6c6..481d3c2c68 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -471,11 +471,10 @@ if(paused || !isturf(loc)) return - var/ds = (SSprojectiles.flags & SS_TICKER)? (wait * world.tick_lag) : wait - var/required_pixels = (pixels_per_second * ds * 0.1) + pixels_tick_leftover + var/required_pixels = (pixels_per_second * wait) + pixels_tick_leftover if(required_pixels >= pixel_increment_amount) pixels_tick_leftover = MODULUS(required_pixels, pixel_increment_amount) - pixel_move(FLOOR(required_pixels / pixel_increment_amount, 1), FALSE, ds, SSprojectiles.global_projectile_speed_multiplier) + pixel_move(FLOOR(required_pixels / pixel_increment_amount, 1), FALSE, wait, SSprojectiles.global_projectile_speed_multiplier) else pixels_tick_leftover = required_pixels @@ -603,7 +602,7 @@ * Trajectory multiplier directly modifies the factor of pixel_increment_amount to go per time. * It's complicated, so probably just don't mess with this unless you know what you're doing. */ -/obj/item/projectile/proc/pixel_move(times, hitscanning = FALSE, deciseconds_equivalent = world.tick_lag, trajectory_multiplier = 1, allow_animation = TRUE) +/obj/item/projectile/proc/pixel_move(times, hitscanning = FALSE, seconds_equivalent = world.tick_lag * 0.1, trajectory_multiplier = 1, allow_animation = TRUE) if(!loc || !trajectory) return if(!nondirectional_sprite && !hitscanning) @@ -620,7 +619,7 @@ if(homing_target) // No datum/points, too expensive. var/angle = closer_angle_difference(Angle, get_projectile_angle(src, homing_target)) - var/max_turn = homing_turn_speed * deciseconds_equivalent * 0.1 + var/max_turn = homing_turn_speed * seconds_equivalent setAngle(Angle + clamp(angle, -max_turn, max_turn)) // HOMING END trajectory.increment(trajectory_multiplier) diff --git a/code/modules/projectiles/projectile/reusable/foam_dart.dm b/code/modules/projectiles/projectile/reusable/foam_dart.dm index 7d21f663c2..b00c35cd18 100644 --- a/code/modules/projectiles/projectile/reusable/foam_dart.dm +++ b/code/modules/projectiles/projectile/reusable/foam_dart.dm @@ -20,8 +20,9 @@ newcasing.modified = modified var/obj/item/projectile/bullet/reusable/foam_dart/newdart = newcasing.BB newdart.modified = modified - newdart.damage = damage - newdart.nodamage = nodamage + if(modified) + newdart.damage = 5 + newdart.nodamage = FALSE newdart.damage_type = damage_type if(pen) newdart.pen = pen diff --git a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm index db16a10d1d..d1c18f0510 100644 --- a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm +++ b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm @@ -259,6 +259,7 @@ say("Not enough energy to complete operation!") return R.add_reagent(reagent, actual) + log_reagent("DISPENSER: ([COORD(src)]) ([REF(src)]) [key_name(usr)] dispensed [actual] of [reagent] to [beaker] ([REF(beaker)]).") work_animation() else @@ -281,11 +282,14 @@ var/list/chemicals_to_dispense = saved_recipes[params["recipe"]] if(!LAZYLEN(chemicals_to_dispense)) return + var/list/logstring = list() + var/earlyabort = FALSE for(var/key in chemicals_to_dispense) var/reagent = GLOB.name2reagent[translate_legacy_chem_id(key)] var/dispense_amount = chemicals_to_dispense[key] + logstring += "[reagent] = [dispense_amount]" if(!dispensable_reagents.Find(reagent)) - return + break if(!recording_recipe) if(!beaker) return @@ -295,11 +299,15 @@ if(actual) if(!cell.use(actual / powerefficiency)) say("Not enough energy to complete operation!") - return + earlyabort = TRUE + break R.add_reagent(reagent, actual) work_animation() else recording_recipe[key] += dispense_amount + logstring = logstring.Join(", ") + if(!recording_recipe) + log_reagent("DISPENSER: [key_name(usr)] dispensed recipe [params["recipe"]] with chemicals [logstring] to [beaker] ([REF(beaker)])[earlyabort? " (aborted early)":""]") . = TRUE if("clear_recipes") if(!is_operational()) @@ -322,15 +330,19 @@ if(saved_recipes[name] && alert("\"[name]\" already exists, do you want to overwrite it?",, "Yes", "No") == "No") return if(name && recording_recipe) + var/list/logstring = list() for(var/reagent in recording_recipe) var/reagent_id = GLOB.name2reagent[translate_legacy_chem_id(reagent)] + logstring += "[reagent_id] = [recording_recipe[reagent]]" if(!dispensable_reagents.Find(reagent_id)) visible_message("[src] buzzes.", "You hear a faint buzz.") to_chat(usr, "[src] cannot find [reagent]!") playsound(src, 'sound/machines/buzz-two.ogg', 50, TRUE) return saved_recipes[name] = recording_recipe + logstring = logstring.Join(", ") recording_recipe = null + log_reagent("DISPENSER: [key_name(usr)] recorded recipe [name] with chemicals [logstring]") . = TRUE if("cancel_recording") if(!is_operational()) diff --git a/code/modules/reagents/chemistry/machinery/chem_master.dm b/code/modules/reagents/chemistry/machinery/chem_master.dm index 32ac7cecba..89fdb52b2a 100644 --- a/code/modules/reagents/chemistry/machinery/chem_master.dm +++ b/code/modules/reagents/chemistry/machinery/chem_master.dm @@ -257,9 +257,9 @@ var/amount = text2num(params["amount"]) if(amount == null) amount = text2num(input(usr, - "Max 10. Buffer content will be split evenly.", + "Max 20. Buffer content will be split evenly.", "How many to make?", 1)) - amount = clamp(round(amount), 0, 10) + amount = clamp(round(amount), 0, 20) if (amount <= 0) return FALSE // Get units per item diff --git a/code/modules/reagents/chemistry/reagents/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drink_reagents.dm index 37fc075c6f..1a8f6edcbe 100644 --- a/code/modules/reagents/chemistry/reagents/drink_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drink_reagents.dm @@ -625,8 +625,9 @@ myseed.adjust_potency(round(chems.get_reagent_amount(src.type) * 0.5)) /datum/reagent/consumable/buzz_fuzz/on_mob_life(mob/living/carbon/M) - M.reagents.add_reagent(/datum/reagent/consumable/sugar,1) - if(prob(5)) + if(prob(33)) + M.reagents.add_reagent(/datum/reagent/consumable/sugar,1) + if(prob(1)) M.reagents.add_reagent(/datum/reagent/consumable/honey,1) ..() diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index e64647028c..17cde0611b 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -1125,8 +1125,8 @@ /datum/reagent/space_cleaner/sterilizine/reaction_obj(obj/O, reac_volume) if(istype(O, /obj/item/stack/medical/gauze)) var/obj/item/stack/medical/gauze/G = O - reac_volume = min((reac_volume / 10), G.amount) - new/obj/item/stack/medical/gauze/adv(get_turf(G), reac_volume) + reac_volume = min((reac_volume / 5), G.amount) + new /obj/item/stack/medical/gauze/adv(get_turf(G), reac_volume) G.use(reac_volume) diff --git a/code/modules/reagents/reagent_containers/glass.dm b/code/modules/reagents/reagent_containers/glass.dm index ec26182813..6e1b753c32 100644 --- a/code/modules/reagents/reagent_containers/glass.dm +++ b/code/modules/reagents/reagent_containers/glass.dm @@ -455,7 +455,7 @@ grinded.on_grind() reagents.add_reagent_list(grinded.grind_results) if(grinded.reagents) //food and pills - grinded.reagents.trans_to(src, grinded.reagents.total_volume) + grinded.reagents.trans_to(src, grinded.reagents.total_volume, log = "mortar powdering") to_chat(user, "You break [grinded] into powder.") QDEL_NULL(grinded) return diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm index 5aeac1bc38..1f89af420e 100644 --- a/code/modules/reagents/reagent_containers/hypospray.dm +++ b/code/modules/reagents/reagent_containers/hypospray.dm @@ -41,7 +41,7 @@ if(M.reagents) var/trans = 0 if(!infinite) - trans = reagents.trans_to(M, amount_per_transfer_from_this) + trans = reagents.trans_to(M, amount_per_transfer_from_this, log = TRUE) else trans = reagents.copy_to(M, amount_per_transfer_from_this) @@ -427,7 +427,7 @@ var/fraction = min(vial.amount_per_transfer_from_this/vial.reagents.total_volume, 1) vial.reagents.reaction(L, method, fraction) - vial.reagents.trans_to(target, vial.amount_per_transfer_from_this) + vial.reagents.trans_to(target, vial.amount_per_transfer_from_this, log = TRUE) var/long_sound = vial.amount_per_transfer_from_this >= 15 playsound(loc, long_sound ? 'sound/items/hypospray_long.ogg' : pick('sound/items/hypospray.ogg','sound/items/hypospray2.ogg'), 50, 1, -1) to_chat(user, "You [fp_verb] [vial.amount_per_transfer_from_this] units of the solution. The hypospray's cartridge now contains [vial.reagents.total_volume] units.") diff --git a/code/modules/reagents/reagent_containers/medspray.dm b/code/modules/reagents/reagent_containers/medspray.dm index 052e85a3d1..8d30f25db2 100644 --- a/code/modules/reagents/reagent_containers/medspray.dm +++ b/code/modules/reagents/reagent_containers/medspray.dm @@ -80,7 +80,7 @@ playsound(src, 'sound/effects/spray2.ogg', 50, 1, -6) var/fraction = min(amount_per_transfer_from_this/reagents.total_volume, 1) reagents.reaction(L, apply_type, fraction) - reagents.trans_to(L, amount_per_transfer_from_this) + reagents.trans_to(L, amount_per_transfer_from_this, log = TRUE) return /obj/item/reagent_containers/medspray/styptic diff --git a/code/modules/reagents/reagent_containers/pill.dm b/code/modules/reagents/reagent_containers/pill.dm index 3c23794e5a..a5b4e5b8ab 100644 --- a/code/modules/reagents/reagent_containers/pill.dm +++ b/code/modules/reagents/reagent_containers/pill.dm @@ -56,7 +56,7 @@ log_combat(user, M, "fed", reagents.log_list()) if(reagents.total_volume) reagents.reaction(M, apply_type) - reagents.trans_to(M, reagents.total_volume) + reagents.trans_to(M, reagents.total_volume, log = TRUE) qdel(src) return TRUE @@ -76,7 +76,8 @@ user.visible_message("[user] slips something into [target]!", "You dissolve [src] in [target].", vision_distance = 2) - reagents.trans_to(target, reagents.total_volume) + log_combat(user, target, "spiked", src, reagents.log_list()) + reagents.trans_to(target, reagents.total_volume, log = TRUE) qdel(src) return STOP_ATTACK_PROC_CHAIN diff --git a/code/modules/reagents/reagent_containers/rags.dm b/code/modules/reagents/reagent_containers/rags.dm index 469a8ef907..5d94e78809 100644 --- a/code/modules/reagents/reagent_containers/rags.dm +++ b/code/modules/reagents/reagent_containers/rags.dm @@ -39,7 +39,7 @@ C.visible_message("[user] is trying to smother \the [C] with \the [src]!", "[user] is trying to smother you with \the [src]!", "You hear some struggling and muffled cries of surprise.") if(do_after(user, 20, target = C)) reagents.reaction(C, INGEST) - reagents.trans_to(C, 5) + reagents.trans_to(C, 5, log = TRUE) C.visible_message("[user] has smothered \the [C] with \the [src]!", "[user] has smothered you with \the [src]!", "You hear some struggling and a heavy breath taken.") log_combat(user, C, "smothered", log_object) else @@ -107,7 +107,7 @@ reagents.clear_reagents() else msg += "'s liquids into \the [target]" - reagents.trans_to(target, reagents.total_volume) + reagents.trans_to(target, reagents.total_volume, log = TRUE) to_chat(user, "[msg].") return TRUE diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm index 926ed27854..eb3b80b693 100644 --- a/code/modules/reagents/reagent_containers/spray.dm +++ b/code/modules/reagents/reagent_containers/spray.dm @@ -81,6 +81,10 @@ else reagents.trans_to(D, amount_per_transfer_from_this, 1/range) D.color = mix_color_from_reagents(D.reagents.reagent_list) + var/turf/T = get_turf(src) + if(!T) + return + log_reagent("SPRAY: [key_name(usr)] fired [src] ([REF(src)]) [COORD(T)] at [A] ([REF(A)]) [COORD(A)] (chempuff: [D.reagents.log_list()])") var/wait_step = max(round(2+ spray_delay * INVERSE(range)), 2) last_spray = world.time INVOKE_ASYNC(src, .proc/do_spray, A, wait_step, D, range, puff_reagent_left) diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm index f42ae668c7..93a07b1a6e 100644 --- a/code/modules/reagents/reagent_containers/syringes.dm +++ b/code/modules/reagents/reagent_containers/syringes.dm @@ -113,7 +113,7 @@ to_chat(user, "You cannot directly remove reagents from [target]!") return - var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this) // transfer from, transfer to - who cares? + var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this, log = TRUE) // transfer from, transfer to - who cares? to_chat(user, "You fill [src] with [trans] units of the solution. It now contains [reagents.total_volume] units.") if (round(reagents.total_volume, 0.1) >= reagents.maximum_volume) @@ -158,7 +158,7 @@ L.log_message("injected themselves ([contained]) with [src.name]", LOG_ATTACK, color="orange") var/fraction = min(amount_per_transfer_from_this/reagents.total_volume, 1) reagents.reaction(L, INJECT, fraction) - reagents.trans_to(target, amount_per_transfer_from_this) + reagents.trans_to(target, amount_per_transfer_from_this, log = TRUE) to_chat(user, "You inject [amount_per_transfer_from_this] units of the solution. The syringe now contains [reagents.total_volume] units.") if (reagents.total_volume <= 0 && mode==SYRINGE_INJECT) mode = SYRINGE_DRAW diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm index ffa3f7478b..39ccdd23a2 100644 --- a/code/modules/reagents/reagent_dispenser.dm +++ b/code/modules/reagents/reagent_dispenser.dm @@ -182,7 +182,7 @@ if(W.reagents.has_reagent(/datum/reagent/fuel, W.max_fuel)) to_chat(user, "Your [W.name] is already full!") return - reagents.trans_to(W, W.max_fuel) + reagents.trans_to(W, W.max_fuel, log = TRUE) user.visible_message("[user] refills [user.p_their()] [W.name].", "You refill [W].") playsound(src, 'sound/effects/refill.ogg', 50, 1) W.update_icon() diff --git a/code/modules/recycling/disposal/construction.dm b/code/modules/recycling/disposal/construction.dm index 348e687e03..c6d015df34 100644 --- a/code/modules/recycling/disposal/construction.dm +++ b/code/modules/recycling/disposal/construction.dm @@ -14,12 +14,12 @@ var/obj/pipe_type = /obj/structure/disposalpipe/segment var/pipename -/obj/structure/disposalconstruct/Initialize(loc, _pipe_type, _dir = SOUTH, flip = FALSE, obj/make_from) +/obj/structure/disposalconstruct/Initialize(mapload, _pipe_type, _dir = SOUTH, flip = FALSE, obj/make_from) . = ..() if(make_from) pipe_type = make_from.type setDir(make_from.dir) - anchored = TRUE + set_anchored(TRUE) else if(_pipe_type) @@ -34,6 +34,8 @@ update_icon() + // AddElement(/datum/element/undertile, TRAIT_T_RAY_VISIBLE) + /obj/structure/disposalconstruct/Move() var/old_dir = dir ..() diff --git a/code/modules/recycling/disposal/holder.dm b/code/modules/recycling/disposal/holder.dm index 2e36a9deaa..f739057699 100644 --- a/code/modules/recycling/disposal/holder.dm +++ b/code/modules/recycling/disposal/holder.dm @@ -73,14 +73,16 @@ /obj/structure/disposalholder/proc/move() set waitfor = FALSE var/obj/structure/disposalpipe/last + var/ticks = 1 while(active) var/obj/structure/disposalpipe/curr = loc last = curr + set_glide_size(DELAY_TO_GLIDE_SIZE(ticks * world.tick_lag)) curr = curr.transfer(src) if(!curr && active) last.expel(src, loc, dir) - stoplag() + ticks = stoplag() if(!(count--)) active = FALSE diff --git a/code/modules/research/designs/autolathe_desings/autolathe_designs_sec_and_hacked.dm b/code/modules/research/designs/autolathe_desings/autolathe_designs_sec_and_hacked.dm index 61d0594d3b..bf9d5886a0 100644 --- a/code/modules/research/designs/autolathe_desings/autolathe_designs_sec_and_hacked.dm +++ b/code/modules/research/designs/autolathe_desings/autolathe_designs_sec_and_hacked.dm @@ -74,12 +74,12 @@ build_path = /obj/item/restraints/handcuffs category = list("hacked", "Security") -/datum/design/rifle_receiver - name = "Rifle Receiver" - id = "rifle_receiver" +/datum/design/reciever + name = "Modular Receiver" + id = "modular_receiver" build_type = AUTOLATHE materials = list(/datum/material/iron = 24000) - build_path = /obj/item/weaponcrafting/improvised_parts/rifle_receiver + build_path = /obj/item/weaponcrafting/receiver category = list("hacked", "Security") /datum/design/shotgun_slug diff --git a/code/modules/research/designs/autolathe_desings/autolathe_designs_tcomms_and_misc.dm b/code/modules/research/designs/autolathe_desings/autolathe_designs_tcomms_and_misc.dm index 539232bbcd..1b1c710e8c 100644 --- a/code/modules/research/designs/autolathe_desings/autolathe_designs_tcomms_and_misc.dm +++ b/code/modules/research/designs/autolathe_desings/autolathe_designs_tcomms_and_misc.dm @@ -282,10 +282,3 @@ build_path = /obj/item/vending_refill/custom category = list("initial", "Misc") -/datum/design/trigger_assembly - name = "Trigger Assembly" - id = "trigger_assembly" - build_type = AUTOLATHE - materials = list(/datum/material/iron = 6500, /datum/material/glass = 50) - build_path = /obj/item/weaponcrafting/improvised_parts/trigger_assembly - category = list("initial", "Misc") diff --git a/code/modules/research/designs/machine_desings/machine_designs_engi.dm b/code/modules/research/designs/machine_desings/machine_designs_engi.dm index 4f70b6ee78..ca522d2ce1 100644 --- a/code/modules/research/designs/machine_desings/machine_designs_engi.dm +++ b/code/modules/research/designs/machine_desings/machine_designs_engi.dm @@ -104,3 +104,11 @@ build_path = /obj/item/circuitboard/machine/thermomachine category = list ("Engineering Machinery") departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING | DEPARTMENTAL_FLAG_SCIENCE + +/datum/design/board/spaceship_navigation_beacon + name = "Machine Design (Bluespace Navigation Gigabeacon)" + desc = "The circuit board for a Bluespace Navigation Gigabeacon." + id = "spaceship_navigation_beacon" + build_path = /obj/item/circuitboard/machine/spaceship_navigation_beacon + category = list ("Teleportation Machinery") + departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING | DEPARTMENTAL_FLAG_SCIENCE diff --git a/code/modules/research/designs/machine_desings/machine_designs_sci.dm b/code/modules/research/designs/machine_desings/machine_designs_sci.dm index 59fae9d09b..28b1235a42 100644 --- a/code/modules/research/designs/machine_desings/machine_designs_sci.dm +++ b/code/modules/research/designs/machine_desings/machine_designs_sci.dm @@ -161,3 +161,11 @@ build_path = /obj/item/circuitboard/machine/circuit_imprinter category = list("Research Machinery") departmental_flags = DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_ENGINEERING + +/datum/design/board/explosive_compressor + name = "Explosive Compressor (Machine Board)" + desc = "The circuit board for an explosive compressor, used to compress raw into finished anomaly cores." + id = "explosive_compressor" + build_path = /obj/item/circuitboard/machine/explosive_compressor + category = list("Research Machinery") + departmental_flags = DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_ENGINEERING diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm index 445ce39ce5..9879171e71 100644 --- a/code/modules/research/designs/medical_designs.dm +++ b/code/modules/research/designs/medical_designs.dm @@ -308,7 +308,7 @@ materials = list(/datum/material/iron = 16000, /datum/material/glass = 18000, /datum/material/gold = 6000, /datum/material/silver = 6000) build_path = /obj/item/disk/medical/defib_heal construction_time = 10 - category = list("Misc") + category = list("Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL /datum/design/defib_shock @@ -319,7 +319,7 @@ materials = list(/datum/material/iron = 16000, /datum/material/glass = 18000, /datum/material/gold = 6000, /datum/material/silver = 6000) build_path = /obj/item/disk/medical/defib_shock construction_time = 10 - category = list("Misc") + category = list("Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL /datum/design/defib_decay @@ -330,7 +330,7 @@ materials = list(/datum/material/iron = 16000, /datum/material/glass = 18000, /datum/material/gold = 16000, /datum/material/silver = 6000, /datum/material/titanium = 2000) build_path = /obj/item/disk/medical/defib_decay construction_time = 10 - category = list("Misc") + category = list("Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL /datum/design/defib_speed @@ -341,7 +341,7 @@ build_path = /obj/item/disk/medical/defib_speed materials = list(/datum/material/iron = 16000, /datum/material/glass = 8000, /datum/material/gold = 26000, /datum/material/silver = 26000) construction_time = 10 - category = list("Misc") + category = list("Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL /datum/design/defibrillator_compact @@ -637,20 +637,20 @@ name = "Cybernetic Liver" desc = "A cybernetic liver" id = "cybernetic_liver" - build_type = PROTOLATHE + build_type = PROTOLATHE | MECHFAB materials = list(/datum/material/iron = 500, /datum/material/glass = 500) build_path = /obj/item/organ/liver/cybernetic - category = list("Medical Designs") + category = list("Misc","Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL /datum/design/cybernetic_heart name = "Cybernetic Heart" desc = "A cybernetic heart" id = "cybernetic_heart" - build_type = PROTOLATHE + build_type = PROTOLATHE | MECHFAB materials = list(/datum/material/iron = 500, /datum/material/glass = 500) build_path = /obj/item/organ/heart/cybernetic - category = list("Medical Designs") + category = list("Misc","Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL /datum/design/cybernetic_heart_u @@ -668,40 +668,40 @@ name = "Upgraded Cybernetic Liver" desc = "An upgraded cybernetic liver" id = "cybernetic_liver_u" - build_type = PROTOLATHE + build_type = PROTOLATHE | MECHFAB materials = list(/datum/material/iron = 500, /datum/material/glass = 500) build_path = /obj/item/organ/liver/cybernetic/upgraded - category = list("Medical Designs") + category = list("Misc","Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL /datum/design/cybernetic_lungs name = "Cybernetic Lungs" desc = "A pair of cybernetic lungs." id = "cybernetic_lungs" - build_type = PROTOLATHE + build_type = PROTOLATHE | MECHFAB materials = list(/datum/material/iron = 500, /datum/material/glass = 500) build_path = /obj/item/organ/lungs/cybernetic - category = list("Medical Designs") + category = list("Misc","Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL /datum/design/cybernetic_lungs_u name = "Upgraded Cybernetic Lungs" desc = "A pair of upgraded cybernetic lungs." id = "cybernetic_lungs_u" - build_type = PROTOLATHE + build_type = PROTOLATHE | MECHFAB materials = list(/datum/material/iron = 500, /datum/material/glass = 500, /datum/material/silver = 500) build_path = /obj/item/organ/lungs/cybernetic/upgraded - category = list("Medical Designs") + category = list("Misc","Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL /datum/design/cybernetic_tongue name = "Cybernetic tongue" desc = "A fancy cybernetic tongue." id = "cybernetic_tongue" - build_type = PROTOLATHE + build_type = PROTOLATHE | MECHFAB materials = list(/datum/material/iron = 500, /datum/material/glass = 500) build_path = /obj/item/organ/tongue/cybernetic - category = list("Medical Designs") + category = list("Misc","Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL /datum/design/cybernetic_ears @@ -726,6 +726,32 @@ category = list("Misc", "Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL +///////////////////// +/////Synth Organs//// +///////////////////// + +/datum/design/ipc_stomach + name = "IPC cell" + desc = "Effectively the robot equivalent of a stomach, handling power storage." + id = "ipc_stomach" + build_type = PROTOLATHE | MECHFAB + construction_time = 40 + materials = list(/datum/material/iron = 1000, /datum/material/glass = 300, /datum/material/silver = 500, /datum/material/gold = 400) + build_path = /obj/item/organ/stomach/ipc + category = list("Misc", "Medical Designs") + departmental_flags = DEPARTMENTAL_FLAG_MEDICAL + +/datum/design/cyberimp_power_cord + name = "IPC power cord" + desc = "A implant for Robots designed to siphon power from APCs to recharge their own cell." + id = "ci-power-cord" + build_type = PROTOLATHE | MECHFAB + construction_time = 75 + materials = list(/datum/material/iron = 4000, /datum/material/glass = 1500, /datum/material/silver = 1200, /datum/material/gold = 1600, /datum/material/plasma = 1000) + build_path = /obj/item/organ/cyberimp/arm/power_cord + category = list("Misc", "Medical Designs") + departmental_flags = DEPARTMENTAL_FLAG_MEDICAL + ///////////////////// ///Surgery Designs/// ///////////////////// @@ -899,88 +925,88 @@ name = "Surplus prosthetic left arm" desc = "Basic outdated and fragile prosthetic left arm." id = "basic_l_arm" - build_type = PROTOLATHE + build_type = PROTOLATHE | MECHFAB materials = list(/datum/material/iron = 5000, /datum/material/glass = 2500) construction_time = 20 build_path = /obj/item/bodypart/l_arm/robot/surplus - category = list("Medical Designs") + category = list("Misc","Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL /datum/design/basic_r_arm name = "Surplus prosthetic right arm" desc = "Basic outdated and fragile prosthetic left arm." id = "basic_r_arm" - build_type = PROTOLATHE + build_type = PROTOLATHE | MECHFAB materials = list(/datum/material/iron = 5000, /datum/material/glass = 2500) construction_time = 20 build_path = /obj/item/bodypart/r_arm/robot/surplus - category = list("Medical Designs") + category = list("Misc","Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL /datum/design/basic_l_leg name = "Surplus prosthetic left leg" desc = "Basic outdated and fragile prosthetic left leg." id = "basic_l_leg" - build_type = PROTOLATHE + build_type = PROTOLATHE | MECHFAB materials = list(/datum/material/iron = 5000, /datum/material/glass = 2500) construction_time = 20 build_path = /obj/item/bodypart/l_leg/robot/surplus - category = list("Medical Designs") + category = list("Misc","Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL /datum/design/basic_r_leg name = "Surplus prosthetic right leg" desc = "Basic outdated and fragile prosthetic right leg." id = "basic_r_leg" - build_type = PROTOLATHE + build_type = PROTOLATHE | MECHFAB materials = list(/datum/material/iron = 5000, /datum/material/glass = 2500) construction_time = 20 build_path = /obj/item/bodypart/r_leg/robot/surplus - category = list("Medical Designs") + category = list("Misc","Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL /datum/design/adv_r_leg name = "Advanced prosthetic right leg" desc = "A renforced prosthetic right leg." id = "adv_r_leg" - build_type = PROTOLATHE + build_type = PROTOLATHE | MECHFAB materials = list(/datum/material/iron = 6000, /datum/material/glass = 3500, /datum/material/gold = 500, /datum/material/titanium = 800) construction_time = 40 build_path = /obj/item/bodypart/r_leg/robot/surplus_upgraded - category = list("Medical Designs") + category = list("Misc","Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL /datum/design/adv_l_leg name = "Advanced prosthetic left leg" desc = "A renforced prosthetic left leg." id = "adv_l_leg" - build_type = PROTOLATHE + build_type = PROTOLATHE | MECHFAB materials = list(/datum/material/iron = 6000, /datum/material/glass = 3500, /datum/material/gold = 500, /datum/material/titanium = 800) construction_time = 40 build_path = /obj/item/bodypart/l_leg/robot/surplus_upgraded - category = list("Medical Designs") + category = list("Misc","Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL /datum/design/adv_l_arm name = "Advanced prosthetic left arm" desc = "A renforced prosthetic left arm." id = "adv_l_arm" - build_type = PROTOLATHE + build_type = PROTOLATHE | MECHFAB materials = list(/datum/material/iron = 6000, /datum/material/glass = 3500, /datum/material/gold = 500, /datum/material/titanium = 800) construction_time = 40 build_path = /obj/item/bodypart/l_arm/robot/surplus_upgraded - category = list("Medical Designs") + category = list("Misc","Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL /datum/design/adv_r_arm name = "Advanced prosthetic right arm" desc = "A renforced prosthetic right arm." id = "adv_r_arm" - build_type = PROTOLATHE + build_type = PROTOLATHE | MECHFAB materials = list(/datum/material/iron = 6000, /datum/material/glass = 3500, /datum/material/gold = 500, /datum/material/titanium = 800) construction_time = 40 build_path = /obj/item/bodypart/r_arm/robot/surplus_upgraded - category = list("Medical Designs") + category = list("Misc","Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL diff --git a/code/modules/research/designs/misc_designs.dm b/code/modules/research/designs/misc_designs.dm index a54fe857e9..7dfe19f635 100644 --- a/code/modules/research/designs/misc_designs.dm +++ b/code/modules/research/designs/misc_designs.dm @@ -481,7 +481,7 @@ build_path = /obj/item/holosign_creator/atmos category = list("Tool Designs") departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING - +/* /datum/design/holosignfirelock name = "ATMOS Holofirelock Projector" desc = "A holographic projector that creates holographic barriers that prevent changes in temperature conditions." @@ -491,7 +491,7 @@ build_path = /obj/item/holosign_creator/firelock category = list("Tool Designs") departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING - +*/ /datum/design/holosigncombifan name = "ATMOS Holo-Combifan Projector" desc = "A holographic projector that creates holographic barriers that prevent changes in atmospheric and temperature conditions." diff --git a/code/modules/research/techweb/nodes/biotech_nodes.dm b/code/modules/research/techweb/nodes/biotech_nodes.dm index 977f8685d6..3c89f0bbab 100644 --- a/code/modules/research/techweb/nodes/biotech_nodes.dm +++ b/code/modules/research/techweb/nodes/biotech_nodes.dm @@ -5,7 +5,7 @@ display_name = "Biological Technology" description = "What makes us tick." //the MC, silly! prereq_ids = list("base") - design_ids = list("medicalkit", "chem_heater", "chem_master", "chem_dispenser", "sleeper", "vr_sleeper", "pandemic", "defibrillator", "defibmount", "operating", "soda_dispenser", "beer_dispenser", "healthanalyzer", "blood_bag", "bloodbankgen", "telescopiciv", "medspray","genescanner","chem_pack") + design_ids = list("medicalkit", "chem_heater", "chem_master", "chem_dispenser", "sleeper", "vr_sleeper", "pandemic", "defibrillator", "defibmount", "operating", "soda_dispenser", "beer_dispenser", "healthanalyzer", "blood_bag", "bloodbankgen", "telescopiciv", "medspray","genescanner","chem_pack", "portable_chem_mixer") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) /datum/techweb_node/adv_biotech diff --git a/code/modules/research/techweb/nodes/bluespace_nodes.dm b/code/modules/research/techweb/nodes/bluespace_nodes.dm index b0705a0b76..ae9fdd6485 100644 --- a/code/modules/research/techweb/nodes/bluespace_nodes.dm +++ b/code/modules/research/techweb/nodes/bluespace_nodes.dm @@ -70,7 +70,7 @@ display_name = "Basic Shuttle Research" description = "Research the technology required to create and use basic shuttles." prereq_ids = list("practical_bluespace", "adv_engi") - design_ids = list("shuttle_creator", "engine_plasma", "engine_heater", "shuttle_control", "shuttle_docker") + design_ids = list("shuttle_creator", "engine_plasma", "engine_heater", "shuttle_control", "shuttle_docker","spaceship_navigation_beacon") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000) /datum/techweb_node/shuttle_route_upgrade diff --git a/code/modules/research/techweb/nodes/engineering_nodes.dm b/code/modules/research/techweb/nodes/engineering_nodes.dm index f4dce58740..2b5d6f3cc1 100644 --- a/code/modules/research/techweb/nodes/engineering_nodes.dm +++ b/code/modules/research/techweb/nodes/engineering_nodes.dm @@ -26,7 +26,7 @@ display_name = "Anomaly Research" description = "Unlock the potential of the mysterious anomalies that appear on station." prereq_ids = list("adv_engi", "practical_bluespace") - design_ids = list("reactive_armour", "anomaly_neutralizer") + design_ids = list("reactive_armour", "anomaly_neutralizer", "explosive_compressor") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 3500) /datum/techweb_node/high_efficiency diff --git a/code/modules/research/techweb/nodes/medical_nodes.dm b/code/modules/research/techweb/nodes/medical_nodes.dm index 2c0240f1da..914a6174ab 100644 --- a/code/modules/research/techweb/nodes/medical_nodes.dm +++ b/code/modules/research/techweb/nodes/medical_nodes.dm @@ -80,7 +80,7 @@ display_name = "Upgraded Cybernetic Organs" description = "We have the technology to upgrade him." prereq_ids = list("cyber_organs") - design_ids = list("cybernetic_ears_u", "cybernetic_heart_u", "cybernetic_liver_u", "cybernetic_lungs_u") + design_ids = list("cybernetic_ears_u", "cybernetic_heart_u", "cybernetic_liver_u", "cybernetic_lungs_u", "ipc_stomach") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1500) /datum/techweb_node/cyber_implants @@ -88,7 +88,7 @@ display_name = "Cybernetic Implants" description = "Electronic implants that improve humans." prereq_ids = list("adv_biotech", "adv_datatheory") - design_ids = list("ci-nutriment", "ci-breather", "ci-gloweyes", "ci-welding", "ci-medhud", "ci-sechud", "ci-service") + design_ids = list("ci-nutriment", "ci-breather", "ci-gloweyes", "ci-welding", "ci-medhud", "ci-sechud", "ci-service", "ci-power-cord") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) /datum/techweb_node/adv_cyber_implants diff --git a/code/modules/research/techweb/nodes/misc_nodes.dm b/code/modules/research/techweb/nodes/misc_nodes.dm index 1bdc144232..94a19924b8 100644 --- a/code/modules/research/techweb/nodes/misc_nodes.dm +++ b/code/modules/research/techweb/nodes/misc_nodes.dm @@ -38,7 +38,7 @@ display_name = "Electromagnetic Theory" description = "Study into usage of frequencies in the electromagnetic spectrum." prereq_ids = list("base") - design_ids = list("holosign", "holosignsec", "holosignengi", "holosignatmos", "holosignfirelock", "inducer", "tray_goggles", "holopad") + design_ids = list("holosign", "holosignsec", "holosignengi", "holosignatmos",/* "holosignfirelock",*/ "inducer", "tray_goggles", "holopad") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) /datum/techweb_node/emp_adv @@ -75,15 +75,14 @@ prereq_ids = list("base") design_ids = list("sticky_tape") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - hidden = TRUE - experimental = TRUE + starting_node = TRUE -// Can be researched after getting the basic sticky technology from the BEPIS major reward +// now a BEPIS locked thing /datum/techweb_node/sticky_advanced id = "sticky_advanced" display_name = "Advanced Sticky Technology" description = "Taking a good joke too far? Nonsense!" - prereq_ids = list("sticky_basic") design_ids = list("super_sticky_tape", "pointy_tape") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000) hidden = TRUE + experimental = TRUE diff --git a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm index cbfbbe2a36..9b19516f26 100644 --- a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm +++ b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm @@ -884,6 +884,7 @@ datum/status_effect/stabilized/blue/on_remove() /datum/status_effect/stabilized/oil/tick() if(owner.stat == DEAD) explosion(get_turf(owner),1,2,4,flame_range = 5) + owner.remove_status_effect(/datum/status_effect/stabilized/oil) return ..() /datum/status_effect/stabilized/black diff --git a/code/modules/ruins/objects_and_mobs/necropolis_gate.dm b/code/modules/ruins/objects_and_mobs/necropolis_gate.dm index fd2f4377e7..5f9b810070 100644 --- a/code/modules/ruins/objects_and_mobs/necropolis_gate.dm +++ b/code/modules/ruins/objects_and_mobs/necropolis_gate.dm @@ -274,6 +274,7 @@ GLOBAL_DATUM(necropolis_gate, /obj/structure/necropolis_gate/legion_gate) return /obj/structure/stone_tile/Crossed(atom/movable/AM) + . = ..() if(falling || fallen) return var/turf/T = get_turf(src) diff --git a/code/modules/ruins/objects_and_mobs/sin_ruins.dm b/code/modules/ruins/objects_and_mobs/sin_ruins.dm index e87382cd6a..5e2fc3d7e4 100644 --- a/code/modules/ruins/objects_and_mobs/sin_ruins.dm +++ b/code/modules/ruins/objects_and_mobs/sin_ruins.dm @@ -136,10 +136,13 @@ return if(ishuman(AM)) var/mob/living/carbon/human/H = AM - if(user.real_name != H.dna.real_name) - user.real_name = H.dna.real_name - H.dna.transfer_identity(user, transfer_SE=1) - user.updateappearance(mutcolor_update=1) - user.domutcheck() - user.visible_message("[user]'s appearance shifts into [H]'s!", \ - "[H.p_they(TRUE)] think[H.p_s()] [H.p_theyre()] sooo much better than you. Not anymore, [H.p_they()] won't.") + if(!(NOTRANSSTING in H.dna.species.species_traits)) + if(user.real_name != H.dna.real_name) + user.real_name = H.dna.real_name + H.dna.transfer_identity(user, transfer_SE=1) + user.updateappearance(mutcolor_update=1) + user.domutcheck() + user.visible_message("[user]'s appearance shifts into [H]'s!", \ + "[H.p_they(TRUE)] think[H.p_s()] [H.p_theyre()] sooo much better than you. Not anymore, [H.p_they()] won't.") + else + to_chat(user, "You are unable to transform into [H]!") diff --git a/code/modules/ruins/spaceruin_code/hilbertshotel.dm b/code/modules/ruins/spaceruin_code/hilbertshotel.dm index 4859fcfca0..33c4a70634 100644 --- a/code/modules/ruins/spaceruin_code/hilbertshotel.dm +++ b/code/modules/ruins/spaceruin_code/hilbertshotel.dm @@ -21,6 +21,9 @@ GLOBAL_VAR_INIT(hhmysteryRoomNumber, 1337) /obj/item/hilbertshotel/Initialize() . = ..() //Load templates + INVOKE_ASYNC(src, .proc/prepare_rooms) + +/obj/item/hilbertshotel/proc/prepare_rooms() hotelRoomTemp = new() hotelRoomTempEmpty = new() hotelRoomTempLore = new() diff --git a/code/modules/shuttle/navigation_computer.dm b/code/modules/shuttle/navigation_computer.dm index 21a9c6c5d7..36abcb41dc 100644 --- a/code/modules/shuttle/navigation_computer.dm +++ b/code/modules/shuttle/navigation_computer.dm @@ -11,6 +11,7 @@ var/list/jumpto_ports = list() //hashset of ports to jump to and ignore for collision purposes var/obj/docking_port/stationary/my_port //the custom docking port placed by this console var/obj/docking_port/mobile/shuttle_port //the mobile docking port of the connected shuttle + var/list/locked_traits = list(ZTRAIT_RESERVED, ZTRAIT_CENTCOM, ZTRAIT_AWAY, ZTRAIT_REEBE) //traits forbided for custom docking var/view_range = 0 var/x_offset = 0 var/y_offset = 0 @@ -186,7 +187,7 @@ var/turf/eyeturf = get_turf(the_eye) if(!eyeturf) return SHUTTLE_DOCKER_BLOCKED - if(z_lock.len && !(eyeturf.z in z_lock)) + if(!eyeturf.z || SSmapping.level_has_any_trait(eyeturf.z, locked_traits)) return SHUTTLE_DOCKER_BLOCKED . = SHUTTLE_DOCKER_LANDING_CLEAR @@ -224,9 +225,9 @@ if(hidden_turf_info) . = SHUTTLE_DOCKER_BLOCKED_BY_HIDDEN_PORT - if(space_turfs_only) + if(length(whitelist_turfs)) var/turf_type = hidden_turf_info ? hidden_turf_info[2] : T.type - if(!ispath(turf_type, /turf/open/space)) + if(!is_type_in_typecache(turf_type, whitelist_turfs)) return SHUTTLE_DOCKER_BLOCKED if(length(whitelist_turfs)) @@ -324,12 +325,25 @@ var/list/L = list() for(var/V in SSshuttle.stationary) if(!V) + stack_trace("SSshuttle.stationary have null entry!") continue var/obj/docking_port/stationary/S = V if(console.z_lock.len && !(S.z in console.z_lock)) continue if(console.jumpto_ports[S.id]) - L[S.name] = S + L["([L.len])[S.name]"] = S + + for(var/V in SSshuttle.beacons) + if(!V) + stack_trace("SSshuttle.beacons have null entry!") + continue + var/obj/machinery/spaceship_navigation_beacon/nav_beacon = V + if(!nav_beacon.z || SSmapping.level_has_any_trait(nav_beacon.z, console.locked_traits)) + break + if(!nav_beacon.locked) + L["([L.len]) [nav_beacon.name] located: [nav_beacon.x] [nav_beacon.y] [nav_beacon.z]"] = nav_beacon + else + L["([L.len]) [nav_beacon.name] locked"] = null playsound(console, 'sound/machines/terminal_prompt.ogg', 25, 0) var/selected = input("Choose location to jump to", "Locations", null) as null|anything in L diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm index 03ff509086..c8ecbf1906 100644 --- a/code/modules/shuttle/shuttle.dm +++ b/code/modules/shuttle/shuttle.dm @@ -807,7 +807,7 @@ for(var/mob/M in SSmobs.clients_by_zlevel[z]) var/dist_far = get_dist(M, distant_source) if(dist_far <= long_range && dist_far > range) - M.playsound_local(distant_source, "sound/effects/[selected_sound]_distance.ogg", 100, falloff = 20) + M.playsound_local(distant_source, "sound/effects/[selected_sound]_distance.ogg", 100) else if(dist_far <= range) var/source if(engine_list.len == 0) @@ -819,7 +819,7 @@ if(dist_near < closest_dist) source = O closest_dist = dist_near - M.playsound_local(source, "sound/effects/[selected_sound].ogg", 100, falloff = range / 2) + M.playsound_local(source, "sound/effects/[selected_sound].ogg", 100) // Losing all initial engines should get you 2 // Adding another set of engines at 0.5 time diff --git a/code/modules/shuttle/spaceship_navigation_beacon.dm b/code/modules/shuttle/spaceship_navigation_beacon.dm new file mode 100644 index 0000000000..e389b32a94 --- /dev/null +++ b/code/modules/shuttle/spaceship_navigation_beacon.dm @@ -0,0 +1,63 @@ +/obj/item/circuitboard/machine/spaceship_navigation_beacon + name = "Bluespace Navigation Gigabeacon (Machine Board)" + build_path = /obj/machinery/spaceship_navigation_beacon + req_components = list() + + +/obj/machinery/spaceship_navigation_beacon + name = "Bluespace Navigation Gigabeacon" + desc = "A device that creates a bluespace anchor that allow ships jump near to it." + icon = 'icons/obj/abductor.dmi' + icon_state = "core" + use_power = IDLE_POWER_USE + idle_power_usage = 0 + density = TRUE + circuit = /obj/item/circuitboard/machine/spaceship_navigation_beacon + + var/locked = FALSE //Locked beacons don't allow to jump to it. + + +/obj/machinery/spaceship_navigation_beacon/Initialize() + . = ..() + SSshuttle.beacons |= src + +obj/machinery/spaceship_navigation_beacon/emp_act() + locked = TRUE + +/obj/machinery/spaceship_navigation_beacon/Destroy() + SSshuttle.beacons -= src + return ..() + +// update the icon_state +/obj/machinery/spaceship_navigation_beacon/update_icon() + if(powered()) + icon_state = "core" + else + icon_state = "core-open" + +/obj/machinery/spaceship_navigation_beacon/power_change() + . = ..() + update_icon() + +/obj/machinery/spaceship_navigation_beacon/multitool_act(mob/living/user, obj/item/multitool/I) + if(panel_open) + var/new_name = "Beacon_[input("Enter the custom name for this beacon", "It be Beacon ..your input..") as text]" + if(new_name && Adjacent(user)) + name = new_name + to_chat(user, "You change beacon name to [name].") + else + locked =!locked + to_chat(user, "You [locked ? "" : "un"]lock [src].") + return TRUE + +/obj/machinery/spaceship_navigation_beacon/examine() + .=..() + . += "Status: [locked ? "LOCKED" : "Stable"] " + +/obj/machinery/spaceship_navigation_beacon/attackby(obj/item/W, mob/user, params) + if(default_deconstruction_screwdriver(user, "core-open", "core", W)) + return + if(default_deconstruction_crowbar(W)) + return + + return ..() diff --git a/code/modules/spells/spell_types/spacetime_distortion.dm b/code/modules/spells/spell_types/spacetime_distortion.dm index 5797cbf8b7..5a8776b16b 100644 --- a/code/modules/spells/spell_types/spacetime_distortion.dm +++ b/code/modules/spells/spell_types/spacetime_distortion.dm @@ -1,6 +1,6 @@ /obj/effect/proc_holder/spell/spacetime_dist name = "Spacetime Distortion" - desc = "Entangle the strings of spacetime to deny easy movement around you. The strings vibrate..." + desc = "Entangle the strings of space-time in an area around you, randomizing the layout and making proper movement impossible. The strings vibrate..." charge_max = 300 var/duration = 150 range = 7 @@ -10,8 +10,9 @@ sound = 'sound/effects/magic.ogg' cooldown_min = 300 level_max = 0 + // action_icon_state = "spacetime" -/obj/effect/proc_holder/spell/spacetime_dist/can_cast(mob/user = usr, skipcharge = FALSE, silent = FALSE) +/obj/effect/proc_holder/spell/spacetime_dist/can_cast(mob/user = usr) if(ready) return ..() return FALSE @@ -97,10 +98,11 @@ busy = TRUE flick("purplesparkles", src) AM.forceMove(get_turf(src)) - playsound(get_turf(src),sound,70,0) + playsound(get_turf(src),sound,70,FALSE) busy = FALSE /obj/effect/cross_action/spacetime_dist/Crossed(atom/movable/AM) + . = ..() if(!busy) walk_link(AM) @@ -110,7 +112,8 @@ else walk_link(user) -/obj/effect/cross_action/spacetime_dist/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) +//ATTACK HAND IGNORING PARENT RETURN VALUE +/obj/effect/cross_action/spacetime_dist/on_attack_hand(mob/user) walk_link(user) /obj/effect/cross_action/spacetime_dist/attack_paw(mob/user) diff --git a/code/modules/spells/spell_types/togglebuff.dm b/code/modules/spells/spell_types/togglebuff.dm new file mode 100644 index 0000000000..4b8f3d02e1 --- /dev/null +++ b/code/modules/spells/spell_types/togglebuff.dm @@ -0,0 +1,39 @@ +/obj/effect/proc_holder/spell/self/mantra + name = "Inner Mantra" + desc = "Control your Inner Mantra, gaining strength and durability for a cost." + clothes_req = NONE + mobs_whitelist = list(/mob/living/carbon/human) + charge_max = 100 + antimagic_allowed = TRUE + invocation = "SU'UP'AH S'EI YEN" + invocation_type = "shout" + level_max = 0 + cooldown_min = 100 + action_icon = 'icons/obj/magic.dmi' + action_icon_state = "iconmantra" + +/obj/effect/proc_holder/spell/self/mantra/cast(mob/living/carbon/human/user) + if(user.has_status_effect(STATUS_EFFECT_MANTRA)) + user.remove_status_effect(STATUS_EFFECT_MANTRA) + else + user.apply_status_effect(STATUS_EFFECT_MANTRA) + +/obj/effect/proc_holder/spell/self/asura + name = "Asura's Wrath" + desc = "Unleash your rage as corrosive power fills your muscles." + clothes_req = NONE + mobs_whitelist = list(/mob/living/carbon/human) + charge_max = 100 + antimagic_allowed = TRUE + invocation = "KYE Y'O'KEN" + invocation_type = "shout" + level_max = 0 + cooldown_min = 100 + action_icon = 'icons/obj/magic.dmi' + action_icon_state = "iconasura" + +/obj/effect/proc_holder/spell/self/asura/cast(mob/living/carbon/human/user) + if(user.has_status_effect(STATUS_EFFECT_ASURA)) + user.remove_status_effect(STATUS_EFFECT_ASURA) + else + user.apply_status_effect(STATUS_EFFECT_ASURA) diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm index cd0ac28daf..962bc8c1ce 100644 --- a/code/modules/surgery/bodyparts/_bodyparts.dm +++ b/code/modules/surgery/bodyparts/_bodyparts.dm @@ -297,6 +297,7 @@ owner.update_stamina() consider_processing() update_disabled() + update_threshhold_state() return update_bodypart_damage_state() /// Allows us to roll for and apply a wound without actually dealing damage. Used for aggregate wounding power with pellet clouds @@ -394,11 +395,10 @@ var/datum/wound/new_wound if(replaced_wound) new_wound = replaced_wound.replace_wound(possible_wound) - log_wound(owner, new_wound, damage, wound_bonus, bare_wound_bonus, base_roll) // dismembering wounds are logged in the apply_wound() for loss wounds since they delete themselves immediately, these will be immediately returned else new_wound = new possible_wound new_wound.apply_wound(src) - log_wound(owner, new_wound, damage, wound_bonus, bare_wound_bonus, base_roll) + log_wound(owner, new_wound, damage, wound_bonus, bare_wound_bonus, base_roll) // dismembering wounds are logged in the apply_wound() for loss wounds since they delete themselves immediately, these will be immediately returned return new_wound // try forcing a specific wound, but only if there isn't already a wound of that severity or greater for that type on this bodypart @@ -476,6 +476,7 @@ owner.updatehealth() consider_processing() update_disabled() + update_threshhold_state() return update_bodypart_damage_state() //Returns total damage. diff --git a/code/modules/surgery/dental_implant.dm b/code/modules/surgery/dental_implant.dm index 9d304b0727..311c886c9d 100644 --- a/code/modules/surgery/dental_implant.dm +++ b/code/modules/surgery/dental_implant.dm @@ -36,6 +36,6 @@ log_combat(owner, null, "swallowed an implanted pill", target) if(target.reagents.total_volume) target.reagents.reaction(owner, INGEST) - target.reagents.trans_to(owner, target.reagents.total_volume) + target.reagents.trans_to(owner, target.reagents.total_volume, log = TRUE) qdel(target) return 1 diff --git a/code/modules/surgery/emergency_reboot.dm b/code/modules/surgery/emergency_reboot.dm new file mode 100644 index 0000000000..046edd884c --- /dev/null +++ b/code/modules/surgery/emergency_reboot.dm @@ -0,0 +1,62 @@ +//Emergency Reboot: A surgery that allows for revival of Synthetics without the need for a defib. Doesn't all all the organs like the Revival surgery though. + +/datum/surgery/emergency_reboot + name = "Emergency Reboot" + desc = "A surgery forcing the posibrain of a robot to begin it's reboot procedure, if their body can sustain its operation." + possible_locs = list(BODY_ZONE_HEAD) + requires_bodypart_type = BODYPART_ROBOTIC //If you are a Synth with a organic head (somehow), this won't work. + steps = list(/datum/surgery_step/mechanic_open, /datum/surgery_step/open_hatch, /datum/surgery_step/mechanic_unwrench, /datum/surgery_step/force_reboot, /datum/surgery_step/mechanic_wrench, /datum/surgery_step/mechanic_close) + +/datum/surgery/emergency_reboot/can_start(mob/user, mob/living/carbon/target, obj/item/tool) + if(!..()) + return FALSE + if(target.stat != DEAD) + return FALSE + if(target.suiciding || HAS_TRAIT(target, TRAIT_NOCLONE) || target.hellbound) + return FALSE + if(!HAS_TRAIT(target, TRAIT_ROBOTIC_ORGANISM)) + return FALSE + var/obj/item/organ/brain/B = target.getorganslot(ORGAN_SLOT_BRAIN) + if(!B || !istype(B, /obj/item/organ/brain/ipc)) + return FALSE + return TRUE + +/datum/surgery_step/force_reboot + name = "initiate system reboot" + implements = list(TOOL_MULTITOOL = 100, /obj/item/borg/upgrade/restart = 100) + time = 100 + +/datum/surgery_step/force_reboot/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You prepare to begin rebooting [target]'s posibrain.", + "[user] prepares to reboot [target]'s posibrain with [tool].", + "[user] prepares to reboot [target]'s posibrain with [tool].") + target.notify_ghost_cloning("Someone is trying to reboot you! Re-enter your corpse if you want to be revived!", source = target) + +/datum/surgery_step/force_reboot/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You successfully initiate a reboot in [target]'s posibrain...", + "[user] initiates a reboot in [target]'s posibrain...", + "[user] initiates a reboot in [target]'s posibrain...") + target.adjustOxyLoss(-50, 0) + target.updatehealth() + var/tplus = world.time - target.timeofdeath + if(target.revive()) + target.visible_message("...[target]'s posibrain flickers to life once again!") + target.emote("ping") + var/list/policies = CONFIG_GET(keyed_list/policyconfig) + var/timelimit = CONFIG_GET(number/defib_cmd_time_limit) * 10 //the config is in seconds, not deciseconds + var/late = timelimit && (tplus > timelimit) + var/policy = late? policies[POLICYCONFIG_ON_DEFIB_LATE] : policies[POLICYCONFIG_ON_DEFIB_INTACT] + if(policy) + to_chat(target, policy) + target.log_message("revived using surgical revival, [tplus] deciseconds from time of death, considered [late? "late" : "memory-intact"] revival under configured policy limits.", LOG_GAME) + return TRUE + else + target.visible_message("...[target]'s posibrain flickers a few times, before the lights fade yet again...") + return FALSE + +/datum/surgery_step/force_reboot/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You attempt to reboot [target]'s posibrain, but [target.p_they()] doesn't react.", + "[user] attempts to reboot [target]'s posibrain, but [target.p_they()] doesn't react.", + "[user] attempts to reboot [target]'s posibrain, but [target.p_they()] doesn't react") + target.adjustOrganLoss(ORGAN_SLOT_BRAIN, 15, 199) + return FALSE diff --git a/code/modules/surgery/limb_augmentation.dm b/code/modules/surgery/limb_augmentation.dm index 059a5aaa34..c65f5f11f6 100644 --- a/code/modules/surgery/limb_augmentation.dm +++ b/code/modules/surgery/limb_augmentation.dm @@ -31,6 +31,12 @@ target_mobtypes = list(/mob/living/carbon/human) possible_locs = list(BODY_ZONE_R_ARM,BODY_ZONE_L_ARM,BODY_ZONE_R_LEG,BODY_ZONE_L_LEG,BODY_ZONE_CHEST,BODY_ZONE_HEAD) requires_real_bodypart = TRUE + +//The augmentation surgery for synthetic limbs +/datum/surgery/augmentation/synth + requires_bodypart_type = BODYPART_HYBRID + steps = list(/datum/surgery_step/mechanic_open, /datum/surgery_step/pry_off_plating, /datum/surgery_step/cut_wires, /datum/surgery_step/prepare_electronics, /datum/surgery_step/replace_limb) + //SURGERY STEP SUCCESSES /datum/surgery_step/replace_limb/success(mob/user, mob/living/carbon/target, target_zone, obj/item/bodypart/tool, datum/surgery/surgery) if(L) diff --git a/code/modules/surgery/organs/heart.dm b/code/modules/surgery/organs/heart.dm index 25b7e8fa48..6b3d47b587 100644 --- a/code/modules/surgery/organs/heart.dm +++ b/code/modules/surgery/organs/heart.dm @@ -114,7 +114,7 @@ obj/item/organ/heart/slime var/last_pump = 0 var/add_colour = TRUE //So we're not constantly recreating colour datums var/pump_delay = 30 //you can pump 1 second early, for lag, but no more (otherwise you could spam heal) - var/blood_loss = 100 //600 blood is human default, so 5 failures (below 122 blood is where humans die because reasons?) + var/blood_loss = 50 //600 blood is human default, so 5 failures (below 122 blood is where humans die because reasons?) //How much to heal per pump, negative numbers would HURT the player var/heal_brute = 0 @@ -123,7 +123,11 @@ obj/item/organ/heart/slime /obj/item/organ/heart/cursed/attack(mob/living/carbon/human/H, mob/living/carbon/human/user, obj/target) + if(H == user && istype(H)) + if(NOBLOOD in H.dna.species.species_traits) + to_chat(user, "[src] refuses to become one with [H]") + return playsound(user,'sound/effects/singlebeat.ogg',40,1) user.temporarilyRemoveItemFromInventory(src, TRUE) Insert(user) @@ -137,6 +141,8 @@ obj/item/organ/heart/slime if(world.time > (last_pump + pump_delay)) if(ishuman(owner) && owner.client) //While this entire item exists to make people suffer, they can't control disconnects. var/mob/living/carbon/human/H = owner + if(NOBLOOD in H.dna.species.species_traits) //Otherwise people without will be eternally stuck red + return if(H.dna && !(NOBLOOD in H.dna.species.species_traits)) H.blood_volume = max(H.blood_volume - blood_loss, 0) to_chat(H, "You have to keep pumping your blood!") @@ -156,6 +162,8 @@ obj/item/organ/heart/slime return ..() /datum/action/item_action/organ_action/cursed_heart + check_flags = AB_CHECK_ALIVE //We wanna be able to do this always, else thisll just stupidly kill whoever has it + required_mobility_flags = NONE name = "Pump your blood" //You are now brea- pumping blood manually @@ -175,7 +183,8 @@ obj/item/organ/heart/slime var/mob/living/carbon/human/H = owner if(istype(H)) if(H.dna && !(NOBLOOD in H.dna.species.species_traits)) - H.blood_volume = min(H.blood_volume + cursed_heart.blood_loss*0.5, BLOOD_VOLUME_MAXIMUM) + if(H.blood_volume < BLOOD_VOLUME_NORMAL) //We don't need to go too high, otherwise we get annoying messages. + H.blood_volume = min(H.blood_volume + cursed_heart.blood_loss * 0.5, BLOOD_VOLUME_MAXIMUM) H.remove_client_colour(/datum/client_colour/cursed_heart_blood) cursed_heart.add_colour = TRUE H.adjustBruteLoss(-cursed_heart.heal_brute) @@ -184,7 +193,7 @@ obj/item/organ/heart/slime /datum/client_colour/cursed_heart_blood - priority = 100 //it's an indicator you're dieing, so it's very high priority + priority = 100 //it's an indicator you're dying, so it's very high priority colour = "red" /obj/item/organ/heart/cybernetic diff --git a/code/modules/surgery/organs/vocal_cords.dm b/code/modules/surgery/organs/vocal_cords.dm index b6b74efe32..47b504c86e 100644 --- a/code/modules/surgery/organs/vocal_cords.dm +++ b/code/modules/surgery/organs/vocal_cords.dm @@ -1319,7 +1319,7 @@ if(E.phase > 1) if(user.ckey == E.enthrallID && user.real_name == E.master.real_name) E.master = user - addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, H, "[(E.lewd?"You hear the words of your [E.enthrallGender] again!! They're back!!":"You recognise the voice of [E.master].")]"), 5) + to_chat(H, "[(E.lewd?"You hear the words of your [E.enthrallGender] again!! They're back!!":"You recognise the voice of [E.master].")]") to_chat(user, "[H] looks at you with sparkling eyes, recognising you!") //I dunno how to do state objectives without them revealing they're an antag diff --git a/code/modules/surgery/remove_embedded_object.dm b/code/modules/surgery/remove_embedded_object.dm index f974c39bb4..dfdb1f7eca 100644 --- a/code/modules/surgery/remove_embedded_object.dm +++ b/code/modules/surgery/remove_embedded_object.dm @@ -2,11 +2,17 @@ name = "removal of embedded objects" steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/remove_object) possible_locs = list(BODY_ZONE_R_ARM,BODY_ZONE_L_ARM,BODY_ZONE_R_LEG,BODY_ZONE_L_LEG,BODY_ZONE_CHEST,BODY_ZONE_HEAD) + +/datum/surgery/embedded_removal/robot + requires_bodypart_type = BODYPART_ROBOTIC + steps = list(/datum/surgery_step/mechanic_open, /datum/surgery_step/open_hatch, /datum/surgery_step/remove_object) + /datum/surgery_step/remove_object name = "remove embedded objects" time = 32 accept_hand = 1 var/obj/item/bodypart/L = null + /datum/surgery_step/remove_object/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) L = surgery.operated_bodypart if(L) diff --git a/code/modules/unit_tests/README.md b/code/modules/unit_tests/README.md new file mode 100644 index 0000000000..420c805fbf --- /dev/null +++ b/code/modules/unit_tests/README.md @@ -0,0 +1,70 @@ +# Unit Tests + +## What is unit testing? + +Unit tests are automated code to verify that parts of the game work exactly as they should. For example, [a test to make sure that the amputation surgery actually amputates the limb](https://github.com/tgstation/tgstation/blob/e416283f162b86345a8623125ab866839b1ac40d/code/modules/unit_tests/surgeries.dm#L1-L13). These are ran every time a PR is made, and thus are very helpful for preventing bugs from cropping up in your code that would've otherwise gone unnoticed. For example, would you have thought to check [that beach boys would still work the same after editing pizza](https://github.com/tgstation/tgstation/pull/53641#issuecomment-691384934)? If you value your time, probably not. + +On their most basic level, when `UNIT_TESTS` is defined, all subtypes of `/datum/unit_test` will have their `Run` proc executed. From here, if `Fail` is called at any point, then the tests will report as failed. + +## How do I write one? +1. Find a relevant file. + +All unit test related code is in `code/modules/unit_tests`. If you are adding a new test for a surgery, for example, then you'd open `surgeries.dm`. If a relevant file does not exist, simply create one in this folder, then `#include` it in `_unit_tests.dm`. + +2. Create the unit test. + +To make a new unit test, you simply need to define a `/datum/unit_test`. + +For example, let's suppose that we are creating a test to make sure a proc `square` correctly raises inputs to the power of two. We'd start with first: + +``` +/datum/unit_test/square/Run() +``` + +This defines our new unit test, `/datum/unit_test/square`. Inside this function, we're then going to run through whatever we want to check. Tests provide a few assertion functions to make this easy. For now, we're going to use `TEST_ASSERT_EQUAL`. + +``` +/datum/unit_test/square/Run() + TEST_ASSERT_EQUAL(square(3), 9, "square(3) did not return 9") + TEST_ASSERT_EQUAL(square(4), 16, "square(4) did not return 16") +``` + +As you can hopefully tell, we're simply checking if the output of `square` matches the output we are expecting. If the test fails, it'll report the error message given as well as whatever the actual output was. + +3. Run the unit test + +Open `code/_compile_options.dm` and uncomment the following line. + +``` +//#define UNIT_TESTS //If this is uncommented, we do a single run though of the game setup and tear down process with unit tests in between +``` + +Then, run tgstation.dmb in Dream Daemon. Don't bother trying to connect, you won't need to. You'll be able to see the outputs of all the tests. You'll get to see which tests failed and for what reason. If they all pass, you're set! + +## How to think about tests + +Unit tests exist to prevent bugs that would happen in a real game. Thus, they should attempt to emulate the game world wherever possible. For example, the [quick swap sanity test](https://github.com/tgstation/tgstation/blob/e416283f162b86345a8623125ab866839b1ac40d/code/modules/unit_tests/quick_swap_sanity.dm) emulates a *real* scenario of the bug it fixed occurring by creating a character and giving it real items. The unrecommended alternative would be to create special test-only items. This isn't a hard rule, the [reagent method exposure tests](https://github.com/tgstation/tgstation/blob/e416283f162b86345a8623125ab866839b1ac40d/code/modules/unit_tests/reagent_mod_expose.dm) create a test-only reagent for example, but do keep it in mind. + +Unit tests should also be just that--testing *units* of code. For example, instead of having one massive test for reagents, there are instead several smaller tests for testing exposure, metabolization, etc. + +## The unit testing API + +You can find more information about all of these from their respective doc comments, but for a brief overview: + +`/datum/unit_test` - The base for all tests to be ran. Subtypes must override `Run()`. `New()` and `Destroy()` can be used for setup and teardown. To fail, use `Fail(reason)`. + +`/datum/unit_test/proc/allocate(type, ...)` - Allocates an instance of the provided type with the given arguments. Is automatically destroyed when the test is over. Commonly seen in the form of `var/mob/living/carbon/human/human = allocate(/mob/living/carbon/human)`. + +`TEST_ASSERT(assertion, reason)` - Stops the unit test and fails if the assertion is not met. For example: `TEST_ASSERT(powered(), "Machine is not powered")`. + +`TEST_ASSERT_EQUAL(a, b, message)` - Same as `TEST_ASSERT`, but checks if `a == b`. If not, gives a helpful message showing what both `a` and `b` were. For example: `TEST_ASSERT_EQUAL(2 + 2, 4, "The universe is falling apart before our eyes!")`. + +`TEST_ASSERT_NOTEQUAL(a, b, message)` - Same as `TEST_ASSERT_EQUAL`, but reversed. + +`TEST_FOCUS(test_path)` - *Only* run the test provided within the parameters. Useful for reducing noise. For example, if we only want to run our example square test, we can add `TEST_FOCUS(/datum/unit_test/square)`. Should *never* be pushed in a pull request--you will be laughed at. + +## Final Notes + +- Writing tests before you attempt to fix the bug can actually speed up development a lot! It means you don't have to go in game and folllow the same exact steps manually every time. This process is known as "TDD" (test driven development). Write the test first, make sure it fails, *then* start work on the fix/feature, and you'll know you're done when your tests pass. If you do try this, do make sure to confirm in a non-testing environment just to double check. +- Make sure that your tests don't accidentally call RNG functions like `prob`. Since RNG is seeded during tests, you may not realize you have until someone else makes a PR and the tests fail! +- Do your best not to change the behavior of non-testing code during tests. While it may sometimes be necessary in the case of situations such as the above, it is still a slippery slope that can lead to the code you're testing being too different from the production environment to be useful. diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm index 37fa35946c..2745d971ff 100644 --- a/code/modules/unit_tests/_unit_tests.dm +++ b/code/modules/unit_tests/_unit_tests.dm @@ -1,42 +1,80 @@ //include unit test files in this module in this ifdef //Keep this sorted alphabetically -#ifdef UNIT_TESTS +#if defined(UNIT_TESTS) || defined(SPACEMAN_DMM) + /// Asserts that a condition is true /// If the condition is not true, fails the test #define TEST_ASSERT(assertion, reason) if (!(assertion)) { return Fail("Assertion failed: [reason || "No reason"]") } /// Asserts that the two parameters passed are equal, fails otherwise /// Optionally allows an additional message in the case of a failure -#define TEST_ASSERT_EQUAL(a, b, message) if ((a) != (b)) { return Fail("Expected [isnull(a) ? "null" : a] to be equal to [isnull(b) ? "null" : b].[message ? " [message]" : ""]") } +#define TEST_ASSERT_EQUAL(a, b, message) do { \ + var/lhs = ##a; \ + var/rhs = ##b; \ + if (lhs != rhs) { \ + return Fail("Expected [isnull(lhs) ? "null" : lhs] to be equal to [isnull(rhs) ? "null" : rhs].[message ? " [message]" : ""]"); \ + } \ +} while (FALSE) + +/// Asserts that the two parameters passed are not equal, fails otherwise +/// Optionally allows an additional message in the case of a failure +#define TEST_ASSERT_NOTEQUAL(a, b, message) do { \ + var/lhs = ##a; \ + var/rhs = ##b; \ + if (lhs == rhs) { \ + return Fail("Expected [isnull(lhs) ? "null" : lhs] to not be equal to [isnull(rhs) ? "null" : rhs].[message ? " [message]" : ""]"); \ + } \ +} while (FALSE) + +/// *Only* run the test provided within the parentheses +/// This is useful for debugging when you want to reduce noise, but should never be pushed +/// Intended to be used in the manner of `TEST_FOCUS(/datum/unit_test/math)` +#define TEST_FOCUS(test_path) ##test_path { focus = TRUE; } #include "anchored_mobs.dm" #include "bespoke_id.dm" -// #include "binary_insert.dm" -// #include "card_mismatch.dm" shame we don't have this! +#include "binary_insert.dm" +// #include "card_mismatch.dm" #include "chain_pull_through_space.dm" -#include "character_saving.dm" +// #include "combat.dm" #include "component_tests.dm" // #include "confusion.dm" -// #include "keybinding_init.dm" +// #include "emoting.dm" +// #include "heretic_knowledge.dm" +// #include "holidays.dm" +#include "initialize_sanity.dm" +#include "keybinding_init.dm" #include "machine_disassembly.dm" #include "medical_wounds.dm" +#include "merge_type.dm" // #include "metabolizing.dm" // #include "outfit_sanity.dm" +// #include "pills.dm" // #include "plantgrowth_tests.dm" -// #include "quick_swap_sanity.dm" - we don't have quick swap yet +// #include "projectiles.dm" #include "reagent_id_typos.dm" +// #include "reagent_mod_expose.dm" +// #include "reagent_mod_procs.dm" #include "reagent_recipe_collisions.dm" #include "resist.dm" -// #include "say.dm" //no saymods, someone update saycode please. +// #include "say.dm" +// #include "serving_tray.dm" // #include "siunit.dm" #include "spawn_humans.dm" // #include "species_whitelists.dm" +// #include "stomach.dm" #include "subsystem_init.dm" -// #include "surgeries.dm" // fails at random due to a race condition, commented out for now +#include "surgeries.dm" +#include "teleporters.dm" #include "timer_sanity.dm" #include "unit_test.dm" +/// CIT TESTS +#include "character_saving.dm" + #undef TEST_ASSERT #undef TEST_ASSERT_EQUAL +#undef TEST_ASSERT_NOTEQUAL +#undef TEST_FOCUS #endif diff --git a/code/modules/unit_tests/card_mismatch.dm b/code/modules/unit_tests/card_mismatch.dm new file mode 100644 index 0000000000..506e88f19c --- /dev/null +++ b/code/modules/unit_tests/card_mismatch.dm @@ -0,0 +1,7 @@ +/datum/unit_test/card_mismatch + +/datum/unit_test/card_mismatch/Run() + var/message = checkCardpacks(SStrading_card_game.card_packs) + message += checkCardDatums() + if(message) + Fail(message) diff --git a/code/modules/unit_tests/combat.dm b/code/modules/unit_tests/combat.dm new file mode 100644 index 0000000000..30bad72175 --- /dev/null +++ b/code/modules/unit_tests/combat.dm @@ -0,0 +1,98 @@ +/datum/unit_test/harm_punch/Run() + var/mob/living/carbon/human/puncher = allocate(/mob/living/carbon/human) + var/mob/living/carbon/human/victim = allocate(/mob/living/carbon/human) + + // Avoid all randomness in tests + ADD_TRAIT(puncher, TRAIT_PERFECT_ATTACKER, INNATE_TRAIT) + + puncher.a_intent_change(INTENT_HARM) + victim.attack_hand(puncher) + + TEST_ASSERT(victim.getBruteLoss() > 0, "Victim took no brute damage after being punched") + +/datum/unit_test/harm_melee/Run() + var/mob/living/carbon/human/tider = allocate(/mob/living/carbon/human) + var/mob/living/carbon/human/victim = allocate(/mob/living/carbon/human) + var/obj/item/storage/toolbox/toolbox = allocate(/obj/item/storage/toolbox) + + tider.put_in_active_hand(toolbox, forced = TRUE) + tider.a_intent_change(INTENT_HARM) + victim.attackby(toolbox, tider) + + TEST_ASSERT(victim.getBruteLoss() > 0, "Victim took no brute damage after being hit by a toolbox") + +/datum/unit_test/harm_different_damage/Run() + var/mob/living/carbon/human/attacker = allocate(/mob/living/carbon/human) + var/mob/living/carbon/human/victim = allocate(/mob/living/carbon/human) + var/obj/item/weldingtool/welding_tool = allocate(/obj/item/weldingtool) + + attacker.put_in_active_hand(welding_tool, forced = TRUE) + attacker.a_intent_change(INTENT_HARM) + welding_tool.attack_self(attacker) // Turn it on + victim.attackby(welding_tool, attacker) + + TEST_ASSERT_EQUAL(victim.getBruteLoss(), 0, "Victim took brute damage from a lit welding tool") + TEST_ASSERT(victim.getFireLoss() > 0, "Victim took no burn damage after being hit by a lit welding tool") + +/datum/unit_test/attack_chain + var/attack_hit + var/post_attack_hit + var/pre_attack_hit + +/datum/unit_test/attack_chain/proc/attack_hit() + attack_hit = TRUE + +/datum/unit_test/attack_chain/proc/post_attack_hit() + post_attack_hit = TRUE + +/datum/unit_test/attack_chain/proc/pre_attack_hit() + pre_attack_hit = TRUE + +/datum/unit_test/attack_chain/Run() + var/mob/living/carbon/human/attacker = allocate(/mob/living/carbon/human) + var/mob/living/carbon/human/victim = allocate(/mob/living/carbon/human) + var/obj/item/storage/toolbox/toolbox = allocate(/obj/item/storage/toolbox) + + RegisterSignal(toolbox, COMSIG_ITEM_PRE_ATTACK, .proc/pre_attack_hit) + RegisterSignal(toolbox, COMSIG_ITEM_ATTACK, .proc/attack_hit) + RegisterSignal(toolbox, COMSIG_ITEM_AFTERATTACK, .proc/post_attack_hit) + + attacker.put_in_active_hand(toolbox, forced = TRUE) + attacker.a_intent_change(INTENT_HARM) + toolbox.melee_attack_chain(attacker, victim) + + TEST_ASSERT(pre_attack_hit, "Pre-attack signal was not fired") + TEST_ASSERT(attack_hit, "Attack signal was not fired") + TEST_ASSERT(post_attack_hit, "Post-attack signal was not fired") + +/datum/unit_test/disarm/Run() + var/mob/living/carbon/human/attacker = allocate(/mob/living/carbon/human) + var/mob/living/carbon/human/victim = allocate(/mob/living/carbon/human) + var/obj/item/storage/toolbox/toolbox = allocate(/obj/item/storage/toolbox) + + victim.put_in_active_hand(toolbox, forced = TRUE) + attacker.a_intent_change(INTENT_DISARM) + + var/obj/structure/barricade/dense_object = allocate(/obj/structure/barricade) + + // Attacker --> Victim --> Empty space --> Wall + attacker.forceMove(run_loc_bottom_left) + victim.forceMove(locate(run_loc_bottom_left.x + 1, run_loc_bottom_left.y, run_loc_bottom_left.z)) + dense_object.forceMove(locate(run_loc_bottom_left.x + 3, run_loc_bottom_left.y, run_loc_bottom_left.z)) + + // First disarm, world should now look like: + // Attacker --> Empty space --> Victim --> Wall + victim.attack_hand(attacker) + + TEST_ASSERT_EQUAL(victim.loc.x, run_loc_bottom_left.x + 2, "Victim wasn't moved back after being pushed") + TEST_ASSERT(!victim.has_status_effect(STATUS_EFFECT_KNOCKDOWN), "Victim was knocked down despite not being against a wall") + TEST_ASSERT_EQUAL(victim.get_active_held_item(), toolbox, "Victim dropped toolbox despite not being against a wall") + + attacker.forceMove(get_step(attacker, EAST)) + + // Second disarm, victim was against wall and should be down + victim.attack_hand(attacker) + + TEST_ASSERT_EQUAL(victim.loc.x, run_loc_bottom_left.x + 2, "Victim was moved after being pushed against a wall") + TEST_ASSERT(victim.has_status_effect(STATUS_EFFECT_KNOCKDOWN), "Victim was not knocked down after being pushed against a wall") + TEST_ASSERT_EQUAL(victim.get_active_held_item(), null, "Victim didn't drop toolbox after being pushed against a wall") diff --git a/code/modules/unit_tests/confusion.dm b/code/modules/unit_tests/confusion.dm new file mode 100644 index 0000000000..8282493c96 --- /dev/null +++ b/code/modules/unit_tests/confusion.dm @@ -0,0 +1,16 @@ +// Checks that the confusion symptom correctly gives, and removes, confusion +/datum/unit_test/confusion_symptom/Run() + var/mob/living/carbon/human/H = allocate(/mob/living/carbon/human) + var/datum/disease/advance/confusion/disease = allocate(/datum/disease/advance/confusion) + var/datum/symptom/confusion/confusion = disease.symptoms[1] + disease.processing = TRUE + disease.update_stage(5) + disease.infect(H, make_copy = FALSE) + confusion.Activate(disease) + TEST_ASSERT(H.get_confusion() > 0, "Human is not confused after getting symptom.") + disease.cure() + TEST_ASSERT_EQUAL(H.get_confusion(), 0, "Human is still confused after curing confusion.") + +/datum/disease/advance/confusion/New() + symptoms += new /datum/symptom/confusion + Refresh() diff --git a/code/modules/unit_tests/emoting.dm b/code/modules/unit_tests/emoting.dm new file mode 100644 index 0000000000..5795ab3437 --- /dev/null +++ b/code/modules/unit_tests/emoting.dm @@ -0,0 +1,25 @@ +/datum/unit_test/emoting + var/emotes_used = 0 + +/datum/unit_test/emoting/Run() + var/mob/living/carbon/human/human = allocate(/mob/living/carbon/human) + RegisterSignal(human, COMSIG_MOB_EMOTE, .proc/on_emote_used) + + human.say("*shrug") + TEST_ASSERT_EQUAL(emotes_used, 1, "Human did not shrug") + + human.say("*beep") + TEST_ASSERT_EQUAL(emotes_used, 1, "Human beeped, when that should be restricted to silicons") + + human.setOxyLoss(140) + + TEST_ASSERT(human.stat != CONSCIOUS, "Human is somehow conscious after receiving suffocation damage") + + human.say("*shrug") + TEST_ASSERT_EQUAL(emotes_used, 1, "Human shrugged while unconscious") + + human.say("*deathgasp") + TEST_ASSERT_EQUAL(emotes_used, 2, "Human could not deathgasp while unconscious") + +/datum/unit_test/emoting/proc/on_emote_used() + emotes_used += 1 diff --git a/code/modules/unit_tests/heretic_knowledge.dm b/code/modules/unit_tests/heretic_knowledge.dm new file mode 100644 index 0000000000..a433bce1ec --- /dev/null +++ b/code/modules/unit_tests/heretic_knowledge.dm @@ -0,0 +1,21 @@ +/// This test checks all heretic knowledge nodes - excluding the ones which are unreachable on purpose - and ensures players can reach them in game. +/// If it finds a node that is unreachable, it throws an error. +/datum/unit_test/heretic_knowledge/Run() + ///List of all knowledge excluding the unreachable base types. + var/list/blacklist = list(/datum/eldritch_knowledge/spell,/datum/eldritch_knowledge/curse,/datum/eldritch_knowledge/final,/datum/eldritch_knowledge/summon) + var/list/all_possible_knowledge = subtypesof(/datum/eldritch_knowledge) - blacklist + + var/list/list_to_check = GLOB.heretic_start_knowledge.Copy() + var/i = 0 + while(i < length(list_to_check)) + var/datum/eldritch_knowledge/eldritch_knowledge = allocate(list_to_check[++i]) + for(var/next_knowledge in eldritch_knowledge.next_knowledge) + if(next_knowledge in list_to_check) + continue + list_to_check += next_knowledge + + if(length(all_possible_knowledge) != length(all_possible_knowledge & list_to_check)) + var/list/unreachables = all_possible_knowledge - list_to_check + for(var/X in unreachables) + var/datum/eldritch_knowledge/eldritch_knowledge = X + Fail("[initial(eldritch_knowledge.name)] is unreachable by players! Add it to the blacklist in /code/modules/unit_tests/heretic_knowledge.dm if it is purposeful!") diff --git a/code/modules/unit_tests/holidays.dm b/code/modules/unit_tests/holidays.dm new file mode 100644 index 0000000000..4df5443e2e --- /dev/null +++ b/code/modules/unit_tests/holidays.dm @@ -0,0 +1,33 @@ +// test Jewish holiday +/datum/unit_test/hanukkah_2123/Run() + var/datum/holiday/hebrew/hanukkah/hanukkah = new + TEST_ASSERT(hanukkah.shouldCelebrate(14, DECEMBER, 2123, 2, TUESDAY), "December 14, 2123 was not Hanukkah.") + +// test Islamic holiday +/datum/unit_test/ramadan_2165/Run() + var/datum/holiday/islamic/ramadan/ramadan = new + TEST_ASSERT(ramadan.shouldCelebrate(6, NOVEMBER, 2165, 1, WEDNESDAY), "November 6, 2165 was not Ramadan.") + +// nth day of week +/datum/unit_test/thanksgiving_2020/Run() + var/datum/holiday/nth_week/thanksgiving/thanksgiving = new + TEST_ASSERT(thanksgiving.shouldCelebrate(26, NOVEMBER, 2020, 4, THURSDAY), "November 26, 2020 was not Thanksgiving.") + +// another nth day of week +/datum/unit_test/indigenous_3683/Run() + var/datum/holiday/nth_week/indigenous/indigenous = new + TEST_ASSERT(indigenous.shouldCelebrate(11, OCTOBER, 3683, 2, MONDAY), "October 11, 3683 was not Indigenous Peoples' Day.") + +// plain old simple holiday +/datum/unit_test/hello_2020/Run() + var/datum/holiday/hello/hello = new + TEST_ASSERT(hello.shouldCelebrate(21, NOVEMBER, 2020, 3, SATURDAY), "November 21, 2020 was not Hello day.") + +// holiday which goes across months +/datum/unit_test/new_year_1983/Run() + var/datum/holiday/new_year/new_year = new + TEST_ASSERT(new_year.shouldCelebrate(2, JANUARY, 1983, 1, SUNDAY), "January 2, 1983 was not New Year.") + +/datum/unit_test/moth_week_2020/Run() + var/datum/holiday/moth/moth = new + TEST_ASSERT(moth.shouldCelebrate(19, JULY, 2020, 3, SATURDAY), "July 19, 2020 was not Moth Week.") diff --git a/code/modules/unit_tests/initialize_sanity.dm b/code/modules/unit_tests/initialize_sanity.dm new file mode 100644 index 0000000000..d183f530c8 --- /dev/null +++ b/code/modules/unit_tests/initialize_sanity.dm @@ -0,0 +1,11 @@ +/datum/unit_test/initialize_sanity/Run() + if(length(SSatoms.BadInitializeCalls)) + Fail("Bad Initialize() calls detected. Please read logs.") + var/list/init_failures_to_text = list( + "[BAD_INIT_QDEL_BEFORE]" = "Qdeleted Before Initialized", + "[BAD_INIT_DIDNT_INIT]" = "Did Not Initialize", + "[BAD_INIT_SLEPT]" = "Initialize() Slept", + "[BAD_INIT_NO_HINT]" = "No Initialize() Hint Returned", + ) + for(var/failure in SSatoms.BadInitializeCalls) + log_world("[failure]: [init_failures_to_text["[SSatoms.BadInitializeCalls[failure]]"]]") // You like stacked brackets? diff --git a/code/modules/unit_tests/keybinding_init.dm b/code/modules/unit_tests/keybinding_init.dm new file mode 100644 index 0000000000..2bd2fdee1e --- /dev/null +++ b/code/modules/unit_tests/keybinding_init.dm @@ -0,0 +1,6 @@ +/datum/unit_test/keybinding_init/Run() + for(var/i in subtypesof(/datum/keybinding)) + var/datum/keybinding/KB = i + if(initial(KB.keybind_signal) || !initial(KB.name)) + continue + Fail("[KB.name] does not have a keybind signal defined.") diff --git a/code/modules/unit_tests/machine_disassembly.dm b/code/modules/unit_tests/machine_disassembly.dm index bcc769bcf2..59edb4ae9d 100644 --- a/code/modules/unit_tests/machine_disassembly.dm +++ b/code/modules/unit_tests/machine_disassembly.dm @@ -3,11 +3,10 @@ var/obj/machinery/freezer = allocate(/obj/machinery/atmospherics/components/unary/thermomachine/freezer) var/turf/freezer_location = freezer.loc - freezer_location.ChangeTurf(/turf/open/floor/plasteel) freezer.deconstruct() // Check that the components are created TEST_ASSERT(locate(/obj/item/stock_parts/micro_laser) in freezer_location, "Couldn't find micro-laser when disassembling freezer") // Check that the circuit board itself is created - TEST_ASSERT(locate(/obj/item/circuitboard/machine/thermomachine/freezer) in freezer_location, "Couldn't find the circuit board when disassembling freezer") + TEST_ASSERT(locate(/obj/item/circuitboard/machine/thermomachine) in freezer_location, "Couldn't find the circuit board when disassembling freezer") diff --git a/code/modules/unit_tests/merge_type.dm b/code/modules/unit_tests/merge_type.dm new file mode 100644 index 0000000000..ba3cfcf492 --- /dev/null +++ b/code/modules/unit_tests/merge_type.dm @@ -0,0 +1,15 @@ +/datum/unit_test/merge_type/Run() + var/list/blacklist = list(/obj/item/stack/sheet, + /obj/item/stack/sheet/mineral, + /obj/item/stack/ore, + /obj/item/stack/spacecash, + // /obj/item/stack/license_plates, + /obj/item/stack/tile/mineral, + /obj/item/stack/tile) + + var/list/paths = subtypesof(/obj/item/stack) - blacklist + + for(var/stackpath in paths) + var/obj/item/stack/stack = stackpath + if(!initial(stack.merge_type)) + Fail("([stack]) lacks set merge_type variable!") diff --git a/code/modules/unit_tests/metabolizing.dm b/code/modules/unit_tests/metabolizing.dm index 895762c0ec..b7f8fc4f6a 100644 --- a/code/modules/unit_tests/metabolizing.dm +++ b/code/modules/unit_tests/metabolizing.dm @@ -17,3 +17,22 @@ /datum/unit_test/metabolization/Destroy() SSmobs.ignite() return ..() + +/datum/unit_test/on_mob_end_metabolize/Run() + var/mob/living/carbon/human/user = allocate(/mob/living/carbon/human) + var/obj/item/reagent_containers/pill/pill = allocate(/obj/item/reagent_containers/pill) + var/datum/reagent/drug/methamphetamine/meth = /datum/reagent/drug/methamphetamine + + // Give them enough meth to be consumed in 2 metabolizations + pill.reagents.add_reagent(meth, initial(meth.metabolization_rate) * 1.9) + pill.attack(user, user) + + user.Life() + + TEST_ASSERT(user.reagents.has_reagent(meth), "User does not have meth in their system after consuming it") + TEST_ASSERT(user.has_movespeed_modifier(/datum/movespeed_modifier/reagent/methamphetamine), "User consumed meth, but did not gain movespeed modifier") + + user.Life() + + TEST_ASSERT(!user.reagents.has_reagent(meth), "User still has meth in their system when it should've finished metabolizing") + TEST_ASSERT(!user.has_movespeed_modifier(/datum/movespeed_modifier/reagent/methamphetamine), "User still has movespeed modifier despite not containing any more meth") diff --git a/code/modules/unit_tests/outfit_sanity.dm b/code/modules/unit_tests/outfit_sanity.dm index 235820f9e9..57ce22434e 100644 --- a/code/modules/unit_tests/outfit_sanity.dm +++ b/code/modules/unit_tests/outfit_sanity.dm @@ -30,8 +30,8 @@ CHECK_OUTFIT_SLOT(glasses, ITEM_SLOT_EYES) CHECK_OUTFIT_SLOT(id, ITEM_SLOT_ID) CHECK_OUTFIT_SLOT(suit_store, ITEM_SLOT_SUITSTORE) - CHECK_OUTFIT_SLOT(l_pocket, ITEM_SLOT_POCKET) - CHECK_OUTFIT_SLOT(r_pocket, ITEM_SLOT_POCKET) + CHECK_OUTFIT_SLOT(l_pocket, ITEM_SLOT_LPOCKET) + CHECK_OUTFIT_SLOT(r_pocket, ITEM_SLOT_RPOCKET) if (outfit.backpack_contents || outfit.box) var/list/backpack_contents = outfit.backpack_contents?.Copy() diff --git a/code/modules/unit_tests/pills.dm b/code/modules/unit_tests/pills.dm new file mode 100644 index 0000000000..ed8f64ce95 --- /dev/null +++ b/code/modules/unit_tests/pills.dm @@ -0,0 +1,10 @@ +/datum/unit_test/pills/Run() + var/mob/living/carbon/human/human = allocate(/mob/living/carbon/human) + var/obj/item/reagent_containers/pill/iron/pill = allocate(/obj/item/reagent_containers/pill/iron) + + TEST_ASSERT_EQUAL(human.has_reagent(/datum/reagent/iron), FALSE, "Human somehow has iron before taking pill") + + pill.attack(human, human) + human.Life() + + TEST_ASSERT(human.has_reagent(/datum/reagent/iron), "Human doesn't have iron after taking pill") diff --git a/code/modules/unit_tests/projectiles.dm b/code/modules/unit_tests/projectiles.dm new file mode 100644 index 0000000000..53ceef01d6 --- /dev/null +++ b/code/modules/unit_tests/projectiles.dm @@ -0,0 +1,5 @@ +/datum/unit_test/projectile_movetypes/Run() + for(var/path in typesof(/obj/item/projectile)) + var/obj/projectile/projectile = path + if(initial(projectile.movement_type) & PHASING) + Fail("[path] has default movement type PHASING. Piercing projectiles should be done using the projectile piercing system, not movement_types!") diff --git a/code/modules/unit_tests/reagent_mod_expose.dm b/code/modules/unit_tests/reagent_mod_expose.dm new file mode 100644 index 0000000000..3fe02e044d --- /dev/null +++ b/code/modules/unit_tests/reagent_mod_expose.dm @@ -0,0 +1,59 @@ +// testing the mob expose procs are working + +/datum/reagent/method_patch_test + name = "method patch test" + +/datum/reagent/method_patch_test/expose_mob(mob/living/target, methods = PATCH, reac_volume, show_message = TRUE) + . = ..() + if(methods & PATCH) + target.health = 90 + if(methods & INJECT) + target.health = 80 + +/datum/unit_test/reagent_mob_expose/Run() + // Life() is handled just by tests + SSmobs.pause() + + var/mob/living/carbon/human/human = allocate(/mob/living/carbon/human) + var/obj/item/reagent_containers/dropper/dropper = allocate(/obj/item/reagent_containers/dropper) + var/obj/item/reagent_containers/food/drinks/drink = allocate(/obj/item/reagent_containers/food/drinks/bottle) + var/obj/item/reagent_containers/pill/patch/patch = allocate(/obj/item/reagent_containers/pill/patch) + var/obj/item/reagent_containers/syringe/syringe = allocate(/obj/item/reagent_containers/syringe) + + // INGEST + TEST_ASSERT_EQUAL(human.fire_stacks, 0, "Human has fire stacks before taking phlogiston") + drink.reagents.add_reagent(/datum/reagent/phlogiston, 10) + drink.attack(human, human) + TEST_ASSERT_EQUAL(human.fire_stacks, 1, "Human does not have fire stacks after taking phlogiston") + human.Life() + TEST_ASSERT(human.fire_stacks > 1, "Human fire stacks did not increase after life tick") + + // TOUCH + dropper.reagents.add_reagent(/datum/reagent/water, 1) + dropper.afterattack(human, human, TRUE) + TEST_ASSERT_EQUAL(human.fire_stacks, 0, "Human still has fire stacks after touching water") + + // VAPOR + TEST_ASSERT_EQUAL(human.drowsyness, 0, "Human is drowsy at the start of testing") + drink.reagents.clear_reagents() + drink.reagents.add_reagent(/datum/reagent/nitrous_oxide, 10) + drink.reagents.trans_to(human, 10, methods = VAPOR) + TEST_ASSERT_NOTEQUAL(human.drowsyness, 0, "Human is not drowsy after exposure to vapors") + + // PATCH + human.health = 100 + TEST_ASSERT_EQUAL(human.health, 100, "Human health did not set properly") + patch.reagents.add_reagent(/datum/reagent/method_patch_test, 1) + patch.self_delay = 0 + patch.attack(human, human) + TEST_ASSERT_EQUAL(human.health, 90, "Human health did not update after patch was applied") + + // INJECT + syringe.reagents.add_reagent(/datum/reagent/method_patch_test, 1) + syringe.mode = SYRINGE_INJECT + syringe.afterattack(human, human, TRUE) + TEST_ASSERT_EQUAL(human.health, 80, "Human health did not update after injection from syringe") + +/datum/unit_test/reagent_mob_expose/Destroy() + SSmobs.ignite() + return ..() diff --git a/code/modules/unit_tests/reagent_mod_procs.dm b/code/modules/unit_tests/reagent_mod_procs.dm new file mode 100644 index 0000000000..a2087f8624 --- /dev/null +++ b/code/modules/unit_tests/reagent_mod_procs.dm @@ -0,0 +1,12 @@ +/datum/unit_test/reagent_mob_procs/Run() + var/mob/living/carbon/human/human = allocate(/mob/living/carbon/human) + var/obj/item/food/hotdog/debug/fooditem = allocate(/obj/item/food/hotdog/debug) + + TEST_ASSERT_EQUAL(human.has_reagent(/datum/reagent/consumable/ketchup), FALSE, "Human somehow has ketchup before eating") + TEST_ASSERT_EQUAL(human.has_reagent(/datum/reagent/medicine/epinephrine), FALSE, "Human somehow has epinephrine before injecting") + + fooditem.attack(human, human) + human.reagents.add_reagent(/datum/reagent/medicine/epinephrine, 5) + + TEST_ASSERT(human.has_reagent(/datum/reagent/consumable/ketchup), "Human doesn't have ketchup after eating") + TEST_ASSERT(human.has_reagent(/datum/reagent/medicine/epinephrine), "Human doesn't have epinephrine after injecting") diff --git a/code/modules/unit_tests/say.dm b/code/modules/unit_tests/say.dm index 3fe6675ab4..a7df5ad624 100644 --- a/code/modules/unit_tests/say.dm +++ b/code/modules/unit_tests/say.dm @@ -10,7 +10,6 @@ test(";%Never gonna give you up", "Never gonna give you up", list(MODE_HEADSET = TRUE, MODE_SING = TRUE)) test(".s Gun plz", "Gun plz", list(RADIO_KEY = RADIO_KEY_SECURITY, RADIO_EXTENSION = RADIO_CHANNEL_SECURITY)) test("...What", "...What", list()) - //note to lettern: add the ++, ||, __, and the verb*text checks /datum/unit_test/get_message_mods/proc/test(message, expected_message, list/expected_mods) var/list/mods = list() diff --git a/code/modules/unit_tests/serving_tray.dm b/code/modules/unit_tests/serving_tray.dm new file mode 100644 index 0000000000..00e911ae50 --- /dev/null +++ b/code/modules/unit_tests/serving_tray.dm @@ -0,0 +1,47 @@ +/** + * Check that standard food items fit on the serving tray + */ +/datum/unit_test/servingtray/Run() + var/mob/living/carbon/human/human = allocate(/mob/living/carbon/human) + var/obj/structure/table/the_table = allocate(/obj/structure/table) + var/obj/item/storage/bag/tray/test_tray = allocate(/obj/item/storage/bag/tray) + var/obj/item/reagent_containers/food/banana = allocate(/obj/item/food/rationpack) + var/obj/item/food/the_bread = allocate(/obj/item/food/breadslice) + var/obj/item/reagent_containers/food/sugarcookie = allocate(/obj/item/food/cookie/sugar) + var/obj/item/clothing/under/jumpsuit = allocate(/obj/item/clothing/under/color/black) + + TEST_ASSERT_EQUAL((the_bread in test_tray.contents), FALSE, "The bread is on the serving tray at test start") + + // set the tray to single item mode the dirty way + var/datum/component/storage/tray_storage = test_tray.GetComponent(/datum/component/storage) + tray_storage.collection_mode = COLLECT_ONE + + test_tray.pre_attack(the_bread, human) + + TEST_ASSERT_EQUAL((the_bread in test_tray.contents), TRUE, "The bread did not get picked up by the serving tray") + + test_tray.pre_attack(banana, human) + + TEST_ASSERT_EQUAL((banana in test_tray.contents), TRUE, "The banana did not get picked up by the serving tray") + + the_table.attackby(test_tray, human) + + TEST_ASSERT_EQUAL(test_tray.contents.len, 0, "The serving tray did not drop all items on hitting the table") + + test_tray.pre_attack(sugarcookie, human) + + TEST_ASSERT_EQUAL((sugarcookie in test_tray.contents), TRUE, "The sugarcookie did not get picked up by the serving tray") + + human.equip_to_slot(jumpsuit, ITEM_SLOT_ICLOTHING) + TEST_ASSERT(human.get_item_by_slot(ITEM_SLOT_ICLOTHING), "Human does not have jumpsuit on") + + human.equip_to_slot(test_tray, ITEM_SLOT_LPOCKET) + TEST_ASSERT(human.get_item_by_slot(ITEM_SLOT_LPOCKET), "Serving tray failed to fit in the Left Pocket") + + human.equip_to_slot(test_tray, ITEM_SLOT_RPOCKET) + TEST_ASSERT(human.get_item_by_slot(ITEM_SLOT_RPOCKET), "Serving tray failed to fit in the Right Pocket") + + test_tray.attack(human, human) + + TEST_ASSERT_EQUAL(test_tray.contents.len, 0, "The serving tray did not drop all items on hitting a human") + diff --git a/code/modules/unit_tests/siunit.dm b/code/modules/unit_tests/siunit.dm new file mode 100644 index 0000000000..3a7a25a98d --- /dev/null +++ b/code/modules/unit_tests/siunit.dm @@ -0,0 +1,15 @@ +/datum/unit_test/siunit/Run() + TEST_ASSERT_EQUAL(siunit(0.5345, "A", 0), "535 mA", "") + TEST_ASSERT_EQUAL(siunit(0.5344, "A", 0), "534 mA", "") + TEST_ASSERT_EQUAL(siunit(-0.5344, "A", 0), "-534 mA", "") + TEST_ASSERT_EQUAL(siunit_pressure(1.234, 1), "1.2 kPa", "") // test for pascal require *10e-3, as the game thinks in kPa, the proc siunit in Pa + TEST_ASSERT_EQUAL(siunit_pressure(1.234, 2), "1.23 kPa", "") + TEST_ASSERT_EQUAL(siunit_pressure(1.234, 3), "1.234 kPa", "") + TEST_ASSERT_EQUAL(siunit_pressure(1, 4), "1 kPa", "") + TEST_ASSERT_EQUAL(siunit_pressure(0), "0 Pa", "") + TEST_ASSERT_EQUAL(siunit_pressure(1e3), "1 MPa", "") + TEST_ASSERT_EQUAL(siunit_pressure(999e3), "999 MPa", "") + TEST_ASSERT_EQUAL(siunit_pressure(999.9e3), "999.9 MPa" , "") + TEST_ASSERT_EQUAL(siunit_pressure(999.9e3, 0), "1 GPa", "") + TEST_ASSERT_EQUAL(siunit_pressure(1e6), "1 GPa", "") + TEST_ASSERT_EQUAL(siunit_pressure(3e17), "300000 PPa", "") diff --git a/code/modules/unit_tests/spawn_humans.dm b/code/modules/unit_tests/spawn_humans.dm index 7189e87277..0500deae0a 100644 --- a/code/modules/unit_tests/spawn_humans.dm +++ b/code/modules/unit_tests/spawn_humans.dm @@ -1,7 +1,7 @@ /datum/unit_test/spawn_humans/Run() - var/locs = block(run_loc_bottom_left, run_loc_top_right) + var/locs = block(run_loc_bottom_left, run_loc_top_right) - for(var/I in 1 to 5) - new /mob/living/carbon/human(pick(locs)) + for(var/I in 1 to 5) + new /mob/living/carbon/human(pick(locs)) - sleep(50) + sleep(50) diff --git a/code/modules/unit_tests/species_whitelists.dm b/code/modules/unit_tests/species_whitelists.dm new file mode 100644 index 0000000000..145f3a259f --- /dev/null +++ b/code/modules/unit_tests/species_whitelists.dm @@ -0,0 +1,5 @@ +/datum/unit_test/species_whitelist_check/Run() + for(var/typepath in subtypesof(/datum/species)) + var/datum/species/S = typepath + if(initial(S.changesource_flags) == NONE) + Fail("A species type was detected with no changesource flags: [S]") diff --git a/code/modules/unit_tests/stomach.dm b/code/modules/unit_tests/stomach.dm new file mode 100644 index 0000000000..06fdc71dd4 --- /dev/null +++ b/code/modules/unit_tests/stomach.dm @@ -0,0 +1,40 @@ +/datum/unit_test/stomach/Run() + + // Pause natural mob life so it can be handled entirely by the test + SSmobs.pause() + + var/mob/living/carbon/human/human = allocate(/mob/living/carbon/human) + var/obj/item/food/hotdog/debug/fooditem = allocate(/obj/item/food/hotdog/debug) + var/obj/item/organ/stomach/belly = human.getorganslot(ORGAN_SLOT_STOMACH) + var/obj/item/reagent_containers/pill/pill = allocate(/obj/item/reagent_containers/pill) + var/datum/reagent/drug/methamphetamine/meth = /datum/reagent/drug/methamphetamine + + TEST_ASSERT_EQUAL(human.has_reagent(/datum/reagent/consumable/ketchup), FALSE, "Human somehow has ketchup before eating") + + fooditem.attack(human, human) + + TEST_ASSERT(belly.reagents.has_reagent(/datum/reagent/consumable/ketchup), "Stomach doesn't have ketchup after eating") + TEST_ASSERT_EQUAL(human.reagents.has_reagent(/datum/reagent/consumable/ketchup), FALSE, "Human body has ketchup after eating it should only be in the stomach") + + //Give them meth and let it kick in + pill.reagents.add_reagent(meth, initial(meth.metabolization_rate) * 1.9) + pill.attack(human, human) + human.Life() + + TEST_ASSERT(human.reagents.has_reagent(meth), "Human body does not have meth after life tick") + TEST_ASSERT(human.has_movespeed_modifier(/datum/movespeed_modifier/reagent/methamphetamine), "Human consumed meth, but did not gain movespeed modifier") + + belly.Remove(human) + human.reagents.remove_all(human.reagents.total_volume) + + TEST_ASSERT_EQUAL(human.has_reagent(/datum/reagent/consumable/ketchup), FALSE, "Human has reagents after clearing") + + fooditem.attack(human, human) + + TEST_ASSERT_EQUAL(human.has_reagent(/datum/reagent/consumable/ketchup), FALSE, "Human has ketchup without a stomach") + + + +/datum/unit_test/stomach/Destroy() + SSmobs.ignite() + return ..() diff --git a/code/modules/unit_tests/surgeries.dm b/code/modules/unit_tests/surgeries.dm index 7b8145ac19..6348057f79 100644 --- a/code/modules/unit_tests/surgeries.dm +++ b/code/modules/unit_tests/surgeries.dm @@ -2,14 +2,14 @@ var/mob/living/carbon/human/patient = allocate(/mob/living/carbon/human) var/mob/living/carbon/human/user = allocate(/mob/living/carbon/human) - TEST_ASSERT_EQUAL(patient.get_missing_limbs().len, 0, "Patient is somehow missing limbs before surgery") + TEST_ASSERT_EQUAL(length(patient.get_missing_limbs()), 0, "Patient is somehow missing limbs before surgery") var/datum/surgery/amputation/surgery = new(patient, BODY_ZONE_R_ARM, patient.get_bodypart(BODY_ZONE_R_ARM)) var/datum/surgery_step/sever_limb/sever_limb = new sever_limb.success(user, patient, BODY_ZONE_R_ARM, null, surgery) - TEST_ASSERT_EQUAL(patient.get_missing_limbs().len, 1, "Patient did not lose any limbs") + TEST_ASSERT_EQUAL(length(patient.get_missing_limbs()), 1, "Patient did not lose any limbs") TEST_ASSERT_EQUAL(patient.get_missing_limbs()[1], BODY_ZONE_R_ARM, "Patient is missing a limb that isn't the one we operated on") /datum/unit_test/brain_surgery/Run() @@ -27,6 +27,33 @@ TEST_ASSERT(!patient.has_trauma_type(), "Patient kept their brain trauma after brain surgery") TEST_ASSERT(patient.getOrganLoss(ORGAN_SLOT_BRAIN) < 20, "Patient did not heal their brain damage after brain surgery") +/datum/unit_test/head_transplant/Run() + var/mob/living/carbon/human/user = allocate(/mob/living/carbon/human) + var/mob/living/carbon/human/alice = allocate(/mob/living/carbon/human) + var/mob/living/carbon/human/bob = allocate(/mob/living/carbon/human) + + alice.fully_replace_character_name(null, "Alice") + bob.fully_replace_character_name(null, "Bob") + + var/obj/item/bodypart/head/alices_head = alice.get_bodypart(BODY_ZONE_HEAD) + alices_head.drop_limb() + + var/obj/item/bodypart/head/bobs_head = bob.get_bodypart(BODY_ZONE_HEAD) + bobs_head.drop_limb() + + TEST_ASSERT_EQUAL(alice.get_bodypart(BODY_ZONE_HEAD), null, "Alice still has a head after dismemberment") + TEST_ASSERT_EQUAL(alice.get_visible_name(), "Unknown", "Alice's head was dismembered, but they are not Unknown") + + TEST_ASSERT_EQUAL(bobs_head.real_name, "Bob", "Bob's head does not remember that it is from Bob") + + // Put Bob's head onto Alice's body + var/datum/surgery_step/add_prosthetic/add_prosthetic = new + user.put_in_active_hand(bobs_head) + add_prosthetic.success(user, alice, BODY_ZONE_HEAD, bobs_head) + + TEST_ASSERT(!isnull(alice.get_bodypart(BODY_ZONE_HEAD)), "Alice has no head after prosthetic replacement") + TEST_ASSERT_EQUAL(alice.get_visible_name(), "Bob", "Bob's head was transplanted onto Alice's body, but their name is not Bob") + /datum/unit_test/multiple_surgeries/Run() var/mob/living/carbon/human/user = allocate(/mob/living/carbon/human) var/mob/living/carbon/human/patient_zero = allocate(/mob/living/carbon/human) @@ -41,8 +68,6 @@ TEST_ASSERT(surgery_for_zero.step_in_progress, "Surgery on patient zero was not initiated") var/datum/surgery/organ_manipulation/surgery_for_one = new - - sleep(0.2) // if we don't have this, then the next surgery step can start *before* the previous one does, which is no good // Without waiting for the incision to complete, try to start a new surgery TEST_ASSERT(!surgery_step.initiate(user, patient_one, BODY_ZONE_CHEST, scalpel, surgery_for_one), "Was allowed to start a second surgery without the rod of asclepius") diff --git a/code/modules/unit_tests/teleporters.dm b/code/modules/unit_tests/teleporters.dm new file mode 100644 index 0000000000..fa2624adaa --- /dev/null +++ b/code/modules/unit_tests/teleporters.dm @@ -0,0 +1,10 @@ +/datum/unit_test/auto_teleporter_linking/Run() + // Put down the teleporter machinery + var/obj/machinery/teleport/hub/hub = allocate(/obj/machinery/teleport/hub) + var/obj/machinery/teleport/station/station = allocate(/obj/machinery/teleport/station, locate(run_loc_bottom_left.x + 1, run_loc_bottom_left.y, run_loc_bottom_left.z)) + var/obj/machinery/computer/teleporter/computer = allocate(/obj/machinery/computer/teleporter, locate(run_loc_bottom_left.x + 2, run_loc_bottom_left.y, run_loc_bottom_left.z)) + + TEST_ASSERT_EQUAL(hub.power_station, station, "Hub didn't link to the station") + TEST_ASSERT_EQUAL(station.teleporter_console, computer, "Station didn't link to the teleporter console") + TEST_ASSERT_EQUAL(station.teleporter_hub, hub, "Station didn't link to the hub") + TEST_ASSERT_EQUAL(computer.power_station, station, "Teleporter console didn't link to the hub") diff --git a/code/modules/unit_tests/unit_test.dm b/code/modules/unit_tests/unit_test.dm index 36b406e75e..15fe6b466c 100644 --- a/code/modules/unit_tests/unit_test.dm +++ b/code/modules/unit_tests/unit_test.dm @@ -1,9 +1,14 @@ /* + Usage: Override /Run() to run your test code + Call Fail() to fail the test (You should specify a reason) + You may use /New() and /Destroy() for setup/teardown respectively + You can use the run_loc_bottom_left and run_loc_top_right to get turfs for testing + */ GLOBAL_DATUM(current_test, /datum/unit_test) @@ -14,19 +19,33 @@ GLOBAL_VAR(test_log) //Bit of metadata for the future maybe var/list/procs_tested - //usable vars + /// The bottom left turf of the testing zone var/turf/run_loc_bottom_left + + /// The top right turf of the testing zone var/turf/run_loc_top_right + /// The type of turf to allocate for the testing zone + var/test_turf_type = /turf/open/floor/plasteel + //internal shit + var/focus = FALSE var/succeeded = TRUE var/list/allocated var/list/fail_reasons + var/static/datum/turf_reservation/turf_reservation + /datum/unit_test/New() + if (isnull(turf_reservation)) + turf_reservation = SSmapping.RequestBlockReservation(5, 5) + + for (var/turf/reserved_turf in turf_reservation.reserved_turfs) + reserved_turf.ChangeTurf(test_turf_type) + allocated = new - run_loc_bottom_left = locate(1, 1, 1) - run_loc_top_right = locate(5, 5, 1) + run_loc_bottom_left = locate(turf_reservation.bottom_left_coords[1], turf_reservation.bottom_left_coords[2], turf_reservation.bottom_left_coords[3]) + run_loc_top_right = locate(turf_reservation.top_right_coords[1], turf_reservation.top_right_coords[2], turf_reservation.top_right_coords[3]) /datum/unit_test/Destroy() //clear the test area @@ -61,7 +80,14 @@ GLOBAL_VAR(test_log) /proc/RunUnitTests() CHECK_TICK - for(var/I in subtypesof(/datum/unit_test)) + var/tests_to_run = subtypesof(/datum/unit_test) + for (var/_test_to_run in tests_to_run) + var/datum/unit_test/test_to_run = _test_to_run + if (initial(test_to_run.focus)) + tests_to_run = list(test_to_run) + break + + for(var/I in tests_to_run) var/datum/unit_test/test = new I GLOB.current_test = test diff --git a/code/modules/uplink/uplink_items/uplink_roles.dm b/code/modules/uplink/uplink_items/uplink_roles.dm index b384106396..4edbe2f2c7 100644 --- a/code/modules/uplink/uplink_items/uplink_roles.dm +++ b/code/modules/uplink/uplink_items/uplink_roles.dm @@ -142,6 +142,14 @@ cost = 4 // Has syndie tools + gloves + a robust weapon restricted_roles = list("Assistant", "Curator") //Curator due to this being made of gold - It fits the theme +/datum/uplink_item/role_restricted/oldtoolboxclean // this is the fourth item relating to toolboxes to be placed into this godforsaken bloated uplink + name = "Ancient Toolbox" + desc = "An iconic toolbox design notorious with Assistants everywhere, this design was especially made to become more robust the more telecrystals it has inside it! Tools and insulated gloves included." + item = /obj/item/storage/toolbox/mechanical/old/clean + cost = 2 // with eighteen telecrystals you are still weaker than a desword and without any of its defenses -- the scary part comes from collaborating with allies for a fifty eight force toolbox oh fuck + restricted_roles = list("Assistant") + surplus = 0 + /datum/uplink_item/role_restricted/mimery name = "Guide to Advanced Mimery Series" desc = "The classical two part series on how to further hone your mime skills. Upon studying the series, the user should be able to make 3x1 invisible walls, and shoot bullets out of their fingers. \ @@ -242,3 +250,11 @@ cost = 2 item = /obj/item/clothing/shoes/magboots/crushing restricted_roles = list("Chief Engineer", "Station Engineer", "Atmospheric Technician") + +/datum/uplink_item/role_restricted/turretbox + name = "Disposable Sentry Gun" + desc = "A disposable sentry gun deployment system cleverly disguised as a toolbox, apply wrench for functionality." + item = /obj/item/storage/toolbox/emergency/turret + cost = 11 + restricted_roles = list("Station Engineer") + diff --git a/code/modules/vehicles/cars/clowncar.dm b/code/modules/vehicles/cars/clowncar.dm index 7a7886e999..0b75dbf4db 100644 --- a/code/modules/vehicles/cars/clowncar.dm +++ b/code/modules/vehicles/cars/clowncar.dm @@ -18,14 +18,12 @@ . = ..() initialize_controller_action_type(/datum/action/vehicle/sealed/horn/clowncar, VEHICLE_CONTROL_DRIVE) - /obj/vehicle/sealed/car/clowncar/driver_move(mob/user, direction) //Prevent it from moving onto space if(isspaceturf(get_step(src, direction))) return FALSE else return ..() - /obj/vehicle/sealed/car/clowncar/auto_assign_occupant_flags(mob/M) if(ishuman(M)) var/mob/living/carbon/human/H = M @@ -138,3 +136,25 @@ /obj/vehicle/sealed/car/clowncar/proc/StopDroppingOil() droppingoil = FALSE + +/obj/vehicle/sealed/car/clowncar/twitch_plays + key_type = null + explode_on_death = FALSE + +/obj/vehicle/sealed/car/clowncar/twitch_plays/Initialize() + . = ..() + AddComponent(/datum/component/twitch_plays/simple_movement) + START_PROCESSING(SSfastprocess, src) + GLOB.poi_list |= src + notify_ghosts("Twitch Plays: Clown Car") + +/obj/vehicle/sealed/car/clowncar/twitch_plays/Destroy() + STOP_PROCESSING(SSfastprocess, src) + GLOB.poi_list -= src + return ..() + +/obj/vehicle/sealed/car/clowncar/twitch_plays/process() + var/dir = SEND_SIGNAL(src, COMSIG_TWITCH_PLAYS_MOVEMENT_DATA, TRUE) + if(!dir) + return + driver_move(null, dir) diff --git a/code/modules/vehicles/sealed.dm b/code/modules/vehicles/sealed.dm index 28f6b1cca8..63c7c9f858 100644 --- a/code/modules/vehicles/sealed.dm +++ b/code/modules/vehicles/sealed.dm @@ -1,6 +1,7 @@ /obj/vehicle/sealed enclosed = TRUE // you're in a sealed vehicle dont get dinked idiot var/enter_delay = 20 + var/explode_on_death = TRUE flags_1 = BLOCK_FACE_ATOM_1 /obj/vehicle/sealed/generate_actions() @@ -87,7 +88,8 @@ /obj/vehicle/sealed/Destroy() DumpMobs() - explosion(loc, 0, 1, 2, 3, 0) + if(explode_on_death) + explosion(loc, 0, 1, 2, 3, 0) return ..() /obj/vehicle/sealed/proc/DumpMobs(randomstep = TRUE) diff --git a/code/modules/vending/kinkmate.dm b/code/modules/vending/kinkmate.dm index e522583772..56d794e341 100644 --- a/code/modules/vending/kinkmate.dm +++ b/code/modules/vending/kinkmate.dm @@ -2,7 +2,6 @@ name = "KinkMate" desc = "A vending machine for all your unmentionable desires." icon_state = "kink" - circuit = /obj/item/circuitboard/machine/kinkmate product_slogans = "Kinky!;Sexy!;Check me out, big boy!" vend_reply = "Have fun, you shameless pervert!" products = list( diff --git a/code/modules/vending/medical.dm b/code/modules/vending/medical.dm index 795d35adc4..a24233b17c 100644 --- a/code/modules/vending/medical.dm +++ b/code/modules/vending/medical.dm @@ -34,7 +34,8 @@ /obj/item/healthanalyzer/wound = 4, /obj/item/stack/medical/ointment = 2, /obj/item/stack/medical/suture = 2, - /obj/item/stack/medical/bone_gel = 4) + /obj/item/stack/medical/bone_gel = 4, + /obj/item/stack/medical/nanogel = 4) contraband = list(/obj/item/reagent_containers/pill/tox = 3, /obj/item/reagent_containers/pill/morphine = 4, /obj/item/reagent_containers/pill/charcoal = 6) diff --git a/code/modules/vending/medical_wall.dm b/code/modules/vending/medical_wall.dm index 31f3dc49f1..2d4c30080d 100644 --- a/code/modules/vending/medical_wall.dm +++ b/code/modules/vending/medical_wall.dm @@ -13,6 +13,7 @@ /obj/item/reagent_containers/medspray/sterilizine = 1, /obj/item/healthanalyzer/wound = 2, /obj/item/stack/medical/bone_gel = 2, + /obj/item/stack/medical/nanogel = 2, /obj/item/reagent_containers/syringe/dart = 10) contraband = list(/obj/item/reagent_containers/pill/tox = 2, /obj/item/reagent_containers/pill/morphine = 2) diff --git a/code/modules/vending/robotics.dm b/code/modules/vending/robotics.dm index 88f65506a6..2d77b2fc51 100644 --- a/code/modules/vending/robotics.dm +++ b/code/modules/vending/robotics.dm @@ -17,7 +17,8 @@ /obj/item/tank/internals/anesthetic = 2, /obj/item/clothing/mask/breath/medical = 5, /obj/item/screwdriver = 5, - /obj/item/crowbar = 5) + /obj/item/crowbar = 6, + /obj/item/stack/medical/nanogel = 5) armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50) resistance_flags = FIRE_PROOF default_price = PRICE_EXPENSIVE diff --git a/code/modules/vending/wardrobes.dm b/code/modules/vending/wardrobes.dm index e15e02f0d5..e88cfe33a3 100644 --- a/code/modules/vending/wardrobes.dm +++ b/code/modules/vending/wardrobes.dm @@ -17,8 +17,8 @@ product_ads = "Beat perps in style!;It's red so you can't see the blood!;You have the right to be fashionable!;Now you can be the fashion police you always wanted to be!" vend_reply = "Thank you for using the SecDrobe!" products = list(/obj/item/clothing/suit/hooded/wintercoat/security = 2, - /obj/item/storage/backpack/security = 2, - /obj/item/storage/backpack/satchel/sec = 2, + /obj/item/storage/backpack/security = 3, + /obj/item/storage/backpack/satchel/sec = 3, /obj/item/storage/backpack/duffelbag/sec = 3, /obj/item/clothing/under/rank/security/officer = 5, /obj/item/clothing/shoes/jackboots = 5, @@ -88,9 +88,9 @@ vend_reply = "Thank you for using the MediDrobe!" products = list(/obj/item/clothing/accessory/pocketprotector = 5, /obj/item/clothing/head/beret/med = 5, - /obj/item/storage/backpack/duffelbag/med = 5, /obj/item/storage/backpack/medic = 5, /obj/item/storage/backpack/satchel/med = 5, + /obj/item/storage/backpack/duffelbag/med = 5, /obj/item/clothing/suit/hooded/wintercoat/medical = 5, /obj/item/clothing/suit/hooded/wintercoat/paramedic = 2, /obj/item/clothing/under/rank/medical/doctor/nurse = 5, @@ -131,9 +131,9 @@ vend_reply = "Thank you for using the EngiDrobe!" products = list(/obj/item/clothing/accessory/pocketprotector = 5, /obj/item/clothing/head/beret/eng = 3, - /obj/item/storage/backpack/duffelbag/engineering = 3, /obj/item/storage/backpack/industrial = 3, /obj/item/storage/backpack/satchel/eng = 3, + /obj/item/storage/backpack/duffelbag/engineering = 3, /obj/item/clothing/suit/hooded/wintercoat/engineering = 3, /obj/item/clothing/under/rank/engineering/engineer = 5, /obj/item/clothing/under/rank/engineering/engineer/skirt = 5, @@ -162,9 +162,9 @@ vend_reply = "Thank you for using the AtmosDrobe!" products = list(/obj/item/clothing/accessory/pocketprotector = 3, /obj/item/clothing/head/beret/atmos = 3, - /obj/item/storage/backpack/duffelbag/engineering = 3, - /obj/item/storage/backpack/satchel/eng = 3, /obj/item/storage/backpack/industrial = 3, + /obj/item/storage/backpack/satchel/eng = 3, + /obj/item/storage/backpack/duffelbag/engineering = 3, /obj/item/clothing/head/hardhat/weldhat/dblue = 3, /obj/item/clothing/suit/hooded/wintercoat/engineering/atmos = 3, /obj/item/clothing/under/rank/engineering/atmospheric_technician = 5, @@ -212,7 +212,7 @@ /obj/item/clothing/under/rank/rnd/roboticist/sleek = 3, /obj/item/clothing/under/rank/rnd/roboticist/skirt = 3, /obj/item/clothing/suit/hooded/wintercoat/robotics = 3, - /obj/item/clothing/suit/toggle/labcoat = 3, + /obj/item/clothing/suit/toggle/labcoat/roboticist = 3, /obj/item/clothing/shoes/sneakers/black = 3, /obj/item/clothing/gloves/fingerless = 3, /obj/item/clothing/head/soft/black = 3, @@ -238,6 +238,7 @@ /obj/item/clothing/head/beret/sci = 3, /obj/item/storage/backpack/science = 3, /obj/item/storage/backpack/satchel/tox = 3, + /obj/item/storage/backpack/duffelbag = 3, /obj/item/clothing/suit/hooded/wintercoat/science = 3, /obj/item/clothing/under/rank/rnd/scientist = 4, /obj/item/clothing/under/rank/rnd/scientist/util = 4, @@ -261,7 +262,9 @@ product_ads = "Do you love soil? Then buy our clothes!;Get outfits to match your green thumb here!" vend_reply = "Thank you for using the Hydrobe!" products = list(/obj/item/storage/backpack/botany = 3, + /obj/item/storage/backpack = 3, /obj/item/storage/backpack/satchel/hyd = 3, + /obj/item/storage/backpack/duffelbag = 3, /obj/item/clothing/suit/hooded/wintercoat/hydro = 2, /obj/item/clothing/suit/apron = 3, /obj/item/clothing/suit/apron/overalls = 5, @@ -375,7 +378,7 @@ /obj/item/paint/paint_remover = 2, /obj/item/melee/flyswatter = 2, /obj/item/flashlight = 2, - /obj/item/caution = 8, + /obj/item/clothing/suit/caution = 8, /obj/item/holosign_creator = 2, /obj/item/lightreplacer = 2, /obj/item/soap = 2, @@ -468,7 +471,7 @@ /obj/item/storage/backpack/chemistry = 3, /obj/item/storage/backpack/satchel/chem = 3, /obj/item/storage/bag/chemistry = 3, - /obj/item/fermichem/pHbooklet = 3)//pH indicator) + /obj/item/fermichem/pHbooklet = 3) refill_canister = /obj/item/vending_refill/wardrobe/chem_wardrobe payment_department = ACCOUNT_MED cost_multiplier_per_dept = list(ACCOUNT_MED = 0) @@ -544,7 +547,7 @@ /obj/item/clothing/glasses/sunglasses/gar/supergar = 1, /obj/item/clothing/gloves/color/captain = 1) refill_canister = /obj/item/vending_refill/wardrobe/cap_wardrobe - payment_department = ACCOUNT_CIV + payment_department = ACCOUNT_SEC default_price = PRICE_ALMOST_EXPENSIVE extra_price = PRICE_ABOVE_EXPENSIVE diff --git a/code/modules/vore/eating/belly_obj.dm b/code/modules/vore/eating/belly_obj.dm index 7f8aed83ef..8e74dd3c92 100644 --- a/code/modules/vore/eating/belly_obj.dm +++ b/code/modules/vore/eating/belly_obj.dm @@ -248,7 +248,7 @@ for(var/mob/living/H in hearing_mobs) if(H && H.client && (isturf(H.loc) || (H.loc != src.contents))) var/sound/releasement = GLOB.pred_release_sounds[release_sound] - H.playsound_local(owner.loc, releasement, vol = 75, vary = 1, falloff = VORE_SOUND_FALLOFF) + H.playsound_local(owner.loc, releasement, 75, TRUE) else if(H?.client && (H in contents)) var/sound/releasement = GLOB.prey_release_sounds[release_sound] SEND_SOUND(H,releasement) @@ -304,7 +304,7 @@ for(var/mob/living/H in hearing_mobs) if(H && H.client && (isturf(H.loc) || (H.loc != src.contents))) var/sound/releasement = GLOB.pred_release_sounds[release_sound] - H.playsound_local(owner.loc, releasement, vol = 75, vary = 1, falloff = VORE_SOUND_FALLOFF) + H.playsound_local(owner.loc, releasement, 75, TRUE) else if(H?.client && (H in contents)) var/sound/releasement = GLOB.prey_release_sounds[release_sound] SEND_SOUND(H,releasement) @@ -366,7 +366,7 @@ for(var/mob/living/H in hearing_mobs) if(H && H.client && (isturf(H.loc) || (H.loc != src.contents))) var/sound/eating = GLOB.pred_vore_sounds[vore_sound] - H.playsound_local(owner.loc, eating, vol = 75, vary = 1, falloff = VORE_SOUND_FALLOFF) + H.playsound_local(owner.loc, eating, 75, TRUE) else if(H?.client && (H in contents)) var/sound/eating = GLOB.prey_vore_sounds[vore_sound] SEND_SOUND(H,eating) @@ -585,14 +585,14 @@ if(is_wet) for(var/mob/living/H in hearing_mobs) if(H && H.client && (isturf(H.loc) || (H.loc != src.contents))) - H.playsound_local(owner.loc, pred_struggle_snuggle, vol = 75, vary = 1, falloff = VORE_SOUND_FALLOFF) + H.playsound_local(owner.loc, pred_struggle_snuggle, 75, TRUE) else if(H && H.client && (H in contents)) SEND_SOUND(H,prey_struggle_snuggle) else for(var/mob/living/H in hearing_mobs) if(H && H.client) - H.playsound_local(owner.loc, struggle_rustle, vol = 75, vary = 1, falloff = VORE_SOUND_FALLOFF) + H.playsound_local(owner.loc, struggle_rustle, 75, TRUE) for(var/mob/living/H in hearing_mobs) if(H && H.client && (isturf(H.loc))) diff --git a/code/modules/vore/eating/bellymodes.dm b/code/modules/vore/eating/bellymodes.dm index 291ef8654f..7cf36ebc50 100644 --- a/code/modules/vore/eating/bellymodes.dm +++ b/code/modules/vore/eating/bellymodes.dm @@ -245,7 +245,7 @@ last_hearcheck = world.time for(var/mob/M in hearing_mobs) //so we don't fill the whole room with the sound effect if(M && M.client && (isturf(M.loc) || (M.loc != src.contents))) //to avoid people on the inside getting the outside sounds and their direct sounds + built in sound pref check - M.playsound_local(owner.loc, play_sound, vol = 75, vary = 1, falloff = VORE_SOUND_FALLOFF) + M.playsound_local(owner.loc, play_sound, 75, TRUE) //these are all external sound triggers now, so it's ok. if(to_update) for(var/mob/living/M in contents) diff --git a/code/modules/vore/eating/living.dm b/code/modules/vore/eating/living.dm index a0ae58a44d..41d7da16a1 100644 --- a/code/modules/vore/eating/living.dm +++ b/code/modules/vore/eating/living.dm @@ -359,6 +359,10 @@ if(QDELETED(tasted) || (tasted.ckey && !(tasted.client?.prefs.vore_flags & LICKABLE)) || !Adjacent(tasted) || incapacitated(ignore_restraints = TRUE)) return + if(ishuman(tasted)) + var/mob/living/carbon/human/H = tasted + H.wash_cream() + visible_message("[src] licks [tasted]!","You lick [tasted]. They taste rather like [tasted.get_taste_message()].","Slurp!") /mob/living/proc/get_taste_message(allow_generic = TRUE, datum/species/mrace) diff --git a/code/world.dm b/code/world.dm index 344ca9be79..71a9853d01 100644 --- a/code/world.dm +++ b/code/world.dm @@ -1,12 +1,22 @@ //This file is just for the necessary /world definition //Try looking in game/world.dm +/** + * # World + * + * Two possibilities exist: either we are alone in the Universe or we are not. Both are equally terrifying. ~ Arthur C. Clarke + * + * The byond world object stores some basic byond level config, and has a few hub specific procs for managing hub visiblity + * + * The world /New() is the root of where a round itself begins + */ /world mob = /mob/dead/new_player turf = /turf/open/space/basic area = /area/space view = "15x15" hub = "Exadv1.spacestation13" + hub_password = "kMZy3U5jJHSiBQjr" name = "/tg/ Station 13" fps = 20 #ifdef FIND_REF_NO_CHECK_TICK diff --git a/config/config.txt b/config/config.txt index 4f8ced5522..928b8de125 100644 --- a/config/config.txt +++ b/config/config.txt @@ -11,6 +11,7 @@ $include dynamic_config.txt $include plushies/defines.txt $include job_threats.txt $include policy.txt +$include persistence.txt $include respawns.txt # You can use the @ character at the beginning of a config option to lock it from being edited in-game diff --git a/config/game_options.txt b/config/game_options.txt index bc5fdf940e..3c53d9fecb 100644 --- a/config/game_options.txt +++ b/config/game_options.txt @@ -668,4 +668,10 @@ ALLOW_CUSTOM_SKINTONES ## Enables the FoV component, which hides objects and mobs behind the parent from their sight, unless they turn around, duh. ## Camera mobs, AIs, ghosts and some other are of course exempt from this. This also doesn't influence simplemob AI, for the best. -#USE_FIELD_OF_VISION \ No newline at end of file +#USE_FIELD_OF_VISION + +## Default turf threshold to get dirt +TURF_DIRT_THRESHOLD 100 + +## Default alpha of dirt on spawn +DIRT_ALPHA_STARTING 127 diff --git a/config/persistence.txt b/config/persistence.txt new file mode 100644 index 0000000000..7d65a150e2 --- /dev/null +++ b/config/persistence.txt @@ -0,0 +1,14 @@ +### Whether or not cleanable object persistence is on +PERSISTENT_DEBRIS + +### Whether or not ONLY persistent cleanable objects should be spawned, for supported objects +PERSISTENT_DEBRIS_ONLY + +### Max objects to store, total +PERSISTENT_DEBRIS_GLOBAL_MAX 10000 + +### Max objects to store per type, total +PERSISTENT_DEBRIS_TYPE_MAX 2000 + +### Wipe objects on nuke for the above +PERSISTENT_DEBRIS_WIPE_ON_NUKE diff --git a/config/respawns.txt b/config/respawns.txt index 337a691b07..804a856a93 100644 --- a/config/respawns.txt +++ b/config/respawns.txt @@ -25,5 +25,5 @@ RESPAWN_MINIMUM_DELAY_ROUNDSTART 30.0 ## Gamemode (config tags!) banlist for respawn RESPAWN_CHAOS_GAMEMODES WIZARD RESPAWN_CHAOS_GAMEMODES NUCLEAR -RESPAWN_CHAOS_GAMEMODES CLONWOPS -RESPAWN_CHOAS_GAMEMODES REVOLUTION +RESPAWN_CHAOS_GAMEMODES CLOWNOPS +RESPAWN_CHAOS_GAMEMODES REVOLUTION diff --git a/dependencies.sh b/dependencies.sh index 75e49f3fe1..e8709d10b1 100644 --- a/dependencies.sh +++ b/dependencies.sh @@ -11,16 +11,13 @@ export BYOND_MINOR=${LIST[1]} unset LIST #rust_g git tag -export RUST_G_VERSION=0.4.4 - -#bsql git tag -export BSQL_VERSION=v1.4.0.0 +export RUST_G_VERSION=0.4.7 #node version export NODE_VERSION=12 -# PHP version -export PHP_VERSION=5.6 - # SpacemanDMM git tag -export SPACEMAN_DMM_VERSION=suite-1.4 +export SPACEMAN_DMM_VERSION=suite-1.6 + +# Extools git tag +export EXTOOLS_VERSION=v0.0.6 diff --git a/html/changelogs/AutoChangeLog-pr-13610.yml b/html/changelogs/AutoChangeLog-pr-13610.yml new file mode 100644 index 0000000000..a3ca8e6f78 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13610.yml @@ -0,0 +1,4 @@ +author: "Putnam3145" +delete-after: True +changes: + - bugfix: "atmos subsystem no longer dies if there's too many gases" diff --git a/html/changelogs/AutoChangeLog-pr-13826.yml b/html/changelogs/AutoChangeLog-pr-13826.yml new file mode 100644 index 0000000000..959dc738b1 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13826.yml @@ -0,0 +1,9 @@ +author: "LetterN" +delete-after: True +changes: + - rscadd: "Coin & Holochip support for slot machine" + - admin: "Stickybans are now saved in the DB too" + - soundadd: "Immersive ™ audio reverbs. (also adds multiz audio)" + - code_imp: "Semi-hardsync from TG" + - code_imp: "Updates rust-g" + - code_imp: "Uses git CI instead of travis/appveyor now" diff --git a/html/changelogs/AutoChangeLog-pr-13834.yml b/html/changelogs/AutoChangeLog-pr-13834.yml new file mode 100644 index 0000000000..46cedff5d5 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13834.yml @@ -0,0 +1,4 @@ +author: "zeroisthebiggay" +delete-after: True +changes: + - rscadd: "Traitor assistants can now purchase the patented POGBox! Put TC into it for even higher damage!" diff --git a/html/changelogs/AutoChangeLog-pr-13856.yml b/html/changelogs/AutoChangeLog-pr-13856.yml new file mode 100644 index 0000000000..583fb38cc2 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13856.yml @@ -0,0 +1,5 @@ +author: "Putnam3145" +delete-after: True +changes: + - bugfix: "gear harness alt-click is now sane" + - code_imp: "rolldown() and toggle_jumpsuit_adjust() now no longer mix behavior-that-should-be-overridden and behavior-that-shouldn't-be-overridden in ways that make no sense." diff --git a/html/changelogs/AutoChangeLog-pr-13859.yml b/html/changelogs/AutoChangeLog-pr-13859.yml new file mode 100644 index 0000000000..2d6dc5c25a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13859.yml @@ -0,0 +1,4 @@ +author: "timothyteakettle" +delete-after: True +changes: + - rscadd: "adds unlockable loadout items, corresponding category in loadouts, etc" diff --git a/html/changelogs/AutoChangeLog-pr-13867.yml b/html/changelogs/AutoChangeLog-pr-13867.yml new file mode 100644 index 0000000000..dd1e44e64c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13867.yml @@ -0,0 +1,4 @@ +author: "Putnam3145" +delete-after: True +changes: + - balance: "Zeolites now only generate 1/5 the heat when reacting and don't require a catalyst." diff --git a/html/changelogs/AutoChangeLog-pr-13871.yml b/html/changelogs/AutoChangeLog-pr-13871.yml new file mode 100644 index 0000000000..f667abe816 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13871.yml @@ -0,0 +1,5 @@ +author: "NT Cleaning Crews On Break" +delete-after: True +changes: + - rscadd: "Most kinds of dirt, grime, and debris are now persistent. Get to work, jannies." + - rscadd: "Dirt can now be removed by tile replacements. Other cleanable decals can't, though." diff --git a/html/changelogs/AutoChangeLog-pr-13885.yml b/html/changelogs/AutoChangeLog-pr-13885.yml new file mode 100644 index 0000000000..88c23d30f1 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13885.yml @@ -0,0 +1,4 @@ +author: "raspy-on-osu" +delete-after: True +changes: + - tweak: "space heater heating range and power" diff --git a/html/changelogs/AutoChangeLog-pr-13909.yml b/html/changelogs/AutoChangeLog-pr-13909.yml new file mode 100644 index 0000000000..e4f0f1e401 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13909.yml @@ -0,0 +1,4 @@ +author: "silicons" +delete-after: True +changes: + - rscadd: "Twitch Plays: Clown Car" diff --git a/html/changelogs/AutoChangeLog-pr-13924.yml b/html/changelogs/AutoChangeLog-pr-13924.yml new file mode 100644 index 0000000000..71092c567d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13924.yml @@ -0,0 +1,4 @@ +author: "SandPoot" +delete-after: True +changes: + - tweak: "You can attack a pile of money on the floor with your id to put it all in quickly." diff --git a/html/changelogs/AutoChangeLog-pr-13930.yml b/html/changelogs/AutoChangeLog-pr-13930.yml new file mode 100644 index 0000000000..282f3fa30a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13930.yml @@ -0,0 +1,4 @@ +author: "MrJWhit" +delete-after: True +changes: + - tweak: "Small fixes on security on boxstation" diff --git a/html/changelogs/AutoChangeLog-pr-13931.yml b/html/changelogs/AutoChangeLog-pr-13931.yml new file mode 100644 index 0000000000..fd903f2d6e --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13931.yml @@ -0,0 +1,4 @@ +author: "shellspeed1" +delete-after: True +changes: + - rscadd: "Adds the disposable sentry gun from tg for 11tc each." diff --git a/html/changelogs/AutoChangeLog-pr-13932.yml b/html/changelogs/AutoChangeLog-pr-13932.yml new file mode 100644 index 0000000000..955d9f5741 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13932.yml @@ -0,0 +1,4 @@ +author: "shellspeed1" +delete-after: True +changes: + - tweak: "Xenomorph powers now list plasma cost in their description." diff --git a/html/changelogs/AutoChangeLog-pr-13934.yml b/html/changelogs/AutoChangeLog-pr-13934.yml new file mode 100644 index 0000000000..74f8ece6fc --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13934.yml @@ -0,0 +1,4 @@ +author: "shellspeed1" +delete-after: True +changes: + - rscadd: "The bluespace navigation gigabeacon design has been added to shuttle research for those wanting to take their ships around space more." diff --git a/html/changelogs/AutoChangeLog-pr-13936.yml b/html/changelogs/AutoChangeLog-pr-13936.yml new file mode 100644 index 0000000000..9b15d2232a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13936.yml @@ -0,0 +1,4 @@ +author: "BlueWildrose" +delete-after: True +changes: + - bugfix: "Polychromic hoodies that were obtained from the loadout have functional colorable hoods now." diff --git a/html/changelogs/AutoChangeLog-pr-13938.yml b/html/changelogs/AutoChangeLog-pr-13938.yml new file mode 100644 index 0000000000..34d76a190b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13938.yml @@ -0,0 +1,4 @@ +author: "timothyteakettle" +delete-after: True +changes: + - rscadd: "anthromorphic synth species" diff --git a/html/changelogs/AutoChangeLog-pr-13940.yml b/html/changelogs/AutoChangeLog-pr-13940.yml new file mode 100644 index 0000000000..60cbcc9a19 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13940.yml @@ -0,0 +1,4 @@ +author: "Chiirno" +delete-after: True +changes: + - rscadd: "Added the paramedics EVA suit as a purchase from the cargo console." diff --git a/html/changelogs/AutoChangeLog-pr-13941.yml b/html/changelogs/AutoChangeLog-pr-13941.yml new file mode 100644 index 0000000000..5a72376ebb --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13941.yml @@ -0,0 +1,4 @@ +author: "Chiirno" +delete-after: True +changes: + - bugfix: "Portable Chem Mixer now researchable from biotech node." diff --git a/html/changelogs/AutoChangeLog-pr-13943.yml b/html/changelogs/AutoChangeLog-pr-13943.yml new file mode 100644 index 0000000000..405d6b0d93 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13943.yml @@ -0,0 +1,6 @@ +author: "Hatterhat" +delete-after: True +changes: + - spellcheck: "Utility uniforms now comply with the \"nonproper equipment names\" thing." + - bugfix: "The CapDrobe now allows the captain to get his own clothes for free. Probably." + - tweak: "All captains' clothes now offer 15 woundarmor, up from the 5. Because apparently only the suit and tie and its suitskirt subtype have this wound armor, which is dumb." diff --git a/html/changelogs/AutoChangeLog-pr-13945.yml b/html/changelogs/AutoChangeLog-pr-13945.yml new file mode 100644 index 0000000000..91b8bb9498 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13945.yml @@ -0,0 +1,4 @@ +author: "DeltaFire15" +delete-after: True +changes: + - rscadd: "IPC cells & power cords are now printable after they are researched." diff --git a/html/changelogs/AutoChangeLog-pr-13946.yml b/html/changelogs/AutoChangeLog-pr-13946.yml new file mode 100644 index 0000000000..d7f3e15024 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13946.yml @@ -0,0 +1,4 @@ +author: "Ryll/Shaps" +delete-after: True +changes: + - admin: "Fixed an issue with player logs becoming confused when someone triggers multiple events within one second (like being attacked by two people at the same time) that would cause holes in the logs" diff --git a/html/changelogs/AutoChangeLog-pr-13947.yml b/html/changelogs/AutoChangeLog-pr-13947.yml new file mode 100644 index 0000000000..0388efc701 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13947.yml @@ -0,0 +1,4 @@ +author: "Chiirno" +delete-after: True +changes: + - tweak: "Chem masters can now dispense 20 instances of its outputs instead of 10." diff --git a/html/changelogs/AutoChangeLog-pr-13948.yml b/html/changelogs/AutoChangeLog-pr-13948.yml new file mode 100644 index 0000000000..73c5ba6b1a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13948.yml @@ -0,0 +1,11 @@ +author: "necromanceranne" +delete-after: True +changes: + - rscadd: "Bokken now come in two lengths; full and wakizashi, and two varieties: wood and ironwood. They have different stats for all four." + - rscadd: "Bokken require menu crafting and part construction, as well as more complicated materials." + - tweak: "Bokken (long and short) require wood, cloth and leather to craft with a hatchet and screwdriver." + - tweak: "Ironwood bokken (long and short) require ironcap logs, cloth and leather to craft with a hatchet, screwdriver and welder." + - balance: "Twin sheathes can only fit a pair of blades (longsword + shortsword) or they can fit two shortswords." + - bugfix: "Fixed a twin sheath runtime." + - imageadd: "A lot of bokken related sprites received an overhaul. Added overlay sprites for weapons sheathed in the twin sheathes." + - imageadd: "The extradimensional blade received improved sprites for inhands/back sprites." diff --git a/html/changelogs/AutoChangeLog-pr-13950.yml b/html/changelogs/AutoChangeLog-pr-13950.yml new file mode 100644 index 0000000000..28affe7ebe --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13950.yml @@ -0,0 +1,6 @@ +author: "TripleShades" +delete-after: True +changes: + - rscadd: "New Paramedic Office next to Genetics where the old Genetics Reception used to be +change: Surgery, Surgery Observation, and Recovery Hall layout revamped drastically +change: Maints below Surgery lowered by one tile to recover lost tile space from Surgery expansion" diff --git a/html/changelogs/AutoChangeLog-pr-13951.yml b/html/changelogs/AutoChangeLog-pr-13951.yml new file mode 100644 index 0000000000..fe3ac84523 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13951.yml @@ -0,0 +1,4 @@ +author: "BlueWildrose" +delete-after: True +changes: + - tweak: "You can now have a max-roundstart-dicksize-config inch long johnson before you start suffering blood loss and slowdowns instead of a 20 inch one." diff --git a/html/changelogs/AutoChangeLog-pr-13954.yml b/html/changelogs/AutoChangeLog-pr-13954.yml new file mode 100644 index 0000000000..a8751d66ca --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13954.yml @@ -0,0 +1,6 @@ +author: "EmeraldSundisk" +delete-after: True +changes: + - rscadd: "Adds a new \"Computer Core\" area designation for CogStation" + - bugfix: "Fixes some missing area strings" + - tweak: "Replaces some firelocks with directional ones as to ensure desks/counters can still be accessed" diff --git a/html/changelogs/AutoChangeLog-pr-13955.yml b/html/changelogs/AutoChangeLog-pr-13955.yml new file mode 100644 index 0000000000..1d43dd6b95 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13955.yml @@ -0,0 +1,5 @@ +author: "Chiirno" +delete-after: True +changes: + - tweak: "Nightmare now deals additional damage to most light sources." + - bugfix: "Nightmare now one-shots miners beacons and glowshrooms" diff --git a/html/changelogs/AutoChangeLog-pr-13959.yml b/html/changelogs/AutoChangeLog-pr-13959.yml new file mode 100644 index 0000000000..1303768344 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13959.yml @@ -0,0 +1,6 @@ +author: "necromanceranne" +delete-after: True +changes: + - bugfix: "You can now make all the variants of the bokken." + - bugfix: "Removes a duplicate sprite." + - tweak: "Renames all instances of 'ironwood' to 'steelwood'." diff --git a/html/changelogs/AutoChangeLog-pr-13961.yml b/html/changelogs/AutoChangeLog-pr-13961.yml new file mode 100644 index 0000000000..f0a6cc267d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13961.yml @@ -0,0 +1,6 @@ +author: "MrJWhit" +delete-after: True +changes: + - tweak: "Removed the wires connecting the AI from the rest of the station on cogstation." + - tweak: "Fixes experimenter on cogstation." + - tweak: "Less pipes in the overall area in toxins on cogstation" diff --git a/html/changelogs/AutoChangeLog-pr-13963.yml b/html/changelogs/AutoChangeLog-pr-13963.yml new file mode 100644 index 0000000000..8a1e923aa0 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13963.yml @@ -0,0 +1,4 @@ +author: "necromanceranne" +delete-after: True +changes: + - rscadd: "Adds new roboticist labcoat sprites!" diff --git a/html/changelogs/AutoChangeLog-pr-13965.yml b/html/changelogs/AutoChangeLog-pr-13965.yml new file mode 100644 index 0000000000..69f5a90122 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13965.yml @@ -0,0 +1,7 @@ +author: "Xantholne" +delete-after: True +changes: + - rscadd: "You can now tuck disky into bed" + - rscadd: "You can now make beds by applying a bed sheet to them" + - rscadd: "You can now tuck in pai cards into bed" + - rscadd: "Added bed tucking element, can be added to any held object to allow tucking into beds" diff --git a/html/changelogs/AutoChangeLog-pr-13967.yml b/html/changelogs/AutoChangeLog-pr-13967.yml new file mode 100644 index 0000000000..d2e580b531 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13967.yml @@ -0,0 +1,6 @@ +author: "keronshb" +delete-after: True +changes: + - balance: "Blob Resource Tower to 2 points per instead of 1 point per." + - balance: "Blob Factory Towers can be placed 5 tiles apart instead of 7." + - bugfix: "Fixes Blobbernaut Factories consuming Factories if no naut is chosen." diff --git a/html/changelogs/AutoChangeLog-pr-13968.yml b/html/changelogs/AutoChangeLog-pr-13968.yml new file mode 100644 index 0000000000..e3ce9e4615 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13968.yml @@ -0,0 +1,4 @@ +author: "Arturlang" +delete-after: True +changes: + - tweak: "Prayers to admins now do a wee ding sound for all prayers, instead of just chaplains" diff --git a/html/changelogs/AutoChangeLog-pr-13970.yml b/html/changelogs/AutoChangeLog-pr-13970.yml new file mode 100644 index 0000000000..54d8d9992d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13970.yml @@ -0,0 +1,8 @@ +author: "TripleShades" +delete-after: True +changes: + - rscadd: "Firelock to Surgery Bay drapes +change: Swapped Nanomed and Fire Alarm button locations in both Surgery Bays +change: Removes the double mirror in both Surgery Bays to be a singular mirror +change: Moved an intercom to not be doorstuck below Paramedical Office +remove: One Surgery Observation Fire Alarm button" diff --git a/html/changelogs/AutoChangeLog-pr-13972.yml b/html/changelogs/AutoChangeLog-pr-13972.yml new file mode 100644 index 0000000000..fdfdd4786d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13972.yml @@ -0,0 +1,4 @@ +author: "MrJWhit" +delete-after: True +changes: + - tweak: "Fixes maint area in boxstation" diff --git a/html/changelogs/AutoChangeLog-pr-13975.yml b/html/changelogs/AutoChangeLog-pr-13975.yml new file mode 100644 index 0000000000..ff643cd19c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13975.yml @@ -0,0 +1,4 @@ +author: "zeroisthebiggay" +delete-after: True +changes: + - imageadd: "fuck the r*d cr*ss" diff --git a/html/changelogs/AutoChangeLog-pr-13976.yml b/html/changelogs/AutoChangeLog-pr-13976.yml new file mode 100644 index 0000000000..dac85f8e9a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13976.yml @@ -0,0 +1,4 @@ +author: "timothyteakettle" +delete-after: True +changes: + - rscadd: "you can teleport bread" diff --git a/html/changelogs/AutoChangeLog-pr-13978.yml b/html/changelogs/AutoChangeLog-pr-13978.yml new file mode 100644 index 0000000000..94c19edec4 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13978.yml @@ -0,0 +1,4 @@ +author: "silicons" +delete-after: True +changes: + - balance: "c4 can no longer gib mobs" diff --git a/html/changelogs/AutoChangeLog-pr-13980.yml b/html/changelogs/AutoChangeLog-pr-13980.yml new file mode 100644 index 0000000000..6838ba48a2 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13980.yml @@ -0,0 +1,4 @@ +author: "MrJWhit" +delete-after: True +changes: + - rscadd: "Makes gas sensors fireproof." diff --git a/html/changelogs/AutoChangeLog-pr-13983.yml b/html/changelogs/AutoChangeLog-pr-13983.yml new file mode 100644 index 0000000000..ba0bf62e6a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13983.yml @@ -0,0 +1,6 @@ +author: "shellspeed1" +delete-after: True +changes: + - rscadd: "Xenomorph hybrids can now select wings +~~add: Xenomorph hybrids can now speak xenomorph~~" + - rscadd: "Xenomorph tongues are available for customization." diff --git a/html/changelogs/AutoChangeLog-pr-13988.yml b/html/changelogs/AutoChangeLog-pr-13988.yml new file mode 100644 index 0000000000..262e5f804f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13988.yml @@ -0,0 +1,4 @@ +author: "DeltaFire15" +delete-after: True +changes: + - bugfix: "Cargo packs marked as 'no private buying' now actually register as such." diff --git a/html/changelogs/AutoChangeLog-pr-13993.yml b/html/changelogs/AutoChangeLog-pr-13993.yml new file mode 100644 index 0000000000..d99ed0e0d1 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13993.yml @@ -0,0 +1,4 @@ +author: "Arturlang" +delete-after: True +changes: + - tweak: "The cursed heart now only takes away half as much blood every loop, and can be used as long as you are alive, instead if only you are awake/able to use your hands" diff --git a/html/changelogs/AutoChangeLog-pr-13995.yml b/html/changelogs/AutoChangeLog-pr-13995.yml new file mode 100644 index 0000000000..e58ee3103c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13995.yml @@ -0,0 +1,4 @@ +author: "DeltaFire15" +delete-after: True +changes: + - bugfix: "Attacking some certain objects no longer has no clickdelay." diff --git a/html/changelogs/AutoChangeLog-pr-13996.yml b/html/changelogs/AutoChangeLog-pr-13996.yml new file mode 100644 index 0000000000..5bea075460 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13996.yml @@ -0,0 +1,4 @@ +author: "MrJWhit" +delete-after: True +changes: + - tweak: "Bugfix of a morph becoming an AI eye" diff --git a/html/changelogs/AutoChangeLog-pr-13997.yml b/html/changelogs/AutoChangeLog-pr-13997.yml new file mode 100644 index 0000000000..354f66010a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13997.yml @@ -0,0 +1,4 @@ +author: "MrJWhit" +delete-after: True +changes: + - tweak: "Porting garbage collection tweak from /tg/" diff --git a/html/changelogs/AutoChangeLog-pr-14001.yml b/html/changelogs/AutoChangeLog-pr-14001.yml new file mode 100644 index 0000000000..31c9e560ab --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14001.yml @@ -0,0 +1,4 @@ +author: "MrJWhit" +delete-after: True +changes: + - tweak: "Fixes two chairs on one table" diff --git a/html/changelogs/AutoChangeLog-pr-14005.yml b/html/changelogs/AutoChangeLog-pr-14005.yml new file mode 100644 index 0000000000..253f4e137a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14005.yml @@ -0,0 +1,4 @@ +author: "DeltaFire15" +delete-after: True +changes: + - bugfix: "Loot items mobs drop are no longer always failing to initialize." diff --git a/html/changelogs/AutoChangeLog-pr-14006.yml b/html/changelogs/AutoChangeLog-pr-14006.yml new file mode 100644 index 0000000000..519ad32752 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14006.yml @@ -0,0 +1,4 @@ +author: "DeltaFire15" +delete-after: True +changes: + - bugfix: "Cyborg B.o.r.i.s. installation now checks for if the chest has a cell, just like how it does with MMIs." diff --git a/html/changelogs/AutoChangeLog-pr-14007.yml b/html/changelogs/AutoChangeLog-pr-14007.yml new file mode 100644 index 0000000000..498aa6b807 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14007.yml @@ -0,0 +1,4 @@ +author: "DeltaFire15" +delete-after: True +changes: + - bugfix: "Antagging / Deantagging Heretics now properly sets their special role." diff --git a/html/changelogs/AutoChangeLog-pr-14008.yml b/html/changelogs/AutoChangeLog-pr-14008.yml new file mode 100644 index 0000000000..836eefd99a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14008.yml @@ -0,0 +1,4 @@ +author: "TheSpaghetti" +delete-after: True +changes: + - bugfix: "no more tumor bread double punctuation" diff --git a/html/changelogs/AutoChangeLog-pr-14009.yml b/html/changelogs/AutoChangeLog-pr-14009.yml new file mode 100644 index 0000000000..03a1ca39dd --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14009.yml @@ -0,0 +1,7 @@ +author: "shellspeed1" +delete-after: True +changes: + - rscadd: "Wings from Cit RP have been ported over" + - rscadd: "Moth wings from cit have been ported over" + - bugfix: "Cleaned up some pixels on existing moth wings." + - tweak: "Organized the lists for wings by if they are for moths or not and than by alphabetical." diff --git a/html/changelogs/AutoChangeLog-pr-14010.yml b/html/changelogs/AutoChangeLog-pr-14010.yml new file mode 100644 index 0000000000..643f28dc99 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14010.yml @@ -0,0 +1,5 @@ +author: "shellspeed1" +delete-after: True +changes: + - rscadd: "The exofab can now print prosthetic limbs" + - bugfix: "The exofab was missing access to multiple cybernetic organs. This has now been rectified." diff --git a/html/changelogs/AutoChangeLog-pr-14014.yml b/html/changelogs/AutoChangeLog-pr-14014.yml new file mode 100644 index 0000000000..ac29b1567b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14014.yml @@ -0,0 +1,4 @@ +author: "necromanceranne" +delete-after: True +changes: + - bugfix: "Fixes various sprites for bokken, as well as being unable to craft certain parts and duplicate entries." diff --git a/html/changelogs/AutoChangeLog-pr-14015.yml b/html/changelogs/AutoChangeLog-pr-14015.yml new file mode 100644 index 0000000000..fe507d0a1e --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14015.yml @@ -0,0 +1,4 @@ +author: "DeltaFire15" +delete-after: True +changes: + - balance: "Some synth damage stuff has been a bit rebalanced, see the PR for details." diff --git a/html/changelogs/AutoChangeLog-pr-14016.yml b/html/changelogs/AutoChangeLog-pr-14016.yml new file mode 100644 index 0000000000..1aab587190 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14016.yml @@ -0,0 +1,4 @@ +author: "timothyteakettle" +delete-after: True +changes: + - bugfix: "disabling adminhelp noises no longer disables looc" diff --git a/html/changelogs/AutoChangeLog-pr-14019.yml b/html/changelogs/AutoChangeLog-pr-14019.yml new file mode 100644 index 0000000000..37bdd52948 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14019.yml @@ -0,0 +1,4 @@ +author: "timothyteakettle" +delete-after: True +changes: + - bugfix: "species with NOTRANSSTING cannot have envy's knife used on them" diff --git a/html/changelogs/AutoChangeLog-pr-14021.yml b/html/changelogs/AutoChangeLog-pr-14021.yml new file mode 100644 index 0000000000..aab94ae724 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14021.yml @@ -0,0 +1,4 @@ +author: "DeltaFire15" +delete-after: True +changes: + - bugfix: "Combat mode now will not stay permanently disabled due to status effects not working as intended." diff --git a/html/changelogs/AutoChangeLog-pr-14025.yml b/html/changelogs/AutoChangeLog-pr-14025.yml new file mode 100644 index 0000000000..6db185baa3 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14025.yml @@ -0,0 +1,7 @@ +author: "DeltaFire15" +delete-after: True +changes: + - rscadd: "A new surgery, allowing revival of synths without a defib at hand." + - balance: "Semi-permanent damage of Synth limbs caused by passing the damage threshold: 10 <- 15." + - tweak: "The embed removal surgery now has a version for Synths." + - balance: "EMPs no longer hardstun Synths." diff --git a/html/changelogs/AutoChangeLog-pr-14026.yml b/html/changelogs/AutoChangeLog-pr-14026.yml new file mode 100644 index 0000000000..1ae9cb5c28 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14026.yml @@ -0,0 +1,4 @@ +author: "BlueWildrose" +delete-after: True +changes: + - bugfix: "Fixes noodle size appearance for 12+ inch members." diff --git a/html/changelogs/AutoChangeLog-pr-14029.yml b/html/changelogs/AutoChangeLog-pr-14029.yml new file mode 100644 index 0000000000..2d4e0cdb17 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14029.yml @@ -0,0 +1,4 @@ +author: "HeroWithYay" +delete-after: True +changes: + - tweak: "Wormhole Projector and Gravity Gun now require anomaly cores to function instead of firing pins." diff --git a/html/changelogs/AutoChangeLog-pr-14030.yml b/html/changelogs/AutoChangeLog-pr-14030.yml new file mode 100644 index 0000000000..9d4ee2647b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14030.yml @@ -0,0 +1,4 @@ +author: "Putnam3145" +delete-after: True +changes: + - tweak: "Replaces majority judgement with usual judgement." diff --git a/html/changelogs/AutoChangeLog-pr-14032.yml b/html/changelogs/AutoChangeLog-pr-14032.yml new file mode 100644 index 0000000000..67f0a80f83 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14032.yml @@ -0,0 +1,8 @@ +author: "kappa-sama" +delete-after: True +changes: + - rscadd: "A new spell for the wizard and his martial apprentices, the Inner Mantra technique. It makes you punch people really good and makes you durable, but drains your energy while it's active." + - rscadd: "A self-buffing spell for valiant bubblegum slayers that is ultimately useless on lavaland and probably overpowered for miner antagonists. Go figure. At least all it does is let you punch hard while draining your health every second." + - balance: "bubblegum now drops a book that makes you into an abusive father instead of a shotgun that plays like pre-nerf shotguns" + - soundadd: "a powerup and powerdown sound effect" + - imageadd: "two icons for two buff spells" diff --git a/html/changelogs/AutoChangeLog-pr-14033.yml b/html/changelogs/AutoChangeLog-pr-14033.yml new file mode 100644 index 0000000000..db6a6b0691 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14033.yml @@ -0,0 +1,4 @@ +author: "BlueWildrose" +delete-after: True +changes: + - rscadd: "Color Mates have been added to all stations (except Snaxi). Enjoy coloring your attire without having to bug science!" diff --git a/html/changelogs/AutoChangeLog-pr-14034.yml b/html/changelogs/AutoChangeLog-pr-14034.yml new file mode 100644 index 0000000000..ecd0d4ca10 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14034.yml @@ -0,0 +1,4 @@ +author: "DeltaFire15" +delete-after: True +changes: + - bugfix: "Some edge cases causing issues with system corruption shouldn't be able to occur anymore." diff --git a/html/changelogs/AutoChangeLog-pr-14035.yml b/html/changelogs/AutoChangeLog-pr-14035.yml new file mode 100644 index 0000000000..b8690368a3 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14035.yml @@ -0,0 +1,4 @@ +author: "SiliconMain" +delete-after: True +changes: + - tweak: "hololocks (which haven't worked for god knows how long) commented out until auxmos is merged" diff --git a/html/changelogs/AutoChangeLog-pr-14036.yml b/html/changelogs/AutoChangeLog-pr-14036.yml new file mode 100644 index 0000000000..a2bb654233 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14036.yml @@ -0,0 +1,4 @@ +author: "BlueWildrose" +delete-after: True +changes: + - tweak: "You will now only unbuckle fireman-carried/piggybacked people on disarm or harm intent." diff --git a/html/changelogs/AutoChangeLog-pr-14037.yml b/html/changelogs/AutoChangeLog-pr-14037.yml new file mode 100644 index 0000000000..b105b5e19a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14037.yml @@ -0,0 +1,4 @@ +author: "DeltaFire15" +delete-after: True +changes: + - rscadd: "Nanogel, available at medical and robotics, which fixes internal damage in sufficiently repaired robotic limbs." diff --git a/html/changelogs/AutoChangeLog-pr-14038.yml b/html/changelogs/AutoChangeLog-pr-14038.yml new file mode 100644 index 0000000000..906f6f7053 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14038.yml @@ -0,0 +1,9 @@ +author: "Hatterhat" +delete-after: True +changes: + - rscadd: "The nature interaction shuttle with the monkeys now has tiny fans on the airlocks in, because that's apparently a feature that was missing." + - rscadd: "More bags have been added to department vendors." + - balance: "Every roundstart species (and also ash walkers) now has flesh and bone that can be wounded." + - balance: "Recipes for sutures, regen mesh, and sterilized gauze have been adjusted to be easier, mostly." + - balance: "Sterilized gauze is better at absorbing blood and being a splint." + - bugfix: "Energy sabres now have an off inhand." diff --git a/html/changelogs/AutoChangeLog-pr-14039.yml b/html/changelogs/AutoChangeLog-pr-14039.yml new file mode 100644 index 0000000000..a799003a02 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14039.yml @@ -0,0 +1,4 @@ +author: "Hatterhat" +delete-after: True +changes: + - rscadd: "Basic sticky technology is now a roundstart tech. Advanced sticky technology is BEPIS-locked, though. Theoretically." diff --git a/html/changelogs/AutoChangeLog-pr-14040.yml b/html/changelogs/AutoChangeLog-pr-14040.yml new file mode 100644 index 0000000000..6202f0b3e1 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14040.yml @@ -0,0 +1,4 @@ +author: "LetterN" +delete-after: True +changes: + - bugfix: "fixed telecomms pda log" diff --git a/html/changelogs/AutoChangeLog-pr-14042.yml b/html/changelogs/AutoChangeLog-pr-14042.yml new file mode 100644 index 0000000000..a924ff582f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14042.yml @@ -0,0 +1,4 @@ +author: "kiwedespars" +delete-after: True +changes: + - rscadd: "the robust dildo weapon now has sound." diff --git a/html/changelogs/AutoChangeLog-pr-14043.yml b/html/changelogs/AutoChangeLog-pr-14043.yml new file mode 100644 index 0000000000..03a347724f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14043.yml @@ -0,0 +1,4 @@ +author: "timothyteakettle" +delete-after: True +changes: + - rscadd: "licking people washes pie off their face" diff --git a/html/changelogs/AutoChangeLog-pr-14044.yml b/html/changelogs/AutoChangeLog-pr-14044.yml new file mode 100644 index 0000000000..e19b6266a7 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14044.yml @@ -0,0 +1,4 @@ +author: "corin9090" +delete-after: True +changes: + - tweak: "The chaplain's prayer beads can now be worn on your belt slot" diff --git a/html/changelogs/AutoChangeLog-pr-14048.yml b/html/changelogs/AutoChangeLog-pr-14048.yml new file mode 100644 index 0000000000..b7b1448b37 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14048.yml @@ -0,0 +1,4 @@ +author: "MrJWhit" +delete-after: True +changes: + - tweak: "Updates suit storage info on Tip Of the Round." diff --git a/html/changelogs/AutoChangeLog-pr-14054.yml b/html/changelogs/AutoChangeLog-pr-14054.yml new file mode 100644 index 0000000000..406e6b2713 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14054.yml @@ -0,0 +1,5 @@ +author: "TheObserver" +delete-after: True +changes: + - rscadd: "Re-adds the rifle stock, and sets the improv shotgun to be as it was." + - rscdel: "The maintenance rifle has been shelved - for now. Watch this space." diff --git a/html/changelogs/AutoChangeLog-pr-14055.yml b/html/changelogs/AutoChangeLog-pr-14055.yml new file mode 100644 index 0000000000..95baa857fa --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14055.yml @@ -0,0 +1,4 @@ +author: "BlueWildrose" +delete-after: True +changes: + - tweak: "No more straining when your cock or breasts are growing via incubus draft or succubus milk." diff --git a/html/changelogs/AutoChangeLog-pr-14060.yml b/html/changelogs/AutoChangeLog-pr-14060.yml new file mode 100644 index 0000000000..f9750fc9be --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14060.yml @@ -0,0 +1,4 @@ +author: "Hatterhat" +delete-after: True +changes: + - rscdel: "Apparently, shrink rays were buyable again, despite a PR having been made a while ago specifically for removing shrink rays. They're gone again." diff --git a/html/changelogs/AutoChangeLog-pr-14061.yml b/html/changelogs/AutoChangeLog-pr-14061.yml new file mode 100644 index 0000000000..c10eded1df --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14061.yml @@ -0,0 +1,5 @@ +author: "Hatterhat" +delete-after: True +changes: + - tweak: "Improvised gauzes can now be crafted in stacks up to 10, like their maximum stacksize implies they should be capable of doing." + - bugfix: "Pouring sterilizine on gauze now takes the proper 5u per sterilized gauze instead of 10u." diff --git a/html/changelogs/AutoChangeLog-pr-14062.yml b/html/changelogs/AutoChangeLog-pr-14062.yml new file mode 100644 index 0000000000..84e40850ec --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14062.yml @@ -0,0 +1,4 @@ +author: "kappa-sama" +delete-after: True +changes: + - bugfix: "super saiyan" diff --git a/html/changelogs/AutoChangeLog-pr-14065.yml b/html/changelogs/AutoChangeLog-pr-14065.yml new file mode 100644 index 0000000000..96a0a7cb3a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14065.yml @@ -0,0 +1,4 @@ +author: "MrJWhit" +delete-after: True +changes: + - tweak: "A small bucket of random fixes," diff --git a/html/changelogs/AutoChangeLog-pr-14070.yml b/html/changelogs/AutoChangeLog-pr-14070.yml new file mode 100644 index 0000000000..f9a694c6ff --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14070.yml @@ -0,0 +1,4 @@ +author: "YakumoChen" +delete-after: True +changes: + - balance: "To lower production costs, Buzz Fuzz is now manufactured with Real™️ Synthetic honey." diff --git a/html/changelogs/AutoChangeLog-pr-14082.yml b/html/changelogs/AutoChangeLog-pr-14082.yml new file mode 100644 index 0000000000..c65f417894 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14082.yml @@ -0,0 +1,7 @@ +author: "kappa-sama" +delete-after: True +changes: + - rscadd: "s" + - tweak: "s" + - balance: "s" + - bugfix: "s" diff --git a/html/changelogs/AutoChangeLog-pr-14089.yml b/html/changelogs/AutoChangeLog-pr-14089.yml new file mode 100644 index 0000000000..4a473d6fa7 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14089.yml @@ -0,0 +1,4 @@ +author: "MrJWhit" +delete-after: True +changes: + - tweak: "Mining station oxygen locker on the cycling airlock starts out wrenched." diff --git a/html/changelogs/example.yml b/html/changelogs/example.yml index 48aa13aa11..c44f796755 100644 --- a/html/changelogs/example.yml +++ b/html/changelogs/example.yml @@ -8,16 +8,41 @@ # # Valid Prefixes: # bugfix -# wip (For works in progress) +# - (fixes bugs) +# wip +# - (work in progress) # tweak +# - (tweaks something) # soundadd +# - (adds a sound) # sounddel -# rscadd (general adding of nice things) -# rscdel (general deleting of nice things) +# - (removes a sound) +# rscdel +# - (adds a feature) +# rscadd +# - (removes a feature) # imageadd +# - (adds an image or sprite) # imagedel -# spellcheck (typo fixes) +# - (removes an image or sprite) +# spellcheck +# - (fixes spelling or grammar) # experiment +# - (experimental change) +# tgs +# - (TGS change) +# balance +# - (balance changes) +# code_imp +# - (misc internal code change) +# refactor +# - (refactors code) +# config +# - (makes a change to the config files) +# admin +# - (makes changes to administrator tools) +# server +# - (miscellaneous changes to server) ################################# # Your name. diff --git a/html/safe_dial.png b/html/safe_dial.png new file mode 100644 index 0000000000..de24f16b67 Binary files /dev/null and b/html/safe_dial.png differ diff --git a/icons/mob/animal.dmi b/icons/mob/animal.dmi index 8db32b304b..68e6170969 100644 Binary files a/icons/mob/animal.dmi and b/icons/mob/animal.dmi differ diff --git a/icons/mob/clothing/back.dmi b/icons/mob/clothing/back.dmi index 8594af8ec2..2afd1b510b 100644 Binary files a/icons/mob/clothing/back.dmi and b/icons/mob/clothing/back.dmi differ diff --git a/icons/mob/clothing/belt.dmi b/icons/mob/clothing/belt.dmi index f84e360179..adcd7b64e1 100644 Binary files a/icons/mob/clothing/belt.dmi and b/icons/mob/clothing/belt.dmi differ diff --git a/icons/mob/clothing/head.dmi b/icons/mob/clothing/head.dmi index 62d6644311..4b0c56c4d2 100644 Binary files a/icons/mob/clothing/head.dmi and b/icons/mob/clothing/head.dmi differ diff --git a/icons/mob/clothing/head_muzzled.dmi b/icons/mob/clothing/head_muzzled.dmi index 0c72221833..e99f1ff6d4 100644 Binary files a/icons/mob/clothing/head_muzzled.dmi and b/icons/mob/clothing/head_muzzled.dmi differ diff --git a/icons/mob/clothing/neck.dmi b/icons/mob/clothing/neck.dmi index 276b5c9458..084a2c3649 100644 Binary files a/icons/mob/clothing/neck.dmi and b/icons/mob/clothing/neck.dmi differ diff --git a/icons/mob/clothing/suit.dmi b/icons/mob/clothing/suit.dmi index d4bb1224cc..6098b8342a 100644 Binary files a/icons/mob/clothing/suit.dmi and b/icons/mob/clothing/suit.dmi differ diff --git a/icons/mob/clothing/suit_digi.dmi b/icons/mob/clothing/suit_digi.dmi index 9f6e3ffb84..5c361feb5f 100644 Binary files a/icons/mob/clothing/suit_digi.dmi and b/icons/mob/clothing/suit_digi.dmi differ diff --git a/icons/mob/inhands/weapons/swords_lefthand.dmi b/icons/mob/inhands/weapons/swords_lefthand.dmi index 5ff248de68..e4f22de1cd 100644 Binary files a/icons/mob/inhands/weapons/swords_lefthand.dmi and b/icons/mob/inhands/weapons/swords_lefthand.dmi differ diff --git a/icons/mob/inhands/weapons/swords_righthand.dmi b/icons/mob/inhands/weapons/swords_righthand.dmi index 0332e60fb5..8716c3627f 100644 Binary files a/icons/mob/inhands/weapons/swords_righthand.dmi and b/icons/mob/inhands/weapons/swords_righthand.dmi differ diff --git a/icons/mob/wings.dmi b/icons/mob/wings.dmi index 4523403344..92de5c150c 100644 Binary files a/icons/mob/wings.dmi and b/icons/mob/wings.dmi differ diff --git a/icons/obj/bedsheets.dmi b/icons/obj/bedsheets.dmi index 05535334cf..f62dd34c66 100644 Binary files a/icons/obj/bedsheets.dmi and b/icons/obj/bedsheets.dmi differ diff --git a/icons/obj/closet.dmi b/icons/obj/closet.dmi index 3653635c56..70f5001c26 100644 Binary files a/icons/obj/closet.dmi and b/icons/obj/closet.dmi differ diff --git a/icons/obj/clothing/belt_overlays.dmi b/icons/obj/clothing/belt_overlays.dmi index cdb2567268..1178588ee7 100644 Binary files a/icons/obj/clothing/belt_overlays.dmi and b/icons/obj/clothing/belt_overlays.dmi differ diff --git a/icons/obj/clothing/hats.dmi b/icons/obj/clothing/hats.dmi index 95a31f8b9f..ee6cf90597 100644 Binary files a/icons/obj/clothing/hats.dmi and b/icons/obj/clothing/hats.dmi differ diff --git a/icons/obj/clothing/suits.dmi b/icons/obj/clothing/suits.dmi index c12720bc8b..6ddac703a0 100644 Binary files a/icons/obj/clothing/suits.dmi and b/icons/obj/clothing/suits.dmi differ diff --git a/icons/obj/food/burgerbread.dmi b/icons/obj/food/burgerbread.dmi index 7ef3a7d418..c5bf88ab6e 100644 Binary files a/icons/obj/food/burgerbread.dmi and b/icons/obj/food/burgerbread.dmi differ diff --git a/icons/obj/items_and_weapons.dmi b/icons/obj/items_and_weapons.dmi index 9b73fa706b..119e612c40 100644 Binary files a/icons/obj/items_and_weapons.dmi and b/icons/obj/items_and_weapons.dmi differ diff --git a/icons/obj/library.dmi b/icons/obj/library.dmi index 6e14c4c6ca..7e3b8058b8 100644 Binary files a/icons/obj/library.dmi and b/icons/obj/library.dmi differ diff --git a/icons/obj/magic.dmi b/icons/obj/magic.dmi index c376dc7321..6555373ae1 100644 Binary files a/icons/obj/magic.dmi and b/icons/obj/magic.dmi differ diff --git a/icons/obj/smith.dmi b/icons/obj/smith.dmi index a40b9a2b19..cbd6b9e85e 100644 Binary files a/icons/obj/smith.dmi and b/icons/obj/smith.dmi differ diff --git a/icons/obj/stack_objects.dmi b/icons/obj/stack_objects.dmi index 1cdb3b6443..3136cf34b2 100644 Binary files a/icons/obj/stack_objects.dmi and b/icons/obj/stack_objects.dmi differ diff --git a/icons/obj/storage.dmi b/icons/obj/storage.dmi index 1f1709a10c..b0e542f618 100644 Binary files a/icons/obj/storage.dmi and b/icons/obj/storage.dmi differ diff --git a/modular_citadel/code/datums/status_effects/chems.dm b/modular_citadel/code/datums/status_effects/chems.dm index 0e971d4ced..8f48e90068 100644 --- a/modular_citadel/code/datums/status_effects/chems.dm +++ b/modular_citadel/code/datums/status_effects/chems.dm @@ -32,82 +32,6 @@ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -/datum/status_effect/chem/breast_enlarger - id = "breast_enlarger" - alert_type = null - var/moveCalc = 1 - var/cachedmoveCalc = 1 - var/last_checked_size //used to prevent potential cpu waste from happening every tick. - -/datum/status_effect/chem/breast_enlarger/on_apply()//Removes clothes, they're too small to contain you. You belong to space now. - log_reagent("FERMICHEM: [owner]'s breasts has reached comical sizes. ID: [owner.key]") - return ..() - -/datum/status_effect/chem/breast_enlarger/tick()//If you try to wear clothes, you fail. Slows you down if you're comically huge - var/mob/living/carbon/human/H = owner - var/obj/item/organ/genital/breasts/B = H.getorganslot(ORGAN_SLOT_BREASTS) - if(!B) - H.remove_status_effect(src) - return - moveCalc = 1+((round(B.cached_size) - 9)/3) //Afffects how fast you move, and how often you can click. - - if(last_checked_size != B.cached_size) - H.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/status_effect/breast_hypertrophy, multiplicative_slowdown = moveCalc) - - if (B.size == "huge") - if(prob(1)) - to_chat(owner, "Your back is feeling sore.") - var/target = H.get_bodypart(BODY_ZONE_CHEST) - H.apply_damage(0.1, BRUTE, target) - else - if(prob(1)) - to_chat(H, "Your back is feeling a little sore.") - last_checked_size = B.cached_size - ..() - -/datum/status_effect/chem/breast_enlarger/on_remove() - log_reagent("FERMICHEM: [owner]'s breasts has reduced to an acceptable size. ID: [owner.key]") - to_chat(owner, "Your expansive chest has become a more managable size, liberating your movements.") - owner.remove_movespeed_modifier(/datum/movespeed_modifier/status_effect/breast_hypertrophy) - return ..() - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -/datum/status_effect/chem/penis_enlarger - id = "penis_enlarger" - alert_type = null - var/bloodCalc - var/moveCalc - var/last_checked_size //used to prevent potential cpu waste, just like the above. - -/datum/status_effect/chem/penis_enlarger/on_apply()//Removes clothes, they're too small to contain you. You belong to space now. - log_reagent("FERMICHEM: [owner]'s dick has reached comical sizes. ID: [owner.key]") - return ..() - - -/datum/status_effect/chem/penis_enlarger/tick() - var/mob/living/carbon/human/H = owner - var/obj/item/organ/genital/penis/P = H.getorganslot(ORGAN_SLOT_PENIS) - if(!P) - owner.remove_status_effect(src) - return - moveCalc = 1+((round(P.length) - 21)/3) //effects how fast you can move - bloodCalc = 1+((round(P.length) - 21)/15) //effects how much blood you need (I didn' bother adding an arousal check because I'm spending too much time on this organ already.) - if(P.length < 22 && H.has_movespeed_modifier(/datum/movespeed_modifier/status_effect/penis_hypertrophy)) - to_chat(owner, "Your rascally willy has become a more managable size, liberating your movements.") - H.remove_movespeed_modifier(/datum/movespeed_modifier/status_effect/penis_hypertrophy) - else if(P.length >= 22 && !H.has_movespeed_modifier(/datum/movespeed_modifier/status_effect/penis_hypertrophy)) - to_chat(H, "Your indulgent johnson is so substantial, it's taking all your blood and affecting your movements!") - H.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/status_effect/penis_hypertrophy, multiplicative_slowdown = moveCalc) - H.AdjustBloodVol(bloodCalc) - ..() - -/datum/status_effect/chem/penis_enlarger/on_remove() - log_reagent("FERMICHEM: [owner]'s dick has reduced to an acceptable size. ID: [owner.key]") - owner.remove_movespeed_modifier(/datum/movespeed_modifier/status_effect/penis_hypertrophy) - owner.ResetBloodVol() - return ..() - /////////////////////////////////////////////// // Astral INSURANCE /////////////////////////////////////////////// diff --git a/modular_citadel/code/modules/client/loadout/unlockable.dm b/modular_citadel/code/modules/client/loadout/unlockable.dm new file mode 100644 index 0000000000..67e0c06d8c --- /dev/null +++ b/modular_citadel/code/modules/client/loadout/unlockable.dm @@ -0,0 +1,30 @@ +/datum/gear/unlockable + category = LOADOUT_CATEGORY_UNLOCKABLE + slot = SLOT_NECK + + var/progress_required //what does our progress need to be to unlock it + var/progress_key //what is the key used to retrieve existing progress for this unlockable + +/datum/gear/unlockable/janitor + name = "Janitor Bedsheet" + description = "Clean 100 messes with a mop to unlock this. It has a warning sign on!" + path = /obj/item/bedsheet/unlockable/janitor + + progress_required = 100 + progress_key = "janitor" + +/datum/gear/unlockable/cook + name = "Cook Bedsheet" + description = "Cook 250 items using the microwave to unlock this. It has a microwave on!" + path = /obj/item/bedsheet/unlockable/cook + + progress_required = 250 + progress_key = "cook" + +/datum/gear/unlockable/miner + name = "Miner Bedsheet" + description = "Redeem a total of 100,000 miner points to unlock this. It's made out of goliath hide!" + path = /obj/item/bedsheet/unlockable/miner + + progress_required = 100000 + progress_key = "miner" diff --git a/modular_citadel/code/modules/reagents/chemistry/reagents/enlargement.dm b/modular_citadel/code/modules/reagents/chemistry/reagents/enlargement.dm index 7403de6215..2e5f3b8994 100644 --- a/modular_citadel/code/modules/reagents/chemistry/reagents/enlargement.dm +++ b/modular_citadel/code/modules/reagents/chemistry/reagents/enlargement.dm @@ -30,7 +30,6 @@ inverse_chem = /datum/reagent/fermi/BEsmaller //At really impure vols, it just becomes 100% inverse can_synth = FALSE value = REAGENT_VALUE_VERY_RARE - var/message_spam = FALSE /datum/reagent/fermi/breast_enlarger/on_mob_metabolize(mob/living/M) . = ..() @@ -81,16 +80,7 @@ H.reagents.remove_reagent(type, 5) B.Insert(H) - //If they have them, increase size. If size is comically big, limit movement and rip clothes. B.modify_size(0.05) - - if (ISINRANGE_EX(B.cached_size, 8.5, 9) && (H.w_uniform || H.wear_suit)) - var/target = H.get_bodypart(BODY_ZONE_CHEST) - if(!message_spam) - to_chat(H, "Your breasts begin to strain against your clothes tightly!") - message_spam = TRUE - H.adjustOxyLoss(5, 0) - H.apply_damage(1, BRUTE, target) return ..() /datum/reagent/fermi/breast_enlarger/overdose_process(mob/living/carbon/M) //Turns you into a female if male and ODing, doesn't touch nonbinary and object genders. @@ -189,7 +179,6 @@ inverse_chem = /datum/reagent/fermi/PEsmaller //At really impure vols, it just becomes 100% inverse and shrinks instead. can_synth = FALSE value = REAGENT_VALUE_VERY_RARE - var/message_spam = FALSE /datum/reagent/fermi/penis_enlarger/on_mob_metabolize(mob/living/M) . = ..() @@ -232,13 +221,6 @@ P.Insert(H) P.modify_size(0.1) - if (ISINRANGE_EX(P.length, 20.5, 21) && (H.w_uniform || H.wear_suit)) - var/target = H.get_bodypart(BODY_ZONE_CHEST) - if(!message_spam) - to_chat(H, "Your cock begin to strain against your clothes tightly!") - message_spam = TRUE - H.apply_damage(2.5, BRUTE, target) - return ..() /datum/reagent/fermi/penis_enlarger/overdose_process(mob/living/carbon/human/M) //Turns you into a male if female and ODing, doesn't touch nonbinary and object genders. diff --git a/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm b/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm index bbecd2f6f4..21f525088c 100644 --- a/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm +++ b/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm @@ -593,7 +593,6 @@ id = /datum/reagent/fermi/zeolites results = list(/datum/reagent/fermi/zeolites = 5) //We make a lot! - But it's now somewhat dangerous, and needs a bit of gold to catalyze the reaction required_reagents = list(/datum/reagent/medicine/potass_iodide = 1, /datum/reagent/aluminium = 1, /datum/reagent/silicon = 1, /datum/reagent/oxygen = 1) - required_catalysts = list(/datum/reagent/gold = 5) //FermiChem vars: OptimalTempMin = 500 OptimalTempMax = 750 @@ -604,7 +603,7 @@ //CatalystFact = 0 CurveSharpT = 1.5 CurveSharppH = 3 - ThermicConstant = 5 + ThermicConstant = 1 HIonRelease = -0.15 RateUpLim = 4 PurityMin = 0.5 //Good luck! diff --git a/rust_g.dll b/rust_g.dll old mode 100755 new mode 100644 diff --git a/sound/effects/ding.ogg b/sound/effects/ding.ogg new file mode 100644 index 0000000000..33516f793f Binary files /dev/null and b/sound/effects/ding.ogg differ diff --git a/sound/machines/grill/grillsizzle.ogg b/sound/machines/grill/grillsizzle.ogg new file mode 100644 index 0000000000..056ce45941 Binary files /dev/null and b/sound/machines/grill/grillsizzle.ogg differ diff --git a/sound/magic/powerdown.ogg b/sound/magic/powerdown.ogg new file mode 100644 index 0000000000..9d514c64ca Binary files /dev/null and b/sound/magic/powerdown.ogg differ diff --git a/sound/magic/powerup.ogg b/sound/magic/powerup.ogg new file mode 100644 index 0000000000..909c2a33c7 Binary files /dev/null and b/sound/magic/powerup.ogg differ diff --git a/strings/tips.txt b/strings/tips.txt index 5336f767a5..68d1cbe57a 100644 --- a/strings/tips.txt +++ b/strings/tips.txt @@ -295,7 +295,7 @@ In a pinch, stripping yourself naked will give you a sizeable resistance to bein Wearing riot armor makes you significantly more effective at performing tackle takedowns, but will use extra stamina with each leap! It will also significantly protect you from other tackles! Epipens contain a powerful coagulant that drastically reduces bleeding on all bleeding wounds. If you don't have time to properly treat someone with lots of slashes or piercings, stick them with a pen to buy some time! Anything you can light a cigarette with, you can use to cauterize a bleeding wound. Technically, that includes the supermatter. -Suit storage units entirely purge radiation from any carbon mob put inside of them when cycling, at the cost of some horrific burns, this is a very effective strategy to clean someone up after they bathed in the engine. +Suit storage units, when hacked, entirely purge radiation from any carbon mob put inside of them when cycling, at the cost of some horrific burns, this is a very effective strategy to clean someone up after they bathed in the engine. Laser pointers can be upgraded by replacing its micro laser with a better one from RnD! Use a screwdriver on it to remove the old laser. Upgrading the laser pointer gives you better odds of stunning a cyborg, and even blinding people with sunglasses. Being out of combat mode makes makes you deal less damage to people and objects when attacking. This stacks with the penalty incurred by resting. Resting makes you deal less damage to people and objects when attacking. This stacks with the penalty incurred by being out of combat mode. diff --git a/tgstation.dme b/tgstation.dme index f53a015ea4..c069e0fdca 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -77,6 +77,7 @@ #include "code\__DEFINES\mobs.dm" #include "code\__DEFINES\monkeys.dm" #include "code\__DEFINES\move_force.dm" +#include "code\__DEFINES\movement.dm" #include "code\__DEFINES\movespeed_modification.dm" #include "code\__DEFINES\nanites.dm" #include "code\__DEFINES\networks.dm" @@ -152,7 +153,6 @@ #include "code\__DEFINES\storage\_storage.dm" #include "code\__DEFINES\storage\volumetrics.dm" #include "code\__HELPERS\_cit_helpers.dm" -#include "code\__HELPERS\_extools_api.dm" #include "code\__HELPERS\_lists.dm" #include "code\__HELPERS\_logging.dm" #include "code\__HELPERS\_string_lists.dm" @@ -201,6 +201,7 @@ #include "code\__HELPERS\sorts\InsertSort.dm" #include "code\__HELPERS\sorts\MergeSort.dm" #include "code\__HELPERS\sorts\TimSort.dm" +#include "code\_globalvars\admin.dm" #include "code\_globalvars\bitfields.dm" #include "code\_globalvars\configuration.dm" #include "code\_globalvars\game_modes.dm" @@ -291,6 +292,7 @@ #include "code\controllers\configuration\entries\fail2topic.dm" #include "code\controllers\configuration\entries\game_options.dm" #include "code\controllers\configuration\entries\general.dm" +#include "code\controllers\configuration\entries\persistence.dm" #include "code\controllers\configuration\entries\plushies.dm" #include "code\controllers\configuration\entries\policy.dm" #include "code\controllers\configuration\entries\resources.dm" @@ -339,7 +341,6 @@ #include "code\controllers\subsystem\pai.dm" #include "code\controllers\subsystem\parallax.dm" #include "code\controllers\subsystem\pathfinder.dm" -#include "code\controllers\subsystem\persistence.dm" #include "code\controllers\subsystem\profiler.dm" #include "code\controllers\subsystem\radiation.dm" #include "code\controllers\subsystem\radio.dm" @@ -362,6 +363,13 @@ #include "code\controllers\subsystem\vis_overlays.dm" #include "code\controllers\subsystem\vore.dm" #include "code\controllers\subsystem\vote.dm" +#include "code\controllers\subsystem\persistence\_persistence.dm" +#include "code\controllers\subsystem\persistence\cleanable_debris.dm" +#include "code\controllers\subsystem\persistence\panic_bunker.dm" +#include "code\controllers\subsystem\persistence\poly_parrot.dm" +#include "code\controllers\subsystem\persistence\recent_votes_etc.dm" +#include "code\controllers\subsystem\persistence\secret_satchels.dm" +#include "code\controllers\subsystem\persistence\trophies.dm" #include "code\controllers\subsystem\processing\chemistry.dm" #include "code\controllers\subsystem\processing\circuit.dm" #include "code\controllers\subsystem\processing\fastprocess.dm" @@ -491,6 +499,7 @@ #include "code\datums\components\swarming.dm" #include "code\datums\components\tackle.dm" #include "code\datums\components\thermite.dm" +#include "code\datums\components\twitch_plays.dm" #include "code\datums\components\twohanded.dm" #include "code\datums\components\uplink.dm" #include "code\datums\components\virtual_reality.dm" @@ -584,6 +593,7 @@ #include "code\datums\elements\_element.dm" #include "code\datums\elements\art.dm" #include "code\datums\elements\beauty.dm" +#include "code\datums\elements\bed_tucking.dm" #include "code\datums\elements\bsa_blocker.dm" #include "code\datums\elements\cleaning.dm" #include "code\datums\elements\decal.dm" @@ -2713,6 +2723,7 @@ #include "code\modules\mob\living\simple_animal\hostile\banana_spider.dm" #include "code\modules\mob\living\simple_animal\hostile\bear.dm" #include "code\modules\mob\living\simple_animal\hostile\bees.dm" +#include "code\modules\mob\living\simple_animal\hostile\bread.dm" #include "code\modules\mob\living\simple_animal\hostile\carp.dm" #include "code\modules\mob\living\simple_animal\hostile\cat_butcher.dm" #include "code\modules\mob\living\simple_animal\hostile\dark_wizard.dm" @@ -3340,6 +3351,7 @@ #include "code\modules\shuttle\shuttle.dm" #include "code\modules\shuttle\shuttle_rotate.dm" #include "code\modules\shuttle\snaxi.dm" +#include "code\modules\shuttle\spaceship_navigation_beacon.dm" #include "code\modules\shuttle\special.dm" #include "code\modules\shuttle\supply.dm" #include "code\modules\shuttle\syndicate.dm" @@ -3389,6 +3401,7 @@ #include "code\modules\spells\spell_types\taeclowndo.dm" #include "code\modules\spells\spell_types\telepathy.dm" #include "code\modules\spells\spell_types\the_traps.dm" +#include "code\modules\spells\spell_types\togglebuff.dm" #include "code\modules\spells\spell_types\touch_attacks.dm" #include "code\modules\spells\spell_types\trigger.dm" #include "code\modules\spells\spell_types\turf_teleport.dm" @@ -3412,6 +3425,7 @@ #include "code\modules\surgery\dental_implant.dm" #include "code\modules\surgery\embalming.dm" #include "code\modules\surgery\emergency_cardioversion_recovery.dm" +#include "code\modules\surgery\emergency_reboot.dm" #include "code\modules\surgery\experimental_dissection.dm" #include "code\modules\surgery\eye_surgery.dm" #include "code\modules\surgery\graft_synthtissue.dm" @@ -3606,6 +3620,7 @@ #include "modular_citadel\code\modules\client\loadout\shoes.dm" #include "modular_citadel\code\modules\client\loadout\suit.dm" #include "modular_citadel\code\modules\client\loadout\uniform.dm" +#include "modular_citadel\code\modules\client\loadout\unlockable.dm" #include "modular_citadel\code\modules\client\verbs\who.dm" #include "modular_citadel\code\modules\clothing\neck.dm" #include "modular_citadel\code\modules\clothing\trek.dm" diff --git a/tgui/packages/tgui-dev-server/package.json b/tgui/packages/tgui-dev-server/package.json index f1ab17a264..f72ac63d1f 100644 --- a/tgui/packages/tgui-dev-server/package.json +++ b/tgui/packages/tgui-dev-server/package.json @@ -3,7 +3,7 @@ "name": "tgui-dev-server", "version": "4.2.0", "dependencies": { - "axios": "^0.19.2", + "axios": "^0.21.1", "common": "workspace:*", "esm": "^3.2.25", "glob": "^7.1.4", diff --git a/tgui/packages/tgui/interfaces/ChemMaster.js b/tgui/packages/tgui/interfaces/ChemMaster.js index 9d16dc82e6..ddca187244 100644 --- a/tgui/packages/tgui/interfaces/ChemMaster.js +++ b/tgui/packages/tgui/interfaces/ChemMaster.js @@ -205,7 +205,7 @@ const PackagingControlsItem = props => { stepPixelSize={15} value={amount} minValue={1} - maxValue={10} + maxValue={20} onChange={onChangeAmount} /> |