diff --git a/.editorconfig b/.editorconfig
index ad578927262d..6b3864a466d1 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -19,4 +19,10 @@ indent_size = 4
[*.yml]
indent_style = space
indent_size = 2
+end_of_line = crlf
+
+[*.txt]
+end_of_line = crlf
+[*.md]
+end_of_line = crlf
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
new file mode 100644
index 000000000000..3de6361f2d28
--- /dev/null
+++ b/.git-blame-ignore-revs
@@ -0,0 +1,27 @@
+# git blame master ignore list.
+#
+# This file contains a list of git hashes of revisions to be ignored by git
+# blame. These revisions are considered "unimportant" in that they
+# are unlikely to be what you are interested in when blaming.
+#
+# Requires git 2.23 or later (or equivalent)
+# To enable, execute: git config blame.ignoreRevsFile .git-blame-ignore-revs
+#
+# Instructions:
+# - Only large (generally automated) reformatting or renaming CLs should be
+# added to this list. Do not put things here just because you feel they are
+# trivial or unimportant. If in doubt, do not put it on this list.
+# - Precede each revision with a comment containing the first line of its log.
+# For bulk work over many commits, place all commits in a block with a single
+# comment at the top describing the work done in those commits.
+# - Only put full 40-character hashes on this list (not short hashes or any
+# other revision reference).
+# - Append to the bottom of the file (revisions should be in chronological order
+# from oldest to newest).
+# - Because you must use a hash, you need to append to this list in a follow-up
+# CL to the actual reformatting CL that you are trying to ignore.
+
+# Major whitespace changes but nothing else
+51e1a662317e4fc5f4048bbd19375e46187dd91b
+bf996203dfc4b09f8dc4dd73b532f9ee49691776
+bfa20cdc17d1794969331c4272c4a8d7ad523a44
diff --git a/.gitattributes b/.gitattributes
index add01d675f96..81a615f78ebe 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -12,3 +12,11 @@ html/changelog.html merge=union
# Declare files that will always have CRLF line endings on checkout.
*.dm text eol=crlf
*.dmm text eol=crlf
+*.dme text eol=crlf
+*.py text eol=crlf
+*.txt text eol=crlf
+*.md text eol=crlf
+*.yml text eol=crlf
+
+# Declare files that will always have LF line endings on checkout.
+*.sh text eol=lf
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
deleted file mode 100644
index 095952513add..000000000000
--- a/.github/CODEOWNERS
+++ /dev/null
@@ -1,6 +0,0 @@
-# Require reviews from Core team for changes to CI or infra stuff
-.github/ @Nebula/Core
-Dockerfile @Nebula/Core
-flyway.conf @Nebula/Core
-sql/ @Nebula/Core
-LICENSE @Nebula/Core
diff --git a/.github/ISSUE_TEMPLATE/issue-report.md b/.github/ISSUE_TEMPLATE/issue-report.md
new file mode 100644
index 000000000000..ea0f0aa4093b
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/issue-report.md
@@ -0,0 +1,62 @@
+---
+name: Issue report
+about: Create a report about a bug or other issue
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+
+
+#### Description of issue
+
+
+
+#### Difference between expected and actual behavior
+
+
+
+#### Steps to reproduce
+
+
+
+#### Specific information for locating
+
+
+
+
+#### Length of time in which bug has been known to occur
+
+
+
+
+#### Client version, Server revision & Game ID
+
+
+
+
+#### Issue bingo
+
+
+- [ ] Issue could be reproduced at least once
+- [ ] Issue could be reproduced by different players
+- [ ] Issue could be reproduced in multiple rounds
+- [ ] Issue happened in a recent (less than 7 days ago) round
+- [ ] [Couldn't find an existing issue about this](https://github.com/NebulaSS13/Nebula/issues)
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index bea1f8d97f4a..15f4a756de80 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -1,14 +1,38 @@
-
\ No newline at end of file
+
+
+
+
+
+
+
+## Description of changes
+
+
+## Why and what will this PR improve
+
+
+## Authorship
+
+
+## Changelog
+:cl:
+add: Added new things
+add: Added more things
+del: Removed old things
+tweak: tweaked a few things
+balance: rebalanced something
+bugfix: fixed a few things
+soundadd: added a new sound thingy
+sounddel: removed an old sound thingy
+imageadd: added some icons and images
+imagedel: deleted some icons and images
+spellcheck: fixed a few typos
+code: changed some code
+refactor: refactored some code
+config: changed some config setting
+admin: messed with admin stuff
+server: something server ops should know
+/:cl:
+
+
+
\ No newline at end of file
diff --git a/.github/workflows/changelog_generation.yml b/.github/workflows/changelog_generation.yml
new file mode 100644
index 000000000000..f5a79a52a197
--- /dev/null
+++ b/.github/workflows/changelog_generation.yml
@@ -0,0 +1,35 @@
+name: Compile changelogs
+
+on:
+ schedule:
+ - cron: "0 0 * * *"
+ workflow_dispatch:
+
+jobs:
+ CompileCL:
+ runs-on: ubuntu-latest
+ if: github.repository == 'NebulaSS13/Nebula' # to prevent this running on forks
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+ with:
+ fetch-depth: 0 # Otherwise, we will fail to push refs
+ ref: dev
+ token: ${{ secrets.BOT_TOKEN }}
+ - name: Python setup
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.x'
+ - name: Install depends
+ run: |
+ python -m pip install --upgrade pip
+ pip install pyyaml bs4
+ - name: Compile CL
+ run: |
+ python tools/changelog/ss13_genchangelog.py html/changelog.html html/changelogs
+ - name: Commit And Push
+ run: |
+ git config --local user.email "${{ secrets.BOT_EMAIL }}"
+ git config --local user.name "${{ secrets.BOT_NAME }}"
+ git commit -m "Automatic changelog generation [ci skip]" -a
+ git push
diff --git a/.github/workflows/generate_documentation.yml b/.github/workflows/generate_documentation.yml
new file mode 100644
index 000000000000..0f5480f5a2e3
--- /dev/null
+++ b/.github/workflows/generate_documentation.yml
@@ -0,0 +1,36 @@
+name: Generate Documentation
+
+on:
+ push:
+ branches:
+ - dev
+ workflow_dispatch:
+
+env:
+ SPACEMAN_DMM_VERSION: suite-1.11
+
+jobs:
+ generate_documentation:
+ if: "!contains(github.event.head_commit.message, '[ci skip]')"
+ runs-on: ubuntu-latest
+ concurrency: gen-docs
+ steps:
+ - uses: actions/checkout@v3
+ - name: Setup Cache
+ uses: actions/cache@v3
+ with:
+ path: $HOME/spaceman_dmm/$SPACEMAN_DMM_VERSION
+ key: ${{ runner.os }}-spacemandmm-${{ env.SPACEMAN_DMM_VERSION }}
+ - name: Install dmdoc
+ run: scripts/install-spaceman-dmm.sh dmdoc
+ - name: Generate documentation
+ run: |
+ ~/dmdoc
+ touch dmdoc/.nojekyll
+ - name: Deploy
+ uses: JamesIves/github-pages-deploy-action@3.7.1
+ with:
+ token: ${{ secrets.GITHUB_TOKEN }}
+ branch: gh-pages-dmdoc
+ folder: dmdoc
+ force: false
diff --git a/.github/workflows/make_changelogs.yml b/.github/workflows/make_changelogs.yml
new file mode 100644
index 000000000000..b6057154e282
--- /dev/null
+++ b/.github/workflows/make_changelogs.yml
@@ -0,0 +1,31 @@
+name: Make changelogs
+
+on:
+ push:
+ branches:
+ - dev
+ workflow_dispatch:
+
+jobs:
+ MakeCL:
+ runs-on: ubuntu-latest
+ if: github.repository == 'NebulaSS13/Nebula' # to prevent this running on forks
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+ with:
+ fetch-depth: 25
+ - name: Python setup
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.x'
+ - name: Install depends
+ run: |
+ python -m pip install --upgrade pip
+ pip install ruamel.yaml PyGithub
+ - name: Make CL
+ env:
+ BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
+ GIT_EMAIL: "${{ secrets.BOT_EMAIL }}"
+ GIT_NAME: "${{ secrets.BOT_NAME }}"
+ run: python tools/changelog/generate_cl.py
\ No newline at end of file
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
new file mode 100644
index 000000000000..7f402ce4ca9f
--- /dev/null
+++ b/.github/workflows/test.yml
@@ -0,0 +1,124 @@
+name: Run Tests
+
+on:
+ push:
+ branches:
+ - dev
+ - stable
+ - staging
+ pull_request:
+ branches:
+ - dev
+ - stable
+ - staging
+ workflow_dispatch:
+
+env:
+ BYOND_MAJOR: "516"
+ BYOND_MINOR: "1663"
+ SPACEMAN_DMM_VERSION: suite-1.11
+
+jobs:
+ DreamChecker:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - name: Setup Cache
+ uses: actions/cache@v3
+ with:
+ path: ~/spaceman_dmm/${{ env.SPACEMAN_DMM_VERSION }}
+ key: ${{ runner.os }}-spacemandmm-${{ env.SPACEMAN_DMM_VERSION }}
+ - name: Install Dreamchecker
+ run: scripts/install-spaceman-dmm.sh dreamchecker
+ - name: Run Dreamchecker
+ run: |
+ set -o pipefail
+ ./test/lint-all-modpacks.sh nebula.dme
+ ./test/lint-each-modpack.sh nebula.dme
+ - name: Annotate Lints
+ uses: yogstation13/DreamAnnotate@v2
+ if: always()
+ with:
+ outputFile: output-annotations.txt
+ - name: Run Failure Webhook
+ env:
+ JOB_STATUS: ${{ job.status }}
+ WEBHOOK_URL: ${{ secrets.WEBHOOK_URL }}
+ HOOK_OS_NAME: ${{ runner.os }}
+ WORKFLOW_NAME: ${{ github.workflow }}
+ if: ${{ failure() }}
+ run: |
+ wget https://raw.githubusercontent.com/DiscordHooks/github-actions-discord-webhook/master/send.sh
+ chmod +x send.sh
+ ./send.sh failure $WEBHOOK_URL
+ OpenDream:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - name: Python setup
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.x'
+ - name: Install OpenDream
+ uses: robinraju/release-downloader@v1.9
+ with:
+ repository: "OpenDreamProject/OpenDream"
+ tag: "latest"
+ fileName: "DMCompiler_linux-x64.tar.gz"
+ extract: true
+ - name: Run OpenDream
+ run: ./test/compile-od-all-modpacks.sh nebula.dme
+ Code:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - name: Setup Cache
+ uses: actions/cache@v3
+ with:
+ path: ~/BYOND-${{ env.BYOND_MAJOR }}.${{ env.BYOND_MINOR }}
+ key: ${{ runner.os }}-byond-${{ env.BYOND_MAJOR }}-${{ env.BYOND_MINOR }}
+ - name: Install Dependencies
+ run: sudo apt-get install -y uchardet
+ - name: Run Tests
+ env:
+ TEST: CODE
+ run: test/run-test.sh
+ - name: Run Failure Webhook
+ env:
+ JOB_STATUS: ${{ job.status }}
+ WEBHOOK_URL: ${{ secrets.WEBHOOK_URL }}
+ HOOK_OS_NAME: ${{ runner.os }}
+ WORKFLOW_NAME: ${{ github.workflow }}
+ if: ${{ failure() }}
+ run: |
+ wget https://raw.githubusercontent.com/DiscordHooks/github-actions-discord-webhook/master/send.sh
+ chmod +x send.sh
+ ./send.sh failure $WEBHOOK_URL
+ Maps:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ map_path: [example, tradeship, exodus, ministation, shaded_hills, away_sites_testing, modpack_testing, planets_testing]
+ steps:
+ - uses: actions/checkout@v3
+ - name: Setup Cache
+ uses: actions/cache@v3
+ with:
+ path: ~/BYOND-${{ env.BYOND_MAJOR }}.${{ env.BYOND_MINOR }}
+ key: ${{ runner.os }}-byond-${{ env.BYOND_MAJOR }}-${{ env.BYOND_MINOR }}
+ - name: Run Tests
+ env:
+ TEST: MAP
+ MAP_PATH: ${{ matrix.map_path }}
+ run: test/run-test.sh
+ - name: Run Failure Webhook
+ env:
+ JOB_STATUS: ${{ job.status }}
+ WEBHOOK_URL: ${{ secrets.WEBHOOK_URL }}
+ HOOK_OS_NAME: ${{ runner.os }}
+ WORKFLOW_NAME: ${{ github.workflow }}
+ if: ${{ failure() }}
+ run: |
+ wget https://raw.githubusercontent.com/DiscordHooks/github-actions-discord-webhook/master/send.sh
+ chmod +x send.sh
+ ./send.sh failure $WEBHOOK_URL
diff --git a/.gitignore b/.gitignore
index 95cdf1eea9c3..3d638d224bdc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,50 +1,62 @@
-# ignore misc BYOND files
-Thumbs.db
-*.log
-*.int
-*.rsc
-*.dmb
-*.lk
-*.backup
-*.before
-data/
-cfg/
-build_log.txt
-use_map
-stopserver
-reboot_called
-atupdate
-
-# ignore config, but not subdirs
-!config/*/
-config/*
-sql/test_db
-
-# vscode
-.vscode/*
-.history
-
-# swap
-[._]*.s[a-v][a-z]
-[._]*.sw[a-p]
-[._]s[a-v][a-z]
-[._]sw[a-p]
-
-# session
-Session.vim
-
-# temporary
-.netrwhist
-*~
-
-# auto-generated tag files
-tags
-nebula.code-workspace
-
-# ignore built libs
-lib/*.dll
-lib/*.so
-
-# python
-*.pyc
-__pycache__
+# ignore misc BYOND files
+*.log
+*.int
+*.rsc
+*.dmb
+*.lk
+*.backup
+*.before
+data/
+dmdoc/
+cfg/
+build_log.txt
+use_map
+stopserver
+reboot_called
+atupdate
+
+# ignore config, but not subdirs
+!config/*/
+config/*
+sql/test_db
+
+# misc OS garbage
+Thumbs.db
+Thumbs.db:encryptable
+.DS_Store
+
+# vscode
+.vscode/*
+*.code-workspace
+.history
+
+# git/kdiff4
+*.orig
+
+# swap
+[._]*.s[a-v][a-z]
+[._]*.sw[a-p]
+[._]s[a-v][a-z]
+[._]sw[a-p]
+
+# session
+Session.vim
+
+# temporary
+.netrwhist
+*~
+
+# auto-generated tag files
+tags
+
+# ignore built libs
+lib/*.dll
+lib/*.so
+/prof.dll
+
+# python
+*.pyc
+__pycache__
+
+# Running OpenDream locally
+nebula.json
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 6413b858e869..000000000000
--- a/.travis.yml
+++ /dev/null
@@ -1,51 +0,0 @@
-language: generic
-os: linux
-dist: xenial
-jdk: openjdk8
-
-env:
- global:
- BYOND_MAJOR="512"
- BYOND_MINOR="1485"
-
-# ALL MAPS MUST BE PRESENT HERE
-# IF THEY ARE NOT, YOUR BUILD WILL FAIL
-jobs:
- include:
- - name: "DreamChecker"
- env: SPACEMAN_DMM_VERSION=suite-1.4
- cache:
- directories: $HOME/spaceman_dmm/$SPACEMAN_DMM_VERSION
- install:
- - ./scripts/install-spaceman-dmm.sh dreamchecker
- script:
- - ~/dreamchecker
- - name: "Code"
- env: TEST=CODE
- - name: "Map - Example"
- env: TEST=MAP MAP_PATH=example
- - name: "Map - Tradeship"
- env: TEST=MAP MAP_PATH=tradeship
- - name: "Map - Away Sites"
- env: TEST=MAP MAP_PATH=away_sites_testing
-
-cache:
- directories:
- - $HOME/BYOND-${BYOND_MAJOR}.${BYOND_MINOR}
-
-addons:
- apt:
- packages:
- - libc6-i386
- - libgcc1:i386
- - libstdc++6:i386
- - libyaml-dev
- - uchardet
-
-script:
- - test/run-test.sh
-
-after_failure:
- - wget https://raw.githubusercontent.com/DiscordHooks/travis-ci-discord-webhook/master/send.sh
- - chmod +x send.sh
- - ./send.sh failure $WEBHOOK_URL
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
new file mode 100644
index 000000000000..ad43ea70311d
--- /dev/null
+++ b/.vscode/extensions.json
@@ -0,0 +1,6 @@
+{
+ "recommendations": [
+ "ss13.byond",
+ "anturk.dmi-editor"
+ ]
+}
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 000000000000..04e29897ec51
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,9 @@
+{
+ "files.associations": {
+ "*.tmpl": "html"
+ },
+ "gitlens.advanced.blame.customArguments": [
+ "--ignore-revs-file",
+ ".git-blame-ignore-revs"
+ ]
+}
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 30027423daea..3940d892dd02 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,3 +1,6 @@
+# Branch Structure
+The repository has two main branches, `dev` and `stable`, and one secondary branch, `staging`. Feature implementation, new assets, new maps, and other 'content' pull requests should be pointed at `dev`, while bugfixes for existing code, or fixes to broken assets like sprites or sounds, should be pointed at `stable`. `stable` will be merged back into `dev` periodically to keep the `dev` branch up to date with fixes, so duplicate pull requests are not necessary. `staging` is used for the period when `dev` is being tested and reviewed for promotion to `stable`, and should be targeted when writing fixes for issues encountered during `staging` testing, and otherwise should not be used.
+
# Contribution Standards
This is a quick and dirty set of agreed-upon standards for contributions to the codebase. It is fairly informal at the moment and should be considered liable to change.
@@ -12,12 +15,14 @@ This is a quick and dirty set of agreed-upon standards for contributions to the
- Use constants instead of magic numbers or bare strings, when the values are being used in logic.
- Do not comment out code, delete it, version control makes keeping it in the codebase pointless.
- Macros/consts UPPERCASE, types and var names lowercase.
-- Use `global.foo` when referencing global variables (rather than just `foo`, or the now deprecated `GLOB.foo`), for the sake of readability.
+- Use the `/global/` keyword when declaring a globally scoped variable (ie. `var/global/list/foo`).
+- Use the `/static/` keyword, rather than `/global/`, when declaring a static member variable that should be static (`/obj/var/static/foo`).
+- Use `global.foo` when referencing global variables (rather than just `foo`).
---
### Pull requests
-- It's ultimately the responsibility of the person opening the PR to keep it up to date with the codebase and fix any issues found by Travis/pointed out during review. Reviewers should be open to discussion objections/alternatives either on Discord or in the diff.
+- It's ultimately the responsibility of the person opening the PR to keep it up to date with the codebase and fix any issues found by unit testing or pointed out during review. Reviewers should be open to discussion objections/alternatives either on Discord or in the diff.
- Opening a PR on behalf of someone else is not recommended unless you are willing to see it through even with changes requested, etc. Opening a PR in bad faith or to make a point is not acceptable.
#### Pull request reviews:
@@ -25,3 +30,14 @@ This is a quick and dirty set of agreed-upon standards for contributions to the
- If there's a personal dislike of the PR, post about it for discussion. Maybe have an 'on hold for discussion' label. Try to reach a consensus/compromise. Failing a compromise, a majority maintainer vote will decide.
- First person to review approves the PR, second person to review can merge it. If 24 hours pass with no objections, first person can merge the PR themselves.
- PRs can have a 24 hour grace period applied by maintainers if it seems important for discussion and responses to be involved. Don't merge for the grace period if applied (reviews are fine).
+
+### Footguns
+A footgun is a pattern, function, assumption etc. that stands a strong chance to shoot you in the foot. They are documented here for ease of reference by new contributors.
+
+#### List footguns
+- Adding lists to lists will actually perform a merge, rather than inserting the list as a new record. If you want to insert a list into a list, you need to either:
+ - double-wrap it, ex. `my_list += list(list("some_new_data" = 25))`
+ - set the index directly, ex. `my_list[my_list.len] = list("some_new_data" = 25)`
+- Using variables and macros as associative list keys have some notable behavior.
+ - If declaring an associative list using a macro as a key, in a case where the macro does not exist (due to misspelling, etc.), that macro name will be treated as a string value for the associative list. You can guard against this by wrapping the macro in parens, ex. `list( (MY_MACRO_NAME) = "some_value" )`, which will fail to compile instead in cases where the macro doesn't exist.
+ - If a variable is used as the associative key, it *must* be wrapped in parens, or it will be used as a string key.
\ No newline at end of file
diff --git a/README.md b/README.md
index 17efba9164c8..60c5fccb5b77 100644
--- a/README.md
+++ b/README.md
@@ -1,37 +1,81 @@
-# Nebula 13
-
-[Discord](https://discord.gg/Ddw58yF) - [Code](http://github.com/NebulaSS13/Nebula/)
-
----
-
-### CONTRIBUTING GUIDELINES
-
-All users are expected to review [/docs/CODE_OF_CONDUCT.md](/docs/CODE_OF_CONDUCT.md) before interacting with the repository or other users.
-
----
-
-### SECURITY
-
-Please see [/docs/SECURITY.md](/docs/SECURITY.md) for this repository's security policy, and how to report security issues.
-
----
-
-### LICENSE
-
-The code for Nebula13 is licensed under the [GNU Affero General Public License v3](http://www.gnu.org/licenses/agpl.html), which can be found in full in [/LICENSE](/LICENSE).
-
-Code with a git authorship date prior to `1420675200 +0000` (2015/01/08 00:00 GMT) is licensed under the GNU General Public License version 3, which can be found in full in [/docs/GPL3.txt](/docs/GPL3.txt)
-
-All code where the authorship dates on or after `1420675200 +0000` is assumed to be licensed under AGPL v3, if you wish to license under GPL v3 please make this clear in the commit message and any added files.
-
-If you wish to develop and host this codebase in a closed source manner you may use all commits prior to `1420675200 +0000`, which are licensed under GPL v3. The major change here is that if you host a server using any code licensed under AGPLv3 you are required to provide full source code for your servers users as well including addons and modifications you have made.
-
-See [here](https://www.gnu.org/licenses/why-affero-gpl.html) for more information.
-
-All assets including icons and sound are under a [Creative Commons 3.0 BY-SA license](http://creativecommons.org/licenses/by-sa/3.0/) unless otherwise indicated.
-
----
-
-### GETTING THE CODE AND INSTALLING
-
-Please see [/docs/installation.md](/docs/installation.md) for instructions on obtaining, installing, updating, and running this code.
+
+
+
+
+ Nebula 13
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Contributing Guidelines •
+ Security •
+ License •
+ Getting the Code and Installing
+
+
+---
+
+### NOTICE OF MODIFICATION
+
+This project was forked from [Baystation 12](https://github.com/Baystation12/Baystation12) on 6 Jan 2020.
+
+---
+
+### CONTRIBUTING GUIDELINES
+
+All users are expected to review [/docs/CODE_OF_CONDUCT.md](/docs/CODE_OF_CONDUCT.md) before interacting with the repository or other users.
+
+---
+
+### SECURITY
+
+Please see [/docs/SECURITY.md](/docs/SECURITY.md) for this repository's security policy, and how to report security issues.
+
+---
+
+### LICENSE
+
+The code for Nebula13 is licensed under the [GNU Affero General Public License v3](http://www.gnu.org/licenses/agpl.html), which can be found in full in [/LICENSE](/LICENSE).
+
+Code with a git authorship date prior to `1420675200 +0000` (2015/01/08 00:00 GMT) is licensed under the GNU General Public License version 3, which can be found in full in [/docs/GPL3.txt](/docs/GPL3.txt)
+
+All code where the authorship dates on or after `1420675200 +0000` is assumed to be licensed under AGPL v3, if you wish to license under GPL v3 please make this clear in the commit message and any added files.
+
+If you wish to develop and host this codebase in a closed source manner you may use all commits prior to `1420675200 +0000`, which are licensed under GPL v3. The major change here is that if you host a server using any code licensed under AGPLv3 you are required to provide full source code for your servers users as well including addons and modifications you have made.
+
+See [here](https://www.gnu.org/licenses/why-affero-gpl.html) for more information.
+
+All assets including icons and sound are under a [Creative Commons 3.0 BY-SA license](http://creativecommons.org/licenses/by-sa/3.0/) unless otherwise indicated.
+
+---
+
+### GETTING THE CODE AND INSTALLING
+
+Please see [/docs/installation.md](/docs/installation.md) for instructions on obtaining, installing, updating, and running this code.
diff --git a/SpacemanDMM.toml b/SpacemanDMM.toml
new file mode 100644
index 000000000000..fc6a281a5178
--- /dev/null
+++ b/SpacemanDMM.toml
@@ -0,0 +1,75 @@
+[langserver]
+dreamchecker = true
+
+[dmdoc]
+use_typepath_names = true
+
+[code_standards]
+disallow_relative_type_definitions = true
+disallow_relative_proc_definitions = true
+
+[debugger]
+engine = "auxtools"
+
+[diagnostics]
+# Raised by DreamChecker
+disabled_directive = "error"
+sets_directive_twice = "error"
+invalid_lint_directive_value = "error"
+invalid_set_value = "error"
+unknown_linter_setting = "error"
+override_missing_keyword_arg = "error"
+must_not_override = "error"
+must_call_parent = "error"
+final_var = "error"
+private_proc = "error"
+protected_proc = "error"
+private_var = "error"
+protected_var = "error"
+must_be_pure = "error"
+must_not_sleep = "error"
+redefined_proc = "off"
+ambiguous_in_lhs = "error"
+ambiguous_not_bitwise = "error"
+no_typehint_implicit_new = "error"
+field_access_static_type = "error"
+proc_call_static_type = "error"
+proc_has_no_parent = "error"
+no_operator_overload = "error"
+unreachable_code = "error"
+control_condition_static = "error"
+if_condition_determinate = "error"
+loop_condition_determinate = "error"
+
+# Raised by Lexer
+integer_precision_loss = "error"
+
+# Raised by Parser
+duplicate_include = "error"
+macro_redefined = "error"
+macro_undefined_no_definition = "error"
+
+# Raised by Object Tree
+override_precedes_definition = "error"
+
+[map_renderer]
+hide_invisible = [
+ "/obj/effect/step_trigger",
+ "/obj/abstract",
+ "/turf/unsimulated/mask",
+ "/obj/effect/shuttle_landmark",
+ "/obj/effect/overmap",
+]
+
+[map_renderer.render_passes]
+overlays = false
+gravity-gen = false
+pretty = false
+icon-smoothing = false
+icon-smoothing-2016 = true
+smart-cables = false
+# TODO: add support for directional_offsets var to Jupyterkat's fork?
+offsets = false
+# maybe also add support for our random spawners?
+random = false
+spawners = false
\ No newline at end of file
diff --git a/code/___compile_options.dm b/code/___compile_options.dm
new file mode 100644
index 000000000000..a4f54bc99b94
--- /dev/null
+++ b/code/___compile_options.dm
@@ -0,0 +1,12 @@
+// If REFTRACK_IN_CI is defined, the reftracker will run in CI.
+#define REFTRACK_IN_CI
+#if defined(REFTRACK_IN_CI) && defined(UNIT_TEST) && !defined(SPACEMAN_DMM)
+#define REFTRACKING_ENABLED
+#define GC_FAILURE_HARD_LOOKUP
+#define FIND_REF_NO_CHECK_TICK
+#endif
+
+// parity with previous behavior where TESTING enabled reftracking
+#ifdef TESTING
+#define REFTRACKING_ENABLED
+#endif
\ No newline at end of file
diff --git a/code/___opendream_linting.dm b/code/___opendream_linting.dm
new file mode 100644
index 000000000000..e9fe9369d681
--- /dev/null
+++ b/code/___opendream_linting.dm
@@ -0,0 +1,36 @@
+#ifdef OPENDREAM
+//1000-1999
+// FileAlreadyIncluded trips up on modpack DMEs
+#pragma FileAlreadyIncluded disabled
+#pragma MissingIncludedFile error
+#pragma MisplacedDirective error
+#pragma UndefineMissingDirective error
+#pragma DefinedMissingParen error
+#pragma ErrorDirective error
+#pragma WarningDirective warning
+#pragma MiscapitalizedDirective error
+
+//2000-2999
+#pragma SoftReservedKeyword error
+#pragma DuplicateVariable error
+#pragma DuplicateProcDefinition error
+#pragma PointlessParentCall error
+#pragma PointlessBuiltinCall error
+#pragma SuspiciousMatrixCall error
+#pragma FallbackBuiltinArgument error
+#pragma MalformedRange error
+#pragma InvalidRange error
+#pragma InvalidSetStatement error
+#pragma InvalidOverride error
+#pragma DanglingVarType error
+#pragma MissingInterpolatedExpression error
+#pragma AmbiguousResourcePath error
+
+//3000-3999
+#pragma EmptyBlock error
+#pragma EmptyProc disabled
+#pragma UnsafeClientAccess disabled
+#pragma SuspiciousSwitchCase error
+#pragma AssignmentInConditional error
+#pragma AmbiguousInOrder error
+#endif
\ No newline at end of file
diff --git a/code/__datastructures/globals.dm b/code/__datastructures/globals.dm
deleted file mode 100644
index 637af7f0fcdc..000000000000
--- a/code/__datastructures/globals.dm
+++ /dev/null
@@ -1,38 +0,0 @@
-//See controllers/globals.dm
-#define GLOBAL_MANAGED(X, InitValue)\
-/datum/controller/global_vars/proc/InitGlobal##X(){\
- ##X = ##InitValue;\
- gvars_datum_init_order += #X;\
-}
-#define GLOBAL_UNMANAGED(X, InitValue) /datum/controller/global_vars/proc/InitGlobal##X()
-
-#ifndef TESTING
-#define GLOBAL_PROTECT(X)\
-/datum/controller/global_vars/InitGlobal##X(){\
- ..();\
- gvars_datum_protected_varlist += #X;\
-}
-#else
-#define GLOBAL_PROTECT(X)
-#endif
-
-#define GLOBAL_REAL_VAR(X) var/global/##X
-#define GLOBAL_REAL(X, Typepath) var/global##Typepath/##X
-
-#define GLOBAL_RAW(X) /datum/controller/global_vars/var/global##X
-
-#define GLOBAL_VAR_INIT(X, InitValue) GLOBAL_RAW(/##X); GLOBAL_MANAGED(X, InitValue)
-
-#define GLOBAL_VAR_CONST(X, InitValue) GLOBAL_RAW(/const/##X) = InitValue; GLOBAL_UNMANAGED(X, InitValue)
-
-#define GLOBAL_LIST_INIT(X, InitValue) GLOBAL_RAW(/list/##X); GLOBAL_MANAGED(X, InitValue)
-
-#define GLOBAL_LIST_EMPTY(X) GLOBAL_LIST_INIT(X, list())
-
-#define GLOBAL_DATUM_INIT(X, Typepath, InitValue) GLOBAL_RAW(Typepath/##X); GLOBAL_MANAGED(X, InitValue)
-
-#define GLOBAL_VAR(X) GLOBAL_RAW(/##X); GLOBAL_MANAGED(X, null)
-
-#define GLOBAL_LIST(X) GLOBAL_RAW(/list/##X); GLOBAL_MANAGED(X, null)
-
-#define GLOBAL_DATUM(X, Typepath) GLOBAL_RAW(Typepath/##X); GLOBAL_MANAGED(X, null)
diff --git a/code/__datastructures/priority_queue.dm b/code/__datastructures/priority_queue.dm
deleted file mode 100644
index 380db428fd24..000000000000
--- a/code/__datastructures/priority_queue.dm
+++ /dev/null
@@ -1,63 +0,0 @@
-
-//////////////////////
-//PriorityQueue object
-//////////////////////
-
-//an ordered list, using the cmp proc to weight the list elements
-/PriorityQueue
- var/list/L //the actual queue
- var/cmp //the weight function used to order the queue
-
-/PriorityQueue/New(compare)
- L = new()
- cmp = compare
-
-/PriorityQueue/proc/IsEmpty()
- return !L.len
-
-//add an element in the list,
-//immediatly ordering it to its position using dichotomic search
-/PriorityQueue/proc/Enqueue(atom/A)
- ADD_SORTED(L, A, cmp)
-
-//removes and returns the first element in the queue
-/PriorityQueue/proc/Dequeue()
- if(!L.len)
- return 0
- . = L[1]
-
- Remove(.)
-
-//removes an element
-/PriorityQueue/proc/Remove(atom/A)
- . = L.Remove(A)
-
-//returns a copy of the elements list
-/PriorityQueue/proc/List()
- . = L.Copy()
-
-//return the position of an element or 0 if not found
-/PriorityQueue/proc/Seek(atom/A)
- . = L.Find(A)
-
-//return the element at the i_th position
-/PriorityQueue/proc/Get(i)
- if(i > L.len || i < 1)
- return 0
- return L[i]
-
-//return the length of the queue
-/PriorityQueue/proc/Length()
- . = L.len
-
-//replace the passed element at it's right position using the cmp proc
-/PriorityQueue/proc/ReSort(atom/A)
- var/i = Seek(A)
- if(i == 0)
- return
- while(i < L.len && call(cmp)(L[i],L[i+1]) > 0)
- L.Swap(i,i+1)
- i++
- while(i > 1 && call(cmp)(L[i],L[i-1]) <= 0) //last inserted element being first in case of ties (optimization)
- L.Swap(i,i-1)
- i--
diff --git a/code/__defines/MC.dm b/code/__defines/MC.dm
index 9177b52d2b69..f01b2f954289 100644
--- a/code/__defines/MC.dm
+++ b/code/__defines/MC.dm
@@ -24,10 +24,10 @@
if (Datum.is_processing) {\
if(Datum.is_processing != #Processor)\
{\
- crash_with("Failed to start processing. [log_info_line(Datum)] is already being processed by [Datum.is_processing] but queue attempt occured on [#Processor]."); \
+ PRINT_STACK_TRACE("Failed to start processing. [log_info_line(Datum)] is already being processed by [Datum.is_processing] but queue attempt occurred on [#Processor]."); \
}\
} else {\
- Datum.is_processing = #Processor;\
+ Datum.is_processing = Processor._internal_name;\
Processor.processing += Datum;\
}
@@ -36,7 +36,7 @@ if(Datum.is_processing) {\
if(Processor.processing.Remove(Datum)) {\
Datum.is_processing = null;\
} else {\
- crash_with("Failed to stop processing. [log_info_line(Datum)] is being processed by [Datum.is_processing] but de-queue attempt occured on [#Processor]."); \
+ PRINT_STACK_TRACE("Failed to stop processing. [log_info_line(Datum)] is being processed by [Datum.is_processing] but de-queue attempt occurred on [#Processor]."); \
}\
}
@@ -89,15 +89,33 @@ if(Datum.is_processing) {\
// -- SStimer stuff --
-#define TIMER_UNIQUE (1 << 0) // Don't run if there is an identical unique timer active
-#define TIMER_OVERRIDE (1 << 1) // For unique timers: Replace the old timer rather then not start this one
-#define TIMER_CLIENT_TIME (1 << 2) // Timing should be based on how timing progresses on clients, not the server - this is more expensive, so should only be used with things that need to progress client-side (like animate or sound)
-#define TIMER_STOPPABLE (1 << 3) // Timer can be stopped using deltimer()
-#define TIMER_NO_HASH_WAIT (1 << 4) // For unique timers: don't distinguish timers by wait
-#define TIMER_LOOP (1 << 5) // Repeat the timer until it's deleted.
+#define TIMER_UNIQUE BITFLAG(0) // Don't run if there is an identical unique timer active.
+#define TIMER_OVERRIDE BITFLAG(1) // For unique timers: Replace the old timer rather than not start this one.
+#define TIMER_CLIENT_TIME BITFLAG(2) // Timing should be based on how timing progresses on clients, not the server - this is more expensive, so should only be used with things that need to progress client-side (like animate or sound).
+#define TIMER_STOPPABLE BITFLAG(3) // Timer can be stopped using deltimer().
+#define TIMER_NO_HASH_WAIT BITFLAG(4) // For unique timers: don't distinguish timers by wait.
+#define TIMER_LOOP BITFLAG(5) // Repeat the timer until it's deleted or the parent is destroyed.
+
+// TIMER_OVERRIDE is impossible to support because we don't track that for DPC queued calls, and adding a third list for that would be a lot of overhead for no real benefit
+// TIMER_STOPPABLE can't work because it uses timer IDs instead of hashes, and DPC queued calls don't have IDs.
+// TIMER_LOOP doesn't work because it needs to be a timer that can re-insert in the list, and a zero-wait looping timer should really be a ticker subsystem instead.
+// Update these defines if any of those change.
+/// These are the flags forbidden when putting zero-wait timers on SSdpc instead of SStimer.
+#define DPC_FORBID_FLAGS TIMER_UNIQUE | TIMER_OVERRIDE | TIMER_STOPPABLE | TIMER_LOOP
+/// These are the flags forbidden when putting zero-wait TIMER_UNIQUE timers on SSdpc instead of SStimer.
+#define UDPC_FORBID_FLAGS TIMER_OVERRIDE | TIMER_STOPPABLE | TIMER_LOOP
#define TIMER_ID_NULL -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__)
+
//SUBSYSTEM STATES
#define SS_IDLE 0 //aint doing shit.
#define SS_QUEUED 1 //queued to run
@@ -111,15 +129,17 @@ if(Datum.is_processing) {\
#define SS_INITSTATE_STARTED 1
#define SS_INITSTATE_DONE 2
-
-#define SUBSYSTEM_DEF(X) GLOBAL_REAL(SS##X, /datum/controller/subsystem/##X);\
+#define SUBSYSTEM_DEF(X) var/global/datum/controller/subsystem/##X/SS##X;\
/datum/controller/subsystem/##X/New(){\
NEW_SS_GLOBAL(SS##X);\
PreInit();\
}\
+/datum/controller/subsystem/##X{\
+ _internal_name = "SS" + #X;\
+}\
/datum/controller/subsystem/##X
-#define PROCESSING_SUBSYSTEM_DEF(X) GLOBAL_REAL(SS##X, /datum/controller/subsystem/processing/##X);\
+#define PROCESSING_SUBSYSTEM_DEF(X) var/global/datum/controller/subsystem/processing/##X/SS##X;\
/datum/controller/subsystem/processing/##X/New(){\
NEW_SS_GLOBAL(SS##X);\
PreInit();\
@@ -129,4 +149,5 @@ if(Datum.is_processing) {\
processing = SS##X.processing; \
}\
}\
-/datum/controller/subsystem/processing/##X
+/datum/controller/subsystem/processing/##X/_internal_name = "SS" + #X;\
+/datum/controller/subsystem/processing/##X
\ No newline at end of file
diff --git a/code/__defines/ZAS.dm b/code/__defines/ZAS.dm
index a5a36e31b2b1..6734ee68ffb1 100644
--- a/code/__defines/ZAS.dm
+++ b/code/__defines/ZAS.dm
@@ -1,3 +1,18 @@
+
+/*
+ Uncomment this to enable ZAS debugging tools. While ghosted, you will see a visualization of the atmos status of turfs.
+ Green turfs are zones that are existing happily.
+ Yellow-orange turfs are a zone that has recently been merged into another zone.
+ Red turfs are turfs are an invalidated zone. Invalid zones are zones that were destroyed.
+ White/overlay-less turfs are turfs that are the origin point of a zone. This is completely useless information.
+ Purple outlines indicate the turf was marked for an update by SSair, and is in its processing list.
+ In addition, all ZAS-related datums and turfs will have a "verbose" var. Set this to 1 using View Variables to get robust to_chat()s about activity.
+ Finally, this is a friendly reminder that using Debug Verbs gives access to the Zone Info and Test ZAS Connection verbs when you right click a turf.
+
+ Addendum:
+ There are additional debug overlays that use ZAS_ZONE_BLOCKER and ZAS_DIRECTIONAL_BLOCKER.
+ They take priority over standard overlays, displaying directional airflow, and are generally not needed so they are commented out by default.
+*/
//#define ZASDBG
#define MULTIZAS
@@ -5,7 +20,8 @@
#define ZONE_BLOCKED 2
#define BLOCKED 3
-#define ZONE_MIN_SIZE 14 //zones with less than this many turfs will always merge, even if the connection is not direct
+/// Zones with less than this many turfs will always merge, even if the connection is not direct.
+#define ZONE_MIN_SIZE 14
#define CANPASS_ALWAYS 1
#define CANPASS_DENSITY 2
@@ -21,48 +37,46 @@
#define SOUTHDOWN (SOUTH|DOWN)
#define WESTDOWN (WEST|DOWN)
-#define TURF_HAS_VALID_ZONE(T) (istype(T, /turf/simulated) && T:zone && !T:zone:invalid)
+#define TURF_HAS_VALID_ZONE(T) (isturf(T) && T:zone && !T:zone:invalid)
+#define SHOULD_PARTICIPATE_IN_ZONES(T) (isturf(T) && T:zone_membership_candidate && (!T:external_atmosphere_participation || !T:is_outside()))
-#ifdef MULTIZAS
+#define ATMOS_CANPASS_MOVABLE(ret, AM, TARG_TURF) \
+ switch (AM.atmos_canpass) { \
+ if (CANPASS_ALWAYS) { EMPTY_BLOCK_GUARD } \
+ if (CANPASS_DENSITY) { \
+ if (AM.density) { \
+ ret |= AIR_BLOCKED; \
+ } \
+ } \
+ if (CANPASS_PROC) { \
+ ret |= (AIR_BLOCKED * !AM.CanPass(null, TARG_TURF, 0, 0)) | (ZONE_BLOCKED * !AM.CanPass(null, TARG_TURF, 1.5, 1)); \
+ } \
+ if (CANPASS_NEVER) { \
+ ret = BLOCKED; \
+ } \
+ }
-var/list/csrfz_check = list(NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST, NORTHUP, EASTUP, WESTUP, SOUTHUP, NORTHDOWN, EASTDOWN, WESTDOWN, SOUTHDOWN)
-var/list/gzn_check = list(NORTH, SOUTH, EAST, WEST, UP, DOWN)
+#ifdef MULTIZAS
+#define ZAS_CSRFZ_CHECK global.cornerdirsz
+#define ZAS_GZN_CHECK global.cardinalz
-#define ATMOS_CANPASS_TURF(ret,A,B) \
+#define ATMOS_CANPASS_TURF(ret, A, B) \
if (A.blocks_air & AIR_BLOCKED || B.blocks_air & AIR_BLOCKED) { \
ret = BLOCKED; \
} \
- else if (B.z != A.z) { \
- if (B.z < A.z) { \
- ret = (A.z_flags & ZM_ALLOW_ATMOS) ? ZONE_BLOCKED : BLOCKED; \
- } \
- else { \
- ret = (B.z_flags & ZM_ALLOW_ATMOS) ? ZONE_BLOCKED : BLOCKED; \
- } \
+ else if (B.z < A.z) { \
+ ret = (A.z_flags & ZM_ALLOW_ATMOS) ? ZONE_BLOCKED : BLOCKED; \
} \
- else if (A.blocks_air & ZONE_BLOCKED || B.blocks_air & ZONE_BLOCKED) { \
- ret = (A.z == B.z) ? ZONE_BLOCKED : AIR_BLOCKED; \
+ else if(B.z > A.z) { \
+ ret = (B.z_flags & ZM_ALLOW_ATMOS) ? ZONE_BLOCKED : BLOCKED; \
} \
- else if (A.contents.len) { \
+ else if ((A.blocks_air & ZONE_BLOCKED) || (B.blocks_air & ZONE_BLOCKED)) { \
+ ret = ZONE_BLOCKED; \
+ } \
+ else if (length(A.contents)) { \
ret = 0;\
- for (var/thing in A) { \
- var/atom/movable/AM = thing; \
- switch (AM.atmos_canpass) { \
- if (CANPASS_ALWAYS) { \
- continue; \
- } \
- if (CANPASS_DENSITY) { \
- if (AM.density) { \
- ret |= AIR_BLOCKED; \
- } \
- } \
- if (CANPASS_PROC) { \
- ret |= AM.c_airblock(B); \
- } \
- if (CANPASS_NEVER) { \
- ret = BLOCKED; \
- } \
- } \
+ for (var/atom/movable/AM as anything in A) { \
+ ATMOS_CANPASS_MOVABLE(ret, AM, B); \
if (ret == BLOCKED) { \
break;\
}\
@@ -70,36 +84,21 @@ var/list/gzn_check = list(NORTH, SOUTH, EAST, WEST, UP, DOWN)
}
#else
-var/list/csrfz_check = list(NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST)
-var/list/gzn_check = list(NORTH, SOUTH, EAST, WEST)
+#define ZAS_CSRFZ_CHECK global.cornerdirs
+#define ZAS_GZN_CHECK global.cardinal
-#define ATMOS_CANPASS_TURF(ret,A,B) \
+#define ATMOS_CANPASS_TURF(ret, A, B) \
if (A.blocks_air & AIR_BLOCKED || B.blocks_air & AIR_BLOCKED) { \
ret = BLOCKED; \
} \
else if (A.blocks_air & ZONE_BLOCKED || B.blocks_air & ZONE_BLOCKED) { \
ret = ZONE_BLOCKED; \
} \
- else if (A.contents.len) { \
+ else if (length(A.contents)) { \
ret = 0;\
for (var/thing in A) { \
var/atom/movable/AM = thing; \
- switch (AM.atmos_canpass) { \
- if (CANPASS_ALWAYS) { \
- continue; \
- } \
- if (CANPASS_DENSITY) { \
- if (AM.density) { \
- ret |= AIR_BLOCKED; \
- } \
- } \
- if (CANPASS_PROC) { \
- ret |= AM.c_airblock(B); \
- } \
- if (CANPASS_NEVER) { \
- ret = BLOCKED; \
- } \
- } \
+ ATMOS_CANPASS_MOVABLE(ret, AM, B); \
if (ret == BLOCKED) { \
break;\
}\
@@ -107,3 +106,5 @@ var/list/gzn_check = list(NORTH, SOUTH, EAST, WEST)
}
#endif
+
+#define GAS_STANDARD_AIRMIX "STANDARD_AIRMIX"
\ No newline at end of file
diff --git a/code/__defines/_byond_version_compat.dm b/code/__defines/_byond_version_compat.dm
new file mode 100644
index 000000000000..61d61853a893
--- /dev/null
+++ b/code/__defines/_byond_version_compat.dm
@@ -0,0 +1,5 @@
+#define REQUIRED_DM_VERSION 515
+
+#if DM_VERSION < REQUIRED_DM_VERSION
+#warn Nebula is not tested on BYOND versions older than 515. The code may not compile, and if it does compile it may have severe problems.
+#endif
\ No newline at end of file
diff --git a/code/__defines/_compile_helpers.dm b/code/__defines/_compile_helpers.dm
new file mode 100644
index 000000000000..38ef79c3f1ca
--- /dev/null
+++ b/code/__defines/_compile_helpers.dm
@@ -0,0 +1,7 @@
+#define BITSHIFT_LEFT(X, N) (X << (N))
+#define BITSHIFT_RIGHT(X, N) (X >> (N))
+#define BITFLAG(X) BITSHIFT_LEFT(1, X)
+
+/// A null statement to guard against EmptyBlock lint without necessitating the use of pass()
+/// Used to avoid proc-call overhead. But use sparingly. Probably pointless in most places.
+#define EMPTY_BLOCK_GUARD ;
\ No newline at end of file
diff --git a/code/__defines/_compile_options.dm b/code/__defines/_compile_options.dm
deleted file mode 100644
index 2595ee6dd1eb..000000000000
--- a/code/__defines/_compile_options.dm
+++ /dev/null
@@ -1,2 +0,0 @@
-#define BACKGROUND_ENABLED 0 // The default value for all uses of set background. Set background can cause gradual lag and is recommended you only turn this on if necessary.
- // 1 will enable set background. 0 will disable set background.
\ No newline at end of file
diff --git a/code/__defines/_planes+layers.dm b/code/__defines/_planes+layers.dm
index ffc83208d595..a93d92514259 100644
--- a/code/__defines/_planes+layers.dm
+++ b/code/__defines/_planes+layers.dm
@@ -76,43 +76,48 @@ What is the naming convention for planes or layers?
#define OVER_OPENSPACE_PLANE -3
#define DEFAULT_PLANE 0
- #define PLATING_LAYER 1
+//BELOW PLATING
+ #define UNDER_TURF_LAYER 1
+ //PLATING
+ #define PLATING_LAYER 1.5
//ABOVE PLATING
- #define HOLOMAP_LAYER 1.01
- #define DECAL_PLATING_LAYER 1.02
- #define DISPOSALS_PIPE_LAYER 1.03
- #define LATTICE_LAYER 1.04
- #define PIPE_LAYER 1.05
- #define WIRE_LAYER 1.06
- #define WIRE_TERMINAL_LAYER 1.07
- #define ABOVE_WIRE_LAYER 1.08
+ #define HOLOMAP_LAYER 1.51
+ #define DECAL_PLATING_LAYER 1.52
+ #define DISPOSALS_PIPE_LAYER 1.53
+ #define LATTICE_LAYER 1.54
+ #define PIPE_LAYER 1.55
+ #define WIRE_LAYER 1.56
+ #define WIRE_TERMINAL_LAYER 1.57
+ #define ABOVE_WIRE_LAYER 1.58
//TURF PLANE
//TURF_LAYER = 2
- #define TURF_DETAIL_LAYER 2.01
- #define TURF_SHADOW_LAYER 2.02
+ #define TURF_OVER_EDGE_LAYER TURF_LAYER + (FLOOR_LAYER_CONSTANT*100)
+ #define TURF_DETAIL_LAYER TURF_OVER_EDGE_LAYER + 0.01
+ #define TURF_SHADOW_LAYER TURF_OVER_EDGE_LAYER + 0.02
//ABOVE TURF
- #define DECAL_LAYER 2.03
- #define RUNE_LAYER 2.04
- #define ABOVE_TILE_LAYER 2.05
- #define EXPOSED_PIPE_LAYER 2.06
- #define EXPOSED_WIRE_LAYER 2.07
- #define EXPOSED_WIRE_TERMINAL_LAYER 2.08
- #define CATWALK_LAYER 2.09
- #define BLOOD_LAYER 2.10
- #define MOUSETRAP_LAYER 2.11
- #define PLANT_LAYER 2.12
- #define AO_LAYER 2.13
+ #define DECAL_LAYER TURF_OVER_EDGE_LAYER + 0.03
+ #define RUNE_LAYER TURF_OVER_EDGE_LAYER + 0.04
+ #define AO_LAYER TURF_OVER_EDGE_LAYER + 0.045
+ #define ABOVE_TILE_LAYER TURF_OVER_EDGE_LAYER + 0.05
+ #define EXPOSED_PIPE_LAYER TURF_OVER_EDGE_LAYER + 0.06
+ #define EXPOSED_WIRE_LAYER TURF_OVER_EDGE_LAYER + 0.07
+ #define EXPOSED_WIRE_TERMINAL_LAYER TURF_OVER_EDGE_LAYER + 0.08
+ #define CATWALK_LAYER TURF_OVER_EDGE_LAYER + 0.09
+ #define BLOOD_LAYER TURF_OVER_EDGE_LAYER + 0.10
+ #define MOUSETRAP_LAYER TURF_OVER_EDGE_LAYER + 0.11
+ #define PLANT_LAYER TURF_OVER_EDGE_LAYER + 0.12
//HIDING MOB
- #define HIDING_MOB_LAYER 2.14
- #define SHALLOW_FLUID_LAYER 2.15
- #define MOB_SHADOW_LAYER 2.16
+ #define HIDING_MOB_LAYER TURF_OVER_EDGE_LAYER + 0.14
+ #define SHALLOW_FLUID_LAYER TURF_OVER_EDGE_LAYER + 0.15
+ #define MOB_SHADOW_LAYER TURF_OVER_EDGE_LAYER + 0.16
//OBJ
- #define BELOW_DOOR_LAYER 2.17
- #define OPEN_DOOR_LAYER 2.18
- #define BELOW_TABLE_LAYER 2.19
- #define TABLE_LAYER 2.20
- #define BELOW_OBJ_LAYER 2.21
- #define STRUCTURE_LAYER 2.22
+ #define BELOW_DOOR_LAYER TURF_OVER_EDGE_LAYER + 0.17
+ #define OPEN_DOOR_LAYER TURF_OVER_EDGE_LAYER + 0.18
+ #define BELOW_TABLE_LAYER TURF_OVER_EDGE_LAYER + 0.19
+ #define TABLE_LAYER TURF_OVER_EDGE_LAYER + 0.20
+ #define BELOW_OBJ_LAYER TURF_OVER_EDGE_LAYER + 0.21
+ #define STRUCTURE_LAYER TURF_OVER_EDGE_LAYER + 0.22
+ #define ABOVE_STRUCTURE_LAYER TURF_OVER_EDGE_LAYER + 0.23
// OBJ_LAYER 3
#define ABOVE_OBJ_LAYER 3.01
#define CLOSED_DOOR_LAYER 3.02
@@ -121,6 +126,7 @@ What is the naming convention for planes or layers?
#define FULL_WINDOW_LAYER 3.05
#define ABOVE_WINDOW_LAYER 3.06
//LYING MOB AND HUMAN
+ #define UNDER_MOB_LAYER 3.065
#define LYING_MOB_LAYER 3.07
#define LYING_HUMAN_LAYER 3.08
#define BASE_ABOVE_OBJ_LAYER 3.09
@@ -158,72 +164,34 @@ What is the naming convention for planes or layers?
//FLY_LAYER 5
//OBSERVER
- #define OBSERVER_LAYER 5.1
-
#define BASE_AREA_LAYER 999
-#define OBSERVER_PLANE 1
-
-#define LIGHTING_PLANE 2 // For Lighting. - The highest plane (ignoring all other even higher planes)
- #define LIGHTBULB_LAYER 0
- #define LIGHTING_LAYER 1
- #define ABOVE_LIGHTING_LAYER 2
-
-#define EFFECTS_ABOVE_LIGHTING_PLANE 3 // For glowy eyes, laser beams, etc. that shouldn't be affected by darkness
- #define EYE_GLOW_LAYER 1
- #define BEAM_PROJECTILE_LAYER 2
- #define SUPERMATTER_WALL_LAYER 3
- #define OBFUSCATION_LAYER 4
-
-#define FULLSCREEN_PLANE 4 // for fullscreen overlays that do not cover the hud.
-
- #define FULLSCREEN_LAYER 0
- #define DAMAGE_LAYER 1
- #define IMPAIRED_LAYER 2
- #define BLIND_LAYER 3
- #define CRIT_LAYER 4
-
-#define HUD_PLANE 5
- #define UNDER_HUD_LAYER 0
- #define HUD_BASE_LAYER 2
- #define HUD_ITEM_LAYER 3
- #define HUD_ABOVE_ITEM_LAYER 4
- #define HUD_ABOVE_HUD_LAYER 5
-
-
-//This is difference between planes used for atoms and effects
-#define PLANE_DIFFERENCE 3
-
-/atom
- plane = DEFAULT_PLANE
-
-/atom/proc/hud_layerise()
- plane = HUD_PLANE
- layer = HUD_ITEM_LAYER
-
-/atom/proc/reset_plane_and_layer()
- plane = initial(plane)
- layer = initial(layer)
-
-/*
- PLANE MASTERS
-*/
-
-/obj/screen/plane_master
- appearance_flags = PLANE_MASTER
- screen_loc = "CENTER,CENTER"
- globalscreen = 1
-
-/obj/screen/plane_master/ghost_master
- plane = OBSERVER_PLANE
-
-/obj/screen/plane_master/ghost_dummy
- // this avoids a bug which means plane masters which have nothing to control get angry and mess with the other plane masters out of spite
- alpha = 0
- appearance_flags = 0
- plane = OBSERVER_PLANE
-
-GLOBAL_LIST_INIT(ghost_master, list(
- new /obj/screen/plane_master/ghost_master(),
- new /obj/screen/plane_master/ghost_dummy()
-))
+#define OBSERVER_PLANE 1
+ #define OBSERVER_LAYER 1
+
+#define LIGHTING_PLANE 2 // For Lighting. - The highest plane (ignoring all other even higher planes)
+ #define LIGHTBULB_LAYER 1
+ #define LIGHTING_LAYER 2
+
+#define EMISSIVE_PLANE 3 // For over-lighting overlays (ex. cigarette glows)
+ #define EMISSIVE_LAYER 1
+
+#define ABOVE_LIGHTING_PLANE 4 // laser beams, etc. that shouldn't be affected by darkness
+ #define ABOVE_LIGHTING_LAYER 1
+ #define BEAM_PROJECTILE_LAYER 2
+ #define SUBSPACE_WALL_LAYER 3
+ #define OBFUSCATION_LAYER 4
+
+#define FULLSCREEN_PLANE 5 // for fullscreen overlays that do not cover the hud.
+ #define FULLSCREEN_LAYER 0
+ #define DAMAGE_LAYER 1
+ #define IMPAIRED_LAYER 2
+ #define BLIND_LAYER 3
+ #define CRIT_LAYER 4
+
+#define HUD_PLANE 6
+ #define UNDER_HUD_LAYER 0
+ #define HUD_BASE_LAYER 2
+ #define HUD_ITEM_LAYER 3
+ #define HUD_ABOVE_ITEM_LAYER 4
+ #define HUD_ABOVE_HUD_LAYER 5
diff --git a/code/__defines/_tick.dm b/code/__defines/_tick.dm
index 9609333eaf9e..2c33329a612f 100644
--- a/code/__defines/_tick.dm
+++ b/code/__defines/_tick.dm
@@ -1,21 +1,34 @@
-#define TICK_LIMIT_RUNNING 80
-#define TICK_LIMIT_TO_RUN 78
+/// Percentage of tick to leave for master controller to run
+#define MAPTICK_MC_MIN_RESERVE 70
+#define MAPTICK_LAST_INTERNAL_TICK_USAGE (world.map_cpu)
+
+/// Tick limit while running normally
+#define TICK_BYOND_RESERVE 2
+#define TICK_LIMIT_RUNNING (max(100 - TICK_BYOND_RESERVE - MAPTICK_LAST_INTERNAL_TICK_USAGE, MAPTICK_MC_MIN_RESERVE))
+/// Tick limit used to resume things in stoplag
+#define TICK_LIMIT_TO_RUN 70
+/// Tick limit for MC while running
#define TICK_LIMIT_MC 70
-#define TICK_LIMIT_MC_INIT_DEFAULT 98
+/// Tick limit while initializing
+#define TICK_LIMIT_MC_INIT_DEFAULT (100 - TICK_BYOND_RESERVE)
-#define TICK_USAGE world.tick_usage //for general usage
-#define TICK_USAGE_REAL world.tick_usage //to be used where the result isn't checked
+/// for general usage of tick_usage
+#define TICK_USAGE world.tick_usage
+/// Returns true if tick_usage is above the limit
#define TICK_CHECK ( TICK_USAGE > Master.current_ticklimit )
-#define CHECK_TICK if TICK_CHECK stoplag()
+/// runs stoplag if tick_usage is above the limit
+#define CHECK_TICK ( TICK_CHECK ? stoplag() : 0 )
+
+#define UNTIL(X) while(!(X)) stoplag()
//"fancy" math for calculating time in ms from tick_usage percentage and the length of ticks
//percent_of_tick_used * (ticklag * 100(to convert to ms)) / 100(percent ratio)
//collapsed to percent_of_tick_used * tick_lag
#define TICK_DELTA_TO_MS(percent_of_tick_used) ((percent_of_tick_used) * world.tick_lag)
-#define TICK_USAGE_TO_MS(starting_tickusage) (TICK_DELTA_TO_MS(TICK_USAGE_REAL - starting_tickusage))
+#define TICK_USAGE_TO_MS(starting_tickusage) (TICK_DELTA_TO_MS(TICK_USAGE - starting_tickusage))
//time of day but automatically adjusts to the server going into the next day within the same round.
//for when you need a reliable time number that doesn't depend on byond time.
#define REALTIMEOFDAY (world.timeofday + (MIDNIGHT_ROLLOVER * MIDNIGHT_ROLLOVER_CHECK))
-#define MIDNIGHT_ROLLOVER_CHECK ( GLOB.rollovercheck_last_timeofday != world.timeofday ? update_midnight_rollover() : GLOB.midnight_rollovers )
+#define MIDNIGHT_ROLLOVER_CHECK ( global.rollovercheck_last_timeofday != world.timeofday ? update_midnight_rollover() : global.midnight_rollovers )
diff --git a/code/__defines/admin.dm b/code/__defines/admin.dm
index e5d25a0141f2..c35126cdcccc 100644
--- a/code/__defines/admin.dm
+++ b/code/__defines/admin.dm
@@ -1,13 +1,13 @@
// A set of constants used to determine which type of mute an admin wishes to apply.
-// Please read and understand the muting/automuting stuff before changing these. MUTE_IC_AUTO, etc. = (MUTE_IC << 1)
+// Please read and understand the muting/automuting stuff before changing these. MUTE_IC_AUTO, etc.
// Therefore there needs to be a gap between the flags for the automute flags.
-#define MUTE_IC 0x1
-#define MUTE_OOC 0x2
-#define MUTE_PRAY 0x4
-#define MUTE_ADMINHELP 0x8
-#define MUTE_DEADCHAT 0x10
-#define MUTE_AOOC 0x20
-#define MUTE_ALL 0xFFFF
+#define MUTE_IC BITFLAG(0)
+#define MUTE_OOC BITFLAG(1)
+#define MUTE_PRAY BITFLAG(2)
+#define MUTE_ADMINHELP BITFLAG(3)
+#define MUTE_DEADCHAT BITFLAG(4)
+#define MUTE_AOOC BITFLAG(5)
+#define MUTE_ALL (MUTE_IC|MUTE_OOC|MUTE_PRAY|MUTE_ADMINHELP|MUTE_DEADCHAT|MUTE_AOOC)
// Some constants for DB_Ban
#define BANTYPE_PERMA 1
@@ -19,24 +19,25 @@
#define ROUNDSTART_LOGOUT_REPORT_TIME 6000 // Amount of time (in deciseconds) after the rounds starts, that the player disconnect report is issued.
// Admin permissions.
-#define R_BUILDMODE 0x1
-#define R_ADMIN 0x2
-#define R_BAN 0x4
-#define R_FUN 0x8
-#define R_SERVER 0x10
-#define R_DEBUG 0x20
-#define R_POSSESS 0x40
-#define R_PERMISSIONS 0x80
-#define R_STEALTH 0x100
-#define R_REJUVINATE 0x200
-#define R_VAREDIT 0x400
-#define R_SOUNDS 0x800
-#define R_SPAWN 0x1000
-#define R_MOD 0x2000
-#define R_HOST 0x8000 //higher than this will overflow
+#define R_BUILDMODE BITFLAG(0)
+#define R_ADMIN BITFLAG(1)
+#define R_BAN BITFLAG(2)
+#define R_FUN BITFLAG(3)
+#define R_SERVER BITFLAG(4)
+#define R_DEBUG BITFLAG(5)
+#define R_POSSESS BITFLAG(6)
+#define R_PERMISSIONS BITFLAG(7)
+#define R_STEALTH BITFLAG(8)
+#define R_REJUVENATE BITFLAG(9)
+#define R_VAREDIT BITFLAG(10)
+#define R_SOUNDS BITFLAG(11)
+#define R_SPAWN BITFLAG(12)
+#define R_MOD BITFLAG(13)
+#define R_HOST BITFLAG(14)
#define R_INVESTIGATE (R_ADMIN|R_MOD)
+#define R_EVERYTHING (~0)
-#define R_MAXPERMISSION 0x8000 // This holds the maximum value for a permission. It is used in iteration, so keep it updated.
+#define R_MAXPERMISSION BITFLAG(14) // This holds the maximum value for a permission. It is used in iteration, so keep it updated.
#define ADDANTAG_PLAYER 1 // Any player may call the add antagonist vote.
#define ADDANTAG_ADMIN 2 // Any player with admin privilegies may call the add antagonist vote.
@@ -47,4 +48,13 @@
#define TICKET_ASSIGNED 2 // An admin has assigned themself to the ticket and will respond
#define LAST_CKEY(M) (M.ckey || M.last_ckey)
-#define LAST_KEY(M) (M.key || M.last_ckey)
\ No newline at end of file
+#define LAST_KEY(M) (M.key || M.last_ckey)
+
+///Max length of a keypress command before it's considered to be a forged packet/bogus command
+#define MAX_KEYPRESS_COMMANDLENGTH 16
+///Maximum keys that can be bound to one button
+#define MAX_COMMANDS_PER_KEY 5
+///Maximum keys per keybind
+#define MAX_KEYS_PER_KEYBIND 3
+///Length of held key buffer
+#define HELD_KEY_BUFFER_LENGTH 15
diff --git a/code/__defines/ai.dm b/code/__defines/ai.dm
new file mode 100644
index 000000000000..03fa03fa9e88
--- /dev/null
+++ b/code/__defines/ai.dm
@@ -0,0 +1,24 @@
+// TODO: FSM/decl based stances
+#define STANCE_NONE /decl/mob_controller_stance/none
+#define STANCE_IDLE /decl/mob_controller_stance/idle
+#define STANCE_ALERT /decl/mob_controller_stance/alert
+#define STANCE_ATTACK /decl/mob_controller_stance/attack
+#define STANCE_ATTACKING /decl/mob_controller_stance/attacking
+#define STANCE_TIRED /decl/mob_controller_stance/tired
+#define STANCE_CONTAINED /decl/mob_controller_stance/contained
+#define STANCE_BUSY /decl/mob_controller_stance/busy
+
+ //basically 'do nothing'
+#define STANCE_COMMANDED_STOP /decl/mob_controller_stance/commanded/stop
+//follows a target
+#define STANCE_COMMANDED_FOLLOW /decl/mob_controller_stance/commanded/follow
+//catch all state for misc commands that need one.
+#define STANCE_COMMANDED_MISC /decl/mob_controller_stance/commanded/misc
+//we got healing powers yo
+#define STANCE_COMMANDED_HEAL /decl/mob_controller_stance/commanded/heal
+#define STANCE_COMMANDED_HEALING /decl/mob_controller_stance/commanded/healing
+
+#define AI_ACTIVITY_IDLE 0
+#define AI_ACTIVITY_MOVING_TO_TARGET 1
+#define AI_ACTIVITY_BUILDING 2
+#define AI_ACTIVITY_REPRODUCING 3
diff --git a/code/__defines/ambience.dm b/code/__defines/ambience.dm
new file mode 100644
index 000000000000..c3b7c14d570a
--- /dev/null
+++ b/code/__defines/ambience.dm
@@ -0,0 +1,11 @@
+#define AMBIENCE_QUEUE_TURF(T) \
+ if(!T.ambience_queued) { \
+ T.ambience_queued = TRUE; \
+ SSambience.queued += T; \
+ }
+
+#define AMBIENCE_DEQUEUE_TURF(T) \
+ if(T.ambience_queued) { \
+ T.ambience_queued = FALSE; \
+ SSambience.queued -= T; \
+ }
\ No newline at end of file
diff --git a/code/__defines/antagonists.dm b/code/__defines/antagonists.dm
deleted file mode 100644
index c6d48971b903..000000000000
--- a/code/__defines/antagonists.dm
+++ /dev/null
@@ -1,3 +0,0 @@
-#define ANTAG_SERVANT "servant"
-#define ANTAG_APPRENTICE "apprentice"
-#define ANTAG_WIZARD "Space Wizard"
\ No newline at end of file
diff --git a/code/__defines/ao_misc.dm b/code/__defines/ao_misc.dm
index 6d2491c4cae7..8a10c974f251 100644
--- a/code/__defines/ao_misc.dm
+++ b/code/__defines/ao_misc.dm
@@ -8,38 +8,38 @@ Define for getting a bitfield of adjacent turfs that meet a condition.
var/result = 0
CALCULATE_NEIGHBORS(src, result, T, isopenturf(T))
*/
-#define CALCULATE_NEIGHBORS(ORIGIN, VAR, TVAR, FUNC) \
- for (var/_tdir in GLOB.cardinal) { \
- TVAR = get_step(ORIGIN, _tdir); \
- if ((TVAR) && (FUNC)) { \
- VAR |= 1 << _tdir; \
- } \
- } \
- if (VAR & N_NORTH) { \
- if (VAR & N_WEST) { \
- TVAR = get_step(ORIGIN, NORTHWEST); \
- if (FUNC) { \
- VAR |= N_NORTHWEST; \
- } \
- } \
- if (VAR & N_EAST) { \
- TVAR = get_step(ORIGIN, NORTHEAST); \
- if (FUNC) { \
- VAR |= N_NORTHEAST; \
- } \
- } \
- } \
- if (VAR & N_SOUTH) { \
- if (VAR & N_WEST) { \
- TVAR = get_step(ORIGIN, SOUTHWEST); \
- if (FUNC) { \
- VAR |= N_SOUTHWEST; \
- } \
- } \
- if (VAR & N_EAST) { \
- TVAR = get_step(ORIGIN, SOUTHEAST); \
- if (FUNC) { \
- VAR |= N_SOUTHEAST; \
- } \
- } \
+#define CALCULATE_NEIGHBORS(ORIGIN, VAR, TVAR, FUNC) \
+ for (var/_tdir in global.cardinal) { \
+ TVAR = get_step_resolving_mimic(ORIGIN, _tdir); \
+ if ((TVAR) && (FUNC)) { \
+ VAR |= BITFLAG(_tdir); \
+ } \
+ } \
+ if (VAR & N_NORTH) { \
+ if (VAR & N_WEST) { \
+ TVAR = get_step_resolving_mimic(ORIGIN, NORTHWEST); \
+ if (FUNC) { \
+ VAR |= N_NORTHWEST; \
+ } \
+ } \
+ if (VAR & N_EAST) { \
+ TVAR = get_step_resolving_mimic(ORIGIN, NORTHEAST); \
+ if (FUNC) { \
+ VAR |= N_NORTHEAST; \
+ } \
+ } \
+ } \
+ if (VAR & N_SOUTH) { \
+ if (VAR & N_WEST) { \
+ TVAR = get_step_resolving_mimic(ORIGIN, SOUTHWEST); \
+ if (FUNC) { \
+ VAR |= N_SOUTHWEST; \
+ } \
+ } \
+ if (VAR & N_EAST) { \
+ TVAR = get_step_resolving_mimic(ORIGIN, SOUTHEAST); \
+ if (FUNC) { \
+ VAR |= N_SOUTHEAST; \
+ } \
+ } \
}
diff --git a/code/__defines/appearance.dm b/code/__defines/appearance.dm
index 5b7a35980c4a..2c3ada675cbd 100644
--- a/code/__defines/appearance.dm
+++ b/code/__defines/appearance.dm
@@ -1,3 +1,3 @@
// Consider these images/atoms as part of the UI/HUD
-#define APPEARANCE_UI_IGNORE_ALPHA RESET_COLOR|RESET_TRANSFORM|NO_CLIENT_COLOR|RESET_ALPHA|PIXEL_SCALE
-#define APPEARANCE_UI RESET_COLOR|RESET_TRANSFORM|NO_CLIENT_COLOR|PIXEL_SCALE
+#define APPEARANCE_UI_IGNORE_ALPHA RESET_COLOR|RESET_TRANSFORM|NO_CLIENT_COLOR|RESET_ALPHA|DEFAULT_APPEARANCE_FLAGS
+#define APPEARANCE_UI RESET_COLOR|RESET_TRANSFORM|NO_CLIENT_COLOR|DEFAULT_APPEARANCE_FLAGS
diff --git a/code/__defines/armor.dm b/code/__defines/armor.dm
index 491b929afc4c..c43e7cc2f263 100644
--- a/code/__defines/armor.dm
+++ b/code/__defines/armor.dm
@@ -33,6 +33,7 @@
#define ARMOR_RAD_MINOR 10
#define ARMOR_RAD_SMALL 25
#define ARMOR_RAD_RESISTANT 40
+#define ARMOR_RAD_LARGE 60
#define ARMOR_RAD_SHIELDED 100
#define ARMOR_BOMB_MINOR 10
@@ -45,3 +46,6 @@
#define ARMOR_ENERGY_RESISTANT 40
#define ARMOR_ENERGY_STRONG 75
#define ARMOR_ENERGY_SHIELDED 100
+
+/**Armor piercing value that will bypass any armors completely */
+#define ARMOR_PIERCING_BYPASSED INFINITY
\ No newline at end of file
diff --git a/code/__defines/atmos.dm b/code/__defines/atmos.dm
index 3872d214b278..ec5511eec1a6 100644
--- a/code/__defines/atmos.dm
+++ b/code/__defines/atmos.dm
@@ -21,7 +21,7 @@
#define SOUND_MINIMUM_PRESSURE 10
#define PRESSURE_DAMAGE_COEFFICIENT 4 // The amount of pressure damage someone takes is equal to (pressure / HAZARD_HIGH_PRESSURE)*PRESSURE_DAMAGE_COEFFICIENT, with the maximum of MAX_PRESSURE_DAMAGE.
-#define MAX_HIGH_PRESSURE_DAMAGE 4 // This used to be 20... I got this much random rage for some retarded decision by polymorph?! Polymorph now lies in a pool of blood with a katana jammed in his spleen. ~Errorage --PS: The katana did less than 20 damage to him :(
+#define MAX_HIGH_PRESSURE_DAMAGE 4 // Caps the amount of pressure damage taken in one tick from a high pressure area.
#define LOW_PRESSURE_DAMAGE 0.6 // The amount of damage someone takes when in a low pressure area. (The pressure threshold is so low that it doesn't make sense to do any calculations, so it just applies this flat value).
#define MINIMUM_PRESSURE_DIFFERENCE_TO_SUSPEND (MINIMUM_AIR_TO_SUSPEND*R_IDEAL_GAS_EQUATION*T20C)/CELL_VOLUME // Minimum pressure difference between zones to suspend
@@ -73,10 +73,10 @@
#define XGM_GAS_OXIDIZER 2
#define XGM_GAS_CONTAMINANT 4
-#define TANK_LEAK_PRESSURE (30 * ONE_ATMOSPHERE) // Tank starts leaking.
-#define TANK_RUPTURE_PRESSURE (40 * ONE_ATMOSPHERE) // Tank spills all contents into atmosphere.
-#define TANK_FRAGMENT_PRESSURE (50 * ONE_ATMOSPHERE) // Boom 3x3 base explosion.
-#define TANK_FRAGMENT_SCALE (10 * ONE_ATMOSPHERE) // +1 for each SCALE kPa above threshold. Was 2 atm.
+#define TANK_LEAK_PRESSURE (30 ATM) // Tank starts leaking.
+#define TANK_RUPTURE_PRESSURE (40 ATM) // Tank spills all contents into atmosphere.
+#define TANK_FRAGMENT_PRESSURE (50 ATM) // Boom 3x3 base explosion.
+#define TANK_FRAGMENT_SCALE (10 ATM) // +1 for each SCALE kPa above threshold. Was 2 atm.
#define NORMPIPERATE 30 // Pipe-insulation rate divisor.
#define HEATPIPERATE 8 // Heat-exchange pipe insulation.
diff --git a/code/__defines/backgrounds.dm b/code/__defines/backgrounds.dm
new file mode 100644
index 000000000000..c24f9fa371fa
--- /dev/null
+++ b/code/__defines/backgrounds.dm
@@ -0,0 +1,19 @@
+#define BACKGROUND_FLAG_NAMING BITFLAG(0)
+#define BACKGROUND_FLAG_CITIZENSHIP BITFLAG(1)
+#define BACKGROUND_FLAG_IDEOLOGY BITFLAG(2)
+#define BACKGROUND_FLAG_RELIGION BITFLAG(3)
+#define BACKGROUND_FLAG_LOCATION BITFLAG(4)
+#define BACKGROUND_FLAG_RESIDENCE BITFLAG(5)
+#define BACKGROUND_FLAG_HOMEWORLD BITFLAG(6)
+
+#ifdef UNIT_TEST
+var/global/list/all_background_flags = list(
+ "BACKGROUND_FLAG_NAMING" = (BACKGROUND_FLAG_NAMING),
+ "BACKGROUND_FLAG_CITIZENSHIP" = (BACKGROUND_FLAG_CITIZENSHIP),
+ "BACKGROUND_FLAG_IDEOLOGY" = (BACKGROUND_FLAG_IDEOLOGY),
+ "BACKGROUND_FLAG_RELIGION" = (BACKGROUND_FLAG_RELIGION),
+ "BACKGROUND_FLAG_LOCATION" = (BACKGROUND_FLAG_LOCATION),
+ "BACKGROUND_FLAG_RESIDENCE" = (BACKGROUND_FLAG_RESIDENCE),
+ "BACKGROUND_FLAG_HOMEWORLD" = (BACKGROUND_FLAG_HOMEWORLD)
+)
+#endif
\ No newline at end of file
diff --git a/code/__defines/bodytype.dm b/code/__defines/bodytype.dm
new file mode 100644
index 000000000000..ca9dccfe6082
--- /dev/null
+++ b/code/__defines/bodytype.dm
@@ -0,0 +1,36 @@
+
+#define BODYTYPE_HUMANOID "humanoid body"
+#define BODYTYPE_QUADRUPED "quadruped body"
+#define BODYTYPE_OTHER "alien body"
+#define BODYTYPE_MONKEY "small humanoid body"
+
+// Bodytype appearance flags
+#define HAS_SKIN_TONE_NORMAL BITFLAG(0) // Skin tone selectable in chargen for baseline humans (0-220)
+#define HAS_SKIN_COLOR BITFLAG(1) // Skin color selectable in chargen. (RGB)
+#define HAS_UNDERWEAR BITFLAG(3) // Underwear is drawn onto the mob icon.
+#define HAS_EYE_COLOR BITFLAG(4) // Eye color selectable in chargen. (RGB)
+#define RADIATION_GLOWS BITFLAG(6) // Radiation causes this character to glow.
+#define HAS_SKIN_TONE_GRAV BITFLAG(7) // Skin tone selectable in chargen for grav-adapted humans (0-100)
+#define HAS_SKIN_TONE_SPCR BITFLAG(8) // Skin tone selectable in chargen for spacer humans (0-165)
+#define HAS_SKIN_TONE_TRITON BITFLAG(9)
+#define HAS_A_SKIN_TONE (HAS_SKIN_TONE_NORMAL | HAS_SKIN_TONE_GRAV | HAS_SKIN_TONE_SPCR | HAS_SKIN_TONE_TRITON) // Bodytype has a numeric skintone
+
+// Bodytype feature flags
+/// Does not create DNA. Replaces SPECIES_FLAG_NO_SCAN.
+#define BODY_FLAG_NO_DNA BITFLAG(0)
+/// Cannot suffer halloss/receives deceptive health indicator.
+#define BODY_FLAG_NO_PAIN BITFLAG(1)
+/// Cannot eat food/drink drinks even if a stomach organ is present.
+#define BODY_FLAG_NO_EAT BITFLAG(2)
+/// Can regenerate missing limbs from mineral baths.
+#define BODY_FLAG_CRYSTAL_REFORM BITFLAG(3)
+/// Does not experience stasis effects (sleeper, cryo)
+#define BODY_FLAG_NO_STASIS BITFLAG(4)
+/// Cannot be revived with a defibrilator.
+#define BODY_FLAG_NO_DEFIB BITFLAG(5)
+
+// Equipment flags for gear and accessory restrictions
+#define BODY_EQUIP_FLAG_EXCLUDE BITFLAG(0)
+#define BODY_EQUIP_FLAG_HUMANOID BITFLAG(1)
+#define BODY_EQUIP_FLAG_MONKEY BITFLAG(2)
+#define BODY_EQUIP_FLAG_QUADRUPED BITFLAG(3)
diff --git a/code/__defines/chemistry.dm b/code/__defines/chemistry.dm
index 134af516b260..db1cd4817e1a 100644
--- a/code/__defines/chemistry.dm
+++ b/code/__defines/chemistry.dm
@@ -6,6 +6,7 @@
#define CHEM_TOUCH 1
#define CHEM_INGEST 2
#define CHEM_INJECT 3
+#define CHEM_INHALE 4
#define MINIMUM_CHEMICAL_VOLUME 0.01
@@ -13,55 +14,113 @@
#define CHEM_SYNTH_ENERGY 500 // How much energy does it take to synthesize 1 unit of chemical, in Joules.
-// Some on_mob_life() procs check for alien races.
-#define IS_SLIME 1
-
-#define CE_STABLE "stable" // Stabilizing brain, pulse and breathing
-#define CE_ANTIBIOTIC "antibiotic" // Spaceacilin
-#define CE_BLOODRESTORE "bloodrestore" // Iron/nutriment
+/// Stabilizing brain, pulse and breathing
+#define CE_STABLE "stable"
+/// Spaceacilin
+#define CE_ANTIBIOTIC "antibiotic"
+/// Iron/nutriment
+#define CE_BLOODRESTORE "bloodrestore"
+/// Reduces the impact of shock/pain
#define CE_PAINKILLER "painkiller"
-#define CE_ALCOHOL "alcohol" // Liver filtering
-#define CE_ALCOHOL_TOXIC "alcotoxic" // Liver damage
-#define CE_SPEEDBOOST "gofast" // Stimulants
-#define CE_SLOWDOWN "goslow" // Slowdown
-#define CE_PULSE "xcardic" // increases or decreases heart rate
-#define CE_NOPULSE "heartstop" // stops heartbeat
-#define CE_ANTITOX "antitox" // Removes toxins
-#define CE_OXYGENATED "oxygen" // Helps oxygenate the brain.
-#define CE_BRAIN_REGEN "brainfix" // Allows the brain to recover after injury
-#define CE_TOXIN "toxins" // Generic toxins, stops autoheal.
-#define CE_BREATHLOSS "breathloss" // Breathing depression, makes you need more air
-#define CE_MIND "mindbending" // Stabilizes or wrecks mind. Used for hallucinations
-#define CE_CRYO "cryogenic" // Prevents damage from being frozen
-#define CE_BLOCKAGE "blockage" // Gets in the way of blood circulation, higher the worse
-#define CE_SQUEAKY "squeaky" // Helium voice. Squeak squeak.
-#define CE_THIRDEYE "thirdeye" // Gives xray vision.
-#define CE_SEDATE "sedate" // Applies sedation effects, i.e. paralysis, inability to use items, etc.
-#define CE_ENERGETIC "energetic" // Speeds up stamina recovery.
-#define CE_VOICELOSS "whispers" // Lowers the subject's voice to a whisper
-#define CE_GLOWINGEYES "eyeglow" // Causes eyes to glow.
+/// Liver filtering
+#define CE_ALCOHOL "alcohol"
+/// Liver damage
+#define CE_ALCOHOL_TOXIC "alcotoxic"
+/// Stimulants
+#define CE_SPEEDBOOST "gofast"
+/// Slowdown
+#define CE_SLOWDOWN "goslow"
+/// increases or decreases heart rate
+#define CE_PULSE "xcardic"
+/// stops heartbeat
+#define CE_NOPULSE "heartstop"
+/// Removes toxins
+#define CE_ANTITOX "antitox"
+/// Helps oxygenate the brain.
+#define CE_OXYGENATED "oxygen"
+/// Allows the brain to recover after injury
+#define CE_BRAIN_REGEN "brainfix"
+/// Generic toxins, stops autoheal.
+#define CE_TOXIN "toxins"
+/// Breathing depression, makes you need more air
+#define CE_BREATHLOSS "breathloss"
+/// Stabilizes or wrecks mind. Used for hallucinations
+#define CE_MIND "mindbending"
+/// Prevents damage from being frozen
+#define CE_CRYO "cryogenic"
+/// Gets in the way of blood circulation, higher the worse
+#define CE_BLOCKAGE "blockage"
+/// Helium voice. Squeak squeak.
+#define CE_SQUEAKY "squeaky"
+/// Gives xray vision.
+#define CE_THIRDEYE "thirdeye"
+/// Applies sedation effects, i.e. paralysis, inability to use items, etc.
+#define CE_SEDATE "sedate"
+/// Speeds up stamina recovery.
+#define CE_ENERGETIC "energetic"
+/// Lowers the subject's voice to a whisper
+#define CE_VOICELOSS "whispers"
+/// Causes eyes to glow.
+#define CE_GLOWINGEYES "eyeglow"
+/// Causes brute damage to regenerate.
+#define CE_REGEN_BRUTE "bruteheal"
+/// Causes burn damage to regenerate.
+#define CE_REGEN_BURN "burnheal"
+/// Anaphylaxis etc.
+#define CE_ALLERGEN "allergyreaction"
+
+#define GET_CHEMICAL_EFFECT(X, C) (LAZYACCESS(X.chem_effects, C) || 0)
//reagent flags
-#define IGNORE_MOB_SIZE 0x1
-#define AFFECTS_DEAD 0x2
+#define IGNORE_MOB_SIZE BITFLAG(0)
+#define AFFECTS_DEAD BITFLAG(1)
-#define HANDLE_REACTIONS(_reagents) SSmaterials.active_holders[_reagents] = TRUE
+#define HANDLE_REACTIONS(_reagents) if(!QDELETED(_reagents)) { SSmaterials.active_holders[_reagents] = TRUE; }
#define UNQUEUE_REACTIONS(_reagents) SSmaterials.active_holders -= _reagents
-#define REAGENT_LIST(R) (R.reagents?.get_reagents() || "No reagent holder")
+#define REAGENT_LIST(R) ((istype(R, /datum/reagents) && R:get_reagents()) || "No reagent holder")
+
+#define REAGENT_TOTAL_VOLUME(R) (UNLINT((istype(R, /datum/reagents) && R:total_volume) || 0))
+#define REAGENT_TOTAL_LIQUID_VOLUME(R) (UNLINT((istype(R, /datum/reagents) && R:total_liquid_volume) || 0))
+
+#define REAGENT_MAXIMUM_VOLUME(R) (UNLINT((istype(R, /datum/reagents) && R:maximum_volume) || 0))
+#define REAGENTS_FREE_SPACE(R) (UNLINT(istype(R, /datum/reagents) ? (R.maximum_volume - R.total_volume) : 0))
+
+#define REAGENT_VOLUMES(R) ( (istype(R, /datum/reagents) && UNLINT(R:reagent_volumes)) || null )
+#define REAGENT_SOLID_VOLUMES(R) ( (istype(R, /datum/reagents) && UNLINT(R:solid_volumes)) || null )
+#define REAGENT_LIQUID_VOLUMES(R) ( (istype(R, /datum/reagents) && UNLINT(R:liquid_volumes)) || null )
+#define REAGENT_GET_MAX_VOL(R) ( (istype(R, /datum/reagents) && UNLINT(R:maximum_volume)) || 0 )
+#define REAGENT_GET_ATOM(R) ( (istype(R, /datum/reagents) && UNLINT(R:my_atom)) || null )
-#define REAGENTS_FREE_SPACE(R) (R.maximum_volume - R.total_volume)
-#define REAGENT_VOLUME(REAGENT_HOLDER, REAGENT_TYPE) (REAGENT_HOLDER?.reagent_volumes && REAGENT_HOLDER.reagent_volumes[REAGENT_TYPE])
-#define REAGENT_DATA(REAGENT_HOLDER, REAGENT_TYPE) (REAGENT_HOLDER?.reagent_data && REAGENT_HOLDER.reagent_data[REAGENT_TYPE])
+#define REAGENT_VOLUME(R, M) ( istype(R, /datum/reagents) && UNLINT(R:reagent_volumes && R:reagent_volumes[RESOLVE_TO_DECL(M)]) )
+#define LIQUID_VOLUME(R, M) ( istype(R, /datum/reagents) && UNLINT(R:liquid_volumes && R:liquid_volumes[RESOLVE_TO_DECL(M)]) )
+#define SOLID_VOLUME(R, M) ( istype(R, /datum/reagents) && UNLINT(R:solid_volumes && R:solid_volumes[RESOLVE_TO_DECL(M)]) )
+#define REAGENT_DATA(R, M) ( istype(R, /datum/reagents) && UNLINT(R:reagent_data && R:reagent_data[RESOLVE_TO_DECL(M)]) )
-#define MAT_SOLVENT_NONE 0
-#define MAT_SOLVENT_MILD 1
-#define MAT_SOLVENT_MODERATE 2
-#define MAT_SOLVENT_STRONG 3
+#define REAGENT_SET_MAX_VOL(R, V) if(istype(R, /datum/reagents)) { UNLINT(R:maximum_volume = V) }
+#define REAGENT_ADD_MAX_VOL(R, V) if(istype(R, /datum/reagents)) { UNLINT(R:maximum_volume += V) }
+#define REAGENT_SET_ATOM(R, A) if(istype(R, /datum/reagents)) { UNLINT(R:my_atom = A) }
+#define REAGENT_SET_DATA(R, M, D) if(istype(R, /datum/reagents)) { LAZYSET(UNLINT(R:reagent_data), M, D) }
-#define DIRTINESS_STERILE -2
-#define DIRTINESS_CLEAN -1
-#define DIRTINESS_NEUTRAL 0
+
+#define CHEM_DOSE(M, R) LAZYACCESS(M._chem_doses, RESOLVE_TO_DECL(R))
+
+#define MAT_SOLVENT_NONE 0
+#define MAT_SOLVENT_MILD 1
+#define MAT_SOLVENT_MODERATE 2
+#define MAT_SOLVENT_STRONG 3
+#define MAT_SOLVENT_VERY_STRONG 7
+#define MAT_SOLVENT_STRONGEST 10
+#define MAT_SOLVENT_IMMUNE INFINITY
+
+#define DIRTINESS_DECONTAMINATE -3
+#define DIRTINESS_STERILE -2
+#define DIRTINESS_CLEAN -1
+#define DIRTINESS_NEUTRAL 0
#define DEFAULT_GAS_ACCELERANT /decl/material/gas/hydrogen
#define DEFAULT_GAS_OXIDIZER /decl/material/gas/oxygen
+
+#define CHEM_REACTION_FLAG_OVERFLOW_CONTAINER BITFLAG(0)
+
+#define MAX_SCRAP_MATTER (SHEET_MATERIAL_AMOUNT * 5) // Maximum amount of matter in chemical scraps
\ No newline at end of file
diff --git a/code/__defines/colors.dm b/code/__defines/colors.dm
index 0e298cc144e2..cb5a5ee32bf1 100644
--- a/code/__defines/colors.dm
+++ b/code/__defines/colors.dm
@@ -1,7 +1,7 @@
-#define HEX_RED(COLOUR) hex2num(copytext(COLOUR,2,4))
-#define HEX_GREEN(COLOUR) hex2num(copytext(COLOUR,4,6))
-#define HEX_BLUE(COLOUR) hex2num(copytext(COLOUR,6,8))
-#define HEX_ALPHA(COLOUR) hex2num(copytext(COLOUR,8,10))
+#define HEX_RED(COLOR) hex2num(copytext(COLOR,2,4))
+#define HEX_GREEN(COLOR) hex2num(copytext(COLOR,4,6))
+#define HEX_BLUE(COLOR) hex2num(copytext(COLOR,6,8))
+#define HEX_ALPHA(COLOR) hex2num(copytext(COLOR,8,10))
// BYOND lower-cases color values, and thus we do so as well to ensure atom.color == COLOR_X will work correctly
#define COLOR_BLACK "#000000"
@@ -39,6 +39,7 @@
#define COLOR_GREEN_GRAY "#8daf6a"
#define COLOR_DARK_GREEN_GRAY "#54654c"
#define COLOR_BLUE_GRAY "#6a97b0"
+#define COLOR_MID_BLUE_GRAY "#666699"
#define COLOR_DARK_BLUE_GRAY "#3e4855"
#define COLOR_SURGERY_BLUE "#e0f2f6"
#define COLOR_SUN "#ec8b2f"
@@ -78,6 +79,7 @@
#define COLOR_AMBER "#ffbf00"
#define COLOR_COMMAND_BLUE "#46698c"
#define COLOR_SKY_BLUE "#5ca1cc"
+#define COLOR_FONT_ORANGE "#e67300"
#define COLOR_PALE_ORANGE "#b88a3b"
#define COLOR_CIVIE_GREEN "#b7f27d"
#define COLOR_TITANIUM "#d1e6e3"
@@ -91,45 +93,70 @@
#define COLOR_CRYSTAL "#00c8a5"
#define COLOR_ASTEROID_ROCK "#735555"
#define COLOR_DIAMOND "#d8d4ea"
-
-
-#define PIPE_COLOR_GREY "#808080"
-#define PIPE_COLOR_RED "#ff0000"
-#define PIPE_COLOR_BLUE "#0000ff"
-#define PIPE_COLOR_CYAN "#00ffff"
-#define PIPE_COLOR_GREEN "#00ff00"
-#define PIPE_COLOR_YELLOW "#ffcc00"
-#define PIPE_COLOR_BLACK "#444444"
-#define PIPE_COLOR_ORANGE "#b95a00"
+#define COLOR_BLOOD_RED "#990000"
+#define COLOR_PALE_GOLD "#cc9900"
+#define COLOR_ROYAL_BLUE "#0033ff"
+#define COLOR_VERDANT_GREEN "#287d00"
+#define COLOR_SCIENCE_PURPLE "#6633cc"
+#define COLOR_DAYLIGHT "#f3e6ca"
+#define COLOR_CHERRY_RED "#902630"
+
+#define PIPE_COLOR_GREY "#808080"
+#define PIPE_COLOR_RED "#ff0000"
+#define PIPE_COLOR_BLUE "#0000ff"
+#define PIPE_COLOR_CYAN "#00ffff"
+#define PIPE_COLOR_GREEN "#00ff00"
+#define PIPE_COLOR_YELLOW "#ffcc00"
+#define PIPE_COLOR_BLACK "#444444"
+#define PIPE_COLOR_ORANGE "#b95a00"
#define PIPE_COLOR_WHITE "#ffffff"
+#define PIPE_COLOR_PURPLE "#880088"
-#define COMMS_COLOR_DEFAULT "#ff00ff"
-#define COMMS_COLOR_ENTERTAIN "#666666"
-#define COMMS_COLOR_AI "#ff00ff"
+#define COMMS_COLOR_DEFAULT "#ff00ff"
+#define COMMS_COLOR_ENTERTAIN "#666666"
+#define COMMS_COLOR_AI "#ff00ff"
#define COMMS_COLOR_COMMON "#408010"
-#define COMMS_COLOR_SERVICE "#709b00"
-#define COMMS_COLOR_SUPPLY "#7f6539"
-#define COMMS_COLOR_SCIENCE "#993399"
-#define COMMS_COLOR_MEDICAL "#009190"
-#define COMMS_COLOR_EXPLORER "#929820"
-#define COMMS_COLOR_ENGINEER "#a66300"
-#define COMMS_COLOR_SECURITY "#930000"
-#define COMMS_COLOR_COMMAND "#204090"
-#define COMMS_COLOR_CENTCOMM "#5c5c7c"
-#define COMMS_COLOR_SYNDICATE "#6d3f40"
+#define COMMS_COLOR_SERVICE "#709b00"
+#define COMMS_COLOR_SUPPLY "#7f6539"
+#define COMMS_COLOR_SCIENCE "#993399"
+#define COMMS_COLOR_MEDICAL "#009190"
+#define COMMS_COLOR_EXPLORER "#929820"
+#define COMMS_COLOR_ENGINEER "#a66300"
+#define COMMS_COLOR_SECURITY "#930000"
+#define COMMS_COLOR_COMMAND "#204090"
+#define COMMS_COLOR_CENTCOMM "#5c5c7c"
+#define COMMS_COLOR_SYNDICATE "#6d3f40"
+#define COMMS_COLOR_ANALOG "#64706b" // special case, not in telecomms_colours
+
+var/global/list/telecomms_colours = list(
+ "Default Pink" = COMMS_COLOR_DEFAULT,
+ "Entertainment Grey" = COMMS_COLOR_ENTERTAIN,
+ "A.I. Pink" = COMMS_COLOR_AI,
+ "Common Green" = COMMS_COLOR_COMMON,
+ "Service Lime" = COMMS_COLOR_SERVICE,
+ "Supply Drab" = COMMS_COLOR_SUPPLY,
+ "Scientific Purple" = COMMS_COLOR_SCIENCE,
+ "Medical Blue" = COMMS_COLOR_MEDICAL,
+ "Explorer Yellow" = COMMS_COLOR_EXPLORER,
+ "Engineering Orange" = COMMS_COLOR_ENGINEER,
+ "Security Red" = COMMS_COLOR_SECURITY,
+ "Command Blue" = COMMS_COLOR_COMMAND,
+ "Steel Blue" = COMMS_COLOR_CENTCOMM,
+ "Syndicate Red" = COMMS_COLOR_SYNDICATE
+)
#define WOOD_COLOR_GENERIC "#d5a66e"
#define WOOD_COLOR_RICH "#792f27"
#define WOOD_COLOR_PALE "#d2bc9d"
#define WOOD_COLOR_PALE2 "#e6d2ba"
-#define WOOD_COLOR_BLACK "#332521"
+#define WOOD_COLOR_BLACK "#39342c"
#define WOOD_COLOR_CHOCOLATE "#543c30"
#define WOOD_COLOR_YELLOW "#e3994e"
-#define GLASS_COLOR "#74c1ee"
+#define GLASS_COLOR "#aaccff"
#define GLASS_COLOR_SILICATE "#7c3a9a"
#define GLASS_COLOR_TINTED "#222222"
-#define GLASS_COLOR_FROSTED "#ffffff"
+#define GLASS_COLOR_FROSTED "#eeeeee"
#define COLOR_BLOOD_HUMAN "#a10808"
@@ -184,8 +211,8 @@
#define LIGHT_COLOR_EMERGENCY "#ff3232" //Red color used by emergency lighting. rgb(255, 50, 50)
// Used by fluid system.
-#define COLOR_OCEAN "#99f5ff"
-
+#define COLOR_LIQUID_WATER "#99f5ff"
+#define COLOR_ICE "#eef5ff"
// Used to easily change research colour in case of ???
#define COLOR_RESEARCH COLOR_PURPLE_GRAY
@@ -198,8 +225,16 @@
#define RANDOM_RGB rgb(rand(0,255), rand(0,255), rand(0,255))
// Codex category colours.
-#define CODEX_COLOR_LORE "#abdb9b"
-#define CODEX_COLOR_MECHANICS "#9ebcd8"
-#define CODEX_COLOR_ANTAG "#e5a2a2"
+#define COLOR_WEBHOOK_DEFAULT 0x8bbbd5
+
+// Colors for input/hotkey panel.
+#define COLOR_INPUT_DISABLED "#f0f0f0"
+#define COLOR_INPUT_ENABLED "#d3b5b5"
+
+#define COLOR_DARKMODE_BACKGROUND "#202020"
+#define COLOR_DARKMODE_DARKBACKGROUND "#171717"
+#define COLOR_DARKMODE_TEXT "#a4bad6"
+
+#define COLORED_SQUARE(COLOR) "___"
-#define COLOR_WEBHOOK_DEFAULT 0x8bbbd5
\ No newline at end of file
+#define hsv(args...) rgb(args, space = COLORSPACE_HSV)
\ No newline at end of file
diff --git a/code/__defines/computers.dm b/code/__defines/computers.dm
index e3e10441ae5b..c61460f6a5b3 100644
--- a/code/__defines/computers.dm
+++ b/code/__defines/computers.dm
@@ -1,9 +1,15 @@
#define NETWORK_MAC uniqueness_repository.Generate(/datum/uniqueness_generator/hex)
- // Network allowed actions
-#define NETWORK_SOFTWAREDOWNLOAD 1 // Downloads of software
-#define NETWORK_COMMUNICATION 2 // Communication (messaging)
-#define NETWORK_SYSTEMCONTROL 4 // Control of various systems, RCon, air alarm control, etc.
-#define NETWORK_ALL_FEATURES (NETWORK_SOFTWAREDOWNLOAD|NETWORK_COMMUNICATION|NETWORK_SYSTEMCONTROL)
+ // Network allowed actions
+#define NET_FEATURE_SOFTWAREDOWNLOAD BITFLAG(0) // Downloads of software.
+#define NET_FEATURE_COMMUNICATION BITFLAG(1) // Communication (messaging), e-mail.
+#define NET_FEATURE_SYSTEMCONTROL BITFLAG(2) // Control of various systems, RCon, air alarm control, etc.
+#define NET_FEATURE_SECURITY BITFLAG(3) // Access to security cameras, crew tracking etc.
+#define NET_FEATURE_ACCESS BITFLAG(4) // Checking access by group membership, not modifying account access.
+#define NET_FEATURE_RECORDS BITFLAG(5) // Modifying accounts, viewing crew records etc.
+#define NET_FEATURE_FILESYSTEM BITFLAG(6) // Accessing mainframe filesystems.
+#define NET_FEATURE_DECK BITFLAG(7) // Control of docking beacons, supply, deck control.
+
+#define NET_ALL_FEATURES (NET_FEATURE_SOFTWAREDOWNLOAD|NET_FEATURE_COMMUNICATION|NET_FEATURE_SYSTEMCONTROL|NET_FEATURE_SECURITY|NET_FEATURE_ACCESS|NET_FEATURE_RECORDS|NET_FEATURE_FILESYSTEM|NET_FEATURE_DECK)
// Transfer speeds, used when downloading/uploading a file/program.
#define NETWORK_SPEED_BASE 1/NETWORK_BASE_BROADCAST_STRENGTH // GQ/s transfer speed, multiplied by signal power
@@ -11,22 +17,23 @@
// Network mainframe roles
#define MF_ROLE_FILESERVER "FILE SERVER"
-#define MF_ROLE_EMAIL_SERVER "EMAIL SERVER"
#define MF_ROLE_LOG_SERVER "LOG SERVER"
#define MF_ROLE_CREW_RECORDS "RECORDS SERVER"
#define MF_ROLE_SOFTWARE "SOFTWARE REPOSITORY"
+#define MF_ROLE_ACCOUNT_SERVER "ACCOUNT SERVER"
// Program bitflags
-#define PROGRAM_ALL 0x1F
-#define PROGRAM_CONSOLE 0x1
-#define PROGRAM_LAPTOP 0x2
-#define PROGRAM_TABLET 0x4
-#define PROGRAM_TELESCREEN 0x8
-#define PROGRAM_PDA 0x10
+#define PROGRAM_CONSOLE BITFLAG(0)
+#define PROGRAM_LAPTOP BITFLAG(1)
+#define PROGRAM_TABLET BITFLAG(2)
+#define PROGRAM_TELESCREEN BITFLAG(3)
+#define PROGRAM_PDA BITFLAG(4)
+#define PROGRAM_ALL (PROGRAM_CONSOLE|PROGRAM_LAPTOP|PROGRAM_TABLET|PROGRAM_TELESCREEN|PROGRAM_PDA)
#define PROGRAM_STATE_KILLED 0
#define PROGRAM_STATE_BACKGROUND 1
#define PROGRAM_STATE_ACTIVE 2
+#define PROGRAM_STATE_BROWSER 3
#define PROG_MISC "Miscellaneous"
#define PROG_ENG "Engineering"
@@ -38,11 +45,34 @@
#define PROG_SEC "Security"
#define PROG_MONITOR "Monitoring"
-#define NETWORK_CONNECTION_WIRELESS 1
-#define NETWORK_CONNECTION_STRONG_WIRELESS 2
-#define NETWORK_CONNECTION_WIRED 3
-#define NETWORK_BASE_BROADCAST_STRENGTH 25
+#define RECEIVER_WIRELESS 1
+#define RECEIVER_STRONG_WIRELESS 2
+#define RECEIVER_BROADCASTER 3
+
+#define NETWORK_BASE_BROADCAST_STRENGTH 25
+#define NETWORK_INTERNET_CONNECTION_STRENGTH 25
+#define NETWORK_WIRED_CONNECTION_STRENGTH 100
// Caps for network logging. Less than 10 would make logging useless anyway, more than 500 may make the log browser too laggy. Defaults to 100 unless user changes it.
#define MAX_NETWORK_LOGS 100
-#define MIN_NETWORK_LOGS 10
\ No newline at end of file
+#define MIN_NETWORK_LOGS 10
+
+// Default directories referenced by the OS or programs.
+#define OS_PROGRAMS_DIR "programs"
+#define OS_RECORDS_DIR "records"
+#define OS_ACCOUNTS_DIR "accounts"
+#define OS_DOCUMENTS_DIR "documents"
+#define OS_LOGS_DIR "logs"
+
+// Return codes for file storage.
+#define OS_FILE_SUCCESS 1
+#define OS_HARDDRIVE_ERROR 0
+#define OS_FILE_NOT_FOUND -1
+#define OS_DIR_NOT_FOUND -2
+#define OS_FILE_EXISTS -3
+#define OS_FILE_NO_READ -4
+#define OS_FILE_NO_WRITE -5
+#define OS_HARDDRIVE_SPACE -6
+#define OS_NETWORK_ERROR -7
+#define OS_BAD_NAME -8
+#define OS_BAD_TYPE -9 // File type is unsupported on this hardware.
\ No newline at end of file
diff --git a/code/__defines/cooking.dm b/code/__defines/cooking.dm
new file mode 100644
index 000000000000..820a6b981445
--- /dev/null
+++ b/code/__defines/cooking.dm
@@ -0,0 +1,25 @@
+#define COOKING_HEAT_ANY 0
+#define COOKING_HEAT_DIRECT 1
+#define COOKING_HEAT_INDIRECT 2
+
+#define FOOD_RAW -1
+#define FOOD_PREPARED 0
+#define FOOD_COOKED 1
+
+#define ALLERGEN_NONE 0
+#define ALLERGEN_MEAT BITFLAG(0)
+#define ALLERGEN_FISH BITFLAG(1)
+#define ALLERGEN_VEGETABLE BITFLAG(2)
+#define ALLERGEN_DAIRY BITFLAG(3)
+#define ALLERGEN_CHEESE BITFLAG(4)
+#define ALLERGEN_EGG BITFLAG(5)
+#define ALLERGEN_FRUIT BITFLAG(6)
+#define ALLERGEN_GLUTEN BITFLAG(7)
+#define ALLERGEN_SOY BITFLAG(8)
+#define ALLERGEN_CAFFEINE BITFLAG(9)
+#define ALLERGEN_FUNGI BITFLAG(10)
+#define ALLERGEN_NUTS BITFLAG(11)
+#define ALLERGEN_ALLIUM BITFLAG(12)
+#define ALLERGEN_STIMULANT BITFLAG(13)
+
+#define ALLERGENS_ALL (ALLERGEN_MEAT|ALLERGEN_FISH|ALLERGEN_VEGETABLE|ALLERGEN_DAIRY|ALLERGEN_CHEESE|ALLERGEN_EGG|ALLERGEN_FRUIT|ALLERGEN_GLUTEN|ALLERGEN_SOY|ALLERGEN_CAFFEINE|ALLERGEN_NUTS|ALLERGEN_ALLIUM|ALLERGEN_STIMULANT)
diff --git a/code/__defines/credits.dm b/code/__defines/credits.dm
new file mode 100644
index 000000000000..8b70c447345e
--- /dev/null
+++ b/code/__defines/credits.dm
@@ -0,0 +1,4 @@
+#define CREDIT_ROLL_SPEED 185
+#define CREDIT_SPAWN_SPEED 20
+#define CREDIT_ANIMATE_HEIGHT (14 * world.icon_size)
+#define CREDIT_EASE_DURATION 22
diff --git a/code/__defines/culture.dm b/code/__defines/culture.dm
deleted file mode 100644
index 2fd251bd3e0d..000000000000
--- a/code/__defines/culture.dm
+++ /dev/null
@@ -1,27 +0,0 @@
-#define TAG_CULTURE "culture"
-#define TAG_HOMEWORLD "home_system"
-#define TAG_FACTION "faction"
-#define TAG_RELIGION "religion"
-
-#define ALL_CULTURAL_TAGS list( \
- TAG_CULTURE = "Culture", \
- TAG_HOMEWORLD = "Residence", \
- TAG_FACTION = "Faction", \
- TAG_RELIGION = "Beliefs" \
- )
-
-// Cultural IDs.
-#define FACTION_OTHER "Other Faction"
-
-#define HOME_SYSTEM_STATELESS "Stateless"
-#define HOME_SYSTEM_OTHER "Other System"
-#define HOME_SYSTEM_DEEP_SPACE "Deep Space"
-
-#define CULTURE_OTHER "Other Culture"
-#define CULTURE_HUMAN "Humankind"
-#define CULTURE_MONKEY "Test Subjects"
-#define CULTURE_ALIUM "Mysterious Aliens"
-#define CULTURE_CULTIST "Blood Cult"
-
-#define RELIGION_OTHER "Other Religion"
-
diff --git a/code/__defines/damage.dm b/code/__defines/damage.dm
new file mode 100644
index 000000000000..e3c45646c796
--- /dev/null
+++ b/code/__defines/damage.dm
@@ -0,0 +1,2 @@
+///The decimal precision for health values. Health will be rounded against this value.
+#define HEALTH_ROUNDING 0.01
diff --git a/code/__defines/damage_organs.dm b/code/__defines/damage_organs.dm
index d20962413ce0..8fbc2d9a9b0f 100644
--- a/code/__defines/damage_organs.dm
+++ b/code/__defines/damage_organs.dm
@@ -1,11 +1,10 @@
-// Damage things. TODO: Merge these down to reduce on defines.
-// Way to waste perfectly good damage-type names (BRUTE) on this... If you were really worried about case sensitivity, you could have just used lowertext(damagetype) in the proc.
#define BRUTE "brute"
#define BURN "fire"
#define TOX "tox"
#define OXY "oxy"
#define CLONE "clone"
#define PAIN "pain"
+#define BRAIN "brain"
#define ELECTROCUTE "electrocute"
#define CUT "cut"
@@ -13,6 +12,7 @@
#define PIERCE "pierce"
#define LASER "laser"
#define SHATTER "shatter"
+#define CHARRED "charred"
#define STUN "stun"
#define WEAKEN "weaken"
@@ -35,36 +35,56 @@
#define FIRE_DAMAGE_MODIFIER 0.0215 // Higher values result in more external fire damage to the skin. (default 0.0215)
#define AIR_DAMAGE_MODIFIER 2.025 // More means less damage from hot air scalding lungs, less = more damage. (default 2.025)
+//Armor Resistance Types
+#define ARMOR_MELEE "melee" //Blunt and cutting weapons
+#define ARMOR_BULLET "bullet" //Kinectic projectiles
+#define ARMOR_BOMB "bomb" //Explosions
+#define ARMOR_LASER "laser" //Laser weapons
+#define ARMOR_ENERGY "energy" //Intense heat, electricity
+#define ARMOR_RAD "rad" //Ionizing radiation
+#define ARMOR_BIO "bio" //Biohazards toxin damage
+
// Organ defines.
-#define ORGAN_CUT_AWAY (1<<0) // The organ is in the process of being surgically removed.
-#define ORGAN_BLEEDING (1<<1) // The organ is currently bleeding.
-#define ORGAN_BROKEN (1<<2) // The organ is broken.
-#define ORGAN_DEAD (1<<3) // The organ is necrotic.
-#define ORGAN_MUTATED (1<<4) // The organ is unusable due to genetic damage.
-#define ORGAN_ARTERY_CUT (1<<6) // The organ has had its artery cut.
-#define ORGAN_TENDON_CUT (1<<7) // The organ has had its tendon cut.
-#define ORGAN_DISFIGURED (1<<8) // The organ is scarred/disfigured. Alters whether or not the face can be recognised.
-#define ORGAN_SABOTAGED (1<<9) // The organ will explode if exposed to EMP, if prosthetic.
-#define ORGAN_ASSISTED (1<<10) // The organ is partially prosthetic. No mechanical effect.
-#define ORGAN_PROSTHETIC (1<<11) // The organ is prosthetic. Changes numerous behaviors, search BP_IS_PROSTHETIC for checks.
-#define ORGAN_BRITTLE (1<<12) // The organ takes additional blunt damage. If robotic, cannot be repaired through normal means.
-#define ORGAN_CRYSTAL (1<<13) // The organ does not suffer laser damage, but shatters on droplimb.
+#define ORGAN_CUT_AWAY BITFLAG(0) // The organ is in the process of being surgically removed.
+#define ORGAN_BLEEDING BITFLAG(1) // The organ is currently bleeding.
+#define ORGAN_BROKEN BITFLAG(2) // The organ is broken.
+#define ORGAN_DEAD BITFLAG(3) // The organ is necrotic.
+#define ORGAN_MUTATED BITFLAG(4) // The organ is unusable due to genetic damage.
+#define ORGAN_ARTERY_CUT BITFLAG(5) // The organ has had its artery cut.
+#define ORGAN_TENDON_CUT BITFLAG(6) // The organ has had its tendon cut.
+#define ORGAN_DISFIGURED BITFLAG(7) // The organ is scarred/disfigured. Alters whether or not the face can be recognised.
+#define ORGAN_SABOTAGED BITFLAG(8) // The organ will explode if exposed to EMP, if prosthetic.
+#define ORGAN_BRITTLE BITFLAG(9) // The organ takes additional blunt damage. If robotic, cannot be repaired through normal means.
+#define ORGAN_DISLOCATED BITFLAG(10) //The organ is dislocated and will cause pain until set back in place.
+
+// Organ Properties
+#define ORGAN_PROP_PROSTHETIC BITFLAG(0) // The organ is prosthetic. Changes numerous behaviors, search BP_IS_PROSTHETIC for checks.
+#define ORGAN_PROP_CRYSTAL BITFLAG(1) // The organ does not suffer laser damage, but shatters on droplimb.
// Organ flag defines.
-#define ORGAN_FLAG_CAN_AMPUTATE (1<<0) // The organ can be amputated.
-#define ORGAN_FLAG_CAN_BREAK (1<<1) // The organ can be broken.
-#define ORGAN_FLAG_CAN_GRASP (1<<2) // The organ contributes to grasping.
-#define ORGAN_FLAG_CAN_STAND (1<<3) // The organ contributes to standing.
-#define ORGAN_FLAG_HAS_TENDON (1<<4) // The organ can have its tendon cut.
-#define ORGAN_FLAG_FINGERPRINT (1<<5) // The organ has a fingerprint.
-#define ORGAN_FLAG_GENDERED_ICON (1<<6) // The icon state for this organ appends _m/_f.
-#define ORGAN_FLAG_HEALS_OVERKILL (1<<7) // The organ heals from overkill damage.
-#define ORGAN_FLAG_DEFORMED (1<<8) // The organ is permanently disfigured.
+#define ORGAN_FLAG_CAN_AMPUTATE BITFLAG(0) // The organ can be amputated.
+#define ORGAN_FLAG_CAN_BREAK BITFLAG(1) // The organ can be broken.
+#define ORGAN_FLAG_CAN_STAND BITFLAG(2) // The organ contributes to standing.
+#define ORGAN_FLAG_HAS_TENDON BITFLAG(3) // The organ can have its tendon cut.
+#define ORGAN_FLAG_FINGERPRINT BITFLAG(4) // The organ has a fingerprint.
+#define ORGAN_FLAG_HEALS_OVERKILL BITFLAG(5) // The organ heals from overkill damage.
+#define ORGAN_FLAG_DEFORMED BITFLAG(6) // The organ is permanently disfigured.
+#define ORGAN_FLAG_CAN_DISLOCATE BITFLAG(7) // The organ can be dislocated.
+#define ORGAN_FLAG_SKELETAL BITFLAG(8) // The organ has been skeletonized.
+
+// Organ category defines.
+/// Limb contributes only to stance damage calculation (foot)
+#define ORGAN_CATEGORY_STANCE "stance"
+/// Limb is considered the 'root' of a given stance limb (leg) - also counted for stance damage a la ORGAN_CATEGORY_STANCE
+#define ORGAN_CATEGORY_STANCE_ROOT "stance_root"
+// Limb is considered a manipulator, currently only used when trying to pilot a wheelchair.
+#define ORGAN_CATEGORY_MANIPLE "maniple"
// Droplimb types.
-#define DROPLIMB_EDGE 0
-#define DROPLIMB_BLUNT 1
-#define DROPLIMB_BURN 2
+#define DISMEMBER_METHOD_EDGE 0
+#define DISMEMBER_METHOD_BLUNT 1
+#define DISMEMBER_METHOD_BURN 2
+#define DISMEMBER_METHOD_ACID 3
// Robotics hatch_state defines.
#define HATCH_CLOSED 0
@@ -95,3 +115,13 @@
#define BLOOD_VOLUME_BAD 60
#define BLOOD_VOLUME_SURVIVE 30
+// enum-ish values for surgery conditions
+#define OPERATE_DENY 0
+#define OPERATE_PASSABLE 1
+#define OPERATE_OKAY 2
+#define OPERATE_IDEAL 3
+
+#define MODULAR_BODYPART_INVALID 0 // Cannot be detached or reattached.
+#define MODULAR_BODYPART_ANYWHERE 1 // Can be detached or reattached freely.
+#define MODULAR_BODYPART_CYBERNETIC 2 // Can be detached or reattached to compatible parent organs.
+
diff --git a/code/__defines/definition_helpers.dm b/code/__defines/definition_helpers.dm
new file mode 100644
index 000000000000..29366c55fb90
--- /dev/null
+++ b/code/__defines/definition_helpers.dm
@@ -0,0 +1,46 @@
+/**Define a poster's decl and its mapper type */
+#define DEFINE_POSTER(TYPENAME, ICONSTATE, NAME, DESC)\
+/decl/poster_design/##TYPENAME{name = NAME; desc = DESC; icon_state = ICONSTATE;};\
+/obj/structure/sign/poster/##TYPENAME{poster_design = /decl/poster_design/##TYPENAME; name = NAME; icon_state = ICONSTATE;};
+
+#define DEFINE_STACK_SUBTYPES(MAT_ID, MAT_NAME, MAT_TYPE, STACK_TYPE, REINF_TYPE) \
+/obj/item/stack/material/##STACK_TYPE/mapped/##MAT_ID { \
+ name = "1 " + MAT_NAME; \
+ material = /decl/material/MAT_TYPE; \
+ reinf_material = REINF_TYPE; \
+ amount = 1; \
+ is_spawnable_type = TRUE; \
+ color = parent_type::paint_color || /decl/material/MAT_TYPE::color; \
+} \
+/obj/item/stack/material/##STACK_TYPE/mapped/##MAT_ID/five { \
+ name = "5 " + MAT_NAME; \
+ amount = 5; \
+} \
+/obj/item/stack/material/##STACK_TYPE/mapped/##MAT_ID/ten { \
+ name = "10 " + MAT_NAME; \
+ amount = 10; \
+} \
+/obj/item/stack/material/##STACK_TYPE/mapped/##MAT_ID/fifteen { \
+ name = "15 " + MAT_NAME; \
+ amount = 15; \
+} \
+/obj/item/stack/material/##STACK_TYPE/mapped/##MAT_ID/twenty { \
+ name = "20 " + MAT_NAME; \
+ amount = 20; \
+} \
+/obj/item/stack/material/##STACK_TYPE/mapped/##MAT_ID/twentyfive { \
+ name = "25 " + MAT_NAME; \
+ amount = 25; \
+} \
+/obj/item/stack/material/##STACK_TYPE/mapped/##MAT_ID/thirty { \
+ name = "30 " + MAT_NAME; \
+ amount = 30; \
+} \
+/obj/item/stack/material/##STACK_TYPE/mapped/##MAT_ID/forty { \
+ name = "40 " + MAT_NAME; \
+ amount = 40; \
+} \
+/obj/item/stack/material/##STACK_TYPE/mapped/##MAT_ID/fifty { \
+ name = "50 " + MAT_NAME; \
+ amount = 50; \
+}
diff --git a/code/__defines/deity.dm b/code/__defines/deity.dm
deleted file mode 100644
index 99f7511bcd95..000000000000
--- a/code/__defines/deity.dm
+++ /dev/null
@@ -1,2 +0,0 @@
-#define DEITY_STRUCTURE_NEAR_IMPORTANT 1 //Whether this needs to be near an important structure.
-#define DEITY_STRUCTURE_ALONE 2 //Whether this can be near another of the same type.
\ No newline at end of file
diff --git a/code/__defines/directions.dm b/code/__defines/directions.dm
index 29436e32cd9f..4f6bff8a3a0c 100644
--- a/code/__defines/directions.dm
+++ b/code/__defines/directions.dm
@@ -6,4 +6,102 @@
#define N_NORTHEAST 32
#define N_NORTHWEST 512
#define N_SOUTHEAST 64
-#define N_SOUTHWEST 1024
\ No newline at end of file
+#define N_SOUTHWEST 1024
+
+#define CORNER_NONE 0
+#define CORNER_COUNTERCLOCKWISE 1
+#define CORNER_DIAGONAL 2
+#define CORNER_CLOCKWISE 4
+// Aquarium-specific corners (due to ordering requirements)
+#define CORNER_EASTWEST CORNER_COUNTERCLOCKWISE
+#define CORNER_NORTHSOUTH CORNER_CLOCKWISE
+
+#define FIRST_DIR(X) ((X) & -(X))
+
+/*
+ turn() is weird:
+ turn(icon, angle) turns icon by angle degrees clockwise
+ turn(matrix, angle) turns matrix by angle degrees clockwise
+ turn(dir, angle) turns dir by angle degrees counter-clockwise
+*/
+
+/proc/dirs_to_corner_states(list/dirs)
+ if(!istype(dirs)) return
+
+ var/list/ret = list(NORTHWEST, SOUTHEAST, NORTHEAST, SOUTHWEST)
+
+ for(var/i = 1 to ret.len)
+ var/dir = ret[i]
+ . = CORNER_NONE
+ if(dir in dirs)
+ . |= CORNER_DIAGONAL
+ if(turn(dir,45) in dirs)
+ . |= CORNER_COUNTERCLOCKWISE
+ if(turn(dir,-45) in dirs)
+ . |= CORNER_CLOCKWISE
+ ret[i] = "[.]"
+
+ return ret
+
+/proc/corner_states_to_dirs(list/corners)
+ if(!istype(corners)) return
+
+ var/list/ret = list(NORTHWEST, SOUTHEAST, NORTHEAST, SOUTHWEST)
+ . = list()
+
+ for(var/i = 1 to ret.len)
+ var/dir = ret[i]
+ var/corner = text2num(corners[i])
+ if(corner & CORNER_DIAGONAL)
+ . |= dir
+ if(corner & CORNER_COUNTERCLOCKWISE)
+ . |= turn(dir, 45)
+ if(corner & CORNER_CLOCKWISE)
+ . |= turn(dir, -45)
+
+// Similar to dirs_to_corner_states(), but returns an *ordered* list, requiring (in order), dir=NORTH, SOUTH, EAST, WEST
+// Note that this means this proc can be used as:
+
+// var/list/corner_states = dirs_to_unified_corner_states(directions)
+// for(var/index = 1 to 4)
+// var/image/I = image(icon, icon_state = corner_states[index], dir = BITFLAG(index - 1))
+// [...]
+
+/proc/dirs_to_unified_corner_states(list/dirs)
+ if(!istype(dirs)) return
+
+ var/NE = CORNER_NONE
+ var/NW = CORNER_NONE
+ var/SE = CORNER_NONE
+ var/SW = CORNER_NONE
+
+ if(NORTH in dirs)
+ NE |= CORNER_NORTHSOUTH
+ NW |= CORNER_NORTHSOUTH
+ if(SOUTH in dirs)
+ SW |= CORNER_NORTHSOUTH
+ SE |= CORNER_NORTHSOUTH
+ if(EAST in dirs)
+ SE |= CORNER_EASTWEST
+ NE |= CORNER_EASTWEST
+ if(WEST in dirs)
+ NW |= CORNER_EASTWEST
+ SW |= CORNER_EASTWEST
+ if(NORTHWEST in dirs)
+ NW |= CORNER_DIAGONAL
+ if(NORTHEAST in dirs)
+ NE |= CORNER_DIAGONAL
+ if(SOUTHEAST in dirs)
+ SE |= CORNER_DIAGONAL
+ if(SOUTHWEST in dirs)
+ SW |= CORNER_DIAGONAL
+
+ return list("[NE]", "[NW]", "[SE]", "[SW]")
+
+#undef CORNER_NONE
+
+#undef CORNER_COUNTERCLOCKWISE
+#undef CORNER_CLOCKWISE
+#undef CORNER_EASTWEST
+#undef CORNER_DIAGONAL
+#undef CORNER_NORTHSOUTH
diff --git a/code/__defines/dna.dm b/code/__defines/dna.dm
deleted file mode 100644
index 44ffd13f965d..000000000000
--- a/code/__defines/dna.dm
+++ /dev/null
@@ -1,73 +0,0 @@
-// Bitflags for mutations.
-#define STRUCDNASIZE 27
-#define UNIDNASIZE 13
-
-// Generic mutations:
-#define MUTATION_COLD_RESISTANCE 1
-#define MUTATION_XRAY 2
-#define MUTATION_HULK 3
-#define MUTATION_CLUMSY 4
-#define MUTATION_FAT 5
-#define MUTATION_HUSK 6
-#define MUTATION_LASER 7 // Harm intent - click anywhere to shoot lasers from eyes.
-#define MUTATION_HEAL 8 // Healing people with hands.
-#define MUTATION_SPACERES 9 // Can't be harmed via pressure damage.
-#define MUTATION_SKELETON 10
-
-// Other Mutations:
-#define mNobreath 100 // No need to breathe.
-#define mRemote 101 // Remote viewing.
-#define mRegen 102 // Health regeneration.
-#define mRun 103 // No slowdown.
-#define mRemotetalk 104 // Remote talking.
-#define mMorph 105 // Hanging appearance.
-#define mBlend 106 // Nothing. (seriously nothing)
-#define mHallucination 107 // Hallucinations.
-#define mFingerprints 108 // No fingerprints.
-#define mShock 109 // Insulated hands.
-#define mSmallsize 110 // Table climbing.
-
-// disabilities
-#define NEARSIGHTED 0x1
-#define EPILEPSY 0x2
-#define COUGHING 0x4
-#define TOURETTES 0x8
-#define NERVOUS 0x10
-
-// sdisabilities
-#define BLINDED 0x1
-#define MUTED 0x2
-#define DEAFENED 0x4
-
-// The way blocks are handled badly needs a rewrite, this is horrible.
-// Too much of a project to handle at the moment, TODO for later.
-GLOBAL_VAR_INIT(BLINDBLOCK,0)
-GLOBAL_VAR_INIT(DEAFBLOCK,0)
-GLOBAL_VAR_INIT(HULKBLOCK,0)
-GLOBAL_VAR_INIT(TELEBLOCK,0)
-GLOBAL_VAR_INIT(FIREBLOCK,0)
-GLOBAL_VAR_INIT(XRAYBLOCK,0)
-GLOBAL_VAR_INIT(CLUMSYBLOCK,0)
-GLOBAL_VAR_INIT(FAKEBLOCK,0)
-GLOBAL_VAR_INIT(COUGHBLOCK,0)
-GLOBAL_VAR_INIT(GLASSESBLOCK,0)
-GLOBAL_VAR_INIT(EPILEPSYBLOCK,0)
-GLOBAL_VAR_INIT(TWITCHBLOCK,0)
-GLOBAL_VAR_INIT(NERVOUSBLOCK,0)
-GLOBAL_VAR_INIT(MONKEYBLOCK, STRUCDNASIZE)
-
-GLOBAL_VAR_INIT(BLOCKADD,0)
-GLOBAL_VAR_INIT(DIFFMUT,0)
-
-GLOBAL_VAR_INIT(HEADACHEBLOCK,0)
-GLOBAL_VAR_INIT(NOBREATHBLOCK,0)
-GLOBAL_VAR_INIT(REMOTEVIEWBLOCK,0)
-GLOBAL_VAR_INIT(REGENERATEBLOCK,0)
-GLOBAL_VAR_INIT(INCREASERUNBLOCK,0)
-GLOBAL_VAR_INIT(REMOTETALKBLOCK,0)
-GLOBAL_VAR_INIT(MORPHBLOCK,0)
-GLOBAL_VAR_INIT(BLENDBLOCK,0)
-GLOBAL_VAR_INIT(HALLUCINATIONBLOCK,0)
-GLOBAL_VAR_INIT(NOPRINTSBLOCK,0)
-GLOBAL_VAR_INIT(SHOCKIMMUNITYBLOCK,0)
-GLOBAL_VAR_INIT(SMALLSIZEBLOCK,0)
diff --git a/code/__defines/dview.dm b/code/__defines/dview.dm
new file mode 100644
index 000000000000..52553ef99784
--- /dev/null
+++ b/code/__defines/dview.dm
@@ -0,0 +1,14 @@
+//DVIEW defines
+
+#define FOR_DVIEW(type, range, center, invis_flags) \
+ global.dview_mob.loc = center; \
+ global.dview_mob.see_invisible = invis_flags; \
+ for(type in view(range, dview_mob))
+
+#define END_FOR_DVIEW dview_mob.loc = null
+
+#define DVIEW(output, range, center, invis_flags) \
+ global.dview_mob.loc = center; \
+ global.dview_mob.see_invisible = invis_flags; \
+ output = view(range, dview_mob); \
+ global.dview_mob.loc = null;
diff --git a/code/__defines/fires.dm b/code/__defines/fires.dm
new file mode 100644
index 000000000000..63decaa66418
--- /dev/null
+++ b/code/__defines/fires.dm
@@ -0,0 +1,4 @@
+#define FUEL_VALUE_SUPPRESSANT -1
+#define FUEL_VALUE_NONE 0
+#define FUEL_VALUE_ACCELERANT 1
+#define FUEL_VALUE_VOLATILE 2
diff --git a/code/__defines/flags.dm b/code/__defines/flags.dm
index 0fab65e4a19d..5e04e9499632 100644
--- a/code/__defines/flags.dm
+++ b/code/__defines/flags.dm
@@ -1,63 +1,109 @@
-GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768))
-
-#define CLOSET_HAS_LOCK 1
-#define CLOSET_CAN_BE_WELDED 2
-
-#define CLOSET_STORAGE_MISC 1
-#define CLOSET_STORAGE_ITEMS 2
-#define CLOSET_STORAGE_MOBS 4
-#define CLOSET_STORAGE_STRUCTURES 8
-#define CLOSET_STORAGE_ALL (~0)
-
-// Flags bitmasks.
-
-#define ATOM_FLAG_CHECKS_BORDER 0x0001 // If a dense atom (potentially) only blocks movements from a given direction, i.e. window panes
-#define ATOM_FLAG_CLIMBABLE 0x0002 // This object can be climbed on
-#define ATOM_FLAG_NO_BLOOD 0x0004 // Used for items if they don't want to get a blood overlay.
-#define ATOM_FLAG_NO_REACT 0x0008 // Reagents don't react inside this container.
-#define ATOM_FLAG_CONTAINER 0x0010 // Is a container for chemistry purposes.
-#define ATOM_FLAG_OPEN_CONTAINER 0x0020 // Is an open container for chemistry purposes.
-#define ATOM_FLAG_INITIALIZED 0x0040 // Has this atom been initialized
-#define ATOM_FLAG_NO_TEMP_CHANGE 0x0080 // Reagents do not cool or heat to ambient temperature in this container.
-#define ATOM_FLAG_SHOW_REAGENT_NAME 0x0100 // Reagent presentation name is attached to the atom name
-
-#define ATOM_IS_CONTAINER(A) (A.atom_flags & ATOM_FLAG_CONTAINER)
-#define ATOM_IS_OPEN_CONTAINER(A) (A.atom_flags & ATOM_FLAG_OPEN_CONTAINER)
-
-#define MOVABLE_FLAG_PROXMOVE 0x0001 // Does this object require proximity checking in Enter()?
-#define MOVABLE_FLAG_Z_INTERACT 0x0002 // Should attackby and attack_hand be relayed through ladders and open spaces?
-#define MOVABLE_FLAG_EFFECTMOVE 0x0004 // Is this an effect that should move?
-#define MOVABLE_FLAG_DEL_SHUTTLE 0x0008 // Shuttle transistion will delete this.
-#define MOVABLE_FLAG_NONDENSE_COLLISION 0x0010 // Used for non-dense movables that should be capable of colliding when attempting to move onto dense atoms
-
-#define OBJ_FLAG_ANCHORABLE 0x0001 // This object can be stuck in place with a tool
-#define OBJ_FLAG_CONDUCTIBLE 0x0002 // Conducts electricity. (metal etc.)
-#define OBJ_FLAG_ROTATABLE 0x0004 // Can be rotated with alt-click
-#define OBJ_FLAG_NOFALL 0x0008 // Will prevent mobs from falling
-
-//Flags for items (equipment)
-#define ITEM_FLAG_NO_BLUDGEON 0x0001 // When an item has this it produces no "X has been hit by Y with Z" message with the default handler.
-#define ITEM_FLAG_NO_CONTAMINATION 0x0002 // Does not get contaminated.
-#define ITEM_FLAG_NO_PRINT 0x0004 // This object does not leave the user's prints/fibres when using it
-#define ITEM_FLAG_INVALID_FOR_CHAMELEON 0x0008 // Chameleon items cannot mimick this.
-#define ITEM_FLAG_THICKMATERIAL 0x0010 // Prevents syringes, reagent pens, and hyposprays if equiped to slot_suit or slot_head.
-#define ITEM_FLAG_AIRTIGHT 0x0040 // Functions with internals.
-#define ITEM_FLAG_NOSLIP 0x0080 // Prevents from slipping on wet floors, in space, etc.
-#define ITEM_FLAG_BLOCK_GAS_SMOKE_EFFECT 0x0100 // Blocks the effect that chemical clouds would have on a mob -- glasses, mask and helmets ONLY! (NOTE: flag shared with ONESIZEFITSALL)
-#define ITEM_FLAG_FLEXIBLEMATERIAL 0x0200 // At the moment, masks with this flag will not prevent eating even if they are covering your face.
-#define ITEM_FLAG_IS_BELT 0x0400 // Items that can be worn on the belt slot, even with no undersuit equipped
-#define ITEM_FLAG_SILENT 0x0800 // sneaky shoes
-#define ITEM_FLAG_NOCUFFS 0x1000 // Gloves that have this flag prevent cuffs being applied
-#define ITEM_FLAG_CAN_HIDE_IN_SHOES 0x2000 // Items that can be hidden in shoes that permit it
-#define ITEM_FLAG_PADDED 0x4000 // When set on gloves, will act like pulling punches in unarmed combat.
-
-// Flags for pass_flags.
-#define PASS_FLAG_TABLE 0x1
-#define PASS_FLAG_GLASS 0x2
-#define PASS_FLAG_GRILLE 0x4
-
-// Sector Flags.
-#define OVERMAP_SECTOR_BASE 0x0001 // Whether or not this sector is a starting sector. Z levels contained in this sector are added to station_levels
-#define OVERMAP_SECTOR_KNOWN 0x0002 // Makes the sector show up on nav computers
-#define OVERMAP_SECTOR_IN_SPACE 0x0004 // If the sector can be accessed by drifting off the map edge
-#define OVERMAP_SECTOR_UNTARGETABLE 0x0008 // If the sector is untargetable by missiles.
\ No newline at end of file
+#define CLOSET_HAS_LOCK BITFLAG(0)
+#define CLOSET_CAN_BE_WELDED BITFLAG(1)
+
+#define CLOSET_STORAGE_MISC BITFLAG(0)
+#define CLOSET_STORAGE_ITEMS BITFLAG(1)
+#define CLOSET_STORAGE_MOBS BITFLAG(2)
+#define CLOSET_STORAGE_STRUCTURES BITFLAG(3)
+#define CLOSET_STORAGE_ALL (~0)
+
+/* Bitflags for flag variables.
+These are used instead of separate boolean vars to reduce the overall number of variables,
+especially on common types like /atom or /atom/movable.
+
+- FLAG SETTING
+// When setting default flags on type definitions, they are combined with bitwise OR:
+// atom_flags = ATOM_FLAG_CLIMBABLE | ATOM_FLAG_OPEN_CONTAINER
+// Be mindful of flags set on parent types, as setting flags on a child type will override the parent flags.
+// Flags are also set at runtime with bitwise OR:
+// atom_flags |= ATOM_FLAG_CLIMBABLE
+// Flags are removed with bitwise AND NOT:
+// atom_flags &= ~ATOM_FLAG_CLIMBABLE
+// Flags can be toggled with bitwise XOR:
+// atom_flags ^= ATOM_FLAG_CLIMBABLE
+
+- FLAG CHECKING
+Flags can be tested with bitwise AND:
+ if (atom_flags & ATOM_FLAG_CLIMBABLE)
+ to_world_log("[src] is climbable!")
+- To test if a flag is not present, use:
+ if (!(atom_flags & ATOM_FLAG_CLIMBABLE))
+rather than
+ if ((!atom_flags & ATOM_FLAG_CLIMBABLE))
+The latter will result in a linter warning and will not work correctly.
+*/
+
+// Atom-level flags (/atom/var/atom_flags)
+#define ATOM_FLAG_CHECKS_BORDER BITFLAG(0) // If a dense atom (potentially) only blocks movements from a given direction, i.e. window panes
+#define ATOM_FLAG_CLIMBABLE BITFLAG(1) // This object can be climbed on
+#define ATOM_FLAG_NO_BLOOD BITFLAG(2) // Used for items if they don't want to get a blood overlay.
+#define ATOM_FLAG_NO_REACT BITFLAG(3) // Reagents don't react inside this container.
+#define ATOM_FLAG_OPEN_CONTAINER BITFLAG(4) // Is an open container for chemistry purposes.
+#define ATOM_FLAG_INITIALIZED BITFLAG(5) // Has this atom been initialized
+#define ATOM_FLAG_CAN_BE_PAINTED BITFLAG(6) // Can be painted using a paint sprayer or similar.
+#define ATOM_FLAG_SHIELD_CONTENTS BITFLAG(7) // Protects contents from some global effects (Solar storms)
+#define ATOM_FLAG_ADJACENT_EXCEPTION BITFLAG(8) // Skips adjacent checks for atoms that should always be reachable in window tiles
+#define ATOM_FLAG_NO_DISSOLVE BITFLAG(9) // Bypasses solvent reactions in the container.
+#define ATOM_FLAG_NO_PHASE_CHANGE BITFLAG(10) // Bypasses heating and cooling product reactions in the container.
+#define ATOM_FLAG_BLOCK_DIAGONAL_FACING BITFLAG(11) // Atom cannot face non-cardinal directions.
+
+#define ATOM_FLAG_NO_CHEM_CHANGE (ATOM_FLAG_NO_REACT | ATOM_FLAG_NO_DISSOLVE | ATOM_FLAG_NO_PHASE_CHANGE)
+
+#define ATOM_IS_OPEN_CONTAINER(A) (A.atom_flags & ATOM_FLAG_OPEN_CONTAINER)
+
+// Movable-level flags (/atom/movable/movable_flags)
+#define MOVABLE_FLAG_PROXMOVE BITFLAG(0) // Does this object require proximity checking in Enter()?
+#define MOVABLE_FLAG_Z_INTERACT BITFLAG(1) // Should attackby and attack_hand be relayed through ladders and open spaces?
+#define MOVABLE_FLAG_ALWAYS_SHUTTLEMOVE BITFLAG(2) // Is this an effect that should move?
+#define MOVABLE_FLAG_DEL_SHUTTLE BITFLAG(3) // Shuttle transistion will delete this.
+#define MOVABLE_FLAG_WHEELED BITFLAG(4) // Movable has reduced stamina cost/speed reduction when pulled.
+
+// Object-level flags (/obj/obj_flags)
+#define OBJ_FLAG_ANCHORABLE BITFLAG(0) // This object can be stuck in place with a tool
+#define OBJ_FLAG_CONDUCTIBLE BITFLAG(1) // Conducts electricity. (metal etc.)
+#define OBJ_FLAG_ROTATABLE BITFLAG(2) // Can be rotated with alt-click
+#define OBJ_FLAG_NOFALL BITFLAG(3) // Will prevent mobs from falling
+#define OBJ_FLAG_MOVES_UNSUPPORTED BITFLAG(4) // Object moves with shuttle transition even if turf below is a background turf.
+#define OBJ_FLAG_HOLLOW BITFLAG(5) // Modifies initial matter values to be lower than w_class normally sets.
+#define OBJ_FLAG_SUPPORT_MOB BITFLAG(6) // Object can be used to prop up a mob with stance damage (broken legs)
+#define OBJ_FLAG_INSULATED_HANDLE BITFLAG(7) // Object skips burn checks when held by unprotected hands.
+#define OBJ_FLAG_NO_STORAGE BITFLAG(8) // Object cannot be placed into storage.
+
+// Item-level flags (/obj/item/item_flags)
+#define ITEM_FLAG_NO_BLUDGEON BITFLAG(0) // When an item has this it produces no "X has been hit by Y with Z" message with the default handler.
+#define ITEM_FLAG_NO_CONTAMINATION BITFLAG(1) // Does not get contaminated.
+#define ITEM_FLAG_NO_PRINT BITFLAG(2) // This object does not leave the user's prints/fibres when using it
+#define ITEM_FLAG_INVALID_FOR_CHAMELEON BITFLAG(3) // Chameleon items cannot mimick this.
+#define ITEM_FLAG_THICKMATERIAL BITFLAG(4) // Prevents syringes, reagent pens, and hyposprays if equiped to slot_suit or slot_head_str.
+#define ITEM_FLAG_AIRTIGHT BITFLAG(5) // Functions with internals.
+#define ITEM_FLAG_NOSLIP BITFLAG(6) // Prevents from slipping on wet floors, in space, etc.
+#define ITEM_FLAG_BLOCK_GAS_SMOKE_EFFECT BITFLAG(7) // Blocks the effect that chemical clouds would have on a mob -- glasses, mask and helmets ONLY! (NOTE: flag shared with ONESIZEFITSALL)
+#define ITEM_FLAG_FLEXIBLEMATERIAL BITFLAG(8) // At the moment, masks with this flag will not prevent eating even if they are covering your face.
+#define ITEM_FLAG_IS_BELT BITFLAG(9) // Items that can be worn on the belt slot, even with no undersuit equipped
+#define ITEM_FLAG_SILENT BITFLAG(10) // sneaky shoes
+#define ITEM_FLAG_NOCUFFS BITFLAG(11) // Gloves that have this flag prevent cuffs being applied
+#define ITEM_FLAG_CAN_HIDE_IN_SHOES BITFLAG(12) // Items that can be hidden in shoes that permit it
+#define ITEM_FLAG_PADDED BITFLAG(13) // When set on gloves, will act like pulling punches in unarmed combat.
+#define ITEM_FLAG_CAN_TAPE BITFLAG(14) // Whether the item can be taped onto something using tape
+#define ITEM_FLAG_IS_WEAPON BITFLAG(15) // Item is considered a weapon. Currently only used for force-based worth calculation.
+#define ITEM_FLAG_MAGNETISED BITFLAG(16) // When worn on feet and standing on an appropriate spot, will prevent slipping.
+
+// Flags for pass_flags (/atom/var/pass_flags)
+#define PASS_FLAG_TABLE BITFLAG(0)
+#define PASS_FLAG_GLASS BITFLAG(1)
+#define PASS_FLAG_GRILLE BITFLAG(2)
+#define PASS_FLAG_MOB BITFLAG(3)
+
+// Overmap sector flags (/obj/effect/overmap/visitable/var/sector_flags)
+#define OVERMAP_SECTOR_BASE BITFLAG(0) // Whether or not this sector is a starting sector. Z levels contained in this sector are added to station_levels
+#define OVERMAP_SECTOR_KNOWN BITFLAG(1) // Makes the sector show up on nav computers
+#define OVERMAP_SECTOR_IN_SPACE BITFLAG(2) // If the sector can be accessed by drifting off the map edge
+#define OVERMAP_SECTOR_UNTARGETABLE BITFLAG(3) // If the sector is untargetable by missiles.
+
+// Flags for reagent presentation (/obj/item/chems/var/presentation_flags)
+#define PRESENTATION_FLAG_NAME BITFLAG(0) // This chems subtype presents the name of its main reagent/cocktail.
+#define PRESENTATION_FLAG_DESC BITFLAG(1) // This chems subtype presents the description of its main reagent/cocktail.
+
+// Decl-level flags (/decl/var/decl_flags)
+#define DECL_FLAG_ALLOW_ABSTRACT_INIT BITFLAG(0) // Abstract subtypes without this set will CRASH() if fetched with GET_DECL().
+#define DECL_FLAG_MANDATORY_UID BITFLAG(1) // Requires uid to be non-null.
\ No newline at end of file
diff --git a/code/__defines/fluids.dm b/code/__defines/fluids.dm
index 7f66b4f71ebc..926a89950e37 100644
--- a/code/__defines/fluids.dm
+++ b/code/__defines/fluids.dm
@@ -1,36 +1,53 @@
-#define FLUID_EVAPORATION_POINT 5 // Depth a fluid begins self-deleting
-#define FLUID_PUDDLE 25
-#define FLUID_SHALLOW 200 // Depth shallow icon is used
-#define FLUID_OVER_MOB_HEAD 300
-#define FLUID_DEEP 800 // Depth deep icon is used
-#define FLUID_MAX_DEPTH FLUID_DEEP*4 // Arbitrary max value for flooding.
-#define FLUID_PUSH_THRESHOLD 20 // Amount of water flow needed to push items.
+#define FLUID_QDEL_POINT 1 // Depth a fluid begins self-deleting
+#define FLUID_MINIMUM_TRANSFER 5 // Minimum amount that a flowing fluid will transfer from one turf to another.
+#define FLUID_PUDDLE 25 // Minimum total depth that a fluid needs before it will start spreading.
+#define FLUID_SLURRY 50 // Mimimum depth before fluids will move solids as reagents.
+#define FLUID_SHALLOW 200 // Depth shallow icon is used
+#define FLUID_OVER_MOB_HEAD 300 // Depth icon layers over mobs.
+#define FLUID_DEEP 800 // Depth deep icon is used
+#define FLUID_VERY_DEEP FLUID_DEEP*2 // Solid fill icon is used
+#define FLUID_MAX_DEPTH FLUID_DEEP*4 // Arbitrary max value for flooding.
+#define FLUID_PUSH_THRESHOLD 20 // Amount of flow needed to push items.
+/turf
+ var/_fluid_source_is_active = FALSE
+ var/_fluid_turf_is_active = FALSE
-// Expects /turf for T.
-#define ADD_ACTIVE_FLUID_SOURCE(T) SSfluids.water_sources[T] = TRUE
-#define REMOVE_ACTIVE_FLUID_SOURCE(T) SSfluids.water_sources -= T
+// Expects /turf for TURF.
+#define ADD_ACTIVE_FLUID_SOURCE(TURF) \
+if(!QDELETED(TURF) && !TURF.changing_turf && !TURF._fluid_source_is_active) { \
+ TURF._fluid_source_is_active = TRUE; \
+ SSfluids.water_sources += TURF; \
+}
-// Expects /obj/effect/fluid for F.
-#define ADD_ACTIVE_FLUID(F) SSfluids.active_fluids[F] = TRUE
-#define REMOVE_ACTIVE_FLUID(F) SSfluids.active_fluids -= F
+#define REMOVE_ACTIVE_FLUID_SOURCE(TURF) \
+if(!QDELETED(TURF) && TURF._fluid_source_is_active) { \
+ TURF._fluid_source_is_active = FALSE; \
+ SSfluids.water_sources -= TURF; \
+}
-// Expects turf for T,
-#define UPDATE_FLUID_BLOCKED_DIRS(T) \
- if(isnull(T.fluid_blocked_dirs)) {\
- T.fluid_blocked_dirs = 0; \
- for(var/obj/structure/window/W in T) { \
- if(W.density) T.fluid_blocked_dirs |= W.dir; \
- } \
- for(var/obj/machinery/door/window/D in T) {\
- if(D.density) T.fluid_blocked_dirs |= D.dir; \
- } \
- }
+#define ADD_ACTIVE_FLUID(TURF) \
+if(!QDELETED(TURF) && !TURF._fluid_turf_is_active) { \
+ TURF._fluid_turf_is_active = TRUE; \
+ SSfluids.active_fluids += TURF; \
+}
-// We share overlays for all fluid turfs to sync icon animation.
-#define APPLY_FLUID_OVERLAY(img_state) \
- if(!SSfluids.fluid_images[img_state]) SSfluids.fluid_images[img_state] = image('icons/effects/liquids.dmi',img_state); \
- overlays += (SSfluids.fluid_images[img_state]);
+#define REMOVE_ACTIVE_FLUID(TURF) \
+if(!QDELETED(TURF) && TURF._fluid_turf_is_active) { \
+ TURF._fluid_turf_is_active = FALSE; \
+ SSfluids.active_fluids -= TURF; \
+}
-#define FLUID_MAX_ALPHA 160
-#define FLUID_MIN_ALPHA 45
+#define UPDATE_FLUID_BLOCKED_DIRS(TURF) \
+if(isnull(TURF.fluid_blocked_dirs)) { \
+ TURF.fluid_blocked_dirs = 0; \
+ for(var/obj/structure/window/window in TURF) { \
+ if(window.density) TURF.fluid_blocked_dirs |= window.dir; \
+ } \
+ for(var/obj/machinery/door/window/windoor in TURF) { \
+ if(windoor.density) TURF.fluid_blocked_dirs |= windoor.dir; \
+ } \
+}
+
+#define FLUID_MAX_ALPHA 200
+#define FLUID_MIN_ALPHA 96
#define TANK_WATER_MULTIPLIER 5
\ No newline at end of file
diff --git a/code/__defines/gamemode.dm b/code/__defines/gamemode.dm
index ef73adfa76e2..b14c47d5768c 100644
--- a/code/__defines/gamemode.dm
+++ b/code/__defines/gamemode.dm
@@ -3,7 +3,7 @@
#define CHOOSE_GAMEMODE_RETRY 2 // The gamemode could not be chosen; we will use the next most popular option voted in, or the default.
#define CHOOSE_GAMEMODE_REVOTE 3 // The gamemode could not be chosen; we need to have a revote.
#define CHOOSE_GAMEMODE_RESTART 4 // The gamemode could not be chosen; we will restart the server.
-#define CHOOSE_GAMEMODE_SILENT_REDO 5 // The gamemode could not be chosen; we request to have the the proc rerun on the next tick.
+#define CHOOSE_GAMEMODE_SILENT_REDO 5 // The gamemode could not be chosen; we request to have the proc rerun on the next tick.
//End game state, to manage round end.
#define END_GAME_NOT_OVER 1
@@ -14,88 +14,25 @@
#define END_GAME_AWAITING_TICKETS 6
#define END_GAME_DELAYED 7
-#define BE_PLANT "BE_PLANT"
-#define BE_SYNTH "BE_SYNTH"
#define BE_PAI "BE_PAI"
// Antagonist datum flags.
-#define ANTAG_OVERRIDE_JOB 0x1 // Assigned job is set to MODE when spawning.
-#define ANTAG_OVERRIDE_MOB 0x2 // Mob is recreated from datum mob_type var when spawning.
-#define ANTAG_CLEAR_EQUIPMENT 0x4 // All preexisting equipment is purged.
-#define ANTAG_CHOOSE_NAME 0x8 // Antagonists are prompted to enter a name.
-#define ANTAG_IMPLANT_IMMUNE 0x10 // Cannot be loyalty implanted.
-#define ANTAG_SUSPICIOUS 0x20 // Shows up on roundstart report.
-#define ANTAG_HAS_LEADER 0x40 // Generates a leader antagonist.
-#define ANTAG_HAS_NUKE 0x80 // Will spawn a nuke at supplied location.
-#define ANTAG_RANDSPAWN 0x100 // Potentially randomly spawns due to events.
-#define ANTAG_VOTABLE 0x200 // Can be voted as an additional antagonist before roundstart.
-#define ANTAG_SET_APPEARANCE 0x400 // Causes antagonists to use an appearance modifier on spawn.
-#define ANTAG_RANDOM_EXCEPTED 0x800 // If a game mode randomly selects antag types, antag types with this flag should be excluded.
-
-// Mode/antag template macros.
-#define MODE_LOYALIST "loyalist"
-#define MODE_COMMANDO "commando"
-#define MODE_DEATHSQUAD "deathsquad"
-#define MODE_ERT "ert"
-#define MODE_ACTOR "actor"
-#define MODE_MERCENARY "mercenary"
-#define MODE_NINJA "ninja"
-#define MODE_RAIDER "raider"
-#define MODE_WIZARD "wizard"
-#define MODE_CHANGELING "changeling"
-#define MODE_CULTIST "cultist"
-#define MODE_MONKEY "monkey"
-#define MODE_RENEGADE "renegade"
-#define MODE_REVOLUTIONARY "revolutionary"
-#define MODE_TRAITOR "traitor"
-#define MODE_DEITY "deity"
-#define MODE_GODCULTIST "god cultist"
-#define MODE_THRALL "mind thrall"
-#define MODE_MISC_AGITATOR "provocateur"
+#define ANTAG_OVERRIDE_JOB BITFLAG(0) // Assigned job is set to MODE when spawning.
+#define ANTAG_OVERRIDE_MOB BITFLAG(1) // Mob is recreated from datum mob_type var when spawning.
+#define ANTAG_CLEAR_EQUIPMENT BITFLAG(2) // All preexisting equipment is purged.
+#define ANTAG_CHOOSE_NAME BITFLAG(3) // Antagonists are prompted to enter a name.
+#define ANTAG_IMPLANT_IMMUNE BITFLAG(4) // Cannot be loyalty implanted.
+#define ANTAG_SUSPICIOUS BITFLAG(5) // Shows up on roundstart report.
+#define ANTAG_HAS_LEADER BITFLAG(6) // Generates a leader antagonist.
+#define ANTAG_HAS_NUKE BITFLAG(7) // Will spawn a nuke at supplied location.
+#define ANTAG_RANDSPAWN BITFLAG(8) // Potentially randomly spawns due to events.
+#define ANTAG_VOTABLE BITFLAG(9) // Can be voted as an additional antagonist before roundstart.
+#define ANTAG_SET_APPEARANCE BITFLAG(10) // Causes antagonists to use an appearance modifier on spawn.
+#define ANTAG_RANDOM_EXCEPTED BITFLAG(11) // If a game mode randomly selects antag types, antag types with this flag should be excluded.
#define DEFAULT_TELECRYSTAL_AMOUNT 130
#define IMPLANT_TELECRYSTAL_AMOUNT(x) (round(x * 0.49)) // If this cost is ever greater than half of DEFAULT_TELECRYSTAL_AMOUNT then it is possible to buy more TC than you spend
-/////////////////
-////WIZARD //////
-/////////////////
-
-/* WIZARD SPELL FLAGS */
-#define GHOSTCAST 0x1 //can a ghost cast it?
-#define NEEDSCLOTHES 0x2 //does it need the wizard garb to cast? Nonwizard spells should not have this
-#define NEEDSHUMAN 0x4 //does it require the caster to be human?
-#define Z2NOCAST 0x8 //if this is added, the spell can't be cast at centcomm
-#define NO_SOMATIC 0x10 //spell will go off if the person is incapacitated or stunned
-#define IGNOREPREV 0x20 //if set, each new target does not overlap with the previous one
-//The following flags only affect different types of spell, and therefore overlap
-//Targeted spells
-#define INCLUDEUSER 0x40 //does the spell include the caster in its target selection?
-#define SELECTABLE 0x80 //can you select each target for the spell?
-#define NOFACTION 0x1000 //Don't do the same as our faction
-#define NONONFACTION 0x2000 //Don't do people other than our faction
-//AOE spells
-#define IGNOREDENSE 0x40 //are dense turfs ignored in selection?
-#define IGNORESPACE 0x80 //are space turfs ignored in selection?
-//End split flags
-#define CONSTRUCT_CHECK 0x100 //used by construct spells - checks for nullrods
-#define NO_BUTTON 0x200 //spell won't show up in the HUD with this
-
-//invocation
-#define SpI_SHOUT "shout"
-#define SpI_WHISPER "whisper"
-#define SpI_EMOTE "emote"
-#define SpI_NONE "none"
-
-//upgrading
-#define Sp_SPEED "speed"
-#define Sp_POWER "power"
-#define Sp_TOTAL "total"
-
-//casting costs
-#define Sp_RECHARGE "recharge"
-#define Sp_CHARGES "charges"
-#define Sp_HOLDVAR "holdervar"
-
//Voting-related
#define VOTE_PROCESS_ABORT 1
#define VOTE_PROCESS_COMPLETE 2
diff --git a/code/__defines/genetics.dm b/code/__defines/genetics.dm
new file mode 100644
index 000000000000..e1af913787b9
--- /dev/null
+++ b/code/__defines/genetics.dm
@@ -0,0 +1,20 @@
+#define GENE_COND_COLD_RESISTANCE /decl/genetic_condition/superpower/cold_resist
+#define GENE_COND_XRAY /decl/genetic_condition/superpower/xray
+#define GENE_COND_SPACE_RESISTANCE /decl/genetic_condition/superpower/space_resist
+#define GENE_COND_NO_BREATH /decl/genetic_condition/superpower/no_breath
+#define GENE_COND_REMOTE_TALK /decl/genetic_condition/superpower/remotetalk
+#define GENE_COND_RUNNING /decl/genetic_condition/superpower/running
+#define GENE_COND_REMOTE_VIEW /decl/genetic_condition/superpower/remoteview
+#define GENE_COND_NO_FINGERPRINTS /decl/genetic_condition/superpower/noprints
+
+#define GENE_COND_CLUMSY /decl/genetic_condition/disability/clumsy
+#define GENE_COND_NEARSIGHTED /decl/genetic_condition/disability/nearsighted
+#define GENE_COND_EPILEPSY /decl/genetic_condition/disability/epilepsy
+#define GENE_COND_COUGHING /decl/genetic_condition/disability/coughing
+#define GENE_COND_TOURETTES /decl/genetic_condition/disability/tourettes
+#define GENE_COND_NERVOUS /decl/genetic_condition/disability/nervous
+#define GENE_COND_BLINDED /decl/genetic_condition/disability/blinded
+#define GENE_COND_MUTED /decl/genetic_condition/disability/muted
+#define GENE_COND_DEAFENED /decl/genetic_condition/disability/deafened
+
+#define GENE_COND_HUSK /decl/genetic_condition/husk
diff --git a/code/__defines/guns.dm b/code/__defines/guns.dm
index d2f04c1e8148..3a69036adfa4 100644
--- a/code/__defines/guns.dm
+++ b/code/__defines/guns.dm
@@ -1,16 +1,18 @@
-#define CALIBER_PISTOL "10mm"
-#define CALIBER_PISTOL_SMALL "7mm"
-#define CALIBER_PISTOL_MAGNUM "15mm"
#define CALIBER_PISTOL_FLECHETTE "4mm"
+#define CALIBER_PISTOL_SMALL "7mm"
+#define CALIBER_PISTOL "10mm"
+#define CALIBER_PISTOL_MAGNUM "15mm"
-#define CALIBER_PISTOL_LASBULB "11mm lasbulb"
+#define CALIBER_PISTOL_LASBULB "11mm lasbulb"
-#define CALIBER_RIFLE "5mmR"
-#define CALIBER_ANTIMATERIAL "15mmR"
+#define CALIBER_RIFLE "6x45mm"
+#define CALIBER_ANTI_MATERIEL "15×99mm"
-#define CALIBER_SHOTGUN "12g"
-#define CALIBER_CAPS "caps"
-#define CALIBER_DART "darts"
+#define CALIBER_SHOTGUN "12g"
+#define CALIBER_CAPS "caps"
+#define CALIBER_DART "darts"
+
+#define CALIBER_UNUSABLE "unusable"
#define HOLD_CASINGS 0 //do not do anything after firing. Manual action, like pump shotguns, or guns that want to define custom behaviour
#define CLEAR_CASINGS 1 //clear chambered so that the next round will be automatically loaded and fired, but don't drop anything on the floor
diff --git a/code/__defines/holomap.dm b/code/__defines/holomap.dm
new file mode 100644
index 000000000000..d82b18c02abb
--- /dev/null
+++ b/code/__defines/holomap.dm
@@ -0,0 +1,37 @@
+//
+// Constants and standard colors for the holomap
+//
+
+#define HOLOMAP_ICON 'icons/480x480.dmi' // Icon file to start with when drawing holomaps (to get a 480x480 canvas).
+#define HOLOMAP_ICON_SIZE 480 // Pixel width & height of the holomap icon. Used for auto-centering etc.
+#define HOLOMAP_MARGIN 100 // minimum marging on sides when combining maps
+#define UI_HOLOMAP "CENTER-7, CENTER-7" // Screen location of the holomap "hud"
+
+// Holomap colors
+#define COLOR_HOLOMAP_OBSTACLE "#ffffffdd" // Color of walls and barriers
+#define COLOR_HOLOMAP_PATH "#66666699" // Color of floors
+#define COLOR_HOLOMAP_HOLOFIER "#79ff79" // Whole map is multiplied by this to give it a green holoish look
+
+#define HOLOMAP_AREACOLOR_BASE "#ffffffff"
+#define HOLOMAP_AREACOLOR_COMMAND "#386d8099"
+#define HOLOMAP_AREACOLOR_SECURITY "#ae121299"
+#define HOLOMAP_AREACOLOR_MEDICAL "#ffffffa5"
+#define HOLOMAP_AREACOLOR_SCIENCE "#f45dff99"
+#define HOLOMAP_AREACOLOR_EXPLORATION "#a154a699"
+#define HOLOMAP_AREACOLOR_ENGINEERING "#f1c23199"
+#define HOLOMAP_AREACOLOR_CARGO "#e06f0099"
+#define HOLOMAP_AREACOLOR_HALLWAYS "#ffffff66"
+#define HOLOMAP_AREACOLOR_AIRLOCK "#0000ffcc"
+#define HOLOMAP_AREACOLOR_ESCAPE "#ff0000cc"
+#define HOLOMAP_AREACOLOR_CREW "#5bc1c199"
+#define HOLOMAP_AREACOLOR_MAINTENANCE "#9c895066"
+// If someone can come up with a non-conflicting color for the lifts, please update this.
+#define HOLOMAP_AREACOLOR_LIFTS null
+
+// Handy defines to lookup the pixel offsets for holomap
+// world.maxx/y should always be greater than or equal to level_max_width/level_max_height
+#define HOLOMAP_PIXEL_OFFSET_X(zlevel) (round((world.maxx - SSmapping.levels_by_z[zlevel]?.level_max_width)/2))
+#define HOLOMAP_PIXEL_OFFSET_Y(zlevel) (round((world.maxy - SSmapping.levels_by_z[zlevel]?.level_max_height)/2))
+
+#define HOLOMAP_LEGEND_X 96
+#define HOLOMAP_LEGEND_Y 156
\ No newline at end of file
diff --git a/code/__defines/hud.dm b/code/__defines/hud.dm
new file mode 100644
index 000000000000..edd1ff5ea4d5
--- /dev/null
+++ b/code/__defines/hud.dm
@@ -0,0 +1,33 @@
+// Keys used to create HUD elements, and to set and retrieve icons from the UI decl system.
+#define HUD_STAMINA /decl/hud_element/stamina
+#define HUD_DROP /decl/hud_element/drop
+#define HUD_RESIST /decl/hud_element/resist
+#define HUD_THROW /decl/hud_element/throw_toggle
+#define HUD_MANEUVER /decl/hud_element/maneuver
+#define HUD_ZONE_SELECT /decl/hud_element/zone_selector
+#define HUD_MOVEMENT /decl/hud_element/movement
+#define HUD_INVENTORY /decl/hud_element/inventory
+#define HUD_ATTACK /decl/hud_element/attack
+#define HUD_HANDS /decl/hud_element/hands
+#define HUD_INTERNALS /decl/hud_element/internals
+#define HUD_HEALTH /decl/hud_element/health
+#define HUD_INTENT /decl/hud_element/intent
+#define HUD_CRIT_MARKER /decl/hud_element/crit
+#define HUD_NUTRITION /decl/hud_element/nutrition
+#define HUD_HYDRATION /decl/hud_element/hydration
+#define HUD_FIRE_INTENT /decl/hud_element/gun_mode
+#define HUD_UP_HINT /decl/hud_element/upward
+#define HUD_BODYTEMP /decl/hud_element/bodytemp
+#define HUD_PRESSURE /decl/hud_element/pressure
+#define HUD_TOX /decl/hud_element/toxins
+#define HUD_OXY /decl/hud_element/oxygen
+#define HUD_FIRE /decl/hud_element/fire
+#define HUD_CHARGE /decl/hud_element/charge
+#define HUD_ROBOT_MODULE /decl/hud_element/module_selection
+#define HUD_MODIFIERS /decl/hud_element/modifiers
+
+#define GET_HUD_ALERT(M, A) ((istype(M?.hud_used, /datum/hud) && (A in M.hud_used.alerts)) ? M.hud_used.alerts[A] : 0)
+#define CLEAR_HUD_ALERTS(M) if(istype(M?.hud_used, /datum/hud) && M.hud_used.alerts) { M.hud_used.alerts = null; }
+#define SET_HUD_ALERT(M, A, V) if(istype(M?.hud_used, /datum/hud)) { LAZYSET(M.hud_used.alerts, A, V); }
+#define SET_HUD_ALERT_MIN(M, A, V) if(istype(M?.hud_used, /datum/hud) && V < LAZYACCESS(M.hud_used.alerts, A)) { LAZYSET(M.hud_used.alerts, A, V); }
+#define SET_HUD_ALERT_MAX(M, A, V) if(istype(M?.hud_used, /datum/hud) && V > LAZYACCESS(M.hud_used.alerts, A)) { LAZYSET(M.hud_used.alerts, A, V); }
diff --git a/code/__defines/hydroponics.dm b/code/__defines/hydroponics.dm
index c6fe64d48732..9d0163f585e6 100644
--- a/code/__defines/hydroponics.dm
+++ b/code/__defines/hydroponics.dm
@@ -1,65 +1,54 @@
//Misc
#define DEAD_PLANT_COLOUR "#c2a180"
-// Definitions for genes (trait groupings)
-#define GENE_BIOCHEMISTRY "biochemistry"
-#define GENE_HARDINESS "hardiness"
-#define GENE_ENVIRONMENT "environment"
-#define GENE_METABOLISM "metabolism"
-#define GENE_STRUCTURE "appearance"
-#define GENE_DIET "diet"
-#define GENE_PIGMENT "pigment"
-#define GENE_OUTPUT "output"
-#define GENE_ATMOSPHERE "atmosphere"
-#define GENE_VIGOUR "vigour"
-#define GENE_FRUIT "fruit"
-#define GENE_SPECIAL "special"
-
-#define ALL_GENES list(GENE_BIOCHEMISTRY,GENE_HARDINESS,GENE_ENVIRONMENT,GENE_METABOLISM,GENE_STRUCTURE,GENE_DIET,GENE_PIGMENT,GENE_OUTPUT,GENE_ATMOSPHERE,GENE_VIGOUR,GENE_FRUIT,GENE_SPECIAL)
-
-//Definitions for traits (individual descriptors)
-#define TRAIT_CHEMS 1
-#define TRAIT_EXUDE_GASSES 2
-#define TRAIT_ALTER_TEMP 3
-#define TRAIT_POTENCY 4
-#define TRAIT_HARVEST_REPEAT 5
-#define TRAIT_PRODUCES_POWER 6
-#define TRAIT_JUICY 7
-#define TRAIT_PRODUCT_ICON 8
-#define TRAIT_PLANT_ICON 9
-#define TRAIT_CONSUME_GASSES 10
-#define TRAIT_REQUIRES_NUTRIENTS 11
-#define TRAIT_NUTRIENT_CONSUMPTION 12
-#define TRAIT_REQUIRES_WATER 13
-#define TRAIT_WATER_CONSUMPTION 14
-#define TRAIT_CARNIVOROUS 15
-#define TRAIT_PARASITE 16
-#define TRAIT_STINGS 17
-#define TRAIT_IDEAL_HEAT 18
-#define TRAIT_HEAT_TOLERANCE 19
-#define TRAIT_IDEAL_LIGHT 20
-#define TRAIT_LIGHT_TOLERANCE 21
-#define TRAIT_LOWKPA_TOLERANCE 22
-#define TRAIT_HIGHKPA_TOLERANCE 23
-#define TRAIT_EXPLOSIVE 24
-#define TRAIT_TOXINS_TOLERANCE 25
-#define TRAIT_PEST_TOLERANCE 26
-#define TRAIT_WEED_TOLERANCE 27
-#define TRAIT_ENDURANCE 28
-#define TRAIT_YIELD 29
-#define TRAIT_SPREAD 30
-#define TRAIT_MATURATION 31
-#define TRAIT_PRODUCTION 32
-#define TRAIT_TELEPORTING 33
-#define TRAIT_PLANT_COLOUR 34
-#define TRAIT_PRODUCT_COLOUR 35
-#define TRAIT_BIOLUM 36
-#define TRAIT_BIOLUM_COLOUR 37
-#define TRAIT_IMMUTABLE 38
-#define TRAIT_FLESH_COLOUR 39
-#define TRAIT_LARGE 40
-#define TRAIT_LEAVES_COLOUR 41
-#define TRAIT_PHOTOSYNTHESIS 42
+// Defining these to point to the relevant decl types just to avoid a massive changeset.
+// TODO: rename to PLANT_TRAIT or bare decls to avoid mixing up with GetTrait etc.
+#define TRAIT_CHEMS /decl/plant_trait/chems
+#define TRAIT_POLLEN /decl/plant_trait/pollen
+#define TRAIT_EXUDE_GASSES /decl/plant_trait/exude_gasses
+#define TRAIT_ALTER_TEMP /decl/plant_trait/alter_temp
+#define TRAIT_POTENCY /decl/plant_trait/potency
+#define TRAIT_HARVEST_REPEAT /decl/plant_trait/harvest_repeat
+#define TRAIT_PRODUCES_POWER /decl/plant_trait/produces_power
+#define TRAIT_JUICY /decl/plant_trait/juicy
+#define TRAIT_PRODUCT_ICON /decl/plant_trait/product_icon
+#define TRAIT_PLANT_ICON /decl/plant_trait/plant_icon
+#define TRAIT_CONSUME_GASSES /decl/plant_trait/consume_gasses
+#define TRAIT_REQUIRES_NUTRIENTS /decl/plant_trait/requires_nutrients
+#define TRAIT_NUTRIENT_CONSUMPTION /decl/plant_trait/nutrient_consumption
+#define TRAIT_REQUIRES_WATER /decl/plant_trait/requires_water
+#define TRAIT_WATER_CONSUMPTION /decl/plant_trait/water_consumption
+#define TRAIT_CARNIVOROUS /decl/plant_trait/carnivorous
+#define TRAIT_PARASITE /decl/plant_trait/parasite
+#define TRAIT_STINGS /decl/plant_trait/stings
+#define TRAIT_IDEAL_HEAT /decl/plant_trait/ideal_heat
+#define TRAIT_HEAT_TOLERANCE /decl/plant_trait/heat_tolerance
+#define TRAIT_IDEAL_LIGHT /decl/plant_trait/ideal_light
+#define TRAIT_LIGHT_TOLERANCE /decl/plant_trait/light_tolerance
+#define TRAIT_LOWKPA_TOLERANCE /decl/plant_trait/lowkpa_tolerance
+#define TRAIT_HIGHKPA_TOLERANCE /decl/plant_trait/highkpa_tolerance
+#define TRAIT_EXPLOSIVE /decl/plant_trait/explosive
+#define TRAIT_TOXINS_TOLERANCE /decl/plant_trait/toxins_tolerance
+#define TRAIT_PEST_TOLERANCE /decl/plant_trait/pest_tolerance
+#define TRAIT_WEED_TOLERANCE /decl/plant_trait/weed_tolerance
+#define TRAIT_ENDURANCE /decl/plant_trait/endurance
+#define TRAIT_YIELD /decl/plant_trait/yield
+#define TRAIT_SPREAD /decl/plant_trait/spread
+#define TRAIT_MATURATION /decl/plant_trait/maturation
+#define TRAIT_PRODUCTION /decl/plant_trait/production
+#define TRAIT_TELEPORTING /decl/plant_trait/teleporting
+#define TRAIT_PLANT_COLOUR /decl/plant_trait/plant_colour
+#define TRAIT_PRODUCT_COLOUR /decl/plant_trait/product_colour
+#define TRAIT_BIOLUM /decl/plant_trait/biolum
+#define TRAIT_BIOLUM_COLOUR /decl/plant_trait/biolum_colour
+#define TRAIT_IMMUTABLE /decl/plant_trait/immutable
+#define TRAIT_FLESH_COLOUR /decl/plant_trait/flesh_colour
+#define TRAIT_LARGE /decl/plant_trait/large
+#define TRAIT_LEAVES_COLOUR /decl/plant_trait/leaves_colour
+#define TRAIT_PHOTOSYNTHESIS /decl/plant_trait/photosynthesis
+#define TRAIT_PRODUCT_TYPE /decl/plant_trait/product_type
+#define TRAIT_SLICE_PRODUCT /decl/plant_trait/slice_product
+#define TRAIT_SLICE_AMOUNT /decl/plant_trait/slice_amount
// Seed noun datums
#define SEED_NOUN_SPORES "spores"
@@ -67,8 +56,15 @@
#define SEED_NOUN_NODES "nodes"
#define SEED_NOUN_CUTTINGS "cuttings"
#define SEED_NOUN_SEEDS "seeds"
+#define SEED_NOUN_EGGS "eggs"
#define GROWTH_WORMS "worms"
#define GROWTH_VINES "vines"
#define GROWTH_BIOMASS "mass"
#define GROWTH_MOLD "mold"
+
+#define PLANT_SEG_BODY "body" // Non-dissectable plants
+
+#define PLANT_STATE_FRESH "fresh"
+#define PLANT_STATE_ROASTED "roasted"
+#define PLANT_STATE_DRIED "dried"
diff --git a/code/__defines/integrated_circuits.dm b/code/__defines/integrated_circuits.dm
deleted file mode 100644
index 3647a61d773b..000000000000
--- a/code/__defines/integrated_circuits.dm
+++ /dev/null
@@ -1,48 +0,0 @@
-#define IC_INPUT "I"
-#define IC_OUTPUT "O"
-#define IC_ACTIVATOR "A"
-
-// Pin functionality.
-#define DATA_CHANNEL "data channel"
-#define PULSE_CHANNEL "pulse channel"
-
-// Methods of obtaining a circuit.
-#define IC_SPAWN_DEFAULT 1 // If the circuit comes in the default circuit box and able to be printed in the IC printer.
-#define IC_SPAWN_RESEARCH 2 // If the circuit design will be available in the IC printer after upgrading it.
-
-// Categories that help differentiate circuits that can do different tipes of actions
-#define IC_ACTION_MOVEMENT (1<<0) // If the circuit can move the assembly
-#define IC_ACTION_COMBAT (1<<1) // If the circuit can cause harm
-#define IC_ACTION_LONG_RANGE (1<<2) // If the circuit communicate with something outside of the assembly
-
-// Displayed along with the pin name to show what type of pin it is.
-#define IC_FORMAT_ANY "\"
-#define IC_FORMAT_STRING "\"
-#define IC_FORMAT_CHAR "\"
-#define IC_FORMAT_COLOR "\"
-#define IC_FORMAT_NUMBER "\"
-#define IC_FORMAT_DIR "\"
-#define IC_FORMAT_BOOLEAN "\"
-#define IC_FORMAT_REF "\["
-#define IC_FORMAT_LIST "\]"
-#define IC_FORMAT_INDEX "\"
-
-#define IC_FORMAT_PULSE "\"
-
-// Used inside input/output list to tell the constructor what pin to make.
-#define IC_PINTYPE_ANY /datum/integrated_io
-#define IC_PINTYPE_STRING /datum/integrated_io/string
-#define IC_PINTYPE_CHAR /datum/integrated_io/char
-#define IC_PINTYPE_COLOR /datum/integrated_io/color
-#define IC_PINTYPE_NUMBER /datum/integrated_io/number
-#define IC_PINTYPE_DIR /datum/integrated_io/dir
-#define IC_PINTYPE_BOOLEAN /datum/integrated_io/boolean
-#define IC_PINTYPE_REF /datum/integrated_io/ref
-#define IC_PINTYPE_LIST /datum/integrated_io/lists
-#define IC_PINTYPE_INDEX /datum/integrated_io/index
-
-#define IC_PINTYPE_PULSE_IN /datum/integrated_io/activate
-#define IC_PINTYPE_PULSE_OUT /datum/integrated_io/activate/out
-
-// Data limits.
-#define IC_MAX_LIST_LENGTH 500
diff --git a/code/__defines/intent.dm b/code/__defines/intent.dm
new file mode 100644
index 000000000000..2fa914a8b4c2
--- /dev/null
+++ b/code/__defines/intent.dm
@@ -0,0 +1,11 @@
+// Intent bitflags for use in check_intent()
+#define I_FLAG_HELP BITFLAG(0)
+#define I_FLAG_DISARM BITFLAG(1)
+#define I_FLAG_GRAB BITFLAG(2)
+#define I_FLAG_HARM BITFLAG(3)
+#define I_FLAG_ALL (I_FLAG_HELP|I_FLAG_DISARM|I_FLAG_GRAB|I_FLAG_HARM)
+
+//NOTE: INTENT_HOTKEY_* defines are not actual intents!
+//they are here to support hotkeys
+#define INTENT_HOTKEY_LEFT "left"
+#define INTENT_HOTKEY_RIGHT "right"
diff --git a/code/__defines/interactions.dm b/code/__defines/interactions.dm
new file mode 100644
index 000000000000..e51fa7ac213f
--- /dev/null
+++ b/code/__defines/interactions.dm
@@ -0,0 +1,10 @@
+/// This interaction requires the user to be adjacent to the target.
+#define INTERACTION_NEEDS_ADJACENCY BITFLAG(0)
+/// This interaction requires the user to pass a physical interaction check.
+#define INTERACTION_NEEDS_PHYSICAL_INTERACTION BITFLAG(1)
+/// This interaction requires the target to be on a turf
+#define INTERACTION_NEEDS_TURF BITFLAG(2)
+/// This interaction requires the target to be in the user's inventory.
+#define INTERACTION_NEEDS_INVENTORY BITFLAG(3)
+/// This interaction will always prompt for a selection from the user, even if it is the only available interaction.
+#define INTERACTION_NEVER_AUTOMATIC BITFLAG(4)
\ No newline at end of file
diff --git a/code/__defines/inventory_sizes.dm b/code/__defines/inventory_sizes.dm
index 0adc1e121cc6..0432f304bd8f 100644
--- a/code/__defines/inventory_sizes.dm
+++ b/code/__defines/inventory_sizes.dm
@@ -1,17 +1,32 @@
// The below should be used to define an item's w_class variable.
// Example: w_class = ITEM_SIZE_LARGE
// This allows the addition of future w_classes without needing to change every file.
-#define ITEM_SIZE_TINY 1
-#define ITEM_SIZE_SMALL 2
-#define ITEM_SIZE_NORMAL 3
-#define ITEM_SIZE_LARGE 4
-#define ITEM_SIZE_HUGE 5
-#define ITEM_SIZE_GARGANTUAN 6
-#define ITEM_SIZE_NO_CONTAINER 10 // Use this to forbid item from being placed in a container.
-#define ITEM_SIZE_STRUCTURE 20
-#define ITEM_SIZE_MIN ITEM_SIZE_TINY
-#define ITEM_SIZE_MAX ITEM_SIZE_STRUCTURE
+/*
+ A note on w_classes - this is an attempt to describe the w_classes currently in use
+ with an attempt at providing examples of the kinds of things that fit each w_class
+
+ 1 - tiny items - things like screwdrivers and pens, sheets of paper
+ 2 - small items - things that can fit in a pocket
+ 3 - normal items
+ 4 - large items - the largest things you can fit in a backpack
+ 5 - bulky items - backpacks are this size, for reference
+ 6 - human sized objects
+ 10 - things that are large enough to not realistically fit into a container (or should not be contained)
+ 20 - things that take up an entire turf, like wall girders or door assemblies
+*/
+
+#define ITEM_SIZE_TINY 1
+#define ITEM_SIZE_SMALL 2
+#define ITEM_SIZE_NORMAL 3
+#define ITEM_SIZE_LARGE 4
+#define ITEM_SIZE_HUGE 5
+#define ITEM_SIZE_GARGANTUAN 6
+#define ITEM_SIZE_STRUCTURE 20
+#define ITEM_SIZE_LARGE_STRUCTURE 30
+
+#define ITEM_SIZE_MIN ITEM_SIZE_TINY
+#define ITEM_SIZE_MAX ITEM_SIZE_LARGE_STRUCTURE
#define BASE_STORAGE_COST(w_class) (2**(w_class-1)) //1,2,4,8,16,...
diff --git a/code/__defines/item_effects.dm b/code/__defines/item_effects.dm
new file mode 100644
index 000000000000..d5c79b402f9a
--- /dev/null
+++ b/code/__defines/item_effects.dm
@@ -0,0 +1,15 @@
+// Identifiers for various categories of item effects.
+#define IE_CAT_DAMAGE "weff_damage"
+#define IE_CAT_STRIKE "weff_strike"
+#define IE_CAT_PARRY "weff_parry"
+#define IE_CAT_USED "weff_used"
+#define IE_CAT_WIELDED "weff_wield"
+#define IE_CAT_VISUAL "weff_visual"
+#define IE_CAT_LISTENER "weff_listener"
+#define IE_CAT_EXAMINE "weff_visible"
+#define IE_CAT_RANGED "weff_ranged"
+#define IE_CAT_PROCESS "weff_process"
+
+// Identifiers for parameters for item effects.
+#define IE_PAR_USES "uses"
+#define IE_PAR_MAX_USES "max_uses"
diff --git a/code/__defines/items_clothing.dm b/code/__defines/items_clothing.dm
index 1af8a8d71473..eaa502407f58 100644
--- a/code/__defines/items_clothing.dm
+++ b/code/__defines/items_clothing.dm
@@ -2,124 +2,120 @@
#define CANDLE_LUM 3 // For how bright candles are.
-// Item inventory slot bitmasks.
-#define SLOT_OCLOTHING 0x1
-#define SLOT_ICLOTHING 0x2
-#define SLOT_GLOVES 0x4
-#define SLOT_EYES 0x8
-#define SLOT_EARS 0x10
-#define SLOT_MASK 0x20
-#define SLOT_HEAD 0x40
-#define SLOT_FEET 0x80
-#define SLOT_ID 0x100
-#define SLOT_BELT 0x200
-#define SLOT_BACK 0x400
-#define SLOT_POCKET 0x800 // This is to allow items with a w_class of 3 or 4 to fit in pockets.
-#define SLOT_DENYPOCKET 0x1000 // This is to deny items with a w_class of 2 or 1 from fitting in pockets.
-#define SLOT_TWOEARS 0x2000
-#define SLOT_TIE 0x4000
-#define SLOT_HOLSTER 0x8000 //16th bit - higher than this will overflow
-
-#define ACCESSORY_SLOT_UTILITY "Utility"
-#define ACCESSORY_SLOT_HOLSTER "Holster"
-#define ACCESSORY_SLOT_ARMBAND "Armband"
-#define ACCESSORY_SLOT_RANK "Rank"
-#define ACCESSORY_SLOT_DEPT "Department"
-#define ACCESSORY_SLOT_DECOR "Decor"
-#define ACCESSORY_SLOT_MEDAL "Medal"
-#define ACCESSORY_SLOT_INSIGNIA "Insignia"
-#define ACCESSORY_SLOT_ARMOR_C "Chest armor"
-#define ACCESSORY_SLOT_ARMOR_A "Arm armor"
-#define ACCESSORY_SLOT_ARMOR_L "Leg armor"
-#define ACCESSORY_SLOT_ARMOR_S "Armor storage"
-#define ACCESSORY_SLOT_ARMOR_M "Misc armor"
-#define ACCESSORY_SLOT_HELM_C "Helmet cover"
-#define ACCESSORY_SLOT_OVER "Over"
+#define ACCESSORY_SLOT_UTILITY "Utility"
+#define ACCESSORY_SLOT_HOLSTER "Holster"
+#define ACCESSORY_SLOT_ARMBAND "Armband"
+#define ACCESSORY_SLOT_RANK "Rank"
+#define ACCESSORY_SLOT_DEPT "Department"
+#define ACCESSORY_SLOT_DECOR "Decor"
+#define ACCESSORY_SLOT_NECK "Neck"
+#define ACCESSORY_SLOT_MEDAL "Medal"
+#define ACCESSORY_SLOT_INSIGNIA "Insignia"
+#define ACCESSORY_SLOT_ARMOR_C "Chest armor"
+#define ACCESSORY_SLOT_ARMOR_A "Arm armor"
+#define ACCESSORY_SLOT_ARMOR_L "Leg armor"
+#define ACCESSORY_SLOT_ARMOR_S "Armor storage"
+#define ACCESSORY_SLOT_ARMOR_M "Misc armor"
+#define ACCESSORY_SLOT_HELM_C "Helmet cover"
+#define ACCESSORY_SLOT_OVER_HELMET "Hat"
+#define ACCESSORY_SLOT_OVER "Over"
+#define ACCESSORY_SLOT_SENSORS "Suit Sensors"
+#define ACCESSORY_SLOT_GREAVES "Greaves"
+#define ACCESSORY_SLOT_GAUNTLETS "Gauntlets"
+
+// Accessory will be shown as part of the name of the item when examined.
+#define ACCESSORY_VISIBILITY_ENSEMBLE 0
+// Accessory will be shown as 'with a [foo] attached'.
+#define ACCESSORY_VISIBILITY_ATTACHMENT 1
+// Accessory will only be shown on 'view accessories'.
+#define ACCESSORY_VISIBILITY_HIDDEN 2
+
+#define UNIFORM_DEFAULT_ACCESSORIES list( \
+ ACCESSORY_SLOT_SENSORS, \
+ ACCESSORY_SLOT_UTILITY, \
+ ACCESSORY_SLOT_HOLSTER, \
+ ACCESSORY_SLOT_ARMBAND, \
+ ACCESSORY_SLOT_RANK, \
+ ACCESSORY_SLOT_DEPT, \
+ ACCESSORY_SLOT_DECOR, \
+ ACCESSORY_SLOT_NECK, \
+ ACCESSORY_SLOT_MEDAL, \
+ ACCESSORY_SLOT_INSIGNIA, \
+ ACCESSORY_SLOT_OVER \
+)
// Bitmasks for the flags_inv variable. These determine when a piece of clothing hides another, i.e. a helmet hiding glasses.
// WARNING: The following flags apply only to the external suit!
-#define HIDEGLOVES 0x1
-#define HIDESUITSTORAGE 0x2
-#define HIDEJUMPSUIT 0x4
-#define HIDESHOES 0x8
-#define HIDETAIL 0x10
+#define HIDEGLOVES BITFLAG(0)
+#define HIDESUITSTORAGE BITFLAG(1)
+#define HIDEJUMPSUIT BITFLAG(2)
+#define HIDESHOES BITFLAG(3)
+#define HIDETAIL BITFLAG(4)
// WARNING: The following flags apply only to the helmets and masks!
-#define HIDEMASK 0x1
-#define HIDEEARS 0x2 // Headsets and such.
-#define HIDEEYES 0x4 // Glasses.
-#define HIDEFACE 0x8 // Dictates whether we appear as "Unknown".
-
-#define BLOCKHEADHAIR 0x20 // Hides the user's hair overlay. Leaves facial hair.
-#define BLOCKHAIR 0x40 // Hides the user's hair, facial and otherwise.
-
-// Slots.
-#define slot_first 1
-#define slot_back 1
-#define slot_wear_mask 2
-#define slot_handcuffed 3
-#define slot_l_hand 4
-#define slot_r_hand 5
-#define slot_belt 6
-#define slot_wear_id 7
-#define slot_l_ear 8
-#define slot_glasses 9
-#define slot_gloves 10
-#define slot_head 11
-#define slot_shoes 12
-#define slot_wear_suit 13
-#define slot_w_uniform 14
-#define slot_l_store 15
-#define slot_r_store 16
-#define slot_s_store 17
-#define slot_in_backpack 18
-#define slot_legcuffed 19
-#define slot_r_ear 20
-#define slot_legs 21
-#define slot_tie 22
-#define slot_last 22
+#define HIDEMASK BITFLAG(5)
+#define HIDEEARS BITFLAG(6) // Headsets and such.
+#define HIDEEYES BITFLAG(7) // Glasses.
+#define HIDEFACE BITFLAG(8) // Dictates whether we appear as "Unknown".
+#define BLOCK_HEAD_HAIR BITFLAG(9) // Hides the user's hair overlay, and replace it with short hairs. Leaves facial hair.
+#define BLOCK_FACIAL_HAIR BITFLAG(10) // Hides the user's hair, facial and otherwise.
+#define BLOCK_ALL_HAIR (BLOCK_HEAD_HAIR | BLOCK_FACIAL_HAIR)
+#define EQUIPMENT_VISIBILITY_FLAGS (HIDEGLOVES|HIDESUITSTORAGE|HIDEJUMPSUIT|HIDESHOES|HIDEMASK|HIDEEYES|HIDEEARS|HIDEFACE)
// Inventory slot strings.
// since numbers cannot be used as associative list keys.
//icon_back, icon_l_hand, etc would be much better names for these...
-#define slot_back_str "slot_back"
-#define slot_l_hand_str "slot_l_hand"
-#define slot_r_hand_str "slot_r_hand"
-#define slot_w_uniform_str "slot_w_uniform"
-#define slot_head_str "slot_head"
-#define slot_wear_suit_str "slot_suit"
-#define slot_l_ear_str "slot_l_ear"
-#define slot_r_ear_str "slot_r_ear"
-#define slot_belt_str "slot_belt"
-#define slot_shoes_str "slot_shoes"
-#define slot_wear_mask_str "slot_wear_mask"
-#define slot_handcuffed_str "slot_handcuffed"
-#define slot_legcuffed_str "slot_legcuffed"
-#define slot_wear_id_str "slot_wear_id"
-#define slot_gloves_str "slot_gloves"
-#define slot_glasses_str "slot_glasses"
-#define slot_s_store_str "slot_s_store"
-#define slot_tie_str "slot_tie"
-
-// Bitflags for clothing parts.
-#define HEAD 0x1
-#define FACE 0x2
-#define EYES 0x4
-#define UPPER_TORSO 0x8
-#define LOWER_TORSO 0x10
-#define LEG_LEFT 0x20
-#define LEG_RIGHT 0x40
-#define LEGS 0x60 // LEG_LEFT | LEG_RIGHT
-#define FOOT_LEFT 0x80
-#define FOOT_RIGHT 0x100
-#define FEET 0x180 // FOOT_LEFT | FOOT_RIGHT
-#define ARM_LEFT 0x200
-#define ARM_RIGHT 0x400
-#define ARMS 0x600 // ARM_LEFT | ARM_RIGHT
-#define HAND_LEFT 0x800
-#define HAND_RIGHT 0x1000
-#define HANDS 0x1800 // HAND_LEFT | HAND_RIGHT
-#define FULL_BODY 0xFFFF
+#define slot_back_str "slot_back"
+#define slot_w_uniform_str "slot_w_uniform"
+#define slot_head_str "slot_head"
+#define slot_wear_suit_str "slot_suit"
+#define slot_l_ear_str "slot_l_ear"
+#define slot_r_ear_str "slot_r_ear"
+#define slot_belt_str "slot_belt"
+#define slot_shoes_str "slot_shoes"
+#define slot_wear_mask_str "slot_wear_mask"
+#define slot_handcuffed_str "slot_handcuffed"
+#define slot_wear_id_str "slot_wear_id"
+#define slot_gloves_str "slot_gloves"
+#define slot_glasses_str "slot_glasses"
+#define slot_l_store_str "slot_l_store"
+#define slot_r_store_str "slot_r_store"
+#define slot_s_store_str "slot_s_store"
+#define slot_in_backpack_str "slot_in_backpack"
+#define slot_in_wallet_str "slot_in_wallet"
+
+// Defined here for consistency, not actually used for slots, just for species clothing offsets.
+#define slot_undershirt_str "slot_undershirt"
+#define slot_underpants_str "slot_underpants"
+#define slot_socks_str "slot_socks"
+
+// Bodypart coverage bitflags.
+#define SLOT_NONE 0
+#define SLOT_UPPER_BODY BITFLAG(0)
+#define SLOT_LOWER_BODY BITFLAG(1)
+#define SLOT_OVER_BODY BITFLAG(2)
+#define SLOT_LEG_LEFT BITFLAG(3)
+#define SLOT_LEG_RIGHT BITFLAG(4)
+#define SLOT_FOOT_LEFT BITFLAG(5)
+#define SLOT_FOOT_RIGHT BITFLAG(6)
+#define SLOT_ARM_LEFT BITFLAG(7)
+#define SLOT_ARM_RIGHT BITFLAG(8)
+#define SLOT_HAND_LEFT BITFLAG(9)
+#define SLOT_HAND_RIGHT BITFLAG(10)
+#define SLOT_EYES BITFLAG(11)
+#define SLOT_EARS BITFLAG(12)
+#define SLOT_FACE BITFLAG(13)
+#define SLOT_HEAD BITFLAG(14)
+#define SLOT_ID BITFLAG(15)
+#define SLOT_BACK BITFLAG(16)
+#define SLOT_HOLSTER BITFLAG(17)
+#define SLOT_POCKET BITFLAG(18)
+#define SLOT_TAIL BITFLAG(19)
+#define SLOT_LEGS (SLOT_LEG_LEFT|SLOT_LEG_RIGHT)
+#define SLOT_FEET (SLOT_FOOT_LEFT|SLOT_FOOT_RIGHT)
+#define SLOT_ARMS (SLOT_ARM_LEFT|SLOT_ARM_RIGHT)
+#define SLOT_HANDS (SLOT_HAND_LEFT|SLOT_HAND_RIGHT)
+#define SLOT_FULL_BODY (SLOT_LEGS|SLOT_FEET|SLOT_ARMS|SLOT_HANDS|SLOT_HEAD|SLOT_FACE|SLOT_EYES|SLOT_EARS|SLOT_UPPER_BODY|SLOT_LOWER_BODY|SLOT_TAIL)
// Bitflags for the percentual amount of protection a piece of clothing which covers the body part offers.
// Used with human/proc/get_heat_protection() and human/proc/get_cold_protection().
@@ -168,74 +164,113 @@
#define GLOVES_MAX_HEAT_PROTECTION_TEMPERATURE 1500 // For some gloves.
#define SHOE_MAX_HEAT_PROTECTION_TEMPERATURE 1500 // For shoes.
-#define FIRESUIT_MAX_PRESSURE 100 * ONE_ATMOSPHERE // Firesuis and atmos voidsuits
-#define RIG_MAX_PRESSURE 50 * ONE_ATMOSPHERE // Rigs
-#define LIGHT_RIG_MAX_PRESSURE 25 * ONE_ATMOSPHERE // Rigs
-#define ENG_VOIDSUIT_MAX_PRESSURE 50 * ONE_ATMOSPHERE
-#define VOIDSUIT_MAX_PRESSURE 25 * ONE_ATMOSPHERE
-#define SPACE_SUIT_MAX_PRESSURE 5 * ONE_ATMOSPHERE
+#define FIRESUIT_MAX_PRESSURE (100 ATM) // Firesuis and atmos voidsuits
+#define RIG_MAX_PRESSURE (50 ATM) // Rigs
+#define LIGHT_RIG_MAX_PRESSURE (25 ATM) // Rigs
+#define ENG_VOIDSUIT_MAX_PRESSURE (50 ATM)
+#define VOIDSUIT_MAX_PRESSURE (25 ATM)
+#define SPACE_SUIT_MAX_PRESSURE (5 ATM)
// Fire.
#define FIRE_MIN_STACKS -20
#define FIRE_MAX_STACKS 25
#define FIRE_MAX_FIRESUIT_STACKS 20 // If the number of stacks goes above this firesuits won't protect you anymore. If not, you can walk around while on fire like a badass.
-#define THROWFORCE_SPEED_DIVISOR 5 // The throwing speed value at which the throwforce multiplier is exactly 1.
+#define THROWFORCE_GIBS 3 // Throw speed for gibbed or dismembered organs.
+#define THROWFORCE_SPEED_DIVISOR 12 // The throwing speed value at which the thrown force multiplier is exactly 1.
#define THROWNOBJ_KNOCKBACK_SPEED 15 // The minumum speed of a w_class 2 thrown object that will cause living mobs it hits to be knocked back. Heavier objects can cause knockback at lower speeds.
#define THROWNOBJ_KNOCKBACK_DIVISOR 2 // Affects how much speed the mob is knocked back with.
// Suit sensor levels
-#define SUIT_SENSOR_OFF 0
-#define SUIT_SENSOR_BINARY 1
-#define SUIT_SENSOR_VITAL 2
-#define SUIT_SENSOR_TRACKING 3
-
-#define SUIT_NO_SENSORS 0
-#define SUIT_HAS_SENSORS 1
-#define SUIT_LOCKED_SENSORS 2
+#define VITALS_SENSOR_OFF 0
+#define VITALS_SENSOR_BINARY 1
+#define VITALS_SENSOR_VITAL 2
+#define VITALS_SENSOR_TRACKING 3
// Hair Flags
-#define VERY_SHORT 0x1
-#define HAIR_TIEABLE 0x2
-#define HAIR_BALD 0x4
-#define HAIR_LOSS_VULNERABLE 0x8
+#define HAIR_VERY_SHORT BITFLAG(0)
+#define HAIR_TIEABLE BITFLAG(1)
+#define HAIR_BALD BITFLAG(2)
+#define HAIR_LOSS_VULNERABLE BITFLAG(3)
//flags to determine if an eyepiece is a hud.
-#define HUD_SCIENCE 0x1
-#define HUD_SECURITY 0x2
-#define HUD_MEDICAL 0x4
-#define HUD_JANITOR 0x8
-
-// Storage
-
-/*
- A note on w_classes - this is an attempt to describe the w_classes currently in use
- with an attempt at providing examples of the kinds of things that fit each w_class
-
- 1 - tiny items - things like screwdrivers and pens, sheets of paper
- 2 - small items - things that can fit in a pocket
- 3 - normal items
- 4 - large items - the largest things you can fit in a backpack
- 5 - bulky items - backpacks are this size, for reference
- 6 - human sized objects
- 7 - things that are large enough to contain humans, like closets, but smaller than entire turfs
- 8 - things that take up an entire turf, like wall girders or door assemblies
-*/
-
-var/list/default_onmob_icons = list(
- slot_l_hand_str = 'icons/mob/onmob/items/lefthand.dmi',
- slot_r_hand_str = 'icons/mob/onmob/items/righthand.dmi',
- slot_belt_str = 'icons/mob/onmob/onmob_belt.dmi',
- slot_back_str = 'icons/mob/onmob/onmob_back.dmi',
- slot_l_ear_str = 'icons/mob/onmob/onmob_ears.dmi',
- slot_r_ear_str = 'icons/mob/onmob/onmob_ears.dmi',
- slot_glasses_str = 'icons/mob/onmob/onmob_eyes.dmi',
- slot_w_uniform_str = 'icons/mob/onmob/onmob_under.dmi',
- slot_wear_suit_str = 'icons/mob/onmob/onmob_suit.dmi',
- slot_head_str = 'icons/mob/onmob/onmob_head.dmi',
- slot_wear_mask_str = 'icons/mob/onmob/onmob_mask.dmi',
- slot_handcuffed_str = 'icons/mob/onmob/onmob_cuff.dmi',
- slot_legcuffed_str = 'icons/mob/onmob/onmob_cuff.dmi',
- slot_s_store_str = 'icons/mob/onmob/onmob_belt_mirror.dmi',
- slot_tie_str = 'icons/mob/onmob/onmob_accessories.dmi'
- )
+#define HUD_SCIENCE BITFLAG(0)
+#define HUD_SECURITY BITFLAG(1)
+#define HUD_MEDICAL BITFLAG(2)
+#define HUD_JANITOR BITFLAG(3)
+
+// Limbs.
+#define BP_L_FOOT "l_foot"
+#define BP_R_FOOT "r_foot"
+#define BP_L_LEG "l_leg"
+#define BP_R_LEG "r_leg"
+#define BP_L_HAND "l_hand"
+#define BP_R_HAND "r_hand"
+#define BP_M_HAND "midlimb"
+#define BP_L_HAND_UPPER "l_u_hand"
+#define BP_R_HAND_UPPER "r_u_hand"
+#define BP_L_ARM "l_arm"
+#define BP_R_ARM "r_arm"
+#define BP_HEAD "head"
+#define BP_CHEST "chest"
+#define BP_GROIN "groin"
+#define BP_TAIL "tail"
+
+// Other inventory-related slots (also organs).
+#define BP_MOUTH "mouth"
+
+var/global/list/all_limb_tags = list(
+ BP_CHEST,
+ BP_GROIN,
+ BP_TAIL,
+ BP_HEAD,
+ BP_L_ARM,
+ BP_R_ARM,
+ BP_L_HAND,
+ BP_R_HAND,
+ BP_M_HAND,
+ BP_L_HAND_UPPER,
+ BP_R_HAND_UPPER,
+ BP_L_LEG,
+ BP_R_LEG,
+ BP_L_FOOT,
+ BP_R_FOOT
+)
+var/global/list/all_limb_tags_by_depth = list(
+ BP_HEAD,
+ BP_L_HAND,
+ BP_L_HAND_UPPER,
+ BP_R_HAND,
+ BP_R_HAND_UPPER,
+ BP_M_HAND,
+ BP_L_ARM,
+ BP_R_ARM,
+ BP_L_FOOT,
+ BP_R_FOOT,
+ BP_L_LEG,
+ BP_R_LEG,
+ BP_GROIN,
+ BP_TAIL,
+ BP_CHEST
+)
+
+var/global/list/default_onmob_icons = list(
+ BP_L_HAND = 'icons/mob/onmob/items/lefthand.dmi',
+ BP_R_HAND = 'icons/mob/onmob/items/righthand.dmi'
+)
+
+var/global/list/all_hand_slots = list(
+ BP_L_HAND,
+ BP_R_HAND,
+ BP_M_HAND,
+ BP_L_HAND_UPPER,
+ BP_R_HAND_UPPER,
+ BP_MOUTH
+)
+
+/// If this item conflicts with a loadout item, simply delete it.
+#define LOADOUT_CONFLICT_DELETE 0
+/// If this item conflicts with a loadout item, place this item in storage.
+#define LOADOUT_CONFLICT_STORAGE 1
+/// If this item conflicts with a loadout item, place THE LOADOUT ITEM in storage.
+#define LOADOUT_CONFLICT_KEEP 2
\ No newline at end of file
diff --git a/code/__defines/jobs.dm b/code/__defines/jobs.dm
index f07d9be33595..6d959623d485 100644
--- a/code/__defines/jobs.dm
+++ b/code/__defines/jobs.dm
@@ -2,14 +2,13 @@
#define BE_ASSISTANT 1
#define RETURN_TO_LOBBY 2
-#define DEPT_COMMAND "command"
-#define DEPT_CIVILIAN "civilian"
-#define DEPT_ENGINEERING "engineering"
-#define DEPT_MEDICAL "medical"
-#define DEPT_SCIENCE "science"
-#define DEPT_SECURITY "security"
-#define DEPT_SUPPORT "support"
-#define DEPT_EXPLORATION "exploration"
-#define DEPT_SUPPLY "supply"
-#define DEPT_SERVICE "service"
-#define DEPT_MISC "misc"
\ No newline at end of file
+// Event category strings.
+#define ASSIGNMENT_ANY "Any"
+#define ASSIGNMENT_COMPUTER "Computer"
+#define ASSIGNMENT_ROBOT "Robot"
+#define ASSIGNMENT_ENGINEER "Engineer"
+#define ASSIGNMENT_GARDENER "Gardener"
+#define ASSIGNMENT_JANITOR "Janitor"
+#define ASSIGNMENT_MEDICAL "Medical"
+#define ASSIGNMENT_SCIENTIST "Scientist"
+#define ASSIGNMENT_SECURITY "Security"
diff --git a/code/__defines/languages.dm b/code/__defines/languages.dm
index eaa45859d347..d7d3ea593476 100644
--- a/code/__defines/languages.dm
+++ b/code/__defines/languages.dm
@@ -1,11 +1,16 @@
// Language flags.
-#define WHITELISTED 1 // Language is available if the speaker is whitelisted.
-#define RESTRICTED 2 // Language can only be acquired by spawning or an admin.
-#define NONVERBAL 4 // Language has a significant non-verbal component. Speech is garbled without line-of-sight.
-#define SIGNLANG 8 // Language is completely non-verbal. Speech is displayed through emotes for those who can understand.
-#define HIVEMIND 16 // Broadcast to all mobs with this language.
-#define NONGLOBAL 32 // Do not add to general languages list.
-#define INNATE 64 // All mobs can be assumed to speak and understand this language. (audible emotes)
-#define NO_TALK_MSG 128 // Do not show the "\The [speaker] talks into \the [radio]" message
-#define NO_STUTTER 256 // No stuttering, slurring, or other speech problems
-#define ALT_TRANSMIT 512 // Language is not based on vision or sound (Todo: add this into the say code and use it for the rootspeak languages)
+#define LANG_FLAG_WHITELISTED BITFLAG(0) // Language is available if the speaker is whitelisted.
+#define LANG_FLAG_RESTRICTED BITFLAG(1) // Language can only be acquired by spawning or an admin.
+#define LANG_FLAG_NONVERBAL BITFLAG(2) // Language has a significant non-verbal component. Speech is garbled without line-of-sight.
+#define LANG_FLAG_SIGNLANG BITFLAG(3) // Language is completely non-verbal. Speech is displayed through emotes for those who can understand.
+#define LANG_FLAG_HIVEMIND BITFLAG(4) // Broadcast to all mobs with this language.
+#define LANG_FLAG_NONGLOBAL BITFLAG(5) // Do not add to general languages list.
+#define LANG_FLAG_INNATE BITFLAG(6) // All mobs can be assumed to speak and understand this language. (audible emotes)
+#define LANG_FLAG_NO_TALK_MSG BITFLAG(7) // Do not show the "\The [speaker] talks into \the [radio]" message
+#define LANG_FLAG_NO_STUTTER BITFLAG(8) // No stuttering, slurring, or other speech problems
+#define LANG_FLAG_ALT_TRANSMIT BITFLAG(9) // Language is not based on vision or sound (Todo: add this into the say code and use it for the rootspeak languages)
+#define LANG_FLAG_FORBIDDEN BITFLAG(10) // Language is not to be granted to a mob under any circumstances.
+
+#define SPEECH_RESULT_INCAPABLE -1
+#define SPEECH_RESULT_MUDDLED 0
+#define SPEECH_RESULT_GOOD 1
diff --git a/code/__defines/level_data.dm b/code/__defines/level_data.dm
new file mode 100644
index 000000000000..2babf279f027
--- /dev/null
+++ b/code/__defines/level_data.dm
@@ -0,0 +1,5 @@
+#define ZLEVEL_STATION BITFLAG(0)
+#define ZLEVEL_ADMIN BITFLAG(1)
+#define ZLEVEL_CONTACT BITFLAG(2)
+#define ZLEVEL_PLAYER BITFLAG(3)
+#define ZLEVEL_SEALED BITFLAG(4)
\ No newline at end of file
diff --git a/code/__defines/lighting.dm b/code/__defines/lighting.dm
index 522bf2c97b88..d9c934a0fb5f 100644
--- a/code/__defines/lighting.dm
+++ b/code/__defines/lighting.dm
@@ -1,29 +1,40 @@
-#define FOR_DVIEW(type, range, center, invis_flags) \
- GLOB.dview_mob.loc = center; \
- GLOB.dview_mob.see_invisible = invis_flags; \
- for(type in view(range, GLOB.dview_mob))
+#define LIGHTING_INTERVAL 1 // Frequency, in 1/10ths of a second, of the lighting process.
-#define END_FOR_DVIEW GLOB.dview_mob.loc = null
+#define LIGHTING_HEIGHT 1 // height off the ground of light sources on the pseudo-z-axis, you should probably leave this alone
+#define LIGHTING_Z_FACTOR 10 // Z diff is multiplied by this and LIGHTING_HEIGHT to get the final height of a light source. Affects how much darker A Z light gets with each level transitioned.
+#define LIGHTING_ROUND_VALUE (1 / 200) //Value used to round lumcounts, values smaller than 1/255 don't matter (if they do, thanks sinking points), greater values will make lighting less precise, but in turn increase performance, VERY SLIGHTLY.
#define LIGHTING_ICON 'icons/effects/lighting_overlay.dmi' // icon used for lighting shading effects
-#define LIGHTING_ICON_STATE_DARK "dark" // Change between "soft_dark" and "dark" to swap soft darkvision
+#define LIGHTING_BASE_ICON_STATE "matrix" // icon_state used for normal color-matrix based lighting overlays.
+#define LIGHTING_STATION_ICON_STATE "tubedefault" // icon_state used for lighting overlays that are just displaying standard station lighting.
+#define LIGHTING_DARKNESS_ICON_STATE "black" // icon_state used for lighting overlays with no luminosity.
+#define LIGHTING_TRANSPARENT_ICON_STATE "blank"
-#define LIGHTING_ROUND_VALUE (1 / 64) // Value used to round lumcounts, values smaller than 1/69 don't matter (if they do, thanks sinking points), greater values will make lighting less precise, but in turn increase performance, VERY SLIGHTLY.
+// This is purely used as a threshold for 'is this turf probably dark' to avoid floating point nonsense.
+#define LIGHTING_SOFT_THRESHOLD 0.001
+#define LIGHTING_BLOCKED_FACTOR 0.5 // How much the range of a directional light will be reduced while facing a wall.
-#define LIGHTING_SOFT_THRESHOLD 0 // If the max of the lighting lumcounts of each spectrum drops below this, disable luminosity on the lighting overlays. This also should be the transparancy of the "soft_dark" icon state.
+// If defined, instant updates will be used whenever server load permits. Otherwise queued updates are always used.
+#define USE_INTELLIGENT_LIGHTING_UPDATES
-#define LIGHTING_MULT_FACTOR 0.9
+// mostly identical to below, but doesn't make sure T is valid first. Should only be used by lighting code.
+#define TURF_IS_DYNAMICALLY_LIT_UNSAFE(T) ((T:dynamic_lighting && T:loc:dynamic_lighting))
+#define TURF_IS_DYNAMICALLY_LIT(T) (isturf(T) && TURF_IS_DYNAMICALLY_LIT_UNSAFE(T))
+
+// Note: this does not imply the above, a turf can have ambient light without being dynamically lit.
+#define TURF_IS_AMBIENT_LIT_UNSAFE(T) (T:ambient_active)
+#define TURF_IS_AMBIENT_LIT(T) (isturf(T) && TURF_IS_AMBIENT_LIT_UNSAFE(T))
// If I were you I'd leave this alone.
#define LIGHTING_BASE_MATRIX \
- list \
- ( \
- LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, 0, \
- LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, 0, \
- LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, 0, \
- LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, 0, \
- 0, 0, 0, 1 \
- )
+ list \
+ ( \
+ 1, 1, 1, 0, \
+ 1, 1, 1, 0, \
+ 1, 1, 1, 0, \
+ 1, 1, 1, 0, \
+ 0, 0, 0, 1 \
+ ) \
// Helpers so we can (more easily) control the colour matrices.
#define CL_MATRIX_RR 1
@@ -46,3 +57,22 @@
#define CL_MATRIX_CG 18
#define CL_MATRIX_CB 19
#define CL_MATRIX_CA 20
+
+// Higher numbers override lower.
+#define LIGHTING_NO_UPDATE 0
+#define LIGHTING_VIS_UPDATE 1
+#define LIGHTING_CHECK_UPDATE 2
+#define LIGHTING_FORCE_UPDATE 3
+
+// This color of overlay is very common - most of the station is this color when lit fully.
+// Tube lights are a bluish-white, so we can't just assume 1-1-1 is full-illumination.
+// -- If you want to change these, find them *by checking in-game*, just converting tubes' RGB color into floats will not work!
+#define LIGHTING_DEFAULT_TUBE_R 0.96
+#define LIGHTING_DEFAULT_TUBE_G 1
+#define LIGHTING_DEFAULT_TUBE_B 1
+
+// Some angle presets for directional lighting.
+#define LIGHT_OMNI null
+#define LIGHT_SEMI 180
+#define LIGHT_WIDE 90
+#define LIGHT_NARROW 45
diff --git a/code/__defines/lists.dm b/code/__defines/lists.dm
index c4928e223345..9935dab6b5c7 100644
--- a/code/__defines/lists.dm
+++ b/code/__defines/lists.dm
@@ -4,7 +4,9 @@
// All of these are null-safe, you can use them without knowing if the list var is initialized yet
//Picks from the list, with some safeties, and returns the "default" arg if it fails
-#define DEFAULTPICK(L, default) ((istype(L, /list) && L:len) ? pick(L) : default)
+#define DEFAULTPICK(L, default) ((islist(L) && length(L)) ? pick(L) : default)
+//Supplies null as the default to DEFAULTPICK
+#define SAFEPICK(L) DEFAULTPICK(L, null)
// Ensures L is initailized after this point
#define LAZYINITLIST(L) if (!L) L = list()
// Sets a L back to null iff it is empty
@@ -30,30 +32,52 @@
// Reads L or an empty list if L is not a list. Note: Does NOT assign, L may be an expression.
#define SANITIZE_LIST(L) ( islist(L) ? L : list() )
-// binary search sorted insert
-// IN: Object to be inserted
-// LIST: List to insert object into
-// TYPECONT: The typepath of the contents of the list
-// COMPARE: The variable on the objects to compare
-#define BINARY_INSERT(IN, LIST, TYPECONT, COMPARE) \
- var/__BIN_CTTL = length(LIST);\
- if(!__BIN_CTTL) {\
- LIST += IN;\
- } else {\
- var/__BIN_LEFT = 1;\
- var/__BIN_RIGHT = __BIN_CTTL;\
- var/__BIN_MID = (__BIN_LEFT + __BIN_RIGHT) >> 1;\
- var/##TYPECONT/__BIN_ITEM;\
- while(__BIN_LEFT < __BIN_RIGHT) {\
- __BIN_ITEM = LIST[__BIN_MID];\
- if(__BIN_ITEM.##COMPARE <= IN.##COMPARE) {\
- __BIN_LEFT = __BIN_MID + 1;\
- } else {\
- __BIN_RIGHT = __BIN_MID;\
+// The above but for alists. Prefixed with A_ because inserting "A" randomly in the name just made it confusing
+#define A_LAZYINITLIST(AL) if (!AL) { AL = alist(); }
+#define A_UNSETEMPTY(AL) if(!length(AL)) { AL = null; }
+#define A_LAZYREMOVE(AL, I) if(AL) { AL -= I; A_UNSETEMPTY(AL) }
+#define A_LAZYSET(AL, A, I) if(!AL) { AL = alist(); } AL[A] = I;
+#define A_LAZYCLEARLIST(AL) if(AL) { AL.Cut(); AL = null; }
+#define A_LAZYLEN(AL) length(AL)
+
+/// Passed into BINARY_INSERT to compare keys
+#define COMPARE_KEY __BIN_LIST[__BIN_MID]
+/// Passed into BINARY_INSERT to compare values
+#define COMPARE_VALUE __BIN_LIST[__BIN_LIST[__BIN_MID]]
+
+/****
+ * Binary search sorted insert
+ * INPUT: Object to be inserted
+ * LIST: List to insert object into
+ * 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 should the values be compared? Either COMPARE_KEY or COMPARE_VALUE.
+ */
+#define BINARY_INSERT(INPUT, LIST, TYPECONT, COMPARE, COMPARISON, COMPTYPE) \
+ do {\
+ var/list/__BIN_LIST = LIST;\
+ var/__BIN_CTTL = length(__BIN_LIST);\
+ if(!__BIN_CTTL) {\
+ __BIN_LIST += INPUT;\
+ } else {\
+ var/__BIN_LEFT = 1;\
+ var/__BIN_RIGHT = __BIN_CTTL;\
+ var/__BIN_MID = BITSHIFT_RIGHT((__BIN_LEFT + __BIN_RIGHT), 1);\
+ var ##TYPECONT/__BIN_ITEM;\
+ while(__BIN_LEFT < __BIN_RIGHT) {\
+ __BIN_ITEM = COMPTYPE;\
+ if(__BIN_ITEM.##COMPARISON <= COMPARE.##COMPARISON) {\
+ __BIN_LEFT = __BIN_MID + 1;\
+ } else {\
+ __BIN_RIGHT = __BIN_MID;\
+ };\
+ __BIN_MID = BITSHIFT_RIGHT((__BIN_LEFT + __BIN_RIGHT), 1);\
};\
- __BIN_MID = (__BIN_LEFT + __BIN_RIGHT) >> 1;\
+ __BIN_ITEM = COMPTYPE;\
+ __BIN_MID = __BIN_ITEM.##COMPARISON > COMPARE.##COMPARISON ? __BIN_MID : __BIN_MID + 1;\
+ __BIN_LIST.Insert(__BIN_MID, INPUT);\
};\
- __BIN_ITEM = LIST[__BIN_MID];\
- __BIN_MID = __BIN_ITEM.##COMPARE > IN.##COMPARE ? __BIN_MID : __BIN_MID + 1;\
- LIST.Insert(__BIN_MID, IN);\
- }
+ } while(FALSE)
+
+#define LIST_CLEAR_NULLS(L) L.RemoveAll(null)
diff --git a/code/__defines/machinery.dm b/code/__defines/machinery.dm
index 2fb24fc0b499..b157b96d5f8a 100644
--- a/code/__defines/machinery.dm
+++ b/code/__defines/machinery.dm
@@ -4,9 +4,8 @@ var/global/defer_powernet_rebuild = 0 // True if net rebuild will be called
#define MEGAWATTS *1000000
#define GIGAWATTS *1000000000
-#define MACHINERY_TICKRATE 2 // Tick rate for machinery in seconds. As it affects CELLRATE calculation it is kept as define here
-
-#define CELLRATE (1 / ( 3600 / MACHINERY_TICKRATE )) // Multiplier for charge units. Converts cell charge units(watthours) to joules. Takes into consideration that our machinery ticks once per two seconds.
+/// Multiplier for charge units. Converts cell charge units(watthours) to joules. Takes into consideration that our machinery ticks once per two seconds.
+#define CELLRATE (/datum/controller/subsystem/machines::wait / (1 HOUR))
// Doors!
#define DOOR_CRUSH_DAMAGE 40
@@ -24,16 +23,16 @@ var/global/defer_powernet_rebuild = 0 // True if net rebuild will be called
#define TOTAL 5 // For total power used only.
// Bitflags for machine stat variable.
-#define BROKEN 0x1
-#define NOPOWER 0x2
-#define MAINT 0x8 // Under maintenance.
-#define EMPED 0x10 // Temporary broken by EMP pulse.
-#define NOSCREEN 0x20 // No UI shown via direct interaction
-#define NOINPUT 0x40 // No input taken from direct interaction
+#define BROKEN BITFLAG(0)
+#define NOPOWER BITFLAG(1)
+#define MAINT BITFLAG(2) // Under maintenance.
+#define EMPED BITFLAG(3) // Temporary broken by EMP.
+#define NOSCREEN BITFLAG(4) // No UI shown via direct interaction
+#define NOINPUT BITFLAG(5) // No input taken from direct interaction
-#define MACHINE_BROKEN_GENERIC 0x1 // Standard legacy brokenness, used on a case-by-case basis
-#define MACHINE_BROKEN_NO_PARTS 0x2 // Missing required parts
-#define MACHINE_BROKEN_CONSTRUCT 0x4 // Construction state is causing the brokenness
+#define MACHINE_BROKEN_GENERIC BITFLAG(0) // Standard legacy brokenness, used on a case-by-case basis
+#define MACHINE_BROKEN_NO_PARTS BITFLAG(1) // Missing required parts
+#define MACHINE_BROKEN_CONSTRUCT BITFLAG(2) // Construction state is causing the brokenness
// Used by firelocks
#define FIREDOOR_OPEN 1
@@ -41,28 +40,29 @@ var/global/defer_powernet_rebuild = 0 // True if net rebuild will be called
#define AI_CAMERA_LUMINOSITY 6
-// Camera networks
-#define NETWORK_CRESCENT "Crescent"
-#define NETWORK_ENGINEERING "Engineering"
-#define NETWORK_ERT "ZeEmergencyResponseTeam"
-#define NETWORK_EXODUS "Exodus"
-#define NETWORK_MEDICAL "Medical"
-#define NETWORK_MERCENARY "MercurialNet"
-#define NETWORK_MINE "Mining"
-#define NETWORK_RESEARCH "Research"
-#define NETWORK_ROBOTS "Robots"
-#define NETWORK_SECURITY "Security"
-#define NETWORK_THUNDER "Thunderdome"
-
-#define NETWORK_ALARM_ATMOS "Atmosphere Alarms"
+// Camera channels
+// Station channels
+#define CAMERA_CHANNEL_PUBLIC "Public"
+#define CAMERA_CHANNEL_ENGINEERING "Engineering"
+#define CAMERA_CHANNEL_MEDICAL "Medical"
+#define CAMERA_CHANNEL_RESEARCH "Research"
+#define CAMERA_CHANNEL_SECURITY "Security"
+#define CAMERA_CHANNEL_ROBOTS "Robots"
+#define CAMERA_CHANNEL_MINE "Mining"
+#define CAMERA_CHANNEL_SECRET "Secret"
+
+// Non-station channels
+#define CAMERA_CHANNEL_CRESCENT "Crescent"
+#define CAMERA_CHANNEL_ERT "Emergency Response Team"
+#define CAMERA_CHANNEL_MERCENARY "MercurialNet"
+#define CAMERA_CHANNEL_TELEVISION "Television"
+
+// Alarm networks
+#define NETWORK_ALARM_ATMOS "Atmosphere Alarms"
#define NETWORK_ALARM_CAMERA "Camera Alarms"
-#define NETWORK_ALARM_FIRE "Fire Alarms"
+#define NETWORK_ALARM_FIRE "Fire Alarms"
#define NETWORK_ALARM_MOTION "Motion Alarms"
-#define NETWORK_ALARM_POWER "Power Alarms"
-
-// Those networks can only be accessed by pre-existing terminals. AIs and new terminals can't use them.
-var/list/restricted_camera_networks = list(NETWORK_ERT, NETWORK_MERCENARY, NETWORK_CRESCENT, "Secret")
-
+#define NETWORK_ALARM_POWER "Power Alarms"
//singularity defines
#define STAGE_ONE 1
@@ -70,7 +70,6 @@ var/list/restricted_camera_networks = list(NETWORK_ERT, NETWORK_MERCENARY, NETWO
#define STAGE_THREE 5
#define STAGE_FOUR 7
#define STAGE_FIVE 9
-#define STAGE_SUPER 11
// NanoUI flags
#define STATUS_INTERACTIVE 2 // GREEN Visability
@@ -101,26 +100,6 @@ var/list/restricted_camera_networks = list(NETWORK_ERT, NETWORK_MERCENARY, NETWO
#define ATMOS_DEFAULT_VOLUME_MIXER 500 // L.
#define ATMOS_DEFAULT_VOLUME_PIPE 70 // L.
-#define TELECOMMS_RECEPTION_NONE 0
-#define TELECOMMS_RECEPTION_SENDER 1
-#define TELECOMMS_RECEPTION_RECEIVER 2
-#define TELECOMMS_RECEPTION_BOTH 3
-
-// These are used by supermatter and supermatter monitor program, mostly for UI updating purposes. Higher should always be worse!
-#define SUPERMATTER_ERROR -1 // Unknown status, shouldn't happen but just in case.
-#define SUPERMATTER_INACTIVE 0 // No or minimal energy
-#define SUPERMATTER_NORMAL 1 // Normal operation
-#define SUPERMATTER_NOTIFY 2 // Ambient temp > 80% of CRITICAL_TEMPERATURE
-#define SUPERMATTER_WARNING 3 // Ambient temp > CRITICAL_TEMPERATURE OR integrity damaged
-#define SUPERMATTER_DANGER 4 // Integrity < 50%
-#define SUPERMATTER_EMERGENCY 5 // Integrity < 25%
-#define SUPERMATTER_DELAMINATING 6 // Pretty obvious.
-
-#define SUPERMATTER_DATA_EER "Relative EER"
-#define SUPERMATTER_DATA_TEMPERATURE "Temperature"
-#define SUPERMATTER_DATA_PRESSURE "Pressure"
-#define SUPERMATTER_DATA_EPR "Chamber EPR"
-
// Scrubber modes
#define SCRUBBER_SIPHON "siphon"
#define SCRUBBER_SCRUB "scrub"
@@ -148,7 +127,6 @@ var/list/restricted_camera_networks = list(NETWORK_ERT, NETWORK_MERCENARY, NETWO
#define PART_FLAG_LAZY_INIT 1 // Will defer init on stock parts until machine is destroyed or parts are otherwise queried.
#define PART_FLAG_QDEL 2 // Will delete on uninstall
#define PART_FLAG_HAND_REMOVE 4 // Can be removed by hand
-#define PART_FLAG_NODAMAGE 8 // Cannot be damaged
// Machinery process flags, for use with START_PROCESSING_MACHINE
#define MACHINERY_PROCESS_SELF 1
@@ -161,10 +139,10 @@ var/list/restricted_camera_networks = list(NETWORK_ERT, NETWORK_MERCENARY, NETWO
#define MCS_BLOCK 2 // Failed to change, but action was performed
#define FABRICATOR_EXTRA_COST_FACTOR 1.25
-#define FAB_HACKED 1
-#define FAB_DISABLED 2
-#define FAB_SHOCKED 4
-#define FAB_BUSY 8
+#define FAB_HACKED BITFLAG(0)
+#define FAB_DISABLED BITFLAG(1)
+#define FAB_SHOCKED BITFLAG(2)
+#define FAB_BUSY BITFLAG(3)
#define PART_CPU /obj/item/stock_parts/computer/processor_unit // CPU. Without it the computer won't run. Better CPUs can run more programs at once.
#define PART_NETWORK /obj/item/stock_parts/computer/network_card // Network Card component of this computer. Allows connection to network
@@ -175,8 +153,9 @@ var/list/restricted_camera_networks = list(NETWORK_ERT, NETWORK_MERCENARY, NETWO
#define PART_CARD /obj/item/stock_parts/computer/card_slot // ID Card slot component of this computer. Mostly for HoP modification console that needs ID slot for modification.
#define PART_PRINTER /obj/item/stock_parts/computer/nano_printer // Nano Printer component of this computer, for your everyday paperwork needs.
#define PART_DRIVE /obj/item/stock_parts/computer/hard_drive/portable // Portable data storage
-#define PART_AI /obj/item/stock_parts/computer/ai_slot // AI slot, an intellicard housing that allows modifications of AIs.
+#define PART_AI /obj/item/stock_parts/computer/ai_slot // AI slot, an intelliCard housing that allows modifications of AIs.
#define PART_TESLA /obj/item/stock_parts/computer/tesla_link // Tesla Link, Allows remote charging from nearest APC.
#define PART_SCANNER /obj/item/stock_parts/computer/scanner // One of several optional scanner attachments.
#define PART_D_SLOT /obj/item/stock_parts/computer/drive_slot // Portable drive slot.
#define PART_MSTICK /obj/item/stock_parts/computer/charge_stick_slot // Charge-slot component for transactions /w charge sticks.
+#define PART_DSKSLOT /obj/item/stock_parts/computer/data_disk_drive // Temporary modcomp version of the disk reader component.
\ No newline at end of file
diff --git a/code/__defines/machinery_public_vars.dm b/code/__defines/machinery_public_vars.dm
new file mode 100644
index 000000000000..80937653bf53
--- /dev/null
+++ b/code/__defines/machinery_public_vars.dm
@@ -0,0 +1,11 @@
+// Displayed along with the pin name to show what type of pin it is.
+#define VAR_FORMAT_ANY "\"
+#define VAR_FORMAT_STRING "\"
+#define VAR_FORMAT_CHAR "\"
+#define VAR_FORMAT_COLOR "\"
+#define VAR_FORMAT_NUMBER "\"
+#define VAR_FORMAT_DIR "\"
+#define VAR_FORMAT_BOOLEAN "\"
+#define VAR_FORMAT_REF "\["
+#define VAR_FORMAT_LIST "\]"
+#define VAR_FORMAT_INDEX "\"
diff --git a/code/__defines/mapping.dm b/code/__defines/mapping.dm
index d61f771f8d2c..a00612da8091 100644
--- a/code/__defines/mapping.dm
+++ b/code/__defines/mapping.dm
@@ -1,3 +1,5 @@
+#define LEVELS_ARE_Z_CONNECTED(ZA, ZB) ((ZA > 0 && ZB > 0 && ZA <= world.maxz && ZB <= world.maxz) && ((ZA == ZB) || ((length(SSmapping.connected_z_cache) >= ZA && SSmapping.connected_z_cache[ZA] && length(SSmapping.connected_z_cache[ZA]) >= ZB) ? SSmapping.connected_z_cache[ZA][ZB] : SSmapping.are_connected_levels(ZA, ZB))))
+
// Maploader bounds indices
#define MAP_MINX 1
#define MAP_MINY 2
@@ -24,6 +26,22 @@ for(var/existing in get_turf(src)) { \
} \
} \
if(other_init) { \
- crash_with("Deleting duplicate of [log_info_line(src)]"); \
+ PRINT_STACK_TRACE("Deleting duplicate of [log_info_line(src)]"); \
return INITIALIZE_HINT_QDEL; \
-}
\ No newline at end of file
+}
+
+#define ADJUST_TAG_VAR(variable, map_hash) (istext(variable) && (variable += map_hash))
+
+/// Map template categories for mass retrieval.
+#define MAP_TEMPLATE_CATEGORY_EXOPLANET "exoplanet_template"
+#define MAP_TEMPLATE_CATEGORY_EXOPLANET_SITE "exoplanet_site_template"
+#define MAP_TEMPLATE_CATEGORY_PLANET "planet_template"
+#define MAP_TEMPLATE_CATEGORY_PLANET_SITE "planet_site_template"
+#define MAP_TEMPLATE_CATEGORY_SPACE "space_template"
+#define MAP_TEMPLATE_CATEGORY_AWAYSITE "awaysite_template"
+#define MAP_TEMPLATE_CATEGORY_LANDMARK_LOADED "landmark_template"
+
+/// Used to filter out some crafting recipes.
+#define MAP_TECH_LEVEL_ANY 0
+#define MAP_TECH_LEVEL_MEDIEVAL 50
+#define MAP_TECH_LEVEL_SPACE 100
diff --git a/code/__defines/materials.dm b/code/__defines/materials.dm
index 2344768d3255..fead13bf7dc6 100644
--- a/code/__defines/materials.dm
+++ b/code/__defines/materials.dm
@@ -2,16 +2,17 @@
#define DEFAULT_WALL_MATERIAL /decl/material/solid/metal/steel
#define DEFAULT_FURNITURE_MATERIAL /decl/material/solid/metal/aluminium
-#define MAT_FLAG_ALTERATION_NONE 0x1
-#define MAT_FLAG_ALTERATION_NAME 0x2
-#define MAT_FLAG_ALTERATION_DESC 0x4
-#define MAT_FLAG_ALTERATION_COLOR 0x8
+#define MAT_FLAG_ALTERATION_NONE 0
+#define MAT_FLAG_ALTERATION_NAME BITFLAG(0)
+#define MAT_FLAG_ALTERATION_DESC BITFLAG(1)
+#define MAT_FLAG_ALTERATION_COLOR BITFLAG(2)
#define MAT_FLAG_ALTERATION_ALL (~MAT_FLAG_ALTERATION_NONE)
-#define MAT_FLAG_UNMELTABLE 0x1
-#define MAT_FLAG_BRITTLE 0x2
-#define MAT_FLAG_PADDING 0x4
-#define MAT_FLAG_FUSION_FUEL 0x8
+#define MAT_FLAG_UNMELTABLE BITFLAG(0)
+#define MAT_FLAG_BRITTLE BITFLAG(1)
+#define MAT_FLAG_PADDING BITFLAG(2)
+#define MAT_FLAG_FUSION_FUEL BITFLAG(3)
+#define MAT_FLAG_FISSIBLE BITFLAG(4) // This material has use in a fission reactor.
#define SHARD_SHARD "shard"
#define SHARD_SHRAPNEL "shrapnel"
@@ -28,17 +29,15 @@
#define MAT_VALUE_VERY_HEAVY 80 // uranium tier
//Construction difficulty
-#define MAT_VALUE_EASY_DIY 0
-#define MAT_VALUE_NORMAL_DIY 1
-#define MAT_VALUE_HARD_DIY 2
-#define MAT_VALUE_VERY_HARD_DIY 3
-
-//Stack flags
-#define USE_MATERIAL_COLOR 0x1
-#define USE_MATERIAL_SINGULAR_NAME 0x2
-#define USE_MATERIAL_PLURAL_NAME 0x4
+#define MAT_VALUE_TRIVIAL_DIY 0 // Does not have any difficulty component at all
+#define MAT_VALUE_EASY_DIY 1 // SKILL_NONE (Unskilled)
+#define MAT_VALUE_NORMAL_DIY 2 // SKILL_BASIC (Basic)
+#define MAT_VALUE_HARD_DIY 3 // SKILL_ADEPT (Trained)
+#define MAT_VALUE_VERY_HARD_DIY 4 // SKILL_EXPERT (Experienced)
+#define MAT_VALUE_EXTREME_DIY 5 // SKILL_PROF (Master)
//Arbitrary hardness thresholds
+#define MAT_VALUE_MALLEABLE 0
#define MAT_VALUE_SOFT 10
#define MAT_VALUE_FLEXIBLE 20
#define MAT_VALUE_RIGID 40
@@ -52,9 +51,33 @@
#define MAT_VALUE_VERY_SHINY 60
#define MAT_VALUE_MIRRORED 80
+// Wall layering flags
+#define PAINT_PAINTABLE BITFLAG(0)
+#define PAINT_STRIPABLE BITFLAG(1)
+#define PAINT_DETAILABLE BITFLAG(2)
+#define PAINT_WINDOW_PAINTABLE BITFLAG(3)
+#define WALL_HAS_EDGES BITFLAG(4)
+
#define STRUCTURE_BRITTLE_MATERIAL_DAMAGE_MULTIPLIER 4 // Amount table damage is multiplied by if it is made of a brittle material (e.g. glass)
#define ORE_SURFACE "surface minerals"
#define ORE_PRECIOUS "precious metals"
#define ORE_NUCLEAR "nuclear fuel"
#define ORE_EXOTIC "exotic matter"
+
+//Phase of matter placeholders
+#define MAT_PHASE_SOLID BITFLAG(0)
+#define MAT_PHASE_LIQUID BITFLAG(1)
+#define MAT_PHASE_GAS BITFLAG(2)
+#define MAT_PHASE_PLASMA BITFLAG(3)
+
+// Fission interactions.
+// For these, associated value is ideal neutron energy for reaction.
+#define INTERACTION_FISSION "fission"
+#define INTERACTION_ABSORPTION "absorption"
+#define INTERACTION_SCATTER "scatter"
+
+#define MAT_RARITY_NOWHERE 0
+#define MAT_RARITY_EXOTIC 5
+#define MAT_RARITY_UNCOMMON 10
+#define MAT_RARITY_MUNDANE 20
diff --git a/code/__defines/math_physics.dm b/code/__defines/math_physics.dm
index b959cc7fab5c..4edf99ad88af 100644
--- a/code/__defines/math_physics.dm
+++ b/code/__defines/math_physics.dm
@@ -24,6 +24,8 @@
#define CELSIUS + T0C
+#define ATM *ONE_ATMOSPHERE
+
#define ATMOS_PRECISION 0.0001
#define QUANTIZE(variable) (round(variable, ATMOS_PRECISION))
@@ -32,5 +34,8 @@
#define TICKS_IN_DAY 24*60*60*10
#define TICKS_IN_SECOND 10
-#define SIMPLE_SIGN(X) ((X) < 0 ? -1 : 1)
-#define SIGN(X) ((X) ? SIMPLE_SIGN(X) : 0)
+#if DM_VERSION < 516
+#define SIGN(X) ( (X) ? ( (X) < 0 ? -1 : 1 ) : 0 )
+#else
+#define SIGN(X) sign(X)
+#endif
diff --git a/code/__defines/maths.dm b/code/__defines/maths.dm
new file mode 100644
index 000000000000..c24aac93d039
--- /dev/null
+++ b/code/__defines/maths.dm
@@ -0,0 +1,25 @@
+// Macro functions.
+#define RAND_F(LOW, HIGH) (rand() * ((HIGH) - (LOW)) + (LOW))
+
+// Float-aware floor and ceiling since round() will round upwards when given a second arg.
+#define NONUNIT_FLOOR(x, y) (floor((x) / (y)) * (y))
+#define NONUNIT_CEILING(x, y) (ceil((x) / (y)) * (y))
+
+// Special two-step rounding for reagents, to avoid floating point errors.
+#define CHEMS_QUANTIZE(x) NONUNIT_FLOOR(round(x, MINIMUM_CHEMICAL_VOLUME * 0.1), MINIMUM_CHEMICAL_VOLUME)
+
+#define MULT_BY_RANDOM_COEF(VAR,LO,HI) VAR = round((VAR * rand(LO * 100, HI * 100))/100, 0.1)
+
+#define EULER 2.7182818285
+
+#define MODULUS_FLOAT(X, Y) ( (X) - (Y) * round((X) / (Y)) )
+
+// Will filter out extra rotations and negative rotations
+// E.g: 540 becomes 180. -180 becomes 180.
+#define SIMPLIFY_DEGREES(degrees) (MODULUS_FLOAT((degrees), 360))
+
+#define IS_POWER_OF_TWO(VAL) ((VAL & (VAL-1)) == 0)
+#define ROUND_UP_TO_POWER_OF_TWO(VAL) (2 ** ceil(log(2,VAL)))
+
+// turn(0, angle) returns a random dir. This macro will instead do nothing if dir is already 0.
+#define SAFE_TURN(DIR, ANGLE) (DIR && turn(DIR, ANGLE))
diff --git a/code/__defines/mech.dm b/code/__defines/mech.dm
new file mode 100644
index 000000000000..e01159f0fd0f
--- /dev/null
+++ b/code/__defines/mech.dm
@@ -0,0 +1,39 @@
+#define HARDPOINT_BACK "back"
+#define HARDPOINT_LEFT_HAND "left hand"
+#define HARDPOINT_RIGHT_HAND "right hand"
+#define HARDPOINT_LEFT_SHOULDER "left shoulder"
+#define HARDPOINT_RIGHT_SHOULDER "right shoulder"
+#define HARDPOINT_HEAD "head"
+
+// No software required: taser. light, radio.
+#define MECH_SOFTWARE_UTILITY "utility equipment" // Plasma torch, clamp, drill.
+#define MECH_SOFTWARE_MEDICAL "medical support systems" // Sleeper.
+#define MECH_SOFTWARE_WEAPONS "standard weapon systems" // Ballistics and energy weapons.
+#define MECH_SOFTWARE_ENGINEERING "advanced engineering systems" // RCD.
+
+// EMP damage points before various effects occur.
+#define EMP_GUI_DISRUPT 5 // 1 ion rifle shot == 8.
+#define EMP_MOVE_DISRUPT 10 // 2 shots.
+#define EMP_ATTACK_DISRUPT 20 // 3 shots.
+
+//About components
+#define MECH_COMPONENT_DAMAGE_UNDAMAGED 1
+#define MECH_COMPONENT_DAMAGE_DAMAGED 2
+#define MECH_COMPONENT_DAMAGE_DAMAGED_BAD 3
+#define MECH_COMPONENT_DAMAGE_DAMAGED_TOTAL 4
+
+//Construction
+#define FRAME_REINFORCED 1
+#define FRAME_REINFORCED_SECURE 2
+#define FRAME_REINFORCED_WELDED 3
+
+#define FRAME_WIRED 1
+#define FRAME_WIRED_ADJUSTED 2
+
+//POWER!
+#define MECH_POWER_OFF 0
+#define MECH_POWER_TRANSITION 1
+#define MECH_POWER_ON 2
+
+#define MECH_UI_STYLE(X) STYLE_SMALLFONTS_OUTLINE(X, 5, COLOR_BLACK, COLOR_WHITE)
+#define MECH_BAR_CAP 12
diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm
index 0289e658c66b..faba544b1bab 100644
--- a/code/__defines/misc.dm
+++ b/code/__defines/misc.dm
@@ -1,12 +1,28 @@
#define DEBUG
// Turf-only flags.
-#define TURF_FLAG_NOJAUNT 1 // This is used in literally one place, turf.dm, to block ethereal jaunt.
-#define TURF_FLAG_NORUINS 2
-
-#define TRANSITIONEDGE 7 // Distance from edge to move to another z-level.
-#define RUIN_MAP_EDGE_PAD 15
+#define TURF_FLAG_NOJAUNT BITFLAG(0) // This is used in literally one place, turf.dm, to block ethereal jaunt.
+#define TURF_FLAG_NO_POINTS_OF_INTEREST BITFLAG(1) // Used by the level subtemplate generator to skip placing loaded templates on this turf.
+#define TURF_FLAG_BACKGROUND BITFLAG(2) // Used by shuttle movement to determine if it should be ignored by turf translation.
+#define TURF_FLAG_HOLY BITFLAG(3)
+#define TURF_FLAG_ABSORB_LIQUID BITFLAG(4)
+#define TURF_IS_HOLOMAP_OBSTACLE BITFLAG(5)
+#define TURF_IS_HOLOMAP_PATH BITFLAG(6)
+#define TURF_IS_HOLOMAP_ROCK BITFLAG(7)
+
+///Width or height of a transition edge area along the map's borders where transition edge turfs are placed to connect levels together.
+#define TRANSITIONEDGE 7
+
+///Enum value for a level edge that's to be untouched
+#define LEVEL_EDGE_NONE 0
+///Enum value for a level edge that's to be looped with the opposite edge
+#define LEVEL_EDGE_LOOP 1
+///Enum value for a level edge that's to be filled with a wall filler turfs
+#define LEVEL_EDGE_WALL 2
+///Enum value for a level edge that's to be connected with another z-level
+#define LEVEL_EDGE_CON 3
// Invisibility constants.
+#define INVISIBILITY_NONE 0
#define INVISIBILITY_LIGHTING 20
#define INVISIBILITY_LEVEL_ONE 35
#define INVISIBILITY_LEVEL_TWO 45
@@ -37,7 +53,7 @@
#define STATUS_HUD 2 // Alive, dead, diseased, etc.
#define ID_HUD 3 // The job asigned to your ID.
#define WANTED_HUD 4 // Wanted, released, paroled, security status.
-#define IMPLOYAL_HUD 5 // Loyality implant.
+#define IMPLOYAL_HUD 5 // Loyalty implant.
#define IMPCHEM_HUD 6 // Chemical implant.
#define IMPTRACK_HUD 7 // Tracking implant.
#define SPECIALROLE_HUD 8 // AntagHUD image.
@@ -70,66 +86,72 @@
#define EVENT_LEVEL_MODERATE 2
#define EVENT_LEVEL_MAJOR 3
-//General-purpose life speed define for plants.
-#define HYDRO_SPEED_MULTIPLIER 1
-
-#define DEFAULT_JOB_TYPE /datum/job/assistant
-
//Area flags, possibly more to come
-#define AREA_FLAG_RAD_SHIELDED 1 // Shielded from radiation, clearly.
-#define AREA_FLAG_EXTERNAL 2 // External as in exposed to space, not outside in a nice, green, forest.
-#define AREA_FLAG_ION_SHIELDED 4 // Shielded from ionospheric anomalies.
-#define AREA_FLAG_IS_NOT_PERSISTENT 8 // SSpersistence will not track values from this area.
-#define AREA_FLAG_IS_BACKGROUND 16// Blueprints can create areas on top of these areas. Cannot edit the name of or delete these areas.
+#define AREA_FLAG_RAD_SHIELDED BITFLAG(1) // Shielded from radiation, clearly.
+#define AREA_FLAG_EXTERNAL BITFLAG(2) // External as in exposed to space, not outside in a nice, green, forest.
+#define AREA_FLAG_ION_SHIELDED BITFLAG(3) // Shielded from ionospheric anomalies.
+#define AREA_FLAG_NO_LEGACY_PERSISTENCE BITFLAG(4) // SSpersistence will not track values from this area.
+#define AREA_FLAG_IS_BACKGROUND BITFLAG(5) // Blueprints can create areas on top of these areas. Cannot edit the name of or delete these areas.
+#define AREA_FLAG_MAINTENANCE BITFLAG(6) // Area is a maintenance area.
+#define AREA_FLAG_SHUTTLE BITFLAG(7) // Area is a shuttle area.
+#define AREA_FLAG_HALLWAY BITFLAG(8) // Area is a public hallway suitable for event selection
+#define AREA_FLAG_PRISON BITFLAG(9) // Area is a prison for the purposes of brigging objectives.
+#define AREA_FLAG_HOLY BITFLAG(10) // Area is holy for the purposes of marking turfs as cult-resistant.
+#define AREA_FLAG_SECURITY BITFLAG(11) // Area is security for the purposes of newscaster init.
+#define AREA_FLAG_HIDE_FROM_HOLOMAP BITFLAG(12) // if we shouldn't be drawn on station holomaps
+#define AREA_FLAG_ALLOW_LEVEL_PERSISTENCE BITFLAG(13) // Whether or not this area should pass changed turfs to SSpersistence.
+#define AREA_FLAG_CONSTRUCTED BITFLAG(13) // Set base flooring above this area to plating.
//Map template flags
-#define TEMPLATE_FLAG_ALLOW_DUPLICATES 1 // Lets multiple copies of the template to be spawned
-#define TEMPLATE_FLAG_SPAWN_GUARANTEED 2 // Makes it ignore away site budget and just spawn (only for away sites)
-#define TEMPLATE_FLAG_CLEAR_CONTENTS 4 // if it should destroy objects it spawns on top of
-#define TEMPLATE_FLAG_NO_RUINS 8 // if it should forbid ruins from spawning on top of it
-#define TEMPLATE_FLAG_NO_RADS 16// Removes all radiation from the template after spawning.
+#define TEMPLATE_FLAG_ALLOW_DUPLICATES BITFLAG(0) // Lets multiple copies of the template to be spawned
+#define TEMPLATE_FLAG_SPAWN_GUARANTEED BITFLAG(1) // Makes it ignore away site budget and just spawn (only for away sites)
+#define TEMPLATE_FLAG_CLEAR_CONTENTS BITFLAG(2) // if it should destroy objects it spawns on top of
+#define TEMPLATE_FLAG_NO_RUINS BITFLAG(3) // if it should forbid ruins from spawning on top of it
+#define TEMPLATE_FLAG_NO_RADS BITFLAG(4) // Removes all radiation from the template after spawning.
+#define TEMPLATE_FLAG_TEST_DUPLICATES BITFLAG(5) // Makes unit testing attempt to spawn mutliple copies of this template. Assumes unit testing is spawning at least one copy.
+#define TEMPLATE_FLAG_GENERIC_REPEATABLE BITFLAG(6) // Template can be picked repeatedly for the same level gen run.
// Convoluted setup so defines can be supplied by Bay12 main server compile script.
// Should still work fine for people jamming the icons into their repo.
#ifndef CUSTOM_ITEM_CONFIG
#define CUSTOM_ITEM_CONFIG "config/custom_items/"
#endif
-#ifndef CUSTOM_ITEM_SYNTH_CONFIG
-#define CUSTOM_ITEM_SYNTH_CONFIG "config/custom_sprites.txt"
-#endif
-#ifndef CUSTOM_ITEM_OBJ
-#define CUSTOM_ITEM_OBJ 'icons/obj/custom_items_obj.dmi'
-#endif
-#ifndef CUSTOM_ITEM_MOB
-#define CUSTOM_ITEM_MOB 'icons/mob/custom_items_mob.dmi'
-#endif
-#ifndef CUSTOM_ITEM_SYNTH
-#define CUSTOM_ITEM_SYNTH 'icons/mob/custom_synthetic.dmi'
+#ifndef CUSTOM_ICON_CONFIG
+#define CUSTOM_ICON_CONFIG "config/custom_icons/"
#endif
#define WALL_CAN_OPEN 1
#define WALL_OPENING 2
-#define BOMBCAP_DVSTN_RADIUS (GLOB.max_explosion_range/4)
-#define BOMBCAP_HEAVY_RADIUS (GLOB.max_explosion_range/2)
-#define BOMBCAP_LIGHT_RADIUS GLOB.max_explosion_range
-#define BOMBCAP_FLASH_RADIUS (GLOB.max_explosion_range*1.5)
+#define BOMBCAP_DVSTN_RADIUS (global.max_explosion_range/4)
+#define BOMBCAP_HEAVY_RADIUS (global.max_explosion_range/2)
+#define BOMBCAP_LIGHT_RADIUS global.max_explosion_range
+#define BOMBCAP_FLASH_RADIUS (global.max_explosion_range*1.5)
// Special return values from bullet_act(). Positive return values are already used to indicate the blocked level of the projectile.
#define PROJECTILE_CONTINUE -1 //if the projectile should continue flying after calling bullet_act()
#define PROJECTILE_FORCE_MISS -2 //if the projectile should treat the attack as a miss (suppresses attack and admin logs) - only applies to mobs.
-//Camera capture modes
-#define CAPTURE_MODE_REGULAR 0 //Regular polaroid camera mode
-#define CAPTURE_MODE_ALL 1 //Admin camera mode
-#define CAPTURE_MODE_PARTIAL 3 //Simular to regular mode, but does not do dummy check
-
-//objectives
+// Objective config enum values.
#define CONFIG_OBJECTIVE_NONE 2
#define CONFIG_OBJECTIVE_VERB 1
#define CONFIG_OBJECTIVE_ALL 0
+// Server whitelist config enums.
+#define CONFIG_SERVER_NO_WHITELIST 1
+#define CONFIG_SERVER_JOBS_WHITELIST 2
+#define CONFIG_SERVER_JOIN_WHITELIST 3
+#define CONFIG_SERVER_CONNECT_WHITELIST 4
+
+// Coating name color config enums
+#define CONFIG_COATING_COLOR_NONE 1
+#define CONFIG_COATING_COLOR_MIXTURE 2
+#define CONFIG_COATING_COLOR_COMPONENTS 3
+
+// Location for server whitelist file to load from.
+#define CONFIG_SERVER_WHITELIST_FILE "config/server_whitelist.txt"
+
// How many times an AI tries to connect to APC before switching to low power mode.
#define AI_POWER_RESTORE_MAX_ATTEMPTS 3
@@ -162,8 +184,6 @@
#define PIXEL_MULTIPLIER WORLD_ICON_SIZE/32
-#define DEFAULT_SPAWNPOINT_ID "Default"
-
#define MIDNIGHT_ROLLOVER 864000 //number of deciseconds in a day
//Error handler defines
@@ -176,8 +196,6 @@
#define RADIATION_THRESHOLD_CUTOFF 0.1 // Radiation will not affect a tile when below this value.
-#define LEGACY_RECORD_STRUCTURE(X, Y) GLOBAL_LIST_EMPTY(##X);/datum/computer_file/data/##Y/var/list/fields[0];/datum/computer_file/data/##Y/New(){..();GLOB.##X.Add(src);}/datum/computer_file/data/##Y/Destroy(){. = ..();GLOB.##X.Remove(src);}
-
#define SUPPLY_SECURITY_ELEVATED 1
#define SUPPLY_SECURITY_HIGH 2
@@ -191,11 +209,6 @@
#define WRINKLES_WRINKLY 1
#define WRINKLES_NONE 2
-//detergent states for clothes
-#define SMELL_DEFAULT 0
-#define SMELL_CLEAN 1
-#define SMELL_STINKY 2
-
//Shuttle mission stages
#define SHUTTLE_MISSION_PLANNED 1
#define SHUTTLE_MISSION_STARTED 2
@@ -219,9 +232,10 @@
#define ANIM_LYING_TIME 2
//Planet habitability class
-#define HABITABILITY_IDEAL 1
-#define HABITABILITY_OKAY 2
-#define HABITABILITY_BAD 3
+#define HABITABILITY_IDEAL 1 //For planets with optimal conditions.
+#define HABITABILITY_OKAY 2 //For planets with survivable conditions.
+#define HABITABILITY_BAD 3 //For planets with very hazardous environment.
+#define HABITABILITY_DEAD 4 //For dead worlds(barren rocks with no atmosphere and etc..).
#ifndef WINDOWS_HTTP_POST_DLL_LOCATION
#define WINDOWS_HTTP_POST_DLL_LOCATION "lib/byhttp.dll"
@@ -236,37 +250,157 @@
#endif
// Surgery candidate flags.
-#define SURGERY_NO_ROBOTIC 1
-#define SURGERY_NO_CRYSTAL 2
-#define SURGERY_NO_STUMP 4
-#define SURGERY_NO_FLESH 8
-#define SURGERY_NEEDS_INCISION 16
-#define SURGERY_NEEDS_RETRACTED 32
-#define SURGERY_NEEDS_ENCASEMENT 64
-
-// Structure interaction flags
-#define TOOL_INTERACTION_ANCHOR 1
-#define TOOL_INTERACTION_DECONSTRUCT 2
-#define TOOL_INTERACTION_WIRING 4
-#define TOOL_INTERACTION_ALL (TOOL_INTERACTION_ANCHOR | TOOL_INTERACTION_DECONSTRUCT | TOOL_INTERACTION_WIRING)
+#define SURGERY_NO_ROBOTIC BITFLAG(0)
+#define SURGERY_NO_CRYSTAL BITFLAG(1)
+#define SURGERY_NO_FLESH BITFLAG(2)
+#define SURGERY_NEEDS_INCISION BITFLAG(3)
+#define SURGERY_NEEDS_RETRACTED BITFLAG(4)
+#define SURGERY_NEEDS_ENCASEMENT BITFLAG(5)
//Inserts 'a' or 'an' before X in ways \a doesn't allow
-#define ADD_ARTICLE(X) "[(lowertext(copytext(X, 1, 2)) in list("a", "e", "i", "o", "u")) ? "an" : "a"] [X]"
-
-#define SOULSTONE_CRACKED -1
-#define SOULSTONE_EMPTY 0
-#define SOULSTONE_ESSENCE 1
-
-#define INCREMENT_WORLD_Z_SIZE world.maxz++; global.connected_z_cache.Cut(); if (SSzcopy.zstack_maximums.len) { SSzcopy.calculate_zstack_limits() }
-#define ARE_Z_CONNECTED(ZA, ZB) (ZA > 0 && ZB > 0 && ZA <= world.maxz && ZB <= world.maxz && ((ZA == ZB) || ((global.connected_z_cache.len >= ZA && global.connected_z_cache[ZA]) ? global.connected_z_cache[ZA][ZB] : AreConnectedZLevels(ZA, ZB))))
+#define ADD_ARTICLE(X) "[(lowertext(X[1]) in global.vowels) ? "an" : "a"] [X]"
+#define ADD_ARTICLE_GENDER(X, GENDER) (GENDER == PLURAL ? "some [X]" : ADD_ARTICLE(X))
//Request Console Department Types
#define RC_ASSIST 1 //Request Assistance
#define RC_SUPPLY 2 //Request Supplies
#define RC_INFO 4 //Relay Info
-#define WORTH_TO_SUPPLY_POINTS_CONSTANT 0.0075
+#define WORTH_TO_SUPPLY_POINTS_CONSTANT 0.03
#define WORTH_TO_SUPPLY_POINTS_ROUND_CONSTANT 5
-#define ICON_STATE_WORLD "world"
-#define ICON_STATE_INV "inventory"
\ No newline at end of file
+#define ICON_STATE_WORLD "world"
+#define ICON_STATE_INV "inventory"
+
+#define hex2num(X) text2num(X, 16)
+/// Returns the hex value of a number given a value assumed to be a base-ten value, padded to a minimum length of 2.
+#define num2hex(num) num2text(num, 2, 16)
+/// Returns the hex value of a number given a value assumed to be a base-ten value, padded to a supplied minimum length.
+#define num2hex_padded(num, len) num2text(num, len, 16)
+
+//Turf/area values for 'this space is outside' checks
+#define OUTSIDE_AREA null
+#define OUTSIDE_NO FALSE
+#define OUTSIDE_YES TRUE
+#define OUTSIDE_UNCERTAIN null
+
+// Weather exposure values for being rained on or hailed on.
+#define WEATHER_IGNORE -1
+#define WEATHER_EXPOSED 0
+#define WEATHER_ROOFED 1
+#define WEATHER_PROTECTED 2
+
+// Literacy check constants.
+#define WRITTEN_SKIP 0
+#define WRITTEN_PHYSICAL 1
+#define WRITTEN_DIGITAL 2
+
+// arbitrary low pressure bound for wind weather effects
+#define MIN_WIND_PRESSURE 10
+
+#define TYPE_IS_ABSTRACT(D) (initial(D.abstract_type) == D)
+#define TYPE_IS_SPAWNABLE(D) (!TYPE_IS_ABSTRACT(D) && initial(D.is_spawnable_type))
+#define INSTANCE_IS_ABSTRACT(D) (D.abstract_type == D.type)
+
+//Damage stuff
+#define ITEM_HEALTH_NO_DAMAGE -1
+
+/// Causes the atom to ignore clicks, hovers, etc.
+#define MOUSE_OPACITY_UNCLICKABLE 0
+/// Causes the atom to catch clicks, hovers, etc.
+#define MOUSE_OPACITY_NORMAL 1
+/// Causes the atom to catch clicks, hovers, etc, taking priority over NORMAL for a shared pointer target.
+#define MOUSE_OPACITY_PRIORITY 2
+
+// Set on many base types.
+#define DEFAULT_APPEARANCE_FLAGS (PIXEL_SCALE)
+
+///Formats exceptions into a readable string with all the details.
+#define EXCEPTION_TEXT(E) "'[E.name]' ('[E.type]'): '[E.file]':[E.line]:\n'[E.desc]'"
+
+#define LEVEL_BELOW_PLATING 1
+#define LEVEL_ABOVE_PLATING 2
+
+// Defines for fluorescence (/atom/var/fluorescent)
+/// Glows when under flourescent light
+#define FLUORESCENT_GLOWS 1
+/// Currently glowing due to flourescent light
+#define FLUORESCENT_GLOWING 2
+
+// Flags used for utensil-food interaction.
+/// Solid or semi-solid food; chopsticks, forks.
+#define UTENSIL_FLAG_COLLECT BITFLAG(0)
+/// Soft, liquid or semi-liquid food; soups, stews, pudding.
+#define UTENSIL_FLAG_SCOOP BITFLAG(1)
+/// Foods that need to be sliced before eating; steak, grapefruit.
+#define UTENSIL_FLAG_SLICE BITFLAG(2)
+/// Unimplemented; condiments that are collected before being spread on other food.
+#define UTENSIL_FLAG_SPREAD BITFLAG(3)
+
+// Default.
+#define GROOMABLE_NONE 0
+// Hair, feathers.
+#define GROOMABLE_COMB BITFLAG(0)
+// Hair, beards.
+#define GROOMABLE_BRUSH BITFLAG(1)
+// Horns.
+#define GROOMABLE_FILE BITFLAG(2)
+
+// Nothing to groom on this organ.
+#define GROOMING_RESULT_FAILED 0
+// Can groom somewhat (short hair with a comb)
+#define GROOMING_RESULT_PARTIAL 1
+// Can groom properly (long hair with a brush)
+#define GROOMING_RESULT_SUCCESS 2
+
+// Used by recipe selection.
+#define RECIPE_CATEGORY_MICROWAVE "microwave"
+#define RECIPE_CATEGORY_POT "pot"
+#define RECIPE_CATEGORY_SKILLET "skillet"
+#define RECIPE_CATEGORY_BAKING_DISH "baking dish"
+
+// So we want to have compile time guarantees these methods exist on local type, unfortunately 515 killed the .proc/procname and .verb/verbname syntax so we have to use nameof()
+// For the record: GLOBAL_VERB_REF would be useless as verbs can't be global.
+
+/// Call by name proc references, checks if the proc exists on either this type or as a global proc.
+#define PROC_REF(X) (nameof(.proc/##X))
+/// Call by name verb references, checks if the verb exists on either this type or as a global verb.
+#define VERB_REF(X) (nameof(.verb/##X))
+
+/// Call by name proc reference, checks if the proc exists on either the given type or as a global proc
+#define TYPE_PROC_REF(TYPE, X) (nameof(##TYPE.proc/##X))
+/// Call by name verb reference, checks if the verb exists on either the given type or as a global verb
+#define TYPE_VERB_REF(TYPE, X) (nameof(##TYPE.verb/##X))
+
+/// Call by name proc reference, checks if the proc is an existing global proc
+#define GLOBAL_PROC_REF(X) (/proc/##X)
+
+#define RADIAL_LABELS_NONE 0
+#define RADIAL_LABELS_OFFSET 1
+#define RADIAL_LABELS_CENTERED 2
+
+#define CRAYON_DRAW_RUNE "rune"
+#define CRAYON_DRAW_GRAFFITI "graffiti"
+#define CRAYON_DRAW_LETTER "letter"
+#define CRAYON_DRAW_ARROW "arrow"
+
+// Enum for results of is_space_movement_permitted()
+// Note that it may also return an instance of /atom/movable, which acts as SPACE_MOVE_SUPPORTED.
+#define SPACE_MOVE_SUPPORTED (-1) //! Mob should run space-slipping checks.
+#define SPACE_MOVE_FORBIDDEN 0 //! Mob should begin spacedrift.
+#define SPACE_MOVE_PERMITTED 1 //! Mob should stop/prevent spacedrift.
+
+// Default UI style applied to client prefs.
+#define DEFAULT_UI_STYLE /decl/ui_style/midnight
+
+// Indicates a modifier will never expire.
+#define MOB_MODIFIER_INDEFINITE (-1)
+
+// Indicators for attack checking proc.
+#define MM_ATTACK_TYPE_WEAPON 0
+#define MM_ATTACK_TYPE_THROWN 1
+#define MM_ATTACK_TYPE_PROJECTILE 2
+
+#define MM_ATTACK_RESULT_NONE 0
+#define MM_ATTACK_RESULT_DEFLECTED BITFLAG(0)
+#define MM_ATTACK_RESULT_BLOCKED BITFLAG(1)
diff --git a/code/__defines/mob_status.dm b/code/__defines/mob_status.dm
new file mode 100644
index 000000000000..238ac560411c
--- /dev/null
+++ b/code/__defines/mob_status.dm
@@ -0,0 +1,5 @@
+#define PENDING_STATUS(MOB, COND) (LAZYACCESS(MOB.pending_status_counters, COND) || LAZYACCESS(MOB.status_counters, COND))
+#define GET_STATUS(MOB, COND) (LAZYACCESS(MOB.status_counters, COND))
+#define HAS_STATUS(MOB, COND) (GET_STATUS(MOB, COND) > 0)
+#define ADJ_STATUS(MOB, COND, AMT) (MOB.set_status_condition(COND, PENDING_STATUS(MOB, COND) + AMT))
+#define SET_STATUS_MAX(MOB, COND, AMT) (MOB.set_status_condition(COND, max(PENDING_STATUS(MOB, COND), AMT)))
\ No newline at end of file
diff --git a/code/__defines/mobs.dm b/code/__defines/mobs.dm
index 4b2e42b266ff..77b1dae70dd5 100644
--- a/code/__defines/mobs.dm
+++ b/code/__defines/mobs.dm
@@ -3,32 +3,25 @@
#define UNCONSCIOUS 1
#define DEAD 2
-// Bitflags defining which status effects could be or are inflicted on a mob.
-#define CANSTUN 0x1
-#define CANWEAKEN 0x2
-#define CANPARALYSE 0x4
-#define CANPUSH 0x8
-#define PASSEMOTES 0x10 // Mob has a holder inside of it that need to see emotes.
-#define GODMODE 0x1000
-#define FAKEDEATH 0x2000 // Replaces stuff like changeling.changeling_fakedeath.
-#define NO_ANTAG 0x4000 // Players are restricted from gaining antag roles when occupying this mob
-#define ENABLE_AI 0x8000 // Regardless of player control, the mob is using AI.
-
-#define BORGMESON 0x1
-#define BORGTHERM 0x2
-#define BORGXRAY 0x4
-#define BORGMATERIAL 8
-
-#define HOSTILE_STANCE_IDLE 1
-#define HOSTILE_STANCE_ALERT 2
-#define HOSTILE_STANCE_ATTACK 3
-#define HOSTILE_STANCE_ATTACKING 4
-#define HOSTILE_STANCE_TIRED 5
-#define HOSTILE_STANCE_INSIDE 6
-
-#define LEFT 0x1
-#define RIGHT 0x2
-#define UNDER 0x4
+// Bitflags defining which status conditions could be or are inflicted on a mob.
+#define CANSTUN BITFLAG(0)
+#define CANWEAKEN BITFLAG(1)
+#define CANPARALYSE BITFLAG(2)
+#define CANPUSH BITFLAG(3)
+#define PASSEMOTES BITFLAG(4) // Mob has a holder inside of it that need to see emotes.
+#define GODMODE BITFLAG(5)
+#define FAKEDEATH BITFLAG(6)
+#define NO_ANTAG BITFLAG(7) // Players are restricted from gaining antag roles when occupying this mob
+#define ENABLE_AI BITFLAG(8) // Regardless of player control, the mob is using AI.
+
+#define BORGMESON BITFLAG(0)
+#define BORGTHERM BITFLAG(1)
+#define BORGXRAY BITFLAG(2)
+#define BORGMATERIAL BITFLAG(3)
+
+#define LEFT BITFLAG(0)
+#define RIGHT BITFLAG(1)
+#define UNDER BITFLAG(2)
// Pulse levels, very simplified.
#define PULSE_NONE 0 // So !M.pulse checks would be possible.
@@ -41,12 +34,6 @@
#define GETPULSE_TOOL 1 // More accurate. (med scanner, sleeper, etc.)
#define PULSE_MAX_BPM 250 // Highest, readable BPM by machines and humans.
-//intent flags
-#define I_HELP "help"
-#define I_DISARM "disarm"
-#define I_GRAB "grab"
-#define I_HURT "harm"
-
//These are used Bump() code for living mobs, in the mob_bump_flag, mob_swap_flags, and mob_push_flags vars to determine whom can bump/swap with whom.
#define HUMAN 1
#define MONKEY 2
@@ -64,17 +51,17 @@
#define ROBOT_NOTIFICATION_MODULE_RESET 4
// Appearance change flags
-#define APPEARANCE_UPDATE_DNA 0x1
-#define APPEARANCE_RACE (0x2|APPEARANCE_UPDATE_DNA)
-#define APPEARANCE_GENDER (0x4|APPEARANCE_UPDATE_DNA)
-#define APPEARANCE_SKIN 0x8
-#define APPEARANCE_HAIR 0x10
-#define APPEARANCE_HAIR_COLOR 0x20
-#define APPEARANCE_FACIAL_HAIR 0x40
-#define APPEARANCE_FACIAL_HAIR_COLOR 0x80
-#define APPEARANCE_EYE_COLOR 0x100
-#define APPEARANCE_ALL_HAIR (APPEARANCE_HAIR|APPEARANCE_HAIR_COLOR|APPEARANCE_FACIAL_HAIR|APPEARANCE_FACIAL_HAIR_COLOR)
-#define APPEARANCE_ALL 0xFFFF
+#define APPEARANCE_RACE BITFLAG(0)
+#define APPEARANCE_GENDER BITFLAG(1)
+#define APPEARANCE_BODY BITFLAG(2)
+#define APPEARANCE_SKIN BITFLAG(3)
+#define APPEARANCE_HAIR BITFLAG(4)
+#define APPEARANCE_HAIR_COLOR BITFLAG(5)
+#define APPEARANCE_FACIAL_HAIR BITFLAG(6)
+#define APPEARANCE_FACIAL_HAIR_COLOR BITFLAG(7)
+#define APPEARANCE_EYE_COLOR BITFLAG(8)
+#define APPEARANCE_ALL_HAIR (APPEARANCE_HAIR|APPEARANCE_HAIR_COLOR|APPEARANCE_FACIAL_HAIR|APPEARANCE_FACIAL_HAIR_COLOR)
+#define APPEARANCE_ALL (APPEARANCE_RACE|APPEARANCE_GENDER|APPEARANCE_BODY|APPEARANCE_SKIN|APPEARANCE_EYE_COLOR|APPEARANCE_ALL_HAIR)
// Click cooldown
#define DEFAULT_ATTACK_COOLDOWN 8 //Default timeout for aggressive actions
@@ -97,11 +84,14 @@
#define COMPANY_ALIGNMENTS list(COMPANY_LOYAL,COMPANY_SUPPORTATIVE,COMPANY_NEUTRAL,COMPANY_SKEPTICAL,COMPANY_OPPOSED)
// Defines mob sizes, used by lockers and to determine what is considered a small sized mob, etc.
-#define MOB_SIZE_LARGE 40
-#define MOB_SIZE_MEDIUM 20
-#define MOB_SIZE_SMALL 10
-#define MOB_SIZE_TINY 5
-#define MOB_SIZE_MINISCULE 1
+#define MOB_SIZE_LARGE ITEM_SIZE_STRUCTURE * 2
+#define MOB_SIZE_MEDIUM ITEM_SIZE_STRUCTURE
+#define MOB_SIZE_SMALL ITEM_SIZE_NORMAL
+#define MOB_SIZE_TINY ITEM_SIZE_SMALL
+#define MOB_SIZE_MINISCULE ITEM_SIZE_TINY
+
+#define MOB_SIZE_MIN MOB_SIZE_MINISCULE
+#define MOB_SIZE_MAX MOB_SIZE_LARGE
// Defines how strong the species is compared to humans. Think like strength in D&D
#define STR_VHIGH 2
@@ -136,104 +126,54 @@
#define FLASH_PROTECTION_MODERATE 2
#define FLASH_PROTECTION_MAJOR 3
-#define ANIMAL_SPAWN_DELAY round(config.respawn_delay / 6)
-#define DRONE_SPAWN_DELAY round(config.respawn_delay / 3)
+#define ANIMAL_SPAWN_DELAY round(get_config_value(/decl/config/num/respawn_delay) / 6)
+#define DRONE_SPAWN_DELAY round(get_config_value(/decl/config/num/respawn_delay) / 3)
// Incapacitation flags, used by the mob/proc/incapacitated() proc
-#define INCAPACITATION_NONE 0
-#define INCAPACITATION_RESTRAINED 1
-#define INCAPACITATION_BUCKLED_PARTIALLY 2
-#define INCAPACITATION_BUCKLED_FULLY 4
-#define INCAPACITATION_STUNNED 8
-#define INCAPACITATION_FORCELYING 16 //needs a better name - represents being knocked down BUT still conscious.
-#define INCAPACITATION_KNOCKOUT 32
-#define INCAPACITATION_WEAKENED 64
+#define INCAPACITATION_NONE 0
+#define INCAPACITATION_RESTRAINED BITFLAG(0)
+#define INCAPACITATION_BUCKLED_PARTIALLY BITFLAG(1)
+#define INCAPACITATION_BUCKLED_FULLY BITFLAG(2)
+#define INCAPACITATION_STUNNED BITFLAG(3)
+#define INCAPACITATION_FORCELYING BITFLAG(4) //needs a better name - represents being knocked down BUT still conscious.
+#define INCAPACITATION_KNOCKOUT BITFLAG(5)
+#define INCAPACITATION_WEAKENED BITFLAG(6)
#define INCAPACITATION_UNRESISTING (INCAPACITATION_KNOCKOUT|INCAPACITATION_STUNNED)
-#define INCAPACITATION_DISRUPTED (INCAPACITATION_UNRESISTING|INCAPACITATION_WEAKENED)
-#define INCAPACITATION_KNOCKDOWN (INCAPACITATION_KNOCKOUT|INCAPACITATION_FORCELYING)
-#define INCAPACITATION_DISABLED (INCAPACITATION_KNOCKDOWN|INCAPACITATION_STUNNED)
-#define INCAPACITATION_DEFAULT (INCAPACITATION_RESTRAINED|INCAPACITATION_BUCKLED_FULLY|INCAPACITATION_DISABLED)
-#define INCAPACITATION_ALL (~INCAPACITATION_NONE)
+#define INCAPACITATION_DISRUPTED (INCAPACITATION_UNRESISTING|INCAPACITATION_WEAKENED)
+#define INCAPACITATION_KNOCKDOWN (INCAPACITATION_KNOCKOUT|INCAPACITATION_FORCELYING)
+#define INCAPACITATION_DISABLED (INCAPACITATION_KNOCKDOWN|INCAPACITATION_STUNNED)
+#define INCAPACITATION_DEFAULT (INCAPACITATION_RESTRAINED|INCAPACITATION_BUCKLED_FULLY|INCAPACITATION_DISABLED)
+#define INCAPACITATION_ALL (~INCAPACITATION_NONE)
// Organs.
-#define BP_MOUTH "mouth"
#define BP_EYES "eyes"
#define BP_HEART "heart"
#define BP_LUNGS "lungs"
-#define BP_TRACH "tracheae"
#define BP_BRAIN "brain"
#define BP_LIVER "liver"
#define BP_KIDNEYS "kidneys"
#define BP_STOMACH "stomach"
-#define BP_PLASMA "plasma vessel"
#define BP_APPENDIX "appendix"
#define BP_CELL "cell"
-#define BP_HIVE "hive node"
-#define BP_NUTRIENT "nutrient vessel"
-#define BP_ACID "acid gland"
-#define BP_EGG "egg sac"
-#define BP_RESIN "resin spinner"
-#define BP_STRATA "neural strata"
-#define BP_RESPONSE "response node"
-#define BP_GBLADDER "gas bladder"
-#define BP_POLYP "polyp segment"
-#define BP_ANCHOR "anchoring ligament"
-#define BP_ACETONE "acetone reactor"
-
-// Vox bits.
-#define BP_HINDTONGUE "hindtongue"
// Robo Organs.
-#define BP_POSIBRAIN "posibrain"
#define BP_VOICE "vocal synthesiser"
-#define BP_STACK "stack"
-#define BP_OPTICS "optics"
-#define BP_FLOAT "floatation disc"
-#define BP_JETS "maneuvering jets"
-#define BP_COOLING_FINS "cooling fins"
-#define BP_SYSTEM_CONTROLLER "system controller"
-
-//Augmetations
-#define BP_AUGMENT_R_ARM "right arm augment"
-#define BP_AUGMENT_L_ARM "left arm augment"
-#define BP_AUGMENT_R_HAND "right hand augment"
-#define BP_AUGMENT_L_HAND "left hand augment"
-#define BP_AUGMENT_R_LEG "right leg augment"
-#define BP_AUGMENT_L_LEG "left leg augment"
-#define BP_AUGMENT_CHEST_ARMOUR "chest armor augment"
-#define BP_AUGMENT_CHEST_ACTIVE "active chest augment"
-#define BP_AUGMENT_HEAD "head augment"
-
-//Augment flags
-#define AUGMENTATION_MECHANIC 1
-#define AUGMENTATION_ORGANIC 2
-
-// Limbs.
-#define BP_L_FOOT "l_foot"
-#define BP_R_FOOT "r_foot"
-#define BP_L_LEG "l_leg"
-#define BP_R_LEG "r_leg"
-#define BP_L_HAND "l_hand"
-#define BP_R_HAND "r_hand"
-#define BP_L_ARM "l_arm"
-#define BP_R_ARM "r_arm"
-#define BP_HEAD "head"
-#define BP_CHEST "chest"
-#define BP_GROIN "groin"
-#define BP_ALL_LIMBS list(BP_CHEST, BP_GROIN, BP_HEAD, BP_L_ARM, BP_R_ARM, BP_L_HAND, BP_R_HAND, BP_L_LEG, BP_R_LEG, BP_L_FOOT, BP_R_FOOT)
-#define BP_BY_DEPTH list(BP_HEAD, BP_L_HAND, BP_R_HAND, BP_L_ARM, BP_R_ARM, BP_L_FOOT, BP_R_FOOT, BP_L_LEG, BP_R_LEG, BP_GROIN, BP_CHEST)
// Prosthetic helpers.
-#define BP_IS_PROSTHETIC(org) (!QDELETED(org) && (org.status & ORGAN_PROSTHETIC))
-#define BP_IS_ASSISTED(org) (!QDELETED(org) && (org.status & ORGAN_ASSISTED))
-#define BP_IS_BRITTLE(org) (!QDELETED(org) && (org.status & ORGAN_BRITTLE))
-#define BP_IS_CRYSTAL(org) (!QDELETED(org) && (org.status & ORGAN_CRYSTAL))
+#define BP_IS_PROSTHETIC(org) (!QDELETED(org) && (org.organ_properties & ORGAN_PROP_PROSTHETIC))
+#define BP_IS_ROBOTIC(org) (!QDELETED(org) && (org.bodytype?.is_robotic))
+#define BP_IS_BRITTLE(org) (!QDELETED(org) && (org.status & ORGAN_BRITTLE))
+#define BP_IS_CRYSTAL(org) (!QDELETED(org) && (org.organ_properties & ORGAN_PROP_CRYSTAL))
+
+//Organ Properties Setters
+#define BP_SET_PROSTHETIC(org) org.organ_properties |= ORGAN_PROP_PROSTHETIC;
+#define BP_SET_CRYSTAL(org) org.organ_properties |= ORGAN_PROP_CRYSTAL;
// Limb flag helpers
#define BP_IS_DEFORMED(org) (org.limb_flags & ORGAN_FLAG_DEFORMED)
-#define SYNTH_BLOOD_COLOUR "#030303"
+#define SYNTH_BLOOD_COLOR "#030303"
#define SYNTH_FLESH_COLOUR "#575757"
#define MOB_PULL_NONE 0
@@ -241,13 +181,45 @@
#define MOB_PULL_SAME 2
#define MOB_PULL_LARGER 3
-//carbon taste sensitivity defines, used in mob/living/carbon/proc/ingest
+// Taste sensitivity defines, used in mob/living/proc/ingest.
#define TASTE_HYPERSENSITIVE 3 //anything below 5%
#define TASTE_SENSITIVE 2 //anything below 7%
#define TASTE_NORMAL 1 //anything below 15%
#define TASTE_DULL 0.5 //anything below 30%
#define TASTE_NUMB 0.1 //anything below 150%
+// One 'unit' of taste sensitivity probability, used in mob/living/proc/ingest
+#define TASTE_DEGREE_PROB 15
+
+// General food data flags
+#define DATA_TASTE /decl/reagent_data_field/taste
+#define DATA_INGREDIENT_LIST /decl/reagent_data_field/ingredient_list
+#define DATA_INGREDIENT_FLAGS /decl/reagent_data_field/ingredient_flags
+#define DATA_MASK_COLOR /decl/reagent_data_field/mask_color
+#define DATA_MASK_NAME /decl/reagent_data_field/mask_name
+#define DATA_EXTRA_COLOR /decl/reagent_data_field/extra_color
+
+// Milk and chees data flags
+#define DATA_MILK_DONOR /decl/reagent_data_field/milk_donor
+#define DATA_MILK_NAME /decl/reagent_data_field/milk_name
+#define DATA_MILK_COLOR /decl/reagent_data_field/milk_color
+#define DATA_CHEESE_NAME /decl/reagent_data_field/cheese_name
+#define DATA_CHEESE_COLOR /decl/reagent_data_field/cheese_color
+
+// Blood data flags
+#define DATA_BLOOD_DNA /decl/reagent_data_field/blood_dna
+#define DATA_BLOOD_DONOR /decl/reagent_data_field/blood_donor
+#define DATA_BLOOD_SPECIES /decl/reagent_data_field/blood_species
+#define DATA_BLOOD_COLOR /decl/reagent_data_field/blood_color
+#define DATA_BLOOD_TYPE /decl/reagent_data_field/blood_type
+#define DATA_BLOOD_TRACE_CHEM /decl/reagent_data_field/blood_trace_chem
+#define DATA_BLOOD_DOSE_CHEM /decl/reagent_data_field/blood_dose_chem
+#define DATA_BLOOD_HAS_OXY /decl/reagent_data_field/blood_has_oxy
+
+// Misc general data.
+#define DATA_COOLDOWN_TIME /decl/reagent_data_field/cooldown_time
+#define DATA_WATER_HOLINESS /decl/reagent_data_field/holy
+
//Used by show_message() and emotes
#define VISIBLE_MESSAGE 1
#define AUDIBLE_MESSAGE 2
@@ -268,37 +240,18 @@
#define SYNTH_HEAT_LEVEL_2 1000
#define SYNTH_HEAT_LEVEL_3 2000
-#define CORPSE_CAN_REENTER 1
-#define CORPSE_CAN_REENTER_AND_RESPAWN 2
-
-#define SPECIES_HUMAN "Human"
-#define SPECIES_MONKEY "Monkey"
-#define SPECIES_ALIEN "Humanoid"
-#define SPECIES_GOLEM "Golem"
-
-#define BODYTYPE_HUMANOID "Humanoid Body"
-#define BODYTYPE_OTHER "Alien Body"
-#define BODYTYPE_MONKEY "Small Humanoid Body"
+#define CORPSE_CANNOT_REENTER 0
+#define CORPSE_CAN_REENTER BITFLAG(0)
+#define CORPSE_CAN_RESPAWN BITFLAG(1)
#define SURGERY_CLOSED 0
#define SURGERY_OPEN 1
#define SURGERY_RETRACTED 2
#define SURGERY_ENCASED 3
-#define STASIS_MISC "misc"
-#define STASIS_CRYOBAG "cryobag"
-#define STASIS_COLD "cold"
-
-#define AURA_CANCEL 1
-#define AURA_FALSE 2
-#define AURA_TYPE_BULLET "Bullet"
-#define AURA_TYPE_WEAPON "Weapon"
-#define AURA_TYPE_THROWN "Thrown"
-#define AURA_TYPE_LIFE "Life"
-
#define SPECIES_BLOOD_DEFAULT 560
-#define SLIME_EVOLUTION_THRESHOLD 10
+#define SLIME_EVOLUTION_THRESHOLD 15
//Used in mob/proc/get_input
#define MOB_INPUT_TEXT "text"
@@ -315,21 +268,149 @@
#define RADIO_INTERRUPT_DEFAULT 30
-#define MOB_FLAG_HOLY_BAD 0x001 // If this mob is allergic to holiness
-
-#define MARKING_TARGET_SKIN 0 // Draw a datum/sprite_accessory/marking to the mob's body, eg. tattoos
-#define MARKING_TARGET_HAIR 1 // Draw a datum/sprite_accessory/marking to the mob's hair, eg. ears & horns
+#define MOB_FLAG_HOLY_BAD BITFLAG(0) // If this mob is allergic to holiness
#define DEXTERITY_NONE 0
-#define DEXTERITY_SIMPLE_MACHINES 1
-#define DEXTERITY_KEYBOARDS 2
-#define DEXTERITY_TOUCHSCREENS 3
-#define DEXTERITY_GRIP 4
-#define DEXTERITY_WEAPONS 5
-#define DEXTERITY_COMPLEX_TOOLS 6
-#define DEXTERITY_FULL 7
-
-// used in /mob/living/carbon/human/can_inject, and by various callers of that proc
+#define DEXTERITY_SIMPLE_MACHINES BITFLAG(0)
+// TODO: let HOLD equip items to hand just not other slots
+#define DEXTERITY_HOLD_ITEM BITFLAG(1)
+#define DEXTERITY_WIELD_ITEM BITFLAG(2)
+#define DEXTERITY_EQUIP_ITEM BITFLAG(3)
+#define DEXTERITY_KEYBOARDS BITFLAG(4)
+#define DEXTERITY_TOUCHSCREENS BITFLAG(5)
+// TODO: actually get grab code to check this one.
+#define DEXTERITY_GRAPPLE BITFLAG(6) // Can the mob grab other mobs?
+#define DEXTERITY_WEAPONS BITFLAG(7) // Can the mob use guns?
+#define DEXTERITY_COMPLEX_TOOLS BITFLAG(8) // Can the mob use complex items like flashlights, handcuffs, etc?
+#define DEXTERITY_BASE (DEXTERITY_SIMPLE_MACHINES|DEXTERITY_HOLD_ITEM|DEXTERITY_WIELD_ITEM|DEXTERITY_EQUIP_ITEM)
+#define DEXTERITY_FULL (DEXTERITY_BASE|DEXTERITY_KEYBOARDS|DEXTERITY_TOUCHSCREENS|DEXTERITY_GRAPPLE|DEXTERITY_WEAPONS|DEXTERITY_COMPLEX_TOOLS)
+
+// List of dexterity flags ordered by 'complexity' for use in brainloss dex malus checking.
+var/global/list/dexterity_levels = list(
+ "[DEXTERITY_COMPLEX_TOOLS]",
+ "[DEXTERITY_WEAPONS]",
+ "[DEXTERITY_GRAPPLE]",
+ "[DEXTERITY_TOUCHSCREENS]",
+ "[DEXTERITY_KEYBOARDS]",
+ "[DEXTERITY_BASE]"
+)
+
+// used in /mob/living/human/can_inject, and by various callers of that proc
#define CAN_INJECT 1
#define INJECTION_PORT 2
#define INJECTION_PORT_DELAY 3 SECONDS // used by injectors to apply delay due to searching for a port on the injectee's suit
+
+#define ADJUSTED_GLIDE_SIZE(DELAY) (NONUNIT_CEILING((WORLD_ICON_SIZE / max((DELAY), world.tick_lag) * world.tick_lag) - world.tick_lag, 1) + (get_config_value(/decl/config/num/movement_glide_size)))
+
+#define PREF_MEM_RECORD "memory"
+#define PREF_SEC_RECORD "sec_record"
+#define PREF_PUB_RECORD "public_record"
+#define PREF_MED_RECORD "med_record"
+#define PREF_GEN_RECORD "gen_record"
+
+// Simple animal icon state flags.
+#define MOB_ICON_HAS_LIVING_STATE BITFLAG(0)
+#define MOB_ICON_HAS_DEAD_STATE BITFLAG(1)
+#define MOB_ICON_HAS_REST_STATE BITFLAG(2)
+#define MOB_ICON_HAS_SITTING_STATE BITFLAG(3)
+#define MOB_ICON_HAS_SLEEP_STATE BITFLAG(4)
+#define MOB_ICON_HAS_GIB_STATE BITFLAG(5)
+#define MOB_ICON_HAS_DUST_STATE BITFLAG(6)
+#define MOB_ICON_HAS_PARALYZED_STATE BITFLAG(7)
+
+// Additional pronoun sets.
+#define NEUTER_ANIMATE "animate singular neutral"
+#define SECOND_PERSON_SINGULAR "second person singular"
+#define PSEUDOPLURAL "pseudoplural"
+
+// Equipment Overlays Indices //
+#define HO_CONDITION_LAYER 1
+#define HO_SKIN_LAYER 2
+#define HO_DAMAGE_LAYER 3
+#define HO_SURGERY_LAYER 4 //bs12 specific.
+#define HO_BANDAGE_LAYER 5
+#define HO_UNDERWEAR_LAYER 6
+#define HO_UNIFORM_LAYER 7
+#define HO_ID_LAYER 8
+#define HO_SHOES_LAYER 9
+#define HO_GLOVES_LAYER 10
+#define HO_BELT_LAYER 11
+#define HO_SUIT_LAYER 12
+#define HO_GLASSES_LAYER 13
+#define HO_BELT_LAYER_ALT 14
+#define HO_SUIT_STORE_LAYER 15
+#define HO_BACK_LAYER 16
+#define HO_TAIL_LAYER 17 //bs12 specific. this hack is probably gonna come back to haunt me
+#define HO_HAIR_LAYER 18 //TODO: make part of head layer?
+#define HO_GOGGLES_LAYER 19
+#define HO_L_EAR_LAYER 20
+#define HO_R_EAR_LAYER 21
+#define HO_FACEMASK_LAYER 22
+#define HO_HEAD_LAYER 23
+#define HO_COLLAR_LAYER 24
+#define HO_HANDCUFF_LAYER 25
+#define HO_INHAND_LAYER 26
+#define HO_FIRE_LAYER 27 //If you're on fire
+#define HO_EFFECT_LAYER 28
+#define TOTAL_OVER_LAYERS 28
+//////////////////////////////////
+
+// Underlay defines; vestigal implementation currently.
+#define HU_TAIL_LAYER 1
+#define TOTAL_UNDER_LAYERS 1
+
+// Enum for result of an attempt to eat/eat from an item.
+#define EATEN_INVALID 0
+#define EATEN_UNABLE 1
+#define EATEN_SUCCESS 2
+
+// Enum for type of consumption, largely just cosmetic currently.
+#define EATING_METHOD_EAT 0
+#define EATING_METHOD_DRINK 1
+
+// Sprite accessory categories for shorter reference.
+#define SAC_HAIR /decl/sprite_accessory_category/hair
+#define SAC_FACIAL_HAIR /decl/sprite_accessory_category/facial_hair
+#define SAC_COSMETICS /decl/sprite_accessory_category/cosmetics
+#define SAC_MARKINGS /decl/sprite_accessory_category/markings
+#define SAC_EARS /decl/sprite_accessory_category/ears
+#define SAC_HORNS /decl/sprite_accessory_category/horns
+#define SAC_FRILLS /decl/sprite_accessory_category/frills
+#define SAC_TAIL /decl/sprite_accessory_category/tail
+
+// Sprite accessory metadata types for shorter reference.
+#define SAM_COLOR /decl/sprite_accessory_metadata/color
+#define SAM_COLOR_INNER /decl/sprite_accessory_metadata/color/alt
+#define SAM_GRADIENT /decl/sprite_accessory_metadata/gradient
+
+// Helpers for setting mob appearance. They are extremely ugly, hence the helpers.
+#define SET_HAIR_STYLE(TARGET, STYLE, SKIP_UPDATE) (TARGET.set_organ_sprite_accessory_by_category((STYLE), SAC_HAIR, null, TRUE, FALSE, BP_HEAD, SKIP_UPDATE))
+#define GET_HAIR_STYLE(TARGET) (TARGET.get_organ_sprite_accessory_by_category(SAC_HAIR, BP_HEAD))
+#define SET_HAIR_COLOR(TARGET, COLOR, SKIP_UPDATE) (TARGET.set_organ_sprite_accessory_by_category(null, SAC_HAIR, list(SAM_COLOR = (COLOR)), FALSE, TRUE, BP_HEAD, SKIP_UPDATE))
+#define GET_HAIR_COLOR(TARGET) (TARGET.get_organ_sprite_accessory_metadata(GET_HAIR_STYLE(TARGET), BP_HEAD, SAM_COLOR))
+
+#define SET_FACIAL_HAIR_STYLE(TARGET, STYLE, SKIP_UPDATE) (TARGET.set_organ_sprite_accessory_by_category((STYLE), SAC_FACIAL_HAIR, null, TRUE, FALSE, BP_HEAD, SKIP_UPDATE))
+#define GET_FACIAL_HAIR_STYLE(TARGET) (TARGET.get_organ_sprite_accessory_by_category(SAC_FACIAL_HAIR, BP_HEAD))
+#define SET_FACIAL_HAIR_COLOR(TARGET, COLOR, SKIP_UPDATE) (TARGET.set_organ_sprite_accessory_by_category(null, SAC_FACIAL_HAIR, list(SAM_COLOR = (COLOR)), FALSE, TRUE, BP_HEAD, SKIP_UPDATE))
+#define GET_FACIAL_HAIR_COLOR(TARGET) (TARGET.get_organ_sprite_accessory_metadata(GET_FACIAL_HAIR_STYLE(TARGET), BP_HEAD, SAM_COLOR))
+
+// Used in death() to skip message broadcast.
+#define SKIP_DEATH_MESSAGE "no message"
+
+// Used in organ stance calc.
+#define LIMB_UNUSABLE 2
+#define LIMB_DAMAGED 1
+#define LIMB_IMPAIRED 0.5
+
+// Used by allergy effects.
+#define ALLERGEN_REACTION_NONE 0
+#define ALLERGEN_REACTION_PHYS_DMG BITFLAG(0)
+#define ALLERGEN_REACTION_BURN_DMG BITFLAG(1)
+#define ALLERGEN_REACTION_TOX_DMG BITFLAG(2)
+#define ALLERGEN_REACTION_OXY_DMG BITFLAG(3)
+#define ALLERGEN_REACTION_EMOTE BITFLAG(4)
+#define ALLERGEN_REACTION_PAIN BITFLAG(5)
+#define ALLERGEN_REACTION_WEAKEN BITFLAG(6)
+#define ALLERGEN_REACTION_BLURRY BITFLAG(7)
+#define ALLERGEN_REACTION_SLEEPY BITFLAG(8)
+#define ALLERGEN_REACTION_CONFUSE BITFLAG(9)
diff --git a/code/__defines/observ.dm b/code/__defines/observ.dm
new file mode 100644
index 000000000000..1eeb9bf65d31
--- /dev/null
+++ b/code/__defines/observ.dm
@@ -0,0 +1 @@
+#define RAISE_EVENT(OBS, args...) UNLINT((GET_DECL(OBS))?.raise_event(args));
diff --git a/code/__defines/organs.dm b/code/__defines/organs.dm
new file mode 100644
index 000000000000..91fb781bfb39
--- /dev/null
+++ b/code/__defines/organs.dm
@@ -0,0 +1,2 @@
+#define GET_EXTERNAL_ORGAN(M, OTAG) M.get_organ(OTAG, /obj/item/organ/external)
+#define GET_INTERNAL_ORGAN(M, OTAG) M.get_organ(OTAG, /obj/item/organ/internal)
diff --git a/code/__defines/overmap.dm b/code/__defines/overmap.dm
index 59fa86e08b94..11b0231b3d8e 100644
--- a/code/__defines/overmap.dm
+++ b/code/__defines/overmap.dm
@@ -16,14 +16,17 @@
#define HasAbove(Z) (((Z) >= world.maxz || (Z) < 1 || (Z) > z_levels.len) ? 0 : z_levels[(Z)])
#define KM_OVERMAP_RATE 100
-#define SHIP_MOVE_RESOLUTION 0.00001
-#define MOVING(speed, min_speed) abs(speed) >= min_speed
-#define SANITIZE_SPEED(speed) SIGN(speed) * Clamp(abs(speed), 0, max_speed)
+#define SHIP_MOVE_RESOLUTION 0.001
+#define MOVING(speed, min_speed) (abs(speed) >= min_speed)
+// You can approach, but never reach, max_speed.
+#define SANITIZE_SPEED(speed) (SIGN(speed) * clamp(NONUNIT_FLOOR(abs(speed), SHIP_MOVE_RESOLUTION), 0, max_speed - SHIP_MOVE_RESOLUTION))
#define CHANGE_SPEED_BY(speed_var, v_diff, min_speed) \
v_diff = SANITIZE_SPEED(v_diff);\
if(!MOVING(speed_var + v_diff, min_speed)) \
{speed_var = 0};\
else \
- {speed_var = round(SANITIZE_SPEED((speed_var + v_diff) / (1 + speed_var * v_diff / (max_speed ** 2))), SHIP_MOVE_RESOLUTION)}
+ {speed_var = SANITIZE_SPEED((speed_var + v_diff) / (1 + speed_var * v_diff / (max_speed ** 2)))}
// Uses Lorentzian dynamics to avoid going too fast.
-#define SENSOR_COEFFICENT 1000
\ No newline at end of file
+#define SENSOR_COEFFICENT 1000
+
+#define OVERMAP_ID_SPACE "Deep Space"
diff --git a/code/__defines/paperwork.dm b/code/__defines/paperwork.dm
new file mode 100644
index 000000000000..5ed1a9713a44
--- /dev/null
+++ b/code/__defines/paperwork.dm
@@ -0,0 +1,17 @@
+#define PEN_FLAG_ACTIVE BITFLAG(0) //If the pen is expanded and ready to write
+#define PEN_FLAG_TOGGLEABLE BITFLAG(1) //If the pen can have its head retracted and extended
+#define PEN_FLAG_FANCY BITFLAG(2) //If the pen is a fancy pen, mainly decides the font used
+#define PEN_FLAG_CRAYON BITFLAG(3) //If the pen is a crayon, mainly decides the font used
+#define PEN_FLAG_DEL_EMPTY BITFLAG(4) //If the pen is deleted when its use count reaches 0
+
+#define TONER_USAGE_PAPER 1 //Amount of toner a paper uses
+#define TONER_USAGE_PHOTO 5 //Amount of toner a photo uses
+
+///The default font for pen writing
+#define PEN_FONT_DEFAULT "Verdana"
+///The font for default pen signature
+#define PEN_FONT_SIGNATURE "Times New Roman"
+///The font for crayon writing
+#define PEN_FONT_CRAYON "Comic Sans MS"
+///The font for fancy pen writing
+#define PEN_FONT_FANCY_PEN "Segoe Script"
\ No newline at end of file
diff --git a/code/__defines/persistence.dm b/code/__defines/persistence.dm
new file mode 100644
index 000000000000..bbd7ffbbf0c0
--- /dev/null
+++ b/code/__defines/persistence.dm
@@ -0,0 +1,5 @@
+// Handled elsewhere, do not let them load like vars.
+var/global/list/_forbid_field_load = list(
+ (nameof(/datum::type)) = TRUE,
+ (nameof(/atom::loc)) = TRUE
+)
diff --git a/code/__defines/power.dm b/code/__defines/power.dm
new file mode 100644
index 000000000000..add9f9310333
--- /dev/null
+++ b/code/__defines/power.dm
@@ -0,0 +1,9 @@
+#define POWERCHAN_OFF 0 // Power channel is off
+#define POWERCHAN_OFF_TEMP 1 // Power channel is off until there is power
+#define POWERCHAN_OFF_AUTO 2 // Power channel is off until power passes a threshold
+#define POWERCHAN_ON 3 // Power channel is on until there is no power
+#define POWERCHAN_ON_AUTO 4 // Power channel is on until power drops below a threshold
+
+#define APC_POWERCHAN_EQUIPMENT 1
+#define APC_POWERCHAN_LIGHTING 2
+#define APC_POWERCHAN_ENVIRONMENT 3
\ No newline at end of file
diff --git a/code/__defines/qdel.dm b/code/__defines/qdel.dm
index ffe750f69a6f..1d2654f16d2c 100644
--- a/code/__defines/qdel.dm
+++ b/code/__defines/qdel.dm
@@ -5,20 +5,43 @@
#define QDEL_HINT_IWILLGC 2 //functionally the same as the above. qdel should assume the object will gc on its own, and not check it.
#define QDEL_HINT_HARDDEL 3 //qdel should assume this object won't gc, and queue a hard delete using a hard reference.
#define QDEL_HINT_HARDDEL_NOW 4 //qdel should assume this object won't gc, and hard del it post haste.
-#define QDEL_HINT_FINDREFERENCE 5 //functionally identical to QDEL_HINT_QUEUE if TESTING is not enabled in _compiler_options.dm.
- //if TESTING is enabled, qdel will call this object's find_references() verb.
+#define QDEL_HINT_FINDREFERENCE 5 //functionally identical to QDEL_HINT_QUEUE if REFTRACKING_ENABLED is not enabled in _compiler_options.dm.
+ //if REFTRACKING_ENABLED is enabled, qdel will call this object's find_references() verb.
#define QDEL_HINT_IFFAIL_FINDREFERENCE 6 //Above but only if gc fails.
//defines for the gc_destroyed var
-#define GC_QUEUE_PREQUEUE 1
+#define GC_QUEUE_FILTER 1
#define GC_QUEUE_CHECK 2
#define GC_QUEUE_HARDDELETE 3
#define GC_QUEUE_COUNT 3 //increase this when adding more steps.
-#define GC_QUEUED_FOR_QUEUING -1
-#define GC_QUEUED_FOR_HARD_DEL -2
-#define GC_CURRENTLY_BEING_QDELETED -3
+// Defines for the ssgarbage queue items
+#define GC_QUEUE_ITEM_QUEUE_TIME 1 //! Time this item entered the queue
+#define GC_QUEUE_ITEM_REF 2 //! Ref to the item
+#define GC_QUEUE_ITEM_GCD_DESTROYED 3 //! Item's gc_destroyed var value. Used to detect ref reuse.
+#define GC_QUEUE_ITEM_INDEX_COUNT 3 //! Number of item indexes, used for allocating the nested lists. Don't forget to increase this if you add a new queue item index
+
+// Defines for the time an item has to get its reference cleaned before it fails the queue and moves to the next.
+#define GC_FILTER_QUEUE (1 SECONDS)
+#define GC_CHECK_QUEUE (5 MINUTES)
+#define GC_DEL_QUEUE (10 SECONDS)
+
+#define GC_CURRENTLY_BEING_QDELETED -1
#define QDELING(X) (X.gc_destroyed)
-#define QDELETED(X) (!X || QDELING(X))
-#define QDESTROYING(X) (!X || X.gc_destroyed == GC_CURRENTLY_BEING_QDELETED)
+#define QDELETED(X) (isnull(X) || QDELING(X))
+#define QDESTROYING(X) (isnull(X) || X.gc_destroyed == GC_CURRENTLY_BEING_QDELETED)
+
+//Qdel helper macros.
+#define QDEL_IN(item, time) if(!isnull(item)) {addtimer(CALLBACK(item, TYPE_PROC_REF(/datum, qdel_self)), time)}
+#define QDEL_IN_CLIENT_TIME(item, time) if(!isnull(item)) {addtimer(CALLBACK(item, TYPE_PROC_REF(/datum, qdel_self)), time, TIMER_CLIENT_TIME)}
+#define QDEL_NULL(item) if(item) {qdel(item); item = null}
+#define QDEL_NULL_SCREEN(item) if(client) { client.screen -= item; }; QDEL_NULL(item)
+#define QDEL_NULL_LIST(x) if(x) { for(var/y in x) { qdel(y) }}; if(x) {x.Cut(); x = null } // Second x check to handle items that LAZYREMOVE on qdel.
+#define QDEL_LIST(L) if(L) { for(var/I in L) qdel(I); L.Cut(); }
+#define QDEL_LIST_IN(L, time) addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(______qdel_list_wrapper), L), time)
+#define QDEL_LIST_ASSOC(L) if(L) { for(var/I in L) { qdel(L[I]); qdel(I); } L.Cut(); }
+#define QDEL_LIST_ASSOC_VAL(L) if(L) { for(var/I in L) qdel(L[I]); L.Cut(); }
+
+/proc/______qdel_list_wrapper(list/L) //the underscores are to encourage people not to use this directly.
+ QDEL_LIST(L)
diff --git a/code/__defines/radio.dm b/code/__defines/radio.dm
new file mode 100644
index 000000000000..1fec306b4091
--- /dev/null
+++ b/code/__defines/radio.dm
@@ -0,0 +1,7 @@
+#define MESSAGE_MODE_LEFT "left"
+#define MESSAGE_MODE_RIGHT "right"
+#define MESSAGE_MODE_INTERCOM "intercom"
+#define MESSAGE_MODE_DEFAULT "default"
+#define MESSAGE_MODE_WHISPER "whisper"
+#define MESSAGE_MODE_DEPARTMENT "department"
+#define MESSAGE_MODE_SPECIAL "special"
\ No newline at end of file
diff --git a/code/__defines/reactions.dm b/code/__defines/reactions.dm
new file mode 100644
index 000000000000..d0a32c77accb
--- /dev/null
+++ b/code/__defines/reactions.dm
@@ -0,0 +1,5 @@
+#define REACTION_TYPE_PHARMACEUTICAL 1
+#define REACTION_TYPE_ALLOYING 2
+#define REACTION_TYPE_COMPOUND 3
+#define REACTION_TYPE_SYNTHESIS 4
+#define REACTION_TYPE_RECIPE 5
diff --git a/code/__defines/reagent_data_fields.dm b/code/__defines/reagent_data_fields.dm
new file mode 100644
index 000000000000..04998150bd8d
--- /dev/null
+++ b/code/__defines/reagent_data_fields.dm
@@ -0,0 +1,70 @@
+// Currently just used for indexing reagent data without
+// having to use strings. UID is provided for serde.
+
+/decl/reagent_data_field
+ abstract_type = /decl/reagent_data_field
+ decl_flags = DECL_FLAG_MANDATORY_UID
+
+/decl/reagent_data_field/taste
+ uid = "rdf_taste"
+
+/decl/reagent_data_field/ingredient_list
+ uid = "rdf_ingredient_list"
+
+/decl/reagent_data_field/ingredient_flags
+ uid = "rdf_ingredient_flags"
+
+/decl/reagent_data_field/mask_color
+ uid = "rdf_mask_color"
+
+/// An extra colour used for things like additional reagent overlays on soups, so that you can have noodle soup with veggie bits a different colour than the main soup.
+/decl/reagent_data_field/extra_color
+ uid = "rdf_extra_color"
+
+/decl/reagent_data_field/mask_name
+ uid = "rdf_mask_name"
+
+/decl/reagent_data_field/milk_donor
+ uid = "rdf_milk_donor"
+
+/decl/reagent_data_field/milk_name
+ uid = "rdf_milk_name"
+
+/decl/reagent_data_field/milk_color
+ uid = "rdf_milk_color"
+
+/decl/reagent_data_field/cheese_name
+ uid = "rdf_cheese_name"
+
+/decl/reagent_data_field/cheese_color
+ uid = "rdf_cheese_color"
+
+/decl/reagent_data_field/blood_dna
+ uid = "rdf_blood_dna"
+
+/decl/reagent_data_field/blood_donor
+ uid = "rdf_blood_donor"
+
+/decl/reagent_data_field/blood_species
+ uid = "rdf_blood_species"
+
+/decl/reagent_data_field/blood_color
+ uid = "rdf_blood_color"
+
+/decl/reagent_data_field/blood_type
+ uid = "rdf_blood_type"
+
+/decl/reagent_data_field/blood_trace_chem
+ uid = "rdf_blood_trace_chem"
+
+/decl/reagent_data_field/blood_dose_chem
+ uid = "rdf_blood_dose_chem"
+
+/decl/reagent_data_field/blood_has_oxy
+ uid = "rdf_blood_has_oxy"
+
+/decl/reagent_data_field/cooldown_time
+ uid = "rdf_cooldown_time"
+
+/decl/reagent_data_field/holy
+ uid = "rdf_water_holy"
\ No newline at end of file
diff --git a/code/__defines/research.dm b/code/__defines/research.dm
index 8d00818dfd0d..3898d8dc2958 100644
--- a/code/__defines/research.dm
+++ b/code/__defines/research.dm
@@ -1,14 +1,28 @@
#define SHEET_MATERIAL_AMOUNT 2000
#define SHEET_UNIT "cm3"
+#define REAGENT_WORTH_MULTIPLIER 1 //0.01
+#define GAS_WORTH_MULTIPLIER 1 //0.001
+#define MATERIAL_WORTH_MULTIPLIER 1 //0.005
+
#define REAGENT_UNITS_PER_MATERIAL_SHEET 20
#define REAGENT_UNITS_PER_GAS_MOLE 10
-#define MATTER_UNITS_PER_REAGENT_UNIT (REAGENT_UNITS_PER_MATERIAL_SHEET / SHEET_MATERIAL_AMOUNT)
+#define REAGENT_UNITS_PER_MATERIAL_UNIT (REAGENT_UNITS_PER_MATERIAL_SHEET / SHEET_MATERIAL_AMOUNT)
+#define MATERIAL_UNITS_TO_REAGENTS_UNITS(AMT) (AMT * REAGENT_UNITS_PER_MATERIAL_UNIT)
+#define MOLES_PER_MATERIAL_UNIT(AMT) round(MATERIAL_UNITS_TO_REAGENTS_UNITS(AMT) / REAGENT_UNITS_PER_GAS_MOLE)
#define MATTER_AMOUNT_PRIMARY SHEET_MATERIAL_AMOUNT
+#define MATTER_AMOUNT_SECONDARY (MATTER_AMOUNT_PRIMARY * 0.75)
#define MATTER_AMOUNT_REINFORCEMENT (MATTER_AMOUNT_PRIMARY * 0.5)
#define MATTER_AMOUNT_TRACE (MATTER_AMOUNT_PRIMARY * 0.1)
+#define HOLLOW_OBJECT_MATTER_MULTIPLIER 0.05
+#define BASE_OBJECT_MATTER_MULTPLIER 0.25
+
+#define LOW_SMELTING_HEAT_POINT 1150 CELSIUS // Reachable with coal in a kiln on the medieval maps.
+#define GENERIC_SMELTING_HEAT_POINT 1350 CELSIUS // Reachable with coal and a bellows in a kiln on medieval maps.
+#define HIGH_SMELTING_HEAT_POINT 4000 CELSIUS // must be at least 4074K (3800 C) to melt graphite
+
#define TECH_MATERIAL "materials"
#define TECH_ENGINEERING "engineering"
#define TECH_EXOTIC_MATTER "exoticmatter"
@@ -19,5 +33,3 @@
#define TECH_MAGNET "magnets"
#define TECH_DATA "programming"
#define TECH_ESOTERIC "esoteric"
-
-#define T_BOARD(name) "circuit board (" + (name) + ")"
\ No newline at end of file
diff --git a/code/__defines/ruin_tags.dm b/code/__defines/ruin_tags.dm
deleted file mode 100644
index caf6e3cf7fb2..000000000000
--- a/code/__defines/ruin_tags.dm
+++ /dev/null
@@ -1,8 +0,0 @@
-//Flags for exoplanet ruin picking
-
-#define RUIN_HABITAT 1 //long term habitat
-#define RUIN_HUMAN 2 //human-made structure
-#define RUIN_ALIEN 4 //artificial structure of an unknown origin
-#define RUIN_WRECK 8 //crashed vessel
-#define RUIN_NATURAL 16 //naturally occuring structure
-#define RUIN_WATER 32 //ruin depending on planet having water accessible
\ No newline at end of file
diff --git a/code/__defines/serde.dm b/code/__defines/serde.dm
new file mode 100644
index 000000000000..a1e84e3fe30c
--- /dev/null
+++ b/code/__defines/serde.dm
@@ -0,0 +1,64 @@
+#define SERDE_HINT_FINISHED 1
+#define SERDE_HINT_POSTINIT 2
+
+#define SERDE_REAGENT_LIST "_reagent_list"
+#define SERDE_REAGENT_VOLUME "_reagent_volume"
+
+#define SERIALIZE_VALUE(V, T, VAL) .[nameof(T::V)] = VAL;
+#define SERIALIZE(V, T) SERIALIZE_VALUE(V, T, V)
+#define SERIALIZE_IF_MODIFIED(V, T) if(V != initial(V)) { SERIALIZE_VALUE(V, T, V) }
+#define SERIALIZE_TYPE_IF_MODIFIED(V, T) if(V != initial(V)) { SERIALIZE_VALUE(V, T, "[V]") }
+#define SERIALIZE_DECL_IF_MODIFIED(V, T) if((isnull(V) && !isnull(initial(V))) || ((istext(V) || istype(V, /decl) || ispath(V, /decl)) && !DECLS_ARE_EQUIVALENT(V, initial(V)))) { var/decl/__D = RESOLVE_TO_DECL(V); SERIALIZE_VALUE(V, T, __D?.uid) }
+#define SERIALIZE_DECL_LIST(V, T) if(islist(V)) { var/list/__decl_uids = list(); for(var/decl/__decl in V) { __decl_uids += __decl.uid }; SERIALIZE_VALUE(V, T, __decl_uids) }
+#define SERIALIZE_REAGENTS(V, T, I) if(istype(V, /datum/reagents)) { \
+ .[I + SERDE_REAGENT_VOLUME] = UNLINT(V.maximum_volume); \
+ if(UNLINT(V.total_volume)) { \
+ var/list/__compiled_reagents = list(); \
+ for(var/decl/material/R in UNLINT(V.liquid_volumes)) { \
+ __compiled_reagents[++__compiled_reagents.len] = list(R.uid, UNLINT(V.liquid_volumes[R]), (MAT_PHASE_LIQUID)); \
+ } \
+ for(var/decl/material/R in UNLINT(V.solid_volumes)) { \
+ __compiled_reagents[++__compiled_reagents.len] = list(R.uid, UNLINT(V.solid_volumes[R]), (MAT_PHASE_SOLID)); \
+ } \
+ .[I + SERDE_REAGENT_LIST] = __compiled_reagents; \
+ } else { \
+ .[I + SERDE_REAGENT_LIST] = list(); \
+ } \
+} else { \
+ .[I + SERDE_REAGENT_LIST] = list(); \
+ .[I + SERDE_REAGENT_VOLUME] = 0; \
+}
+
+#define DESERIALIZE_REAGENTS(V, I) if(((I + SERDE_REAGENT_LIST) in __deserialization_payload) && ((I + SERDE_REAGENT_VOLUME) in __deserialization_payload)) { \
+ V = list((SERDE_REAGENT_VOLUME) = __deserialization_payload[I + SERDE_REAGENT_VOLUME], (SERDE_REAGENT_LIST) = __deserialization_payload[I + SERDE_REAGENT_LIST]); \
+}
+
+#define DESERIALIZE_DECL_TO_TYPE(V) if(istext(V) || ispath(V, /decl) || istype(V, /decl)) { var/decl/__D = RESOLVE_TO_DECL(V); V = __D?.type; } else { V = null; }
+#define DESERIALIZE_TYPE(V) if(istext(V)) { V = text2path(V); } else if(!ispath(V)) { V = null; }
+#define DESERIALIZE_DECL(V) if(istext(V) || ispath(V)) { V = RESOLVE_TO_DECL(V); } else { V = null; }
+
+// List cast is to avoid OpenDream complaining about V typically being typed as a reagents datum, but holding a list for serde.
+#define FINALIZE_REAGENTS_SERDE_BODY(V) try { \
+ if((SERDE_REAGENT_LIST in V) && (SERDE_REAGENT_VOLUME in V)) { \
+ var/list/LV = V; \
+ var/__serde_volume = LV[SERDE_REAGENT_VOLUME]; \
+ if(__serde_volume <= 0) { \
+ V = null; \
+ } else { \
+ var/list/__serde_reagents = LV[SERDE_REAGENT_LIST]; \
+ V = new /datum/reagents(__serde_volume, src); \
+ for(var/list/entry in __serde_reagents) { \
+ V.add_reagent(RESOLVE_TO_DECL(entry[1]), entry[2], phase = entry[3], defer_update = TRUE); \
+ } \
+ V.handle_update(); \
+ } \
+ } else { \
+ V = null; \
+ } \
+} catch(var/exception/E) { \
+ log_error("Exception while finalizing reagents load for [type]: [EXCEPTION_TEXT(E)]"); \
+ V = null; \
+}
+
+#define FINALIZE_REAGENTS_SERDE(V) if(islist(V)) { FINALIZE_REAGENTS_SERDE_BODY(V); }
+#define FINALIZE_REAGENTS_SERDE_AND_RETURN(V) if(islist(V)) { FINALIZE_REAGENTS_SERDE_BODY(V); return; }
diff --git a/code/__defines/shields.dm b/code/__defines/shields.dm
index 85de1ae89f03..f3b075265e41 100644
--- a/code/__defines/shields.dm
+++ b/code/__defines/shields.dm
@@ -1,4 +1,4 @@
-#define SHIELD_DAMTYPE_PHYSICAL 1 // Physical damage - bullets, meteors, various hand objects - aka. "brute" damtype.
+#define SHIELD_DAMTYPE_PHYSICAL 1 // Physical damage - bullets, meteors, various hand objects - aka. BRUTE damtype.
#define SHIELD_DAMTYPE_EM 2 // Electromagnetic damage - Ion weaponry, stun beams, ...
#define SHIELD_DAMTYPE_HEAT 3 // Heat damage - Lasers, fire
diff --git a/code/__defines/shuttle.dm b/code/__defines/shuttle.dm
index 168ea1ae9834..8b28b098294d 100644
--- a/code/__defines/shuttle.dm
+++ b/code/__defines/shuttle.dm
@@ -1,15 +1,17 @@
#define SHUTTLE_FLAGS_NONE 0
-#define SHUTTLE_FLAGS_PROCESS 1
-#define SHUTTLE_FLAGS_SUPPLY 2
-#define SHUTTLE_FLAGS_ZERO_G 4
+#define SHUTTLE_FLAGS_PROCESS BITFLAG(0)
+#define SHUTTLE_FLAGS_SUPPLY BITFLAG(1)
+#define SHUTTLE_FLAGS_ZERO_G BITFLAG(2)
+#define SHUTTLE_FLAGS_NO_CODE BITFLAG(3) // Essentially bypasses docking codes by extracting them from the target docking controller. Only relevant on /autodock.
#define SHUTTLE_FLAGS_ALL (~SHUTTLE_FLAGS_NONE)
-#define SLANDMARK_FLAG_AUTOSET 1 // If set, will set base area and turf type to same as where it was spawned at.
-#define SLANDMARK_FLAG_ZERO_G 2 // Zero-G shuttles moved here will lose gravity unless the area has ambient gravity.
-#define SLANDMARK_FLAG_DISCONNECTED 4 // Landable ships that land here will be forceably removed if the sector moves out of range.
+#define SLANDMARK_FLAG_AUTOSET BITFLAG(0) // If set, will set base area and turf type to same as where it was spawned at.
+#define SLANDMARK_FLAG_ZERO_G BITFLAG(1) // Zero-G shuttles moved here will lose gravity unless the area has ambient gravity.
+#define SLANDMARK_FLAG_DISCONNECTED BITFLAG(2) // Landable ships that land here will be forceably removed if the sector moves out of range.
+#define SLANDMARK_FLAG_REORIENT BITFLAG(3) // Shuttles that land here will be reoriented to face the correct dir for docking.
//Overmap landable shuttles
-#define SHIP_STATUS_LANDED 1
-#define SHIP_STATUS_TRANSIT 2
-#define SHIP_STATUS_OVERMAP 3
-#define SHIP_STATUS_ENCOUNTER 4
\ No newline at end of file
+#define SHIP_STATUS_LANDED BITFLAG(0)
+#define SHIP_STATUS_TRANSIT BITFLAG(1)
+#define SHIP_STATUS_OVERMAP BITFLAG(2)
+#define SHIP_STATUS_ENCOUNTER BITFLAG(3)
\ No newline at end of file
diff --git a/code/__defines/skills.dm b/code/__defines/skills.dm
index 8c38c4ae20d1..ef7fcdd8ea48 100644
--- a/code/__defines/skills.dm
+++ b/code/__defines/skills.dm
@@ -5,6 +5,8 @@
#define SKILL_PROF 5
#define HAS_PERK SKILL_NONE + 1
+#define SKILL_IMPOSSIBLE INFINITY
+
#define SKILL_MIN 1 // Min skill value selectable
#define SKILL_MAX 5 // Max skill value selectable
#define SKILL_DEFAULT 4 //most mobs will default to this
@@ -13,24 +15,24 @@
#define SKILL_AVERAGE 2
#define SKILL_HARD 4
-#define SKILL_LITERACY /decl/hierarchy/skill/organizational/literacy
-#define SKILL_FINANCE /decl/hierarchy/skill/organizational/finance
-#define SKILL_EVA /decl/hierarchy/skill/general/EVA
-#define SKILL_MECH /decl/hierarchy/skill/general/EVA/mech
-#define SKILL_PILOT /decl/hierarchy/skill/general/pilot
-#define SKILL_HAULING /decl/hierarchy/skill/general/hauling
-#define SKILL_COMPUTER /decl/hierarchy/skill/general/computer
-#define SKILL_BOTANY /decl/hierarchy/skill/service/botany
-#define SKILL_COOKING /decl/hierarchy/skill/service/cooking
-#define SKILL_COMBAT /decl/hierarchy/skill/security/combat
-#define SKILL_WEAPONS /decl/hierarchy/skill/security/weapons
-#define SKILL_FORENSICS /decl/hierarchy/skill/security/forensics
-#define SKILL_CONSTRUCTION /decl/hierarchy/skill/engineering/construction
-#define SKILL_ELECTRICAL /decl/hierarchy/skill/engineering/electrical
-#define SKILL_ATMOS /decl/hierarchy/skill/engineering/atmos
-#define SKILL_ENGINES /decl/hierarchy/skill/engineering/engines
-#define SKILL_DEVICES /decl/hierarchy/skill/research/devices
-#define SKILL_SCIENCE /decl/hierarchy/skill/research/science
-#define SKILL_MEDICAL /decl/hierarchy/skill/medical/medical
-#define SKILL_ANATOMY /decl/hierarchy/skill/medical/anatomy
-#define SKILL_CHEMISTRY /decl/hierarchy/skill/medical/chemistry
\ No newline at end of file
+#define SKILL_LITERACY /decl/skill/literacy
+#define SKILL_FINANCE /decl/skill/finance
+#define SKILL_EVA /decl/skill/general/eva
+#define SKILL_MECH /decl/skill/general/mech
+#define SKILL_PILOT /decl/skill/general/pilot
+#define SKILL_HAULING /decl/skill/general/hauling
+#define SKILL_COMPUTER /decl/skill/general/computer
+#define SKILL_BOTANY /decl/skill/service/botany
+#define SKILL_COOKING /decl/skill/service/cooking
+#define SKILL_COMBAT /decl/skill/combat
+#define SKILL_WEAPONS /decl/skill/weapons
+#define SKILL_FORENSICS /decl/skill/forensics
+#define SKILL_CONSTRUCTION /decl/skill/construction
+#define SKILL_ELECTRICAL /decl/skill/electrical
+#define SKILL_ATMOS /decl/skill/atmos
+#define SKILL_ENGINES /decl/skill/engines
+#define SKILL_DEVICES /decl/skill/devices
+#define SKILL_SCIENCE /decl/skill/science
+#define SKILL_MEDICAL /decl/skill/medicine/medical
+#define SKILL_ANATOMY /decl/skill/medicine/anatomy
+#define SKILL_CHEMISTRY /decl/skill/medicine/chemistry
\ No newline at end of file
diff --git a/code/__defines/sound.dm b/code/__defines/sound.dm
index 2946b1417fd1..fc8288708fe5 100644
--- a/code/__defines/sound.dm
+++ b/code/__defines/sound.dm
@@ -61,3 +61,10 @@
//Defines for controlling how zsound sounds.
#define ZSOUND_DRYLOSS_PER_Z -2000 //Affects what happens to the dry channel as the sound travels through z-levels
#define ZSOUND_DISTANCE_PER_Z 2 //Affects the distance added to the sound per z-level travelled
+
+/**
+ * Returns the `extrarange` parameter for the `/proc/playsound` if we want the sound range to be exactly the value of RANGE,
+ * instead of being added up to the client's view range.
+ * Is more intuitive and maintainable to use than setting the parameter to a negative value.
+ **/
+#define SOUND_RANGE_ABS(RANGE) (max((world.view * -1) + RANGE, 0))
\ No newline at end of file
diff --git a/code/__defines/spaceman_dmm.dm b/code/__defines/spaceman_dmm.dm
index 247d28d359cf..fd14916edc87 100644
--- a/code/__defines/spaceman_dmm.dm
+++ b/code/__defines/spaceman_dmm.dm
@@ -11,6 +11,7 @@
#define SHOULD_BE_PURE(X) set SpacemanDMM_should_be_pure = X
#define PRIVATE_PROC(X) set SpacemanDMM_private_proc = X
#define PROTECTED_PROC(X) set SpacemanDMM_protected_proc = X
+ #define CAN_BE_REDEFINED(X) set SpacemanDMM_can_be_redefined = X
#define VAR_FINAL var/SpacemanDMM_final
#define VAR_PRIVATE var/SpacemanDMM_private
#define VAR_PROTECTED var/SpacemanDMM_protected
@@ -23,7 +24,8 @@
#define SHOULD_BE_PURE(X)
#define PRIVATE_PROC(X)
#define PROTECTED_PROC(X)
+ #define CAN_BE_REDEFINED(X)
#define VAR_FINAL var
#define VAR_PRIVATE var
#define VAR_PROTECTED var
-#endif
+#endif
\ No newline at end of file
diff --git a/code/__defines/spawn.dm b/code/__defines/spawn.dm
new file mode 100644
index 000000000000..c576e4f0ac42
--- /dev/null
+++ b/code/__defines/spawn.dm
@@ -0,0 +1,8 @@
+/// Allows the spawn point to be used for observers spawning.
+#define SPAWN_FLAG_GHOSTS_CAN_SPAWN BITFLAG(0)
+/// Allows admin prison releases to use this spawn point.
+#define SPAWN_FLAG_PRISONERS_CAN_SPAWN BITFLAG(1)
+/// Allows general job latejoining to use this spawn point.
+#define SPAWN_FLAG_JOBS_CAN_SPAWN BITFLAG(2)
+/// Allows persistence decls (currently just bookcases) to use this spawn point.
+#define SPAWN_FLAG_PERSISTENCE_CAN_SPAWN BITFLAG(3)
\ No newline at end of file
diff --git a/code/__defines/species.dm b/code/__defines/species.dm
index 27b8cc7669c3..791e81cd17d3 100644
--- a/code/__defines/species.dm
+++ b/code/__defines/species.dm
@@ -1,44 +1,21 @@
// Species flags.
-#define SPECIES_FLAG_NO_MINOR_CUT 0x0001 // Can step on broken glass with no ill-effects. Either thick skin, cut resistant (slimes) or incorporeal (shadows)
-#define SPECIES_FLAG_IS_PLANT 0x0002 // Is a treeperson.
-#define SPECIES_FLAG_NO_SCAN 0x0004 // Cannot be scanned in a DNA machine/genome-stolen.
-#define SPECIES_FLAG_NO_PAIN 0x0008 // Cannot suffer halloss/recieves deceptive health indicator.
-#define SPECIES_FLAG_NO_SLIP 0x0010 // Cannot fall over.
-#define SPECIES_FLAG_NO_POISON 0x0020 // Cannot not suffer toxloss.
-#define SPECIES_FLAG_NO_EMBED 0x0040 // Can step on broken glass with no ill-effects and cannot have shrapnel embedded in it.
-#define SPECIES_FLAG_NO_TANGLE 0x0080 // This species wont get tangled up in weeds
-#define SPECIES_FLAG_NO_BLOCK 0x0100 // Unable to block or defend itself from attackers.
-#define SPECIES_FLAG_NEED_DIRECT_ABSORB 0x0200 // This species can only have their DNA taken by direct absorption.
-#define SPECIES_FLAG_LOW_GRAV_ADAPTED 0x0400 // This species is used to lower than standard gravity, affecting stamina in high-grav
-
-// unused: 0x8000 - higher than this will overflow
+#define SPECIES_FLAG_NO_MINOR_CUT BITFLAG(0) // Can step on broken glass with no ill-effects. Either thick skin, cut resistant (slimes) or incorporeal (shadows)
+#define SPECIES_FLAG_IS_PLANT BITFLAG(1) // Is a treeperson.
+#define SPECIES_FLAG_NO_SLIP BITFLAG(2) // Cannot fall over.
+#define SPECIES_FLAG_NO_POISON BITFLAG(3) // Cannot not suffer toxloss.
+#define SPECIES_FLAG_NO_EMBED BITFLAG(4) // Can step on broken glass with no ill-effects and cannot have shrapnel embedded in it.
+#define SPECIES_FLAG_NO_TANGLE BITFLAG(5) // This species wont get tangled up in weeds
+#define SPECIES_FLAG_NO_BLOCK BITFLAG(6) // Unable to block or defend itself from attackers.
+#define SPECIES_FLAG_NEED_DIRECT_ABSORB BITFLAG(7) // This species can only have their DNA taken by direct absorption.
+#define SPECIES_FLAG_LOW_GRAV_ADAPTED BITFLAG(8) // This species is used to lower than standard gravity, affecting stamina in high-grav
+#define SPECIES_FLAG_ABSORB_ELECTRICITY BITFLAG(9) // This species can absorb electricity; snowflake flag for old slime people.
// Species spawn flags
-#define SPECIES_IS_WHITELISTED 0x1 // Must be whitelisted to play.
-#define SPECIES_IS_RESTRICTED 0x2 // Is not a core/normally playable species. (castes, mutantraces)
-#define SPECIES_CAN_JOIN 0x4 // Species is selectable in chargen.
-#define SPECIES_NO_ROBOTIC_INTERNAL_ORGANS 0x8 // Species cannot start with robotic organs or have them attached.
-
-// Species appearance flags
-#define HAS_SKIN_TONE_NORMAL 0x1 // Skin tone selectable in chargen for baseline humans (0-220)
-#define HAS_SKIN_COLOR 0x2 // Skin colour selectable in chargen. (RGB)
-#define HAS_LIPS 0x4 // Lips are drawn onto the mob icon. (lipstick)
-#define HAS_UNDERWEAR 0x8 // Underwear is drawn onto the mob icon.
-#define HAS_EYE_COLOR 0x10 // Eye colour selectable in chargen. (RGB)
-#define HAS_HAIR_COLOR 0x20 // Hair colour selectable in chargen. (RGB)
-#define RADIATION_GLOWS 0x40 // Radiation causes this character to glow.
-#define HAS_SKIN_TONE_GRAV 0x80 // Skin tone selectable in chargen for grav-adapted humans (0-100)
-#define HAS_SKIN_TONE_SPCR 0x100 // Skin tone selectable in chargen for spacer humans (0-165)
-#define HAS_SKIN_TONE_TRITON 0x200
-#define HAS_BASE_SKIN_COLOURS 0x400 // Has multiple base skin sprites to go off of
-#define HAS_A_SKIN_TONE (HAS_SKIN_TONE_NORMAL | HAS_SKIN_TONE_GRAV | HAS_SKIN_TONE_SPCR | HAS_SKIN_TONE_TRITON) // Species has a numeric skintone
+#define SPECIES_IS_WHITELISTED BITFLAG(0) // Must be whitelisted to play.
+#define SPECIES_IS_RESTRICTED BITFLAG(1) // Is not a core/normally playable species. (castes, mutantraces)
+#define SPECIES_CAN_JOIN BITFLAG(2) // Species is selectable in chargen.
+#define SPECIES_NO_ROBOTIC_INTERNAL_ORGANS BITFLAG(3) // Species cannot start with robotic organs or have them attached.
// Skin Defines
#define SKIN_NORMAL 0
#define SKIN_THREAT 1
-
-// Darkvision Levels these are inverted from normal so pure white is the darkest
-// possible and pure black is none
-#define DARKTINT_NONE "#ffffff"
-#define DARKTINT_MODERATE "#f9f9f5"
-#define DARKTINT_GOOD "#ebebe6"
diff --git a/code/__defines/status.dm b/code/__defines/status.dm
new file mode 100644
index 000000000000..78e99d6ba16f
--- /dev/null
+++ b/code/__defines/status.dm
@@ -0,0 +1,17 @@
+// Defines some paths so the code is less ugly.
+#define STAT_CONFUSE /decl/status_condition/confused
+#define STAT_STUN /decl/status_condition/stunned
+#define STAT_WEAK /decl/status_condition/weakened
+#define STAT_PARA /decl/status_condition/paralyzed
+#define STAT_DIZZY /decl/status_condition/dizzy
+#define STAT_JITTER /decl/status_condition/jittery
+#define STAT_STUTTER /decl/status_condition/stuttering
+#define STAT_SLUR /decl/status_condition/slurring
+#define STAT_ASLEEP /decl/status_condition/sleeping
+#define STAT_DRUGGY /decl/status_condition/drugged
+#define STAT_DROWSY /decl/status_condition/drowsy
+#define STAT_SILENCE /decl/status_condition/silenced
+#define STAT_BLURRY /decl/status_condition/eye_blurry
+#define STAT_BLIND /decl/status_condition/eye_blind
+#define STAT_TINNITUS /decl/status_condition/ear_damage
+#define STAT_DEAF /decl/status_condition/ear_deaf
diff --git a/code/__defines/stress.dm b/code/__defines/stress.dm
new file mode 100644
index 000000000000..55ee054cfc3a
--- /dev/null
+++ b/code/__defines/stress.dm
@@ -0,0 +1,6 @@
+#define STRESSOR_DURATION_INDEFINITE -1
+#define STRESSOR_DEGREE_MILD 0.1
+#define STRESSOR_DEGREE_MODERATE 0.3
+#define STRESSOR_DEGREE_SEVERE 0.6
+#define MAX_STRESS 1
+#define MIN_STRESS -1
diff --git a/code/__defines/structures.dm b/code/__defines/structures.dm
new file mode 100644
index 000000000000..39849cecebc9
--- /dev/null
+++ b/code/__defines/structures.dm
@@ -0,0 +1,4 @@
+// Structure counts as a surface for the purposes of placing items on.
+#define STRUCTURE_FLAG_SURFACE BITFLAG(0)
+// Structure takes damage from thrown objects colliding with it.
+#define STRUCTURE_FLAG_THROWN_DAMAGE BITFLAG(1)
\ No newline at end of file
diff --git a/code/__defines/subsystem-priority.dm b/code/__defines/subsystem-priority.dm
index f1efc6d4483e..f0625f099a76 100644
--- a/code/__defines/subsystem-priority.dm
+++ b/code/__defines/subsystem-priority.dm
@@ -3,52 +3,64 @@
// SS_BACKGROUND handles high server load differently than Normal and SS_TICKER do.
// Higher priority also means a larger share of a given tick before sleep checks.
-#define SS_PRIORITY_DEFAULT 50 // Default priority for all processes levels
+#define SS_PRIORITY_DEFAULT 50 // Default priority for all processes levels
// SS_TICKER
-#define SS_PRIORITY_OVERLAY 100 // Applies overlays. May cause overlay pop-in if it gets behind.
-#define SS_PRIORITY_TIMER 20
-#define SS_PRIORITY_ICON_UPDATE 20 // Queued icon updates. Mostly used by APCs and tables.
+#define SS_PRIORITY_OVERLAY 100 // Applies overlays. May cause overlay pop-in if it gets behind.
+#define SS_PRIORITY_TIMER 20
+#define SS_PRIORITY_DPC 19
// Normal
-#define SS_PRIORITY_TICKER 100 // Gameticker.
-#define SS_PRIORITY_MOB 95 // Mob Life().
-#define SS_PRIORITY_MACHINERY 95 // Machinery + powernet ticks.
-#define SS_PRIORITY_AIR 80 // ZAS processing.
-#define SS_PRIORITY_THROWING 75 // Throwing calculation and constant checks
-#define SS_PRIORITY_MATERIALS 60 // Multi-tick chemical reactions.
-#define SS_PRIORITY_SPACEDRIFT 40 // Drifting things
-#define SS_PRIORITY_ALARM 20 // Alarm processing.
-#define SS_PRIORITY_EVENT 20 // Event processing and queue handling.
-#define SS_PRIORITY_SHUTTLE 20 // Shuttle movement.
-#define SS_PRIORITY_CIRCUIT_COMP 20 // Processing circuit component do_work.
-#define SS_PRIORITY_TEMPERATURE 20 // Cooling and heating of atoms.
-#define SS_PRIORITY_RADIATION 20 // Radiation processing and cache updates.
-#define SS_PRIORITY_OPEN_SPACE 20 // Open turf updates.
-#define SS_PRIORITY_AIRFLOW 15 // Object movement from ZAS airflow.
-#define SS_PRIORITY_VOTE 10 // Vote management.
-#define SS_PRIORITY_INACTIVITY 10 // Idle kicking.
-#define SS_PRIORITY_SUPPLY 10 // Supply point accumulation.
-#define SS_PRIORITY_TRADE 10 // Adds/removes traders.
-#define SS_PRIORITY_GHOST_IMAGES 10 // Updates ghost client images.
-#define SS_PRIORITY_ZCOPY 10 // Builds appearances for Z-Mimic.
+#define SS_PRIORITY_TICKER 100 // Gameticker.
+#define SS_PRIORITY_MOB 95 // Mob Life().
+#define SS_PRIORITY_MACHINERY 95 // Machinery + powernet ticks.
+#define SS_PRIORITY_AIR 80 // ZAS processing.
+#define SS_PRIORITY_THROWING 75 // Throwing calculation and constant checks
+#define SS_PRIORITY_MATERIALS 60 // Multi-tick chemical reactions.
+#define SS_PRIORITY_LIGHTING 50 // Queued lighting engine updates.
+#define SS_PRIORITY_SPACEDRIFT 40 // Drifting things.
+#define SS_PRIORITY_INPUT 20 // Input things.
+#define SS_PRIORITY_ICON_UPDATE 20 // Queued icon updates. Mostly used by APCs and tables.
+#define SS_PRIORITY_VIS_CONTENTS 20 // Queued vis_contents updates.
+#define SS_PRIORITY_AMBIENCE 20 // Queued ambient lighting updates.
+#define SS_PRIORITY_ALARM 20 // Alarm processing.
+#define SS_PRIORITY_EVENT 20 // Event processing and queue handling.
+#define SS_PRIORITY_SHUTTLE 20 // Shuttle movement.
+#define SS_PRIORITY_CIRCUIT_COMP 20 // Processing circuit component do_work.
+#define SS_PRIORITY_TEMPERATURE 20 // Cooling and heating of atoms.
+#define SS_PRIORITY_RADIATION 20 // Radiation processing and cache updates.
+#define SS_PRIORITY_OPEN_SPACE 20 // Open turf updates.
+#define SS_PRIORITY_AIRFLOW 15 // Object movement from ZAS airflow.
+#define SS_PRIORITY_FLUIDS 11 // Liquid flows.
+#define SS_PRIORITY_VOTE 10 // Vote management.
+#define SS_PRIORITY_INACTIVITY 10 // Idle kicking.
+#define SS_PRIORITY_SUPPLY 10 // Supply point accumulation.
+#define SS_PRIORITY_TRADE 10 // Adds/removes traders.
+#define SS_PRIORITY_GHOST_IMAGES 10 // Updates ghost client images.
+#define SS_PRIORITY_ZCOPY 10 // Builds appearances for Z-Mimic.
+#define SS_PRIORITY_PROJECTILES 10 // Projectile processing!
+#define SS_PRIORITY_PATHFINDING 10 // Processing pathfinding requests
// SS_BACKGROUND
-#define SS_PRIORITY_OBJECTS 100 // processing_objects processing.
-#define SS_PRIORITY_PROCESSING 95 // Generic datum processor. Replaces objects processor.
-#define SS_PRIORITY_PLANTS 90 // Plant processing, slow ticks.
-#define SS_PRIORITY_VINES 50 // Spreading vine effects.
-#define SS_PRIORITY_PSYCHICS 45 // Psychic complexus processing.
-#define SS_PRIORITY_AI 45 // Artificial Intelligence on mobs processing.
-#define SS_PRIORITY_NANO 40 // Updates to nanoui uis.
-#define SS_PRIORITY_TURF 30 // Radioactive walls/blob.
-#define SS_PRIORITY_EVAC 30 // Processes the evac controller.
-#define SS_PRIORITY_CIRCUIT 30 // Processing Circuit's ticks and all that
-#define SS_PRIORITY_GRAPH 30 // Merging and splitting of graphs
-#define SS_PRIORITY_CHAR_SETUP 25 // Writes player preferences to savefiles.
-#define SS_PRIORITY_COMPUTER_NETS 25 // Handles computer network devices hookups
-#define SS_PRIORITY_GARBAGE 20 // Garbage collection.
-
+#define SS_PRIORITY_OBJECTS 100 // processing_objects processing.
+#define SS_PRIORITY_OVERMAP 95 // Moving objects on the overmap.
+#define SS_PRIORITY_PROCESSING 95 // Generic datum processor. Replaces objects processor.
+#define SS_PRIORITY_PLANTS 90 // Plant processing, slow ticks.
+#define SS_PRIORITY_VINES 50 // Spreading vine effects.
+#define SS_PRIORITY_MOB_AI 45 // Mob AI logic; finding targets, attacking, etc.
+#define SS_PRIORITY_AUTO_MOVE 42 // Automated atom movement, fires much more frequently than MOB_AI.
+#define SS_PRIORITY_NANO 40 // Updates to nanoui uis.
+#define SS_PRIORITY_TURF 30 // Radioactive walls/blob.
+#define SS_PRIORITY_EVAC 30 // Processes the evac controller.
+#define SS_PRIORITY_CIRCUIT 30 // Processing Circuit's ticks and all that
+#define SS_PRIORITY_GRAPH 30 // Merging and splitting of graphs
+#define SS_PRIORITY_CHAR_SETUP 25 // Writes player preferences to savefiles.
+#define SS_PRIORITY_COMPUTER_NETS 25 // Handles computer network devices hookups
+#define SS_PRIORITY_GARBAGE 20 // Garbage collection.
+#define SS_PRIORITY_WEATHER 10 // Weather processing.
+#define SS_PRIORITY_DAYCYCLE 10 // Day cycle processing on planetoids
+#define SS_PRIORITY_BLOB 0 // Blob processing.
+#define SS_PRIORITY_ITEM_EFFECTS 0 // Weapon effect processing.
// Subsystem fire priority, from lowest to highest priority
// If the subsystem isn't listed here it's either DEFAULT or PROCESS (if it's a processing subsystem child)
diff --git a/code/__defines/subsystems.dm b/code/__defines/subsystems.dm
index 7a48aa815e32..87f4b099d0f5 100644
--- a/code/__defines/subsystems.dm
+++ b/code/__defines/subsystems.dm
@@ -1,7 +1,6 @@
#define INITIALIZATION_INSSATOMS 0 //New should not call Initialize
-#define INITIALIZATION_INSSATOMS_LATE 1 //New should not call Initialize; after the first pass is complete (handled differently)
-#define INITIALIZATION_INNEW_MAPLOAD 2 //New should call Initialize(TRUE)
-#define INITIALIZATION_INNEW_REGULAR 3 //New should call Initialize(FALSE)
+#define INITIALIZATION_INNEW_MAPLOAD 1 //New should call Initialize(TRUE)
+#define INITIALIZATION_INNEW_REGULAR 2 //New should call Initialize(FALSE)
#define INITIALIZE_HINT_NORMAL 0 //Nothing happens
#define INITIALIZE_HINT_LATELOAD 1 //Call LateInitialize
@@ -20,22 +19,26 @@
// Subsystems shutdown in the reverse of the order they initialize in
// The numbers just define the ordering, they are meaningless otherwise.
-#define SS_INIT_EARLY 19
+#define SS_INIT_INPUT 23
+#define SS_INIT_EARLY 22
+#define SS_INIT_WEBHOOKS 21
+#define SS_INIT_MODPACKS 20
+#define SS_INIT_SECRETS 19
#define SS_INIT_GARBAGE 18
-#define SS_INIT_MATERIALS 17
-#define SS_INIT_PLANTS 16
-#define SS_INIT_ANTAGS 15
+#define SS_INIT_SERDE 17
+#define SS_INIT_MATERIALS 16
+#define SS_INIT_PLANTS 15
#define SS_INIT_LORE 14
#define SS_INIT_MISC 13
#define SS_INIT_SKYBOX 12
#define SS_INIT_MAPPING 11
-#define SS_INIT_DEPARTMENTS 10
-#define SS_INIT_JOBS 9
-#define SS_INIT_CHAR_SETUP 8
-#define SS_INIT_CIRCUIT 7
-#define SS_INIT_GRAPH 6
-#define SS_INIT_OPEN_SPACE 5
-#define SS_INIT_ATOMS 4
+#define SS_INIT_JOBS 10
+#define SS_INIT_CIRCUIT 9
+#define SS_INIT_GRAPH 8
+#define SS_INIT_OPEN_SPACE 7
+#define SS_INIT_ATOMS 6
+#define SS_INIT_PRE_CHAR_SETUP 5
+#define SS_INIT_CHAR_SETUP 4
#define SS_INIT_MACHINES 3
#define SS_INIT_ICON_UPDATE 2
#define SS_INIT_OVERLAY 1
@@ -45,20 +48,23 @@
#define SS_INIT_MISC_CODEX -3
#define SS_INIT_ALARM -4
#define SS_INIT_SHUTTLE -5
-#define SS_INIT_GOALS -5
-#define SS_INIT_LIGHTING -6
-#define SS_INIT_ZCOPY -7
-#define SS_INIT_XENOARCH -10
-#define SS_INIT_BAY_LEGACY -12
+#define SS_INIT_GOALS -6
+#define SS_INIT_LIGHTING -7
+#define SS_INIT_WEATHER -8
+#define SS_INIT_VIS_CONTENTS -9
+#define SS_INIT_ZCOPY -10
+#define SS_INIT_HOLOMAP -11
+#define SS_INIT_XENOARCH -12
#define SS_INIT_TICKER -20
#define SS_INIT_UNIT_TESTS -100
// SS runlevels
-
#define RUNLEVEL_INIT 0
#define RUNLEVEL_LOBBY 1
#define RUNLEVEL_SETUP 2
#define RUNLEVEL_GAME 4
#define RUNLEVEL_POSTGAME 8
-
+/// default runlevels for most subsystems
#define RUNLEVELS_DEFAULT (RUNLEVEL_SETUP | RUNLEVEL_GAME | RUNLEVEL_POSTGAME)
+/// all valid runlevels - subsystems with this will run all the time after their MC init stage.
+#define RUNLEVELS_ALL (RUNLEVEL_LOBBY | RUNLEVEL_SETUP | RUNLEVEL_GAME | RUNLEVEL_POSTGAME)
diff --git a/code/__defines/temperature.dm b/code/__defines/temperature.dm
index 098cdf3ee3eb..8258b1001f6e 100644
--- a/code/__defines/temperature.dm
+++ b/code/__defines/temperature.dm
@@ -1,22 +1,41 @@
-#define ATOM_IS_TEMPERATURE_SENSITIVE(A) (A && !QDELETED(A) && !(A.atom_flags & ATOM_FLAG_NO_TEMP_CHANGE))
+#define ATOM_IS_TEMPERATURE_SENSITIVE(A) (istype(A) && A.simulated && A.temperature_sensitive)
+#define ATOM_SHOULD_TEMPERATURE_ENQUEUE(A) (ATOM_IS_TEMPERATURE_SENSITIVE(A) && !QDELETED(A))
#define ATOM_TEMPERATURE_EQUILIBRIUM_THRESHOLD 5
-#define ATOM_TEMPERATURE_EQUILIBRIUM_CONSTANT 0.25
+#define MIN_TEMPERATURE_COEFFICIENT 1
+#define MAX_TEMPERATURE_COEFFICIENT 10
+#define THERMAL_MASS_CONSTANT 1
#define ADJUST_ATOM_TEMPERATURE(_atom, _temp) \
_atom.temperature = _temp; \
- if(_atom.reagents) { \
- HANDLE_REACTIONS(_atom.reagents); \
- } \
- QUEUE_TEMPERATURE_ATOMS(_atom);
+ HANDLE_REACTIONS(_atom.reagents); \
+ queue_temperature_atoms(_atom);
-#define QUEUE_TEMPERATURE_ATOMS(_atoms) \
+#define QUEUE_TEMPERATURE_ATOM(_atom) \
+ if(ATOM_SHOULD_TEMPERATURE_ENQUEUE(_atom)) { \
+ SStemperature.processing[_atom] = TRUE; \
+ }
+
+#define UNQUEUE_TEMPERATURE_ATOMS(_atoms) \
if(islist(_atoms)) { \
for(var/thing in _atoms) { \
var/atom/A = thing; \
- if(ATOM_IS_TEMPERATURE_SENSITIVE(A)) { \
- SStemperature.processing[A] = TRUE; \
- } \
+ UNQUEUE_TEMPERATURE_ATOM(A); \
} \
- } else if(ATOM_IS_TEMPERATURE_SENSITIVE(_atoms)) { \
- SStemperature.processing[_atoms] = TRUE; \
+ } else { \
+ UNQUEUE_TEMPERATURE_ATOM(_atoms); \
+ }
+
+#define UNQUEUE_TEMPERATURE_ATOM(_atom) \
+ if(ATOM_IS_TEMPERATURE_SENSITIVE(_atom)) { \
+ SStemperature.processing -= _atom; \
}
+
+
+// This is a proc primarily for profiling purposes.
+/proc/queue_temperature_atoms(var/atom/atom)
+ if(islist(atom))
+ for(var/thing in atom)
+ var/atom/A = thing
+ QUEUE_TEMPERATURE_ATOM(A)
+ else if(atom)
+ QUEUE_TEMPERATURE_ATOM(atom)
diff --git a/code/__defines/template_tags.dm b/code/__defines/template_tags.dm
new file mode 100644
index 000000000000..1da57b5307f9
--- /dev/null
+++ b/code/__defines/template_tags.dm
@@ -0,0 +1,9 @@
+//Flags for exoplanet ruin picking
+
+#define TEMPLATE_TAG_HABITAT BITFLAG(0) //long term habitat
+#define TEMPLATE_TAG_HUMAN BITFLAG(1) //human-made structure
+#define TEMPLATE_TAG_ALIEN BITFLAG(2) //artificial structure of an unknown origin
+#define TEMPLATE_TAG_WRECK BITFLAG(3) //crashed vessel
+#define TEMPLATE_TAG_NATURAL BITFLAG(4) //naturally occuring structure
+#define TEMPLATE_TAG_WATER BITFLAG(5) //ruin depending on planet having water accessible
+#define TEMPLATE_TAG_HABITABLE BITFLAG(6) //ruin depending on planet being habitable
diff --git a/code/__defines/time.dm b/code/__defines/time.dm
index 3d42eb81b50f..5c4e68a23449 100644
--- a/code/__defines/time.dm
+++ b/code/__defines/time.dm
@@ -10,7 +10,6 @@
#define DAY *864000
#define DAYS *864000
-#define TimeOfGame (get_game_time())
#define TimeOfTick (world.tick_usage*0.01*world.tick_lag)
#define TICKS *world.tick_lag
diff --git a/code/__defines/tools.dm b/code/__defines/tools.dm
new file mode 100644
index 000000000000..4b0065e96b71
--- /dev/null
+++ b/code/__defines/tools.dm
@@ -0,0 +1,102 @@
+// Engineering tools.
+#define TOOL_WELDER /decl/tool_archetype/welder
+#define TOOL_CABLECOIL /decl/tool_archetype/cable_coil
+#define TOOL_WIRECUTTERS /decl/tool_archetype/wirecutters
+#define TOOL_SCREWDRIVER /decl/tool_archetype/screwdriver
+#define TOOL_MULTITOOL /decl/tool_archetype/multitool
+#define TOOL_CROWBAR /decl/tool_archetype/crowbar
+#define TOOL_HATCHET /decl/tool_archetype/hatchet
+#define TOOL_WRENCH /decl/tool_archetype/wrench
+#define TOOL_SHOVEL /decl/tool_archetype/shovel
+#define TOOL_PICK /decl/tool_archetype/pick
+#define TOOL_HAMMER /decl/tool_archetype/hammer
+#define TOOL_KNIFE /decl/tool_archetype/knife
+#define TOOL_HOE /decl/tool_archetype/hoe
+
+// Misc tools.
+#define TOOL_PEN /decl/tool_archetype/pen
+#define TOOL_STAMP /decl/tool_archetype/stamp
+#define TOOL_SHEARS /decl/tool_archetype/shears
+#define TOOL_CHISEL /decl/tool_archetype/chisel
+
+// Surgical tools.
+#define TOOL_SCALPEL /decl/tool_archetype/scalpel
+#define TOOL_RETRACTOR /decl/tool_archetype/retractor
+#define TOOL_HEMOSTAT /decl/tool_archetype/hemostat
+#define TOOL_SAW /decl/tool_archetype/saw
+#define TOOL_CAUTERY /decl/tool_archetype/cautery
+#define TOOL_SUTURES /decl/tool_archetype/sutures
+#define TOOL_BONE_GEL /decl/tool_archetype/bone_gel
+#define TOOL_BONE_SETTER /decl/tool_archetype/bone_setter
+#define TOOL_SURGICAL_DRILL /decl/tool_archetype/surgical_drill
+
+// Tool qualities (positive multplier)
+#define TOOL_QUALITY_NONE 0
+#define TOOL_QUALITY_WORST 0.1
+#define TOOL_QUALITY_BAD 0.5
+#define TOOL_QUALITY_MEDIOCRE 0.75
+#define TOOL_QUALITY_DEFAULT 1
+#define TOOL_QUALITY_DECENT 1.2
+#define TOOL_QUALITY_GOOD 1.5
+#define TOOL_QUALITY_BEST 2
+
+// Tool speeds (smaller values mean a shorter delay)
+#define TOOL_SPEED_WORST 3
+#define TOOL_SPEED_MEDIOCRE 2
+#define TOOL_SPEED_DEFAULT 1
+#define TOOL_SPEED_BEST 0.5
+
+// Helper macros for interaction checks.
+#define IS_TOOL(A, T) (isatom(A) && A.get_tool_quality(T) > 0)
+#define IS_SAW(A) IS_TOOL(A, TOOL_SAW)
+#define IS_WRENCH(A) IS_TOOL(A, TOOL_WRENCH)
+#define IS_WELDER(A) IS_TOOL(A, TOOL_WELDER)
+#define IS_COIL(A) IS_TOOL(A, TOOL_CABLECOIL)
+#define IS_WIRECUTTER(A) IS_TOOL(A, TOOL_WIRECUTTERS)
+#define IS_SCREWDRIVER(A) IS_TOOL(A, TOOL_SCREWDRIVER)
+#define IS_MULTITOOL(A) IS_TOOL(A, TOOL_MULTITOOL)
+#define IS_CROWBAR(A) IS_TOOL(A, TOOL_CROWBAR)
+#define IS_HATCHET(A) IS_TOOL(A, TOOL_HATCHET)
+#define IS_SHOVEL(A) IS_TOOL(A, TOOL_SHOVEL)
+#define IS_PEN(A) IS_TOOL(A, TOOL_PEN)
+#define IS_PICK(A) IS_TOOL(A, TOOL_PICK)
+#define IS_KNIFE(A) IS_TOOL(A, TOOL_KNIFE)
+#define IS_HAMMER(A) IS_TOOL(A, TOOL_HAMMER)
+#define IS_HOE(A) IS_TOOL(A, TOOL_HOE)
+#define IS_SHEARS(A) IS_TOOL(A, TOOL_SHEARS)
+#define IS_CHISEL(A) IS_TOOL(A, TOOL_CHISEL)
+#define IS_HEMOSTAT(A) IS_TOOL(A, TOOL_HEMOSTAT)
+#define IS_RETRACTOR(A) IS_TOOL(A, TOOL_RETRACTOR)
+
+// Structure interaction flags
+#define TOOL_INTERACTION_NONE 0
+#define TOOL_INTERACTION_ANCHOR BITFLAG(0)
+#define TOOL_INTERACTION_DECONSTRUCT BITFLAG(1)
+#define TOOL_INTERACTION_WIRING BITFLAG(2)
+#define TOOL_INTERACTION_ALL (TOOL_INTERACTION_ANCHOR | TOOL_INTERACTION_DECONSTRUCT | TOOL_INTERACTION_WIRING)
+
+// Codex strings for looking up tool information.
+#define TOOL_CODEX_WRENCH "wrench (tool)"
+#define TOOL_CODEX_SCREWDRIVER "screwdriver (tool)"
+#define TOOL_CODEX_WIRECUTTERS "wirecutters (tool)"
+#define TOOL_CODEX_WELDER "welder (tool)"
+#define TOOL_CODEX_CROWBAR "crowbar (tool)"
+#define TOOL_CODEX_MULTITOOL "multitool (tool)"
+
+// Tool properties for tool specific stuff
+#define TOOL_PROP_VERB "use_verb"
+#define TOOL_PROP_SOUND "use_sound"
+#define TOOL_PROP_COLOR_NAME "color_name" //Property containing a color name for some tools. Namely the pen tool.
+#define TOOL_PROP_COLOR "color" //Property for specifying a color, for something like a pen.
+#define TOOL_PROP_USES "uses_left" //Property for things that have a fixed amount of uses. -1 is unlimited.
+#define TOOL_PROP_EMPTY_MESSAGE "empty_msg" //The message given on depletion when a tool runs out of charges.
+
+//Pen specific stuff
+#define TOOL_PROP_PEN_FLAG "pen_flag" //Property for pens to specify additional properties about themselves
+#define TOOL_PROP_PEN_SIG "signature" //Property for pens specifically. Returns a stored forged signature if there's one.
+#define TOOL_PROP_PEN_SHADE_COLOR "shade_color" //Property for pens returns the shade color if applicable
+///Property for pens returns the font the pen uses
+#define TOOL_PROP_PEN_FONT "pen_font"
+
+// Property for xenoarch.
+#define TOOL_PROP_EXCAVATION_DEPTH "excav_depth"
\ No newline at end of file
diff --git a/code/__defines/topic.dm b/code/__defines/topic.dm
index 981de408f906..219abf3728e4 100644
--- a/code/__defines/topic.dm
+++ b/code/__defines/topic.dm
@@ -1,3 +1,9 @@
-#define TOPIC_NOACTION 0
-#define TOPIC_HANDLED 1
-#define TOPIC_REFRESH 2
+#define TOPIC_NOACTION 0
+#define TOPIC_HANDLED BITFLAG(0)
+#define TOPIC_REFRESH BITFLAG(1)
+#define TOPIC_UPDATE_PREVIEW BITFLAG(2)
+/// Return this to force a browse() call, unblocking some rsc operations
+#define TOPIC_HARD_REFRESH BITFLAG(3)
+/// Return this to indicate the window associated with this Topic() call should be closed.
+#define TOPIC_CLOSE BITFLAG(4)
+#define TOPIC_REFRESH_UPDATE_PREVIEW (TOPIC_HARD_REFRESH|TOPIC_UPDATE_PREVIEW)
diff --git a/code/__defines/traits.dm b/code/__defines/traits.dm
new file mode 100644
index 000000000000..2404c521bc13
--- /dev/null
+++ b/code/__defines/traits.dm
@@ -0,0 +1,72 @@
+#define TRAIT_LEVEL_EXISTS 0
+#define TRAIT_LEVEL_MINOR 1
+#define TRAIT_LEVEL_MODERATE 2
+#define TRAIT_LEVEL_MAJOR 3
+
+#define DEFINE_ROBOLIMB_MODEL_TRAITS(MODEL_PATH, MODEL_ID, COST, MODEL_STRING) \
+/decl/trait/prosthetic_limb/left_hand/##MODEL_ID { \
+ model = MODEL_PATH; \
+ parent = /decl/trait/prosthetic_limb/left_hand; \
+ trait_cost = COST * 0.5; \
+ uid = "trait_prosthetic_left_hand_" + MODEL_STRING; \
+} \
+/decl/trait/prosthetic_limb/left_arm/##MODEL_ID { \
+ model = MODEL_PATH; \
+ parent = /decl/trait/prosthetic_limb/left_arm; \
+ trait_cost = COST; \
+ uid = "trait_prosthetic_left_arm_" + MODEL_STRING; \
+} \
+/decl/trait/prosthetic_limb/right_hand/##MODEL_ID { \
+ model = MODEL_PATH; \
+ parent = /decl/trait/prosthetic_limb/right_hand; \
+ trait_cost = COST * 0.5; \
+ uid = "trait_prosthetic_right_hand_" + MODEL_STRING; \
+} \
+/decl/trait/prosthetic_limb/right_arm/##MODEL_ID { \
+ model = MODEL_PATH; \
+ parent = /decl/trait/prosthetic_limb/right_arm; \
+ trait_cost = COST; \
+ uid = "trait_prosthetic_right_arm_" + MODEL_STRING; \
+} \
+/decl/trait/prosthetic_limb/left_foot/##MODEL_ID { \
+ model = MODEL_PATH; \
+ parent = /decl/trait/prosthetic_limb/left_foot; \
+ trait_cost = COST * 0.5; \
+ uid = "trait_prosthetic_left_foot_" + MODEL_STRING; \
+} \
+/decl/trait/prosthetic_limb/left_leg/##MODEL_ID { \
+ model = MODEL_PATH; \
+ parent = /decl/trait/prosthetic_limb/left_leg; \
+ trait_cost = COST; \
+ uid = "trait_prosthetic_left_leg_" + MODEL_STRING; \
+} \
+/decl/trait/prosthetic_limb/right_foot/##MODEL_ID { \
+ model = MODEL_PATH; \
+ parent = /decl/trait/prosthetic_limb/right_foot; \
+ trait_cost = COST * 0.5; \
+ uid = "trait_prosthetic_right_foot_" + MODEL_STRING; \
+} \
+/decl/trait/prosthetic_limb/right_leg/##MODEL_ID { \
+ model = MODEL_PATH; \
+ parent = /decl/trait/prosthetic_limb/right_leg; \
+ trait_cost = COST; \
+ uid = "trait_prosthetic_right_leg_" + MODEL_STRING; \
+} \
+/decl/trait/prosthetic_limb/head/##MODEL_ID { \
+ model = MODEL_PATH; \
+ parent = /decl/trait/prosthetic_limb/head; \
+ trait_cost = COST * 0.5; \
+ uid = "trait_prosthetic_head_" + MODEL_STRING; \
+} \
+/decl/trait/prosthetic_limb/chest/##MODEL_ID { \
+ model = MODEL_PATH; \
+ parent = /decl/trait/prosthetic_limb/chest; \
+ trait_cost = COST * 0.5; \
+ uid = "trait_prosthetic_chest_" + MODEL_STRING; \
+} \
+/decl/trait/prosthetic_limb/groin/##MODEL_ID { \
+ model = MODEL_PATH; \
+ parent = /decl/trait/prosthetic_limb/groin; \
+ trait_cost = COST * 0.5; \
+ uid = "trait_prosthetic_groin_" + MODEL_STRING; \
+}
diff --git a/code/__defines/turfs.dm b/code/__defines/turfs.dm
index 94e4fd49a5a8..6c46f5f1a9fb 100644
--- a/code/__defines/turfs.dm
+++ b/code/__defines/turfs.dm
@@ -1,16 +1,11 @@
-#define TURF_REMOVE_CROWBAR 1
-#define TURF_REMOVE_SCREWDRIVER 2
-#define TURF_REMOVE_SHOVEL 4
-#define TURF_REMOVE_WRENCH 8
-#define TURF_CAN_BREAK 16
-#define TURF_CAN_BURN 32
-#define TURF_HAS_EDGES 64
-#define TURF_HAS_CORNERS 128
-#define TURF_HAS_INNER_CORNERS 256
-#define TURF_IS_FRAGILE 512
-#define TURF_ACID_IMMUNE 1024
-#define TURF_IS_WET 2048
-#define TURF_HAS_RANDOM_BORDER 4096
+#define TURF_REMOVE_CROWBAR BITFLAG(0)
+#define TURF_REMOVE_SCREWDRIVER BITFLAG(1)
+#define TURF_REMOVE_SHOVEL BITFLAG(2)
+#define TURF_REMOVE_WRENCH BITFLAG(3)
+#define TURF_IS_FRAGILE BITFLAG(4)
+#define TURF_ACID_IMMUNE BITFLAG(5)
+#define TURF_IS_WET BITFLAG(6)
+#define TURF_HAS_RANDOM_BORDER BITFLAG(7)
//Used for floor/wall smoothing
#define SMOOTH_NONE 0 //Smooth only with itself
@@ -18,4 +13,35 @@
#define SMOOTH_WHITELIST 2 //Smooth with a whitelist of subtypes
#define SMOOTH_BLACKLIST 3 //Smooth with all but a blacklist of subtypes
-#define RANGE_TURFS(CENTER, RADIUS) block(locate(max(CENTER.x-(RADIUS), 1), max(CENTER.y-(RADIUS),1), CENTER.z), locate(min(CENTER.x+(RADIUS), world.maxx), min(CENTER.y+(RADIUS), world.maxy), CENTER.z))
+#define RANGE_TURFS(CENTER, RADIUS) block(max(CENTER.x-(RADIUS), 1), max(CENTER.y-(RADIUS),1), CENTER.z, min(CENTER.x+(RADIUS), world.maxx), min(CENTER.y+(RADIUS), world.maxy), CENTER.z)
+#define Z_ALL_TURFS(Z) block(1, 1, Z, world.maxx, world.maxy)
+
+//Here are a few macros to help with people always forgetting to round the coordinates somewhere, and forgetting that not everything automatically rounds decimals.
+///Helper macro for the x coordinate of the turf at the center of the world. Handles rounding.
+#define WORLD_CENTER_X ceil((1 + world.maxx) / 2)
+///Helper macro for the y coordinate of the turf at the center of the world. Handles rounding.
+#define WORLD_CENTER_Y ceil((1 + world.maxy) / 2)
+///Helper macro for getting the center turf on a given z-level. Handles rounding.
+#define WORLD_CENTER_TURF(Z) locate(WORLD_CENTER_X, WORLD_CENTER_Y, Z)
+///Helper macro to check if a position is within the world's bounds.
+#define IS_WITHIN_WORLD(X, Y) ((X > 0) && (Y > 0) && (X <= world.maxx) && (Y <= world.maxy))
+///Helper macro for printing to text the world's x,y,z size to a string.
+#define WORLD_SIZE_TO_STRING "[world.maxx]x[world.maxy]x[world.maxz]"
+
+#define FLOOR_EDGE_NONE -1
+#define FLOOR_LAYER_CONSTANT 0.001
+#define FLOOR_LAYER_OCEAN (10 * FLOOR_LAYER_CONSTANT)
+#define FLOOR_EDGE_SEAFLOOR (11 * FLOOR_LAYER_CONSTANT)
+#define FLOOR_EDGE_VOLCANIC (12 * FLOOR_LAYER_CONSTANT)
+#define FLOOR_EDGE_DIRT (20 * FLOOR_LAYER_CONSTANT)
+#define FLOOR_EDGE_BARREN (21 * FLOOR_LAYER_CONSTANT)
+#define FLOOR_EDGE_CLAY (21 * FLOOR_LAYER_CONSTANT)
+#define FLOOR_EDGE_MUD (22 * FLOOR_LAYER_CONSTANT)
+#define FLOOR_EDGE_SAND (30 * FLOOR_LAYER_CONSTANT)
+#define FLOOR_EDGE_CHLORINE_SAND (50 * FLOOR_LAYER_CONSTANT)
+#define FLOOR_EDGE_WATER (50 * FLOOR_LAYER_CONSTANT)
+#define FLOOR_EDGE_GRASS (55 * FLOOR_LAYER_CONSTANT)
+#define FLOOR_EDGE_PATH (60 * FLOOR_LAYER_CONSTANT)
+#define FLOOR_EDGE_GRASS_WILD (65 * FLOOR_LAYER_CONSTANT)
+#define FLOOR_EDGE_SNOW (70 * FLOOR_LAYER_CONSTANT)
+#define FLOOR_EDGE_CARPET (75 * FLOOR_LAYER_CONSTANT)
diff --git a/code/__defines/unit_tests.dm b/code/__defines/unit_tests.dm
new file mode 100644
index 000000000000..dbd67aab94d8
--- /dev/null
+++ b/code/__defines/unit_tests.dm
@@ -0,0 +1,8 @@
+
+#define UT_NORMAL 1 // Standard one atmosphere 20celsius
+#define UT_VACUUM 2 // Vacume on simulated turfs
+#define UT_NORMAL_COLD 3 // Cold but standard atmosphere.
+
+#define FAILURE 0
+#define SUCCESS 1
+#define SKIP 2
diff --git a/code/__defines/webhooks.dm b/code/__defines/webhooks.dm
index a82151df3384..57fe27fefc06 100644
--- a/code/__defines/webhooks.dm
+++ b/code/__defines/webhooks.dm
@@ -6,3 +6,5 @@
#define WEBHOOK_SUBMAP_LOADED "webhook_submap_loaded"
#define WEBHOOK_CUSTOM_EVENT "webhook_custom_event"
#define WEBHOOK_ELEVATOR_FALL "webhook_elevator_fall"
+#define WEBHOOK_AHELP_SENT "webhook_ahelp_sent"
+#define WEBHOOK_FAX_SENT "webhook_fax_sent"
diff --git a/code/__defines/xenoarcheaology.dm b/code/__defines/xenoarcheaology.dm
index cc615c0a1cac..488ff4790670 100644
--- a/code/__defines/xenoarcheaology.dm
+++ b/code/__defines/xenoarcheaology.dm
@@ -1,16 +1,3 @@
-#define XENOFIND_APPLY_PREFIX (2 << 0)
-#define XENOFIND_APPLY_DECOR (2 << 1)
-#define XENOFIND_REPLACE_ICON (2 << 2)
-
-#define EFFECT_TOUCH 0
-#define EFFECT_AURA 1
-#define EFFECT_PULSE 2
-#define MAX_EFFECT 2
-
-#define EFFECT_UNKNOWN 0
-#define EFFECT_ENERGY 1
-#define EFFECT_PSIONIC 2
-#define EFFECT_ELECTRO 3
-#define EFFECT_PARTICLE 4
-#define EFFECT_ORGANIC 5
-#define EFFECT_SYNTH 6
\ No newline at end of file
+#define XENOFIND_APPLY_PREFIX BITFLAG(0)
+#define XENOFIND_APPLY_DECOR BITFLAG(1)
+#define XENOFIND_REPLACE_ICON BITFLAG(2)
diff --git a/code/__defines/zmimic.dm b/code/__defines/zmimic.dm
index 5f48020fb445..a9af1b126f5c 100644
--- a/code/__defines/zmimic.dm
+++ b/code/__defines/zmimic.dm
@@ -1,24 +1,58 @@
-#define TURF_IS_MIMICING(T) (isturf(T) && (T:z_flags & ZM_MIMIC_BELOW))
-#define CHECK_OO_EXISTENCE(OO) if (OO && !TURF_IS_MIMICING(OO.loc)) { qdel(OO); }
+#define ZM_DESTRUCTION_TIMER(TARGET) addtimer(CALLBACK(TARGET, TYPE_PROC_REF(/datum, qdel_self)), 10 SECONDS, TIMER_STOPPABLE)
+#define TURF_IS_MIMICKING(T) (isturf(T) && (T:z_flags & ZM_MIMIC_BELOW))
+#define CHECK_OO_EXISTENCE(OO) if (OO && !MOVABLE_IS_ON_ZTURF(OO) && !OO.destruction_timer) { OO.destruction_timer = ZM_DESTRUCTION_TIMER(OO); }
#define UPDATE_OO_IF_PRESENT CHECK_OO_EXISTENCE(bound_overlay); if (bound_overlay) { update_above(); }
+// I do not apologize.
+
+// These aren't intended to be used anywhere else, they just can't be undef'd because DM is dum.
+#define ZM_INTERNAL_SCAN_LOOKAHEAD(M,VTR,F) ((get_step(M, M:dir)?:VTR & F) || (get_step(M, turn(M:dir, 180))?:VTR & F))
+#define ZM_INTERNAL_SCAN_LOOKBESIDE(M,VTR,F) ((get_step(M, turn(M:dir, 90))?:VTR & F) || (get_step(M, turn(M:dir, -90))?:VTR & F))
+
+/// Is this movable visible from a turf that is mimicking below? Note: this does not necessarily mean *directly* below.
+#define MOVABLE_IS_BELOW_ZTURF(M) (\
+ isturf(M:loc) && (TURF_IS_MIMICKING(M:loc:above) \
+ || ((M:z_flags & ZMM_LOOKAHEAD) && ZM_INTERNAL_SCAN_LOOKAHEAD(M, above?:z_flags, ZM_MIMIC_BELOW)) \
+ || ((M:z_flags & ZMM_LOOKBESIDE) && ZM_INTERNAL_SCAN_LOOKBESIDE(M, above?:z_flags, ZM_MIMIC_BELOW))) \
+)
+/// Is this movable located on a turf that is mimicking below? Note: this does not necessarily mean *directly* on.
+#define MOVABLE_IS_ON_ZTURF(M) (\
+ (TURF_IS_MIMICKING(M:loc) \
+ || ((M:z_flags & ZMM_LOOKAHEAD) && ZM_INTERNAL_SCAN_LOOKAHEAD(M, z_flags, ZM_MIMIC_BELOW)) \
+ || ((M:z_flags & ZMM_LOOKBESIDE) && ZM_INTERNAL_SCAN_LOOKBESIDE(M, z_flags, ZM_MIMIC_BELOW))) \
+)
+#define MOVABLE_SHALL_MIMIC(AM) (!(AM.z_flags & ZMM_IGNORE) && MOVABLE_IS_BELOW_ZTURF(AM))
+
// Turf MZ flags.
-#define ZM_MIMIC_BELOW 1 // If this turf should mimic the turf on the Z below.
-#define ZM_MIMIC_OVERWRITE 2 // If this turf is Z-mimicing, overwrite the turf's appearance instead of using a movable. This is faster, but means the turf cannot have its own appearance (say, edges or a translucent sprite).
-#define ZM_ALLOW_LIGHTING 4 // If this turf should permit passage of lighting.
-#define ZM_ALLOW_ATMOS 8 // If this turf permits passage of air.
-#define ZM_MIMIC_NO_AO 16 // If the turf shouldn't apply regular turf AO and only do Z-mimic AO.
-#define ZM_FIX_BIGTURF 32 // Fix bigturf (greater than world.icon_size) rendering at the cost of breaking object layering a bit. This flag is infectious, so all Z-turfs above this one will also get this flag. Valid on non-zturfs.
+#define ZM_MIMIC_BELOW 1 //! If this turf should mimic the turf on the Z below.
+#define ZM_MIMIC_OVERWRITE 2 //! If this turf is Z-mimicking, overwrite the turf's appearance instead of using a movable. This is faster, but means the turf cannot have its own appearance (say, edges or a translucent sprite).
+#define ZM_ALLOW_LIGHTING 4 //! If this turf should permit passage of lighting.
+#define ZM_ALLOW_ATMOS 8 //! If this turf permits passage of air.
+#define ZM_MIMIC_NO_AO 16 //! If the turf shouldn't apply regular turf AO and only do Z-mimic AO.
+#define ZM_NO_OCCLUDE 32 //! Don't occlude below atoms if we're a non-mimic z-turf.
+#define ZM_OVERRIDE 64 //! Copy only z_appearance or baseturf and bail, do not attempt to copy movables. This is significantly cheaper and allows you to override the mimic, but results in movables not being visible.
+#define ZM_NO_SHADOW 128 //! If this turf is being copied, hide the shadower.
+#define ZM_TERMINATOR 256 //! Consider this turf the terminus of a Z-group, like the bottom of a Z-group or a ZM_OVERRIDE turf.
-// Convenience flag.
-#define ZM_MIMIC_DEFAULTS (ZM_MIMIC_BELOW|ZM_ALLOW_LIGHTING)
+// Convenience flags.
+#define ZM_MIMIC_DEFAULTS (ZM_MIMIC_BELOW|ZM_ALLOW_LIGHTING) //! Common defaults for zturfs.
+#define ZMM_WIDE_LOAD (ZMM_LOOKAHEAD | ZMM_LOOKBESIDE) //! Atom is big and needs to scan one extra turf in both X and Y. This only extends the range by one turf. Cheap, but not free.
// For debug purposes, should contain the above defines in ascending order.
-var/list/mimic_defines = list(
+var/global/list/mimic_defines = list(
"ZM_MIMIC_BELOW",
"ZM_MIMIC_OVERWRITE",
"ZM_ALLOW_LIGHTING",
"ZM_ALLOW_ATMOS",
"ZM_MIMIC_NO_AO",
- "ZM_FIX_BIGTURF"
+ "ZM_NO_OCCLUDE",
+ "ZM_OVERRIDE",
+ "ZM_NO_SHADOW",
+ "ZM_TERMINATOR"
)
+
+// Movable flags.
+#define ZMM_IGNORE BITFLAG(0) //! Do not copy this movable.
+#define ZMM_MANGLE_PLANES BITFLAG(1) //! Check this movable's overlays/underlays for explicit plane use and mangle for compatibility with Z-Mimic. If you're using emissive overlays, you probably should be using this flag. Expensive, only use if necessary.
+#define ZMM_LOOKAHEAD BITFLAG(2) //! Look one turf ahead and one turf back when considering z-turfs that might be seeing this atom. Cheap, but not free.
+#define ZMM_LOOKBESIDE BITFLAG(3) //! Look one turf beside (left/right) when considering z-turfs that might be seeing this atom. Cheap, but not free.
diff --git a/code/__defines/~unit_testing.dm b/code/__defines/~unit_testing.dm
deleted file mode 100644
index 88eebd5aec1b..000000000000
--- a/code/__defines/~unit_testing.dm
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- *
- * This file is used by Travis to indicate that Unit Tests are to be ran.
- * Do not add anything but the UNIT_TEST definition here as it will be overwritten by Travis when running tests.
- *
- *
- * Should you wish to edit set UNIT_TEST to 1 like so:
- * #define UNIT_TEST 1
- */
-#define UNIT_TEST 0
diff --git a/code/__globals.dm b/code/__globals.dm
new file mode 100644
index 000000000000..a328e0649715
--- /dev/null
+++ b/code/__globals.dm
@@ -0,0 +1,33 @@
+// Defined here due to being used immediately below.
+#define GET_DECL(D) (ispath(D, /decl) ? (decls_repository.fetched_decls[D] || decls_repository.get_decl(D)) : null)
+#define IMPLIED_DECL GET_DECL(__IMPLIED_TYPE__)
+#define RESOLVE_TO_DECL(D) (istype(D, /decl) ? D : (istext(D) ? decls_repository.get_decl_by_id(D, validate_decl_type = FALSE) : GET_DECL(D)))
+#define DECLS_ARE_EQUIVALENT(F, S) ((RESOLVE_TO_DECL(F) == RESOLVE_TO_DECL(S)))
+
+// Defined here due to compile order; overrides in macros make the compiler complain.
+/decl/global_vars
+ var/static/list/protected_vars = list("protected_vars") // No editing the protected list!
+/decl/global_vars/Initialize()
+ . = ..()
+ mark_protected_vars()
+/decl/global_vars/proc/mark_protected_vars()
+ return
+
+#define GLOBAL_GETTER(NAME, TYPE, VAL) \
+var/global##TYPE/##NAME; \
+/proc/get_global_##NAME() { \
+ if(!global.##NAME) { global.##NAME = VAL } \
+ return global.##NAME; \
+}
+
+#define GLOBAL_GETTER_PROTECTED(NAME, TYPE, VAL) \
+GLOBAL_GETTER(NAME, TYPE, VAL) \
+/decl/global_vars/mark_protected_vars() { ..(); protected_vars += #NAME }
+
+#define GLOBAL_PROTECTED(NAME, TYPE, VAL) \
+var/global##TYPE/##NAME = VAL; \
+/decl/global_vars/mark_protected_vars() { ..(); protected_vars += #NAME }
+
+#define GLOBAL_PROTECTED_UNTYPED(NAME, VAL) \
+var/global/##NAME = VAL; \
+/decl/global_vars/mark_protected_vars() { ..(); protected_vars += #NAME }
diff --git a/code/_global_vars/client.dm b/code/_global_vars/client.dm
new file mode 100644
index 000000000000..5a8b7f1b1c5c
--- /dev/null
+++ b/code/_global_vars/client.dm
@@ -0,0 +1,29 @@
+// This is a mapping from JS keys to Byond - ref: https://keycode.info/
+var/global/list/_kbMap = list(
+ "UP" = "North",
+ "RIGHT" = "East",
+ "DOWN" = "South",
+ "LEFT" = "West",
+ "INSERT" = "Insert",
+ "HOME" = "Northwest",
+ "PAGEUP" = "Northeast",
+ "DEL" = "Delete",
+ "END" = "Southwest",
+ "PAGEDOWN" = "Southeast",
+ "SPACEBAR" = "Space",
+ "ALT" = "Alt",
+ "SHIFT" = "Shift",
+ "CONTROL" = "Ctrl"
+)
+
+// Without alt, shift, ctrl and etc because its not necessary
+var/global/list/_kbMap_reverse = list(
+ "North" = "Up",
+ "East" = "Right",
+ "South" = "Down",
+ "West" = "Left",
+ "Northwest" = "Home",
+ "Northeast" = "PageUp",
+ "Southwest" = "End",
+ "Southeast" = "PageDown",
+)
diff --git a/code/_global_vars/configuration.dm b/code/_global_vars/configuration.dm
index 77508c0ddf5d..377c65a2aa30 100644
--- a/code/_global_vars/configuration.dm
+++ b/code/_global_vars/configuration.dm
@@ -1,31 +1,20 @@
// Bomb cap!
-GLOBAL_VAR_INIT(max_explosion_range, 14)
+var/global/max_explosion_range = 14
+var/global/game_version = "Nebula"
+var/global/changelog_hash = ""
+var/global/join_motd = null
-
-var/href_logfile = null
-var/game_version = "Nebula13"
-var/changelog_hash = ""
-var/game_year = (text2num(time2text(world.realtime, "YYYY")) + 288)
-var/join_motd = null
-
-var/secret_force_mode = "secret" // if this is anything but "secret", the secret rotation will forceably choose this mode.
-
-var/Debug2 = 0
-
-var/gravity_is_on = 1
+var/global/secret_force_mode = "secret" // if this is anything but "secret", the secret rotation will forceably choose this mode.
// Database connections. A connection is established on world creation.
// Ideally, the connection dies when the server restarts (After feedback logging.).
-var/DBConnection/dbcon = new() // Feedback database (New database)
-var/DBConnection/dbcon_old = new() // /tg/station database (Old database) -- see the files in the SQL folder for information on what goes where.
-
+var/global/DBConnection/dbcon // General-purpose record database.
// For FTP requests. (i.e. downloading runtime logs.)
// However it'd be ok to use for accessing attack logs and such too, which are even laggier.
-var/fileaccess_timer = 0
-var/custom_event_msg = null
+var/global/fileaccess_timer = 0
+var/global/custom_event_msg = null
-GLOBAL_VAR_INIT(visibility_pref, FALSE)
// Used for admin shenanigans.
-GLOBAL_VAR_INIT(random_players, 0)
-GLOBAL_VAR_INIT(triai, 0)
\ No newline at end of file
+var/global/random_players = FALSE
+var/global/triai = FALSE
diff --git a/code/_global_vars/lists/clothing.dm b/code/_global_vars/lists/clothing.dm
new file mode 100644
index 000000000000..c77cb035a88b
--- /dev/null
+++ b/code/_global_vars/lists/clothing.dm
@@ -0,0 +1,47 @@
+var/global/list/standard_clothing_slots = list(
+ slot_head_str,
+ slot_wear_mask_str,
+ slot_wear_suit_str,
+ slot_w_uniform_str,
+ slot_gloves_str,
+ slot_shoes_str
+)
+
+var/global/list/standard_headgear_slots = list(
+ slot_head_str,
+ slot_wear_mask_str,
+ slot_glasses_str
+)
+
+var/global/list/ear_slots = list(
+ slot_l_ear_str,
+ slot_r_ear_str
+)
+
+var/global/list/pocket_slots = list(
+ slot_l_store_str,
+ slot_r_store_str
+)
+
+var/global/list/airtight_slots = list(
+ slot_wear_mask_str,
+ slot_head_str
+)
+
+var/global/list/abstract_inventory_slots = list(
+ slot_in_backpack_str,
+ slot_in_wallet_str,
+ slot_undershirt_str,
+ slot_underpants_str,
+ slot_socks_str
+)
+
+var/global/list/vitals_sensor_equip_slots = list(
+ slot_w_uniform_str
+)
+
+var/global/list/headphone_slots = list(
+ slot_l_ear_str,
+ slot_r_ear_str,
+ slot_head_str
+)
diff --git a/code/_global_vars/lists/flavor.dm b/code/_global_vars/lists/flavor.dm
index b73c9ab5cab3..7a21627335d2 100644
--- a/code/_global_vars/lists/flavor.dm
+++ b/code/_global_vars/lists/flavor.dm
@@ -1,8 +1,8 @@
// Noises made when hit while typing.
-GLOBAL_LIST_INIT(hit_appends, list("-OOF", "-ACK", "-UGH", "-HRNK", "-HURGH", "-GLORF"))
+var/global/list/hit_appends = list("-OOF", "-ACK", "-UGH", "-HRNK", "-HURGH", "-GLORF")
// Some scary sounds.
-GLOBAL_LIST_INIT(scarySounds, list(
+var/global/list/scarySounds = list(
'sound/weapons/thudswoosh.ogg',
'sound/weapons/Taser.ogg',
'sound/weapons/armbomb.ogg',
@@ -20,106 +20,105 @@ GLOBAL_LIST_INIT(scarySounds, list(
'sound/machines/airlock.ogg',
'sound/effects/clownstep1.ogg',
'sound/effects/clownstep2.ogg'
-))
+)
// Reference list for disposal sort junctions. Filled up by sorting junction's New()
-GLOBAL_LIST_EMPTY(tagger_locations)
+var/global/list/tagger_locations = list()
-GLOBAL_LIST_INIT(station_prefixes, list("", "Imperium", "Heretical", "Cuban",
+var/global/list/station_prefixes = list("", "Imperium", "Heretical", "Cuban",
"Psychic", "Elegant", "Common", "Uncommon", "Rare", "Unique",
"Houseruled", "Religious", "Atheist", "Traditional", "Houseruled",
"Mad", "Super", "Ultra", "Secret", "Top Secret", "Deep", "Death",
"Zybourne", "Central", "Main", "Government", "Uoi", "Fat",
- "Automated", "Experimental", "Augmented"))
-
-GLOBAL_LIST_INIT(station_names, list("", "Stanford", "Dorf", "Alium",
- "Prefix", "Clowning", "Aegis", "Ishimura", "Scaredy", "Death-World",
- "Mime", "Honk", "Rogue", "MacRagge", "Ultrameens", "Safety", "Paranoia",
- "Explosive", "Neckbear", "Donk", "Muppet", "North", "West", "East",
- "South", "Slant-ways", "Widdershins", "Rimward", "Expensive",
- "Procreatory", "Imperial", "Unidentified", "Immoral", "Carp", "Ork",
- "Pete", "Control", "Nettle", "Aspie", "Class", "Crab", "Fist",
- "Corrogated","Skeleton","Race", "Fatguy", "Gentleman", "Capitalist",
- "Communist", "Bear", "Beard", "Derp", "Space", "Spess", "Star", "Moon",
- "System", "Mining", "Neckbeard", "Research", "Supply", "Military",
+ "Automated", "Experimental", "Augmented")
+
+var/global/list/station_names = list("", "Stanford", "Dwarf", "Alien",
+ "Aegis", "Death-World", "Rogue", "Safety", "Paranoia",
+ "Explosive", "North", "West", "East", "South", "Slant-ways",
+ "Widdershins", "Rimward", "Expensive", "Procreatory", "Imperial",
+ "Unidentified", "Immoral", "Carp", "Orc", "Pete", "Control",
+ "Nettle", "Class", "Crab", "Fist", "Corrogated", "Skeleton",
+ "Gentleman", "Capitalist", "Communist", "Bear", "Beard", "Space",
+ "Star", "Moon", "System", "Mining", "Research", "Supply", "Military",
"Orbital", "Battle", "Science", "Asteroid", "Home", "Production",
"Transport", "Delivery", "Extraplanetary", "Orbital", "Correctional",
- "Robot", "Hats", "Pizza"))
+ "Robot", "Hats", "Pizza"
+)
-GLOBAL_LIST_INIT(station_suffixes, list("Station", "Frontier",
- "Suffix", "Death-trap", "Space-hulk", "Lab", "Hazard","Spess Junk",
+var/global/list/station_suffixes = list("Station", "Frontier",
+ "Death-trap", "Space-hulk", "Lab", "Hazard", "Junker",
"Fishery", "No-Moon", "Tomb", "Crypt", "Hut", "Monkey", "Bomb",
"Trade Post", "Fortress", "Village", "Town", "City", "Edition", "Hive",
"Complex", "Base", "Facility", "Depot", "Outpost", "Installation",
"Drydock", "Observatory", "Array", "Relay", "Monitor", "Platform",
"Construct", "Hangar", "Prison", "Center", "Port", "Waystation",
"Factory", "Waypoint", "Stopover", "Hub", "HQ", "Office", "Object",
- "Fortification", "Colony", "Planet-Cracker", "Roost", "Fat Camp",
- "Airstrip"))
+ "Fortification", "Colony", "Planet-Cracker", "Roost", "Airstrip")
-GLOBAL_LIST_INIT(greek_letters, list("Alpha", "Beta", "Gamma", "Delta",
+var/global/list/greek_letters = list("Alpha", "Beta", "Gamma", "Delta",
"Epsilon", "Zeta", "Eta", "Theta", "Iota", "Kappa", "Lambda", "Mu",
"Nu", "Xi", "Omicron", "Pi", "Rho", "Sigma", "Tau", "Upsilon", "Phi",
- "Chi", "Psi", "Omega"))
+ "Chi", "Psi", "Omega")
-GLOBAL_LIST_INIT(phonetic_alphabet, list("Alpha", "Bravo", "Charlie",
+var/global/list/phonetic_alphabet = list("Alpha", "Bravo", "Charlie",
"Delta", "Echo", "Foxtrot", "Golf", "Hotel", "India", "Juliet",
"Kilo", "Lima", "Mike", "November", "Oscar", "Papa", "Quebec",
"Romeo", "Sierra", "Tango", "Uniform", "Victor", "Whiskey", "X-ray",
- "Yankee", "Zulu"))
+ "Yankee", "Zulu")
-GLOBAL_LIST_INIT(numbers_as_words, list("One", "Two", "Three", "Four",
+var/global/list/numbers_as_words = list("One", "Two", "Three", "Four",
"Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve",
"Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen",
- "Eighteen", "Nineteen"))
-
-GLOBAL_LIST_INIT(music_tracks, list(
- "Beyond" = /music_track/ambispace,
- "Clouds of Fire" = /music_track/clouds_of_fire,
- "Stage Three" = /music_track/dilbert,
- "Asteroids" = /music_track/df_theme,
- "Floating" = /music_track/floating,
- "Endless Space" = /music_track/endless_space,
- "Fleet Party Theme" = /music_track/one_loop,
- "Scratch" = /music_track/level3_mod,
- "Absconditus" = /music_track/absconditus,
- "lasers rip apart the bulkhead" = /music_track/lasers,
- "Maschine Klash" = /music_track/digit_one,
- "Comet Halley" = /music_track/comet_haley,
- "Please Come Back Any Time" = /music_track/elevator,
- "Human" = /music_track/human,
- "Memories of Lysendraa" = /music_track/lysendraa,
- "Marhaba" = /music_track/marhaba,
- "Space Oddity" = /music_track/space_oddity,
- "THUNDERDOME" = /music_track/thunderdome,
- "Torch: A Light in the Darkness" = /music_track/torch,
- "Treacherous Voyage" = /music_track/treacherous_voyage,
- "Wake" = /music_track/wake,
- "phoron will make us rich" = /music_track/pwmur,
- "every light is blinking at once" = /music_track/elibao,
- "In Orbit" = /music_track/inorbit,
- "Martian Cowboy" = /music_track/martiancowboy,
- "Monument" = /music_track/monument,
- "As Far As It Gets" = /music_track/asfarasitgets,
- "80s All Over Again" = /music_track/eighties,
- "Wild Encounters" = /music_track/wildencounters,
- "Torn" = /music_track/torn,
- "Nebula" = /music_track/nebula
-))
+ "Eighteen", "Nineteen")
+
+// This is, for some reason, used exclusively for headphones, jukeboxes, and boomboxes.
+// It also seems to exist mostly for the purpose of allowing admins to upload their own songs to those at runtime?
+var/global/list/music_tracks = list(
+ "Beyond" = /decl/music_track/ambispace,
+ "Clouds of Fire" = /decl/music_track/clouds_of_fire,
+ "Stage Three" = /decl/music_track/dilbert,
+ "Asteroids" = /decl/music_track/df_theme,
+ "Floating" = /decl/music_track/floating,
+ "Endless Space" = /decl/music_track/endless_space,
+ "Fleet Party Theme" = /decl/music_track/one_loop,
+ "Scratch" = /decl/music_track/level3_mod,
+ "Absconditus" = /decl/music_track/absconditus,
+ "lasers rip apart the bulkhead" = /decl/music_track/lasers,
+ "Maschine Klash" = /decl/music_track/digit_one,
+ "Comet Halley" = /decl/music_track/comet_haley,
+ "Please Come Back Any Time" = /decl/music_track/elevator,
+ "Human" = /decl/music_track/human,
+ "Memories of Lysendraa" = /decl/music_track/lysendraa,
+ "Marhaba" = /decl/music_track/marhaba,
+ "Space Oddity" = /decl/music_track/space_oddity,
+ "THUNDERDOME" = /decl/music_track/thunderdome,
+ "Treacherous Voyage" = /decl/music_track/treacherous_voyage,
+ "Wake" = /decl/music_track/wake,
+ "phoron will make us rich" = /decl/music_track/pwmur,
+ "every light is blinking at once" = /decl/music_track/elibao,
+ "In Orbit" = /decl/music_track/inorbit,
+ "Martian Cowboy" = /decl/music_track/martiancowboy,
+ "Monument" = /decl/music_track/monument,
+ "As Far As It Gets" = /decl/music_track/asfarasitgets,
+ "80s All Over Again" = /decl/music_track/eighties,
+ "Wild Encounters" = /decl/music_track/wildencounters,
+ "Torn" = /decl/music_track/torn,
+ "Nebula" = /decl/music_track/nebula
+)
/proc/setup_music_tracks(var/list/tracks)
. = list()
- var/track_list = LAZYLEN(tracks) ? tracks : GLOB.music_tracks
+ var/track_list = LAZYLEN(tracks) ? tracks : global.music_tracks
for(var/track_name in track_list)
var/track_path = track_list[track_name]
. += new/datum/track(track_name, track_path)
-GLOBAL_LIST_INIT(possible_cable_colours, SetupCableColors())
-
+GLOBAL_GETTER(cable_colors, /list, SetupCableColors())
/proc/SetupCableColors()
. = list()
- var/invalid_cable_coils = list(
+ var/list/valid_cable_coils = typesof(/obj/item/stack/cable_coil) - typesof(
+ /obj/item/stack/cable_coil/five,
/obj/item/stack/cable_coil/single,
/obj/item/stack/cable_coil/cut,
/obj/item/stack/cable_coil/cyborg,
@@ -128,12 +127,12 @@ GLOBAL_LIST_INIT(possible_cable_colours, SetupCableColors())
)
var/special_name_mappings = list(/obj/item/stack/cable_coil = "Red")
-
- for(var/coil_type in (typesof(/obj/item/stack/cable_coil) - invalid_cable_coils))
+ for(var/coil_type in valid_cable_coils)
var/name = special_name_mappings[coil_type] || capitalize(copytext_after_last("[coil_type]", "/"))
var/obj/item/stack/cable_coil/C = coil_type
- var/color = initial(C.color)
-
+ if(!initial(C.can_have_color))
+ continue
+ var/color = initial(C.paint_color) || initial(C.color)
.[name] = color
- . = sortAssoc(.)
+ . = sortTim(., /proc/cmp_text_asc)
diff --git a/code/_global_vars/lists/jewellery.dm b/code/_global_vars/lists/jewellery.dm
new file mode 100644
index 000000000000..9ec4cded16c0
--- /dev/null
+++ b/code/_global_vars/lists/jewellery.dm
@@ -0,0 +1,23 @@
+var/global/list/random_jewellery_material_types = list(
+ /decl/material/solid/metal/gold,
+ /decl/material/solid/metal/silver,
+ /decl/material/solid/metal/copper,
+ /decl/material/solid/metal/platinum,
+ /decl/material/solid/metal/steel,
+ /decl/material/solid/organic/bone,
+ /decl/material/solid/organic/wood/oak
+)
+var/global/list/random_jewellery_gem_types = list(
+ /obj/item/gemstone/baguette/topaz,
+ /obj/item/gemstone/baguette/sapphire,
+ /obj/item/gemstone/baguette/ruby,
+ /obj/item/gemstone/hexagon/topaz,
+ /obj/item/gemstone/hexagon/sapphire,
+ /obj/item/gemstone/hexagon/ruby,
+ /obj/item/gemstone/octagon/topaz,
+ /obj/item/gemstone/octagon/sapphire,
+ /obj/item/gemstone/octagon/ruby,
+ /obj/item/gemstone/round/topaz,
+ /obj/item/gemstone/round/sapphire,
+ /obj/item/gemstone/round/ruby
+)
diff --git a/code/_global_vars/lists/locations.dm b/code/_global_vars/lists/locations.dm
deleted file mode 100644
index b7c25a818b39..000000000000
--- a/code/_global_vars/lists/locations.dm
+++ /dev/null
@@ -1,19 +0,0 @@
-GLOBAL_LIST_EMPTY(monkeystart)
-GLOBAL_LIST_EMPTY(newplayer_start)
-var/list/ninjastart = list()
-
-//Spawnpoints.
-GLOBAL_LIST_EMPTY(latejoin)
-GLOBAL_LIST_EMPTY(latejoin_gateway)
-GLOBAL_LIST_EMPTY(latejoin_cryo)
-GLOBAL_LIST_EMPTY(latejoin_cyborg)
-
-GLOBAL_LIST_EMPTY(prisonwarp) // Prisoners go to these
-GLOBAL_LIST_EMPTY(tdome1)
-GLOBAL_LIST_EMPTY(tdome2)
-GLOBAL_LIST_EMPTY(tdomeobserve)
-GLOBAL_LIST_EMPTY(tdomeadmin)
-GLOBAL_LIST_EMPTY(prisonsecuritywarp) // Prison security goes to these.
-GLOBAL_LIST_EMPTY(prisonwarped) // List of players already warped.
-
-GLOBAL_LIST_EMPTY(awaydestinations) // Away missions. A list of landmarks that the warpgate can take you to.
diff --git a/code/_global_vars/lists/logs.dm b/code/_global_vars/lists/logs.dm
index 6f79a5103aaf..8face994fe93 100644
--- a/code/_global_vars/lists/logs.dm
+++ b/code/_global_vars/lists/logs.dm
@@ -1,4 +1,3 @@
-GLOBAL_LIST_EMPTY(bombers)
-GLOBAL_LIST_EMPTY(admin_log)
-GLOBAL_LIST_EMPTY(lastsignalers) // Keeps last 100 signals here in format: "[src] used \ref[src] @ location [src.loc]: [freq]/[code]"
-GLOBAL_LIST_EMPTY(lawchanges) // Stores who uploaded laws to which silicon-based lifeform, and what the law was.
+var/global/list/bombers = list()
+var/global/list/admin_log = list()
+var/global/list/lawchanges = list() // Stores who uploaded laws to which silicon-based lifeform, and what the law was.
diff --git a/code/_global_vars/lists/mapping.dm b/code/_global_vars/lists/mapping.dm
index 47bd677e0777..6f4c14eb9b6e 100644
--- a/code/_global_vars/lists/mapping.dm
+++ b/code/_global_vars/lists/mapping.dm
@@ -1,32 +1,43 @@
-GLOBAL_LIST_INIT(cardinal, list(NORTH, SOUTH, EAST, WEST))
-GLOBAL_LIST_INIT(cardinalz, list(NORTH, SOUTH, EAST, WEST, UP, DOWN))
-GLOBAL_LIST_INIT(cornerdirs, list(NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST))
-GLOBAL_LIST_INIT(cornerdirsz, list(NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST, NORTH|UP, EAST|UP, WEST|UP, SOUTH|UP, NORTH|DOWN, EAST|DOWN, WEST|DOWN, SOUTH|DOWN))
-GLOBAL_LIST_INIT(alldirs, list(NORTH, SOUTH, EAST, WEST, NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST))
-GLOBAL_LIST_INIT(reverse_dir, list( // reverse_dir[dir] = reverse of dir
+var/global/list/cardinal = list(NORTH, SOUTH, EAST, WEST)
+var/global/list/cardinalz = list(NORTH, SOUTH, EAST, WEST, UP, DOWN)
+var/global/list/cornerdirs = list(NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST)
+var/global/list/cornerdirsz = list(NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST, NORTH|UP, EAST|UP, WEST|UP, SOUTH|UP, NORTH|DOWN, EAST|DOWN, WEST|DOWN, SOUTH|DOWN)
+var/global/list/alldirs = list(NORTH, SOUTH, EAST, WEST, NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST)
+var/global/list/cabledirs = list(0, NORTH, SOUTH, EAST, WEST, NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST, UP, DOWN)
+var/global/list/reverse_dir = list( // reverse_dir[dir] = reverse of dir
2, 1, 3, 8, 10, 9, 11, 4, 6, 5, 7, 12, 14, 13, 15,
32, 34, 33, 35, 40, 42, 41, 43, 36, 38, 37, 39, 44, 46, 45, 47,
16, 18, 17, 19, 24, 26, 25, 27, 20, 22, 21, 23, 28, 30, 29, 31,
48, 50, 49, 51, 56, 58, 57, 59, 52, 54, 53, 55, 60, 62, 61, 63
-))
+)
-GLOBAL_LIST_INIT(flip_dir, list( // flip_dir[dir] = 180 degree rotation of dir. Unlike reverse_dir, UP remains UP & DOWN remains DOWN.
+var/global/list/adjacentdirs = list( // adjacentdirs[dir] = list of directions adjacent to that direction
+ 12, 12, 12, 3, 15, 15, 15, 3, 15, 15, 15, 3, 15, 15, 15,
+ 16, 28, 28, 28, 19, 31, 31, 31, 19, 31, 31, 31, 31, 31, 31, 31, // UP - Same as first line but +16
+ 32, 44, 44, 44, 35, 47, 47, 47, 35, 47, 47, 47, 35, 47, 47, 47, // DOWN - Same as first line but +32
+ 48, 60, 60, 60, 51, 63, 63, 63, 51, 63, 63, 63, 51, 63, 63, 63 // UP+DOWN - Same as first line but +48
+)
+
+// global.flip_dir[dir] = 180 degree rotation of dir. Unlike reverse_dir, UP remains UP & DOWN remains DOWN.
+var/global/list/flip_dir = list(
2, 1, 3, 8, 10, 9, 11, 4, 6, 5, 7, 12, 14, 13, 15,
16, 18, 17, 19, 24, 26, 25, 27, 20, 22, 21, 23, 28, 30, 29, 31, // UP - Same as first line but +16
32, 34, 33, 35, 40, 42, 41, 43, 36, 38, 37, 39, 44, 46, 45, 47, // DOWN - Same as first line but +32
48, 50, 49, 51, 56, 58, 57, 59, 52, 54, 53, 55, 60, 62, 61, 63 // UP+DOWN - Same as first line but +48
-))
+)
-GLOBAL_LIST_INIT(cw_dir, list( // cw_dir[dir] = clockwise rotation of dir. Unlike reverse_dir, UP remains UP & DOWN remains DOWN.
+// global.cw_dir[dir] = clockwise rotation of dir. Unlike reverse_dir, UP remains UP & DOWN remains DOWN.
+var/global/list/cw_dir = list(
4, 8, 12, 2, 6, 10, 14, 1, 5, 9, 13, 3, 7, 11, 15,
16, 20, 24, 28, 18, 22, 26, 30, 17, 21, 25, 19, 29, 23, 27, 31, // UP - Same as first line but +16
32, 36, 40, 44, 34, 38, 42, 46, 33, 37, 41, 45, 35, 39, 43, 47, // DOWN - Same as first line but +32
48, 52, 56, 40, 50, 54, 58, 62, 49, 53, 57, 61, 51, 55, 59, 63 // UP+DOWN - Same as first line but +48
-))
+)
-GLOBAL_LIST_INIT(ccw_dir, list( // ccw_dir[dir] = counter-clockwise rotation of dir. Unlike reverse_dir, UP remains UP & DOWN remains DOWN.
+// global.ccw_dir[dir] = counter-clockwise rotation of dir. Unlike reverse_dir, UP remains UP & DOWN remains DOWN.
+var/global/list/ccw_dir = list(
8, 4, 12, 1, 9, 5, 13, 2, 10, 6, 14, 3, 11, 7, 15,
16, 24, 20, 28, 17, 25, 21, 29, 18, 26, 22, 30, 19, 27, 23, 31, // UP - Same as first line but +16
32, 40, 36, 44, 33, 41, 37, 45, 34, 42, 38, 46, 35, 43, 39, 47, // DOWN - Same as first line but +32
48, 56, 52, 60, 49, 57, 53, 61, 50, 58, 54, 62, 51, 59, 55, 63 // UP+DOWN - Same as first line but +48
-))
+)
diff --git a/code/_global_vars/lists/names.dm b/code/_global_vars/lists/names.dm
index c2570e230ba1..741c433285d7 100644
--- a/code/_global_vars/lists/names.dm
+++ b/code/_global_vars/lists/names.dm
@@ -1,16 +1,11 @@
-GLOBAL_LIST_INIT(ai_names, world.file2list("config/names/ai.txt"))
-GLOBAL_LIST_INIT(wizard_first, world.file2list("config/names/wizardfirst.txt"))
-GLOBAL_LIST_INIT(wizard_second, world.file2list("config/names/wizardsecond.txt"))
-GLOBAL_LIST_INIT(ninja_titles, world.file2list("config/names/ninjatitle.txt"))
-GLOBAL_LIST_INIT(ninja_names, world.file2list("config/names/ninjaname.txt"))
-GLOBAL_LIST_INIT(commando_names, world.file2list("config/names/death_commando.txt"))
-GLOBAL_LIST_INIT(first_names_male, world.file2list("config/names/first_male.txt"))
-GLOBAL_LIST_INIT(first_names_female, world.file2list("config/names/first_female.txt"))
-GLOBAL_LIST_INIT(last_names, world.file2list("config/names/last.txt"))
-GLOBAL_LIST_INIT(clown_names, world.file2list("config/names/clown.txt"))
+// All variables here use double quotes to able load information on every startup.
+var/global/list/ai_names = file2list("config/names/ai.txt")
-GLOBAL_LIST_INIT(verbs, world.file2list("config/names/verbs.txt"))
-GLOBAL_LIST_INIT(adjectives, world.file2list("config/names/adjectives.txt"))
-//loaded on startup because of "
-//would include in rsc if ' was used
+var/global/list/verbs = file2list("config/names/verbs.txt")
+var/global/list/adjectives = file2list("config/names/adjectives.txt")
+
+var/global/list/abstract_slot_names = list(
+ slot_in_backpack_str = "In Backpack",
+ slot_in_wallet_str = "In Wallet"
+)
diff --git a/code/_global_vars/lists/objects.dm b/code/_global_vars/lists/objects.dm
index 7cd3e328cd58..97d7e3490ce3 100644
--- a/code/_global_vars/lists/objects.dm
+++ b/code/_global_vars/lists/objects.dm
@@ -1,28 +1,18 @@
-GLOBAL_LIST_EMPTY(med_hud_users) // List of all entities using a medical HUD.
-GLOBAL_LIST_EMPTY(sec_hud_users) // List of all entities using a security HUD.
-GLOBAL_LIST_EMPTY(jani_hud_users)
-GLOBAL_LIST_EMPTY(hud_icon_reference)
-
-GLOBAL_LIST_EMPTY(listening_objects) // List of objects that need to be able to hear, used to avoid recursive searching through contents.
-
-GLOBAL_LIST_EMPTY(global_mutations) // List of hidden mutation things.
-
-GLOBAL_LIST_EMPTY(reg_dna)
-
-GLOBAL_LIST_EMPTY(global_map)
-
-// Announcer intercom, because too much stuff creates an intercom for one message then hard del()s it. Also headset, for things that should be affected by comms outages.
-GLOBAL_DATUM_INIT(global_announcer, /obj/item/radio/announcer, new)
-GLOBAL_DATUM_INIT(global_headset, /obj/item/radio/announcer/subspace, new)
-
-var/host = null //only here until check @ code\modules\ghosttrap\trap.dm:112 is fixed
-GLOBAL_DATUM_INIT(sun, /datum/sun, new)
-GLOBAL_DATUM_INIT(universe, /datum/universal_state, new)
-
-GLOBAL_LIST_INIT(vowels, list("a","e","i","o","u"))
-GLOBAL_LIST_INIT(alphabet_no_vowels, list("b","c","d","f","g","h","j","k","l","m","n","p","q","r","s","t","v","w","x","z"))
-GLOBAL_LIST_INIT(full_alphabet, list("a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"))
-
-GLOBAL_LIST_EMPTY(meteor_list)
-
-var/list/is_currently_exploding = list()
+var/global/list/med_hud_users = list() // List of all entities using a medical HUD.
+var/global/list/sec_hud_users = list() // List of all entities using a security HUD.
+var/global/list/jani_hud_users = list()
+var/global/list/hud_icon_reference = list()
+var/global/list/listening_objects = list() // List of objects that need to be able to hear, used to avoid recursive searching through contents.
+
+var/global/datum/universal_state/universe = new
+
+/// Vowels.
+var/global/list/vowels = list("a","e","i","o","u")
+/// Alphabet a-z.
+var/global/list/alphabet = list("a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z")
+/// Alphabet A-Z.
+var/global/list/alphabet_capital = list("A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z")
+/// Numbers 0-9.
+var/global/list/numbers = list("0","1","2","3","4","5","6","7","8","9")
+
+var/global/list/meteor_list = list()
diff --git a/code/_global_vars/lists/times.dm b/code/_global_vars/lists/times.dm
deleted file mode 100644
index ceaaba10e159..000000000000
--- a/code/_global_vars/lists/times.dm
+++ /dev/null
@@ -1 +0,0 @@
-GLOBAL_LIST_INIT(days_per_month, acquire_days_per_month())
diff --git a/code/_global_vars/logging.dm b/code/_global_vars/logging.dm
index 2b2901368c59..43ea604377c9 100644
--- a/code/_global_vars/logging.dm
+++ b/code/_global_vars/logging.dm
@@ -1,16 +1,5 @@
-var/list/combatlog = list()
-var/list/IClog = list()
-var/list/OOClog = list()
-var/list/adminlog = list()
+var/global/diary = null
-var/datum/configuration/config = null
-var/list/jobMax = list()
-
-var/diary = null
-
-GLOBAL_VAR(log_directory)
-GLOBAL_PROTECT(log_directory)
-GLOBAL_VAR(world_qdel_log)
-GLOBAL_PROTECT(world_qdel_log)
-GLOBAL_VAR(world_href_log)
-GLOBAL_PROTECT(world_href_log)
\ No newline at end of file
+GLOBAL_PROTECTED_UNTYPED(log_directory, null)
+GLOBAL_PROTECTED_UNTYPED(world_qdel_log, null)
+GLOBAL_PROTECTED_UNTYPED(world_href_log, null)
diff --git a/code/_global_vars/mapping.dm b/code/_global_vars/mapping.dm
deleted file mode 100644
index 11cbcd7ea49a..000000000000
--- a/code/_global_vars/mapping.dm
+++ /dev/null
@@ -1 +0,0 @@
-GLOBAL_LIST_EMPTY(ruin_landmarks)
\ No newline at end of file
diff --git a/code/_global_vars/misc.dm b/code/_global_vars/misc.dm
deleted file mode 100644
index 672058953386..000000000000
--- a/code/_global_vars/misc.dm
+++ /dev/null
@@ -1,3 +0,0 @@
-GLOBAL_LIST_EMPTY(all_observable_events)
-
-GLOBAL_LIST_INIT(font_resources, list('fonts/Shage/Shage.ttf'))
\ No newline at end of file
diff --git a/code/_global_vars/mobs.dm b/code/_global_vars/mobs.dm
index 3e7b7289da7d..efa72acd8429 100644
--- a/code/_global_vars/mobs.dm
+++ b/code/_global_vars/mobs.dm
@@ -1,12 +1,11 @@
-GLOBAL_LIST_EMPTY(clients) //all clients
-GLOBAL_LIST_EMPTY(admins) //all clients whom are admins
-GLOBAL_PROTECT(admins)
-GLOBAL_LIST_EMPTY(ckey_directory) //all ckeys with associated client
+GLOBAL_PROTECTED(admins, /list, list()) // all clients whom are admins
+var/global/list/clients = list() // all clients
+var/global/list/ckey_directory = list() // all ckeys with associated client
-GLOBAL_LIST_EMPTY(player_list) //List of all mobs **with clients attached**. Excludes /mob/new_player
-GLOBAL_LIST_EMPTY(human_mob_list) //List of all human mobs and sub-types, including clientless
-GLOBAL_LIST_EMPTY(silicon_mob_list) //List of all silicon mobs, including clientless
-GLOBAL_LIST_EMPTY(living_mob_list_) //List of all alive mobs, including clientless. Excludes /mob/new_player
-GLOBAL_LIST_EMPTY(dead_mob_list_) //List of all dead mobs, including clientless. Excludes /mob/new_player
-GLOBAL_LIST_EMPTY(ghost_mob_list) //List of all ghosts, including clientless. Excludes /mob/new_player
+var/global/list/player_list = list() // List of all mobs **with clients attached**. Excludes /mob/new_player
+var/global/list/human_mob_list = list() // List of all human mobs and sub-types, including clientless
+var/global/list/silicon_mob_list = list() // List of all silicon mobs, including clientless
+var/global/list/living_mob_list_ = list() // List of all alive mobs, including clientless. Excludes /mob/new_player
+var/global/list/dead_mob_list_ = list() // List of all dead mobs, including clientless. Excludes /mob/new_player
+var/global/list/ghost_mob_list = list() // List of all ghosts, including clientless. Excludes /mob/new_player
diff --git a/code/_global_vars/radio.dm b/code/_global_vars/radio.dm
deleted file mode 100644
index d3ec7f7b5eea..000000000000
--- a/code/_global_vars/radio.dm
+++ /dev/null
@@ -1,7 +0,0 @@
-// These globals are the worst
-
-GLOBAL_LIST_INIT(default_medbay_channels, list(
- num2text(PUB_FREQ) = list(),
- num2text(MED_FREQ) = list(access_medical_equip),
- num2text(MED_I_FREQ) = list(access_medical_equip)
-))
diff --git a/code/_global_vars/sensitive.dm b/code/_global_vars/sensitive.dm
index 0e53c44249cc..b298253d1fbf 100644
--- a/code/_global_vars/sensitive.dm
+++ b/code/_global_vars/sensitive.dm
@@ -1,13 +1,7 @@
// MySQL configuration
-GLOBAL_REAL_VAR(sqlenabled) = FALSE
-
-GLOBAL_REAL_VAR(sqladdress) = "localhost"
-GLOBAL_REAL_VAR(sqlport) = "3306"
-GLOBAL_REAL_VAR(sqldb) = "tgstation"
-GLOBAL_REAL_VAR(sqllogin) = "root"
-GLOBAL_REAL_VAR(sqlpass) = ""
-
-// Feedback gathering sql connection
-GLOBAL_REAL_VAR(sqlfdbkdb) = "test"
-GLOBAL_REAL_VAR(sqlfdbklogin) = "root"
-GLOBAL_REAL_VAR(sqlfdbkpass) = ""
+var/global/sqlenabled = FALSE
+GLOBAL_PROTECTED_UNTYPED(sqladdress, "localhost")
+GLOBAL_PROTECTED_UNTYPED(sqlport, "3306")
+GLOBAL_PROTECTED_UNTYPED(sqldb, "tgstation")
+GLOBAL_PROTECTED_UNTYPED(sqllogin, "root")
+GLOBAL_PROTECTED_UNTYPED(sqlpass, "")
diff --git a/code/_global_vars/sound.dm b/code/_global_vars/sound.dm
index 618040ac35c8..fec9867b5f09 100644
--- a/code/_global_vars/sound.dm
+++ b/code/_global_vars/sound.dm
@@ -1,120 +1,138 @@
-GLOBAL_LIST_INIT(shatter_sound,\
- list(\
- 'sound/effects/Glassbr1.ogg',\
- 'sound/effects/Glassbr2.ogg',\
- 'sound/effects/Glassbr3.ogg'))
-
-GLOBAL_LIST_INIT(explosion_sound,\
- list(\
- 'sound/effects/Explosion1.ogg',\
- 'sound/effects/Explosion2.ogg'))
-
-GLOBAL_LIST_INIT(spark_sound,\
- list(\
- 'sound/effects/sparks1.ogg',\
- 'sound/effects/sparks2.ogg',\
- 'sound/effects/sparks3.ogg',\
- 'sound/effects/sparks4.ogg'))
-
-GLOBAL_LIST_INIT(rustle_sound,\
- list(\
- 'sound/effects/rustle1.ogg',\
- 'sound/effects/rustle2.ogg',\
- 'sound/effects/rustle3.ogg',\
- 'sound/effects/rustle4.ogg',\
- 'sound/effects/rustle5.ogg'))
-
-GLOBAL_LIST_INIT(punch_sound,\
- list(\
- 'sound/weapons/punch1.ogg',\
- 'sound/weapons/punch2.ogg',\
- 'sound/weapons/punch3.ogg',\
- 'sound/weapons/punch4.ogg'))
-
-GLOBAL_LIST_INIT(clown_sound,\
- list(\
- 'sound/effects/clownstep1.ogg',
- 'sound/effects/clownstep2.ogg'))
-
-GLOBAL_LIST_INIT(swing_hit_sound,\
- list(\
- 'sound/weapons/genhit1.ogg',\
- 'sound/weapons/genhit2.ogg',\
- 'sound/weapons/genhit3.ogg'))
-
-GLOBAL_LIST_INIT(hiss_sound,\
- list(\
- 'sound/voice/hiss1.ogg',\
- 'sound/voice/hiss2.ogg',\
- 'sound/voice/hiss3.ogg',\
- 'sound/voice/hiss4.ogg'))
-
-GLOBAL_LIST_INIT(page_sound,\
- list(\
- 'sound/effects/pageturn1.ogg',\
- 'sound/effects/pageturn2.ogg',\
- 'sound/effects/pageturn3.ogg'))
-
-GLOBAL_LIST_INIT(fracture_sound,\
- list(\
- 'sound/effects/bonebreak1.ogg',\
- 'sound/effects/bonebreak2.ogg',\
- 'sound/effects/bonebreak3.ogg',\
- 'sound/effects/bonebreak4.ogg'))
-
-GLOBAL_LIST_INIT(lighter_sound,\
- list(\
- 'sound/items/lighter1.ogg',\
- 'sound/items/lighter2.ogg',\
- 'sound/items/lighter3.ogg'))
-
-GLOBAL_LIST_INIT(keyboard_sound,\
- list(\
- 'sound/machines/keyboard/keypress1.ogg',\
- 'sound/machines/keyboard/keypress2.ogg',\
- 'sound/machines/keyboard/keypress3.ogg',\
- 'sound/machines/keyboard/keypress4.ogg'))
-
-GLOBAL_LIST_INIT(keystroke_sound,\
- list(
- 'sound/machines/keyboard/keystroke1.ogg',\
- 'sound/machines/keyboard/keystroke2.ogg',\
- 'sound/machines/keyboard/keystroke3.ogg',\
- 'sound/machines/keyboard/keystroke4.ogg'))
-
-GLOBAL_LIST_INIT(switch_sound,\
- list(\
- 'sound/machines/switch1.ogg',\
- 'sound/machines/switch2.ogg',\
- 'sound/machines/switch3.ogg',\
- 'sound/machines/switch4.ogg'))
-
-GLOBAL_LIST_INIT(button_sound,\
- list(\
- 'sound/machines/button1.ogg',\
- 'sound/machines/button2.ogg',\
- 'sound/machines/button3.ogg',\
- 'sound/machines/button4.ogg'))
-
-GLOBAL_LIST_INIT(chop_sound,\
- list(\
- 'sound/weapons/chop1.ogg',\
- 'sound/weapons/chop2.ogg',\
- 'sound/weapons/chop3.ogg'))
-
-GLOBAL_LIST_INIT(glasscrack_sound,\
- list(\
- 'sound/effects/glass_crack1.ogg',\
- 'sound/effects/glass_crack2.ogg',\
- 'sound/effects/glass_crack3.ogg',\
- 'sound/effects/glass_crack4.ogg'))
-
-GLOBAL_LIST_INIT(light_strike_sound,\
- list(\
- 'sound/effects/hit_kick.ogg',
- 'sound/effects/hit_punch.ogg'))
-
-GLOBAL_LIST_INIT(tray_hit_sound,\
- list(\
- 'sound/items/trayhit1.ogg',
- 'sound/items/trayhit2.ogg'))
+// TODO: make a code/game/sound folder to store these and playsound code?
+var/global/list/shatter_sound = list(
+ 'sound/effects/Glassbr1.ogg',
+ 'sound/effects/Glassbr2.ogg',
+ 'sound/effects/Glassbr3.ogg'
+)
+
+var/global/list/explosion_sound = list(
+ 'sound/effects/Explosion1.ogg',
+ 'sound/effects/Explosion2.ogg'
+)
+
+var/global/list/spark_sound = list(
+ 'sound/effects/sparks1.ogg',
+ 'sound/effects/sparks2.ogg',
+ 'sound/effects/sparks3.ogg',
+ 'sound/effects/sparks4.ogg'
+)
+
+var/global/list/rustle_sound = list(
+ 'sound/effects/rustle1.ogg',
+ 'sound/effects/rustle2.ogg',
+ 'sound/effects/rustle3.ogg',
+ 'sound/effects/rustle4.ogg',
+ 'sound/effects/rustle5.ogg'
+)
+
+var/global/list/punch_sound = list(
+ 'sound/weapons/punch1.ogg',
+ 'sound/weapons/punch2.ogg',
+ 'sound/weapons/punch3.ogg',
+ 'sound/weapons/punch4.ogg'
+)
+
+var/global/list/clown_sound = list(
+ 'sound/effects/clownstep1.ogg',
+ 'sound/effects/clownstep2.ogg'
+)
+
+var/global/list/swing_hit_sound = list(
+ 'sound/weapons/genhit1.ogg',
+ 'sound/weapons/genhit2.ogg',
+ 'sound/weapons/genhit3.ogg'
+)
+
+var/global/list/hiss_sound = list(
+ 'sound/voice/hiss1.ogg',
+ 'sound/voice/hiss2.ogg',
+ 'sound/voice/hiss3.ogg',
+ 'sound/voice/hiss4.ogg'
+)
+
+var/global/list/page_sound = list(
+ 'sound/effects/pageturn1.ogg',
+ 'sound/effects/pageturn2.ogg',
+ 'sound/effects/pageturn3.ogg'
+)
+
+var/global/list/fracture_sound = list(
+ 'sound/effects/bonebreak1.ogg',
+ 'sound/effects/bonebreak2.ogg',
+ 'sound/effects/bonebreak3.ogg',
+ 'sound/effects/bonebreak4.ogg'
+)
+
+var/global/list/lighter_sound = list(
+ 'sound/items/lighter1.ogg',
+ 'sound/items/lighter2.ogg',
+ 'sound/items/lighter3.ogg'
+)
+
+var/global/list/keyboard_sound = list(
+ 'sound/machines/keyboard/keypress1.ogg',
+ 'sound/machines/keyboard/keypress2.ogg',
+ 'sound/machines/keyboard/keypress3.ogg',
+ 'sound/machines/keyboard/keypress4.ogg'
+)
+
+var/global/list/keystroke_sound = list(
+ 'sound/machines/keyboard/keystroke1.ogg',
+ 'sound/machines/keyboard/keystroke2.ogg',
+ 'sound/machines/keyboard/keystroke3.ogg',
+ 'sound/machines/keyboard/keystroke4.ogg'
+)
+
+var/global/list/switch_sound = list(
+ 'sound/machines/switch1.ogg',
+ 'sound/machines/switch2.ogg',
+ 'sound/machines/switch3.ogg',
+ 'sound/machines/switch4.ogg'
+)
+
+var/global/list/button_sound = list(
+ 'sound/machines/button1.ogg',
+ 'sound/machines/button2.ogg',
+ 'sound/machines/button3.ogg',
+ 'sound/machines/button4.ogg'
+)
+
+var/global/list/chop_sound = list(
+ 'sound/weapons/chop1.ogg',
+ 'sound/weapons/chop2.ogg',
+ 'sound/weapons/chop3.ogg'
+)
+
+var/global/list/glasscrack_sound = list(
+ 'sound/effects/glass_crack1.ogg',
+ 'sound/effects/glass_crack2.ogg',
+ 'sound/effects/glass_crack3.ogg',
+ 'sound/effects/glass_crack4.ogg'
+)
+
+var/global/list/light_strike_sound = list(
+ 'sound/effects/hit_kick.ogg',
+ 'sound/effects/hit_punch.ogg'
+)
+
+var/global/list/tray_hit_sound = list(
+ 'sound/items/trayhit1.ogg',
+ 'sound/items/trayhit2.ogg'
+)
+
+var/global/list/sweeping_sound = list(
+ 'sound/foley/sweeping1.ogg',
+ 'sound/foley/sweeping2.ogg',
+ 'sound/foley/sweeping3.ogg',
+ 'sound/foley/sweeping4.ogg',
+ 'sound/foley/sweeping5.ogg',
+ 'sound/foley/sweeping6.ogg',
+ 'sound/foley/sweeping7.ogg',
+)
+
+var/global/list/ricochet_sound = list(
+ 'sound/weapons/guns/ricochet1.ogg',
+ 'sound/weapons/guns/ricochet2.ogg',
+ 'sound/weapons/guns/ricochet3.ogg',
+ 'sound/weapons/guns/ricochet4.ogg'
+)
diff --git a/code/_helpers/_global_objects.dm b/code/_helpers/_global_objects.dm
index ba8643cc5415..705aab49b27c 100644
--- a/code/_helpers/_global_objects.dm
+++ b/code/_helpers/_global_objects.dm
@@ -1,8 +1,9 @@
-var/datum/gear_tweak/color/gear_tweak_free_color_choice_
+var/global/datum/gear_tweak/color/gear_tweak_free_color_choice_
/proc/gear_tweak_free_color_choice()
if(!gear_tweak_free_color_choice_) gear_tweak_free_color_choice_ = new()
return gear_tweak_free_color_choice_
-//var/datum/gear_tweak/color/gear_tweak_free_color_choice_
-//#define gear_tweak_free_color_choice (gear_tweak_free_color_choice_ ? gear_tweak_free_color_choice_ : (gear_tweak_free_color_choice_ = new()))
-// Might work in 511 assuming x=y=5 gets implemented.
+var/global/datum/gear_tweak/color/markings/gear_tweek_free_markings_color_choice_
+/proc/gear_tweak_free_markings_color_choice()
+ if(!gear_tweek_free_markings_color_choice_) gear_tweek_free_markings_color_choice_ = new()
+ return gear_tweek_free_markings_color_choice_
\ No newline at end of file
diff --git a/code/_helpers/animations.dm b/code/_helpers/animations.dm
index ddcd65489874..e549a677f797 100644
--- a/code/_helpers/animations.dm
+++ b/code/_helpers/animations.dm
@@ -5,9 +5,11 @@
/proc/fade_out(image/I, list/show_to)
animate(I, alpha = 0, time = 0.5 SECONDS, easing = EASE_IN)
- addtimer(CALLBACK(GLOBAL_PROC, .proc/remove_images_from_clients, I, show_to), 0.5 SECONDS)
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(remove_images_from_clients), I, show_to), 0.5 SECONDS)
/proc/animate_speech_bubble(image/I, list/show_to, duration)
+ if(!I)
+ return
var/matrix/M = matrix()
M.Scale(0,0)
I.transform = M
@@ -15,10 +17,102 @@
for(var/client/C in show_to)
C.images += I
animate(I, transform = 0, alpha = 255, time = 0.2 SECONDS, easing = EASE_IN)
- addtimer(CALLBACK(GLOBAL_PROC, .proc/fade_out, I, show_to), (duration - 0.5 SECONDS))
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(fade_out), I, show_to), (duration - 0.5 SECONDS))
/proc/animate_receive_damage(atom/A)
var/pixel_x_diff = rand(-2,2)
var/pixel_y_diff = rand(-2,2)
animate(A, pixel_x = A.pixel_x + pixel_x_diff, pixel_y = A.pixel_y + pixel_y_diff, time = 2)
animate(pixel_x = initial(A.pixel_x), pixel_y = initial(A.pixel_y), time = 2)
+
+/proc/animate_throw(atom/A)
+ var/ipx = A.pixel_x
+ var/ipy = A.pixel_y
+ var/mpx = 0
+ var/mpy = 0
+
+ if(A.dir & NORTH)
+ mpy += 3
+ else if(A.dir & SOUTH)
+ mpy -= 3
+ if(A.dir & EAST)
+ mpx += 3
+ else if(A.dir & WEST)
+ mpx -= 3
+
+ var/x = mpx + ipx
+ var/y = mpy + ipy
+
+ animate(A, pixel_x = x, pixel_y = y, time = 0.6, easing = EASE_OUT)
+
+ var/matrix/M = matrix(A.transform)
+ animate(transform = turn(A.transform, (mpx - mpy) * 4), time = 0.6, easing = EASE_OUT)
+ animate(pixel_x = ipx, pixel_y = ipy, time = 0.6, easing = EASE_IN)
+ animate(transform = M, time = 0.6, easing = EASE_IN)
+
+/proc/flick_overlay(image/I, list/show_to, duration)
+ for(var/client/C in show_to)
+ C.images += I
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(remove_images_from_clients), I, show_to), duration)
+
+/atom/movable/proc/do_attack_effect(atom/A, effect) //Simple effects for telegraphing or marking attack locations
+ if (effect)
+ var/image/I = image('icons/effects/effects.dmi', A, effect, ABOVE_PROJECTILE_LAYER)
+
+ if (!I)
+ return
+
+ flick_overlay(I, global.clients, 10)
+
+ // And animate the attack!
+ animate(I, alpha = 175, transform = matrix() * 0.75, pixel_x = 0, pixel_y = 0, pixel_z = 0, time = 3)
+ animate(time = 1)
+ animate(alpha = 0, time = 3, easing = CIRCULAR_EASING|EASE_OUT)
+
+// Shake animation stolen from Polaris.
+/atom
+ /// How much to shake the atom when struck.
+ /// Larger objs should have smaller numbers or it looks weird.
+ var/shake_animation_degrees = 4
+
+/atom/proc/shake_animation(var/intensity = 8)
+ var/init_px = pixel_x
+ var/shake_dir = pick(-1, 1)
+ var/matrix/M = matrix()
+ M.Scale(icon_scale_x, icon_scale_y)
+ M.Translate(0, 16*(icon_scale_y-1))
+ animate(src, transform=turn(M, shake_animation_degrees * shake_dir), pixel_x=init_px + 2*shake_dir, time=1)
+ animate(transform=M, pixel_x=init_px, time=6, easing=ELASTIC_EASING)
+
+/atom/proc/SpinAnimation(speed = 10, loops = -1, clockwise = 1, segments = 3, parallel = TRUE)
+ if(!segments)
+ return
+ var/segment = 360/segments
+ if(!clockwise)
+ segment = -segment
+ speed /= segments
+
+ animate(src, transform = matrix().Turn(segment), time = speed, loops, flags = parallel ? (ANIMATION_PARALLEL | ANIMATION_RELATIVE) : ANIMATION_RELATIVE)
+ for(var/i in 2 to segments) //2 because 1 is covered above
+ animate(transform = matrix().Turn(segment), time = speed, loops, flags = ANIMATION_RELATIVE)
+ //doesn't have an object argument because this is "Stacking" with the animate call above
+ //3 billion% intentional
+
+// This proc is used to move an atom to a target loc and then interpolite to give the illusion of sliding from start to end.
+/proc/do_visual_slide(var/atom/movable/sliding, var/turf/from, var/from_pixel_x, var/from_pixel_y, var/turf/target, var/target_pixel_x, var/target_pixel_y, var/center_of_mass)
+ set waitfor = FALSE
+ var/start_pixel_x = sliding.pixel_x - ((target.x-from.x) * world.icon_size)
+ var/start_pixel_y = sliding.pixel_y - ((target.y-from.y) * world.icon_size)
+ // Clear our glide so we don't do an animation when dropped into the target turf.
+ var/old_animate_movement = sliding.animate_movement
+ sliding.animate_movement = NO_STEPS
+ sleep(2 * world.tick_lag) // Due to BYOND being byond, animate_movement has to be set for at least 2 ticks before gliding will be disabled.
+ sliding.forceMove(target)
+ // Reset our glide_size now that movement has completed.
+ sliding.animate_movement = old_animate_movement
+ sliding.pixel_x = start_pixel_x
+ sliding.pixel_y = start_pixel_y
+ if(center_of_mass)
+ target_pixel_x -= center_of_mass["x"]
+ target_pixel_y -= center_of_mass["y"]
+ animate(sliding, pixel_x = target_pixel_x, pixel_y = target_pixel_y, time = 1 SECOND)
diff --git a/code/_helpers/areas.dm b/code/_helpers/areas.dm
index 4017bd5021ec..c26f3d2e9969 100644
--- a/code/_helpers/areas.dm
+++ b/code/_helpers/areas.dm
@@ -20,21 +20,10 @@
if(!predicates || all_predicates_true(list(T), predicates))
. += T
-/proc/get_subarea_turfs(var/area/A, var/list/predicates)
- . = new/list()
- A = istype(A) ? A.type : A
- if(!ispath(A))
- return
- for(var/sub_area_type in typesof(A))
- var/area/sub_area = locate(sub_area_type)
- for(var/turf/T in sub_area.contents)
- if(!predicates || all_predicates_true(list(T), predicates))
- . += T
-
/proc/group_areas_by_name(var/list/predicates)
. = list()
for(var/area/A in get_filtered_areas(predicates))
- group_by(., A.name, A)
+ group_by(., A.proper_name, A)
/proc/group_areas_by_z_level(var/list/predicates)
. = list()
@@ -45,20 +34,31 @@
/*
Pick helpers
*/
-/proc/pick_subarea_turf(var/areatype, var/list/predicates)
- var/list/turfs = get_subarea_turfs(areatype, predicates)
- if(LAZYLEN(turfs))
- return pick(turfs)
+/proc/pick_area_turf_by_flag(var/area_flags, var/list/predicates)
+ var/list/turfs
+ var/list/valid_areas = list()
+ for(var/area/candidate_area as anything in global.areas)
+ if(!(candidate_area.area_flags & area_flags))
+ continue
+ valid_areas[candidate_area] = TRUE
+ if(!length(valid_areas)) // no turfs at all have that flag
+ return null
+ // Each area contents loop is an in-world loop, so we just do one here.
+ for(var/turf/turf_candidate in world)
+ var/area/candidate_area = get_area(turf_candidate)
+ if(!valid_areas[candidate_area])
+ continue
+ if(!predicates || all_predicates_true(list(turf_candidate), predicates))
+ LAZYADD(turfs, turf_candidate)
+ return SAFEPICK(turfs)
/proc/pick_area_turf(var/areatype, var/list/predicates)
var/list/turfs = get_area_turfs(areatype, predicates)
- if(turfs && turfs.len)
- return pick(turfs)
+ return SAFEPICK(turfs)
/proc/pick_area(var/list/predicates)
var/list/areas = get_filtered_areas(predicates)
- if(LAZYLEN(areas))
- . = pick(areas)
+ return SAFEPICK(areas)
/proc/pick_area_and_turf(var/list/area_predicates, var/list/turf_predicates)
var/list/areas = get_filtered_areas(area_predicates)
@@ -70,7 +70,7 @@
/proc/pick_area_turf_in_connected_z_levels(var/list/area_predicates, var/list/turf_predicates, var/z_level)
area_predicates = area_predicates.Copy()
- var/z_levels = GetConnectedZlevels(z_level)
+ var/z_levels = SSmapping.get_connected_levels(z_level)
area_predicates[/proc/area_belongs_to_zlevels] = z_levels
return pick_area_and_turf(area_predicates, turf_predicates)
@@ -81,52 +81,56 @@
. = (A.z in z_levels)
/proc/is_station_area(var/area/A)
- . = isStationLevel(A.z)
+ if(istype(A))
+ . = isStationLevel(A.z)
/proc/is_contact_area(var/area/A)
- . = isContactLevel(A.z)
+ if(istype(A))
+ . = isContactLevel(A.z)
/proc/is_player_area(var/area/A)
- . = isPlayerLevel(A.z)
+ if(istype(A))
+ . = isPlayerLevel(A.z)
/proc/is_not_space_area(var/area/A)
. = !istype(A,/area/space)
/proc/is_not_shuttle_area(var/area/A)
- . = !istype(A,/area/shuttle)
+ . = !istype(A) || !(A.area_flags & AREA_FLAG_SHUTTLE)
/proc/is_area_with_turf(var/area/A)
- . = isnum(A.x)
+ if(istype(A))
+ . = isnum(A.x)
/proc/is_area_without_turf(var/area/A)
. = !is_area_with_turf(A)
/proc/is_maint_area(var/area/A)
- . = istype(A,/area/maintenance)
+ . = !istype(A) || !(A.area_flags & AREA_FLAG_MAINTENANCE)
/proc/is_not_maint_area(var/area/A)
. = !is_maint_area(A)
/proc/is_coherent_area(var/area/A)
- return !is_type_in_list(A, GLOB.using_map.area_coherency_test_exempt_areas)
+ return !is_type_in_list(A, global.using_map.area_coherency_test_exempt_areas)
-GLOBAL_LIST_INIT(is_station_but_not_space_or_shuttle_area, list(/proc/is_station_area, /proc/is_not_space_area, /proc/is_not_shuttle_area))
+var/global/list/is_station_but_not_space_or_shuttle_area = list(/proc/is_station_area, /proc/is_not_space_area, /proc/is_not_shuttle_area)
-GLOBAL_LIST_INIT(is_contact_but_not_space_or_shuttle_area, list(/proc/is_contact_area, /proc/is_not_space_area, /proc/is_not_shuttle_area))
+var/global/list/is_contact_but_not_space_or_shuttle_area = list(/proc/is_contact_area, /proc/is_not_space_area, /proc/is_not_shuttle_area)
-GLOBAL_LIST_INIT(is_player_but_not_space_or_shuttle_area, list(/proc/is_player_area, /proc/is_not_space_area, /proc/is_not_shuttle_area))
+var/global/list/is_player_but_not_space_or_shuttle_area = list(/proc/is_player_area, /proc/is_not_space_area, /proc/is_not_shuttle_area)
-GLOBAL_LIST_INIT(is_station_area, list(/proc/is_station_area))
+var/global/list/is_station_area = list(/proc/is_station_area)
-GLOBAL_LIST_INIT(is_station_and_maint_area, list(/proc/is_station_area, /proc/is_maint_area))
+var/global/list/is_station_and_maint_area = list(/proc/is_station_area, /proc/is_maint_area)
-GLOBAL_LIST_INIT(is_station_but_not_maint_area, list(/proc/is_station_area, /proc/is_not_maint_area))
+var/global/list/is_station_but_not_maint_area = list(/proc/is_station_area, /proc/is_not_maint_area)
/*
Misc Helpers
*/
-#define teleportlocs area_repository.get_areas_by_name_and_coords(GLOB.is_player_but_not_space_or_shuttle_area)
-#define stationlocs area_repository.get_areas_by_name(GLOB.is_player_but_not_space_or_shuttle_area)
-#define wizteleportlocs area_repository.get_areas_by_name(GLOB.is_station_area)
-#define maintlocs area_repository.get_areas_by_name(GLOB.is_station_and_maint_area)
-#define wizportallocs area_repository.get_areas_by_name(GLOB.is_station_but_not_space_or_shuttle_area)
+#define teleportlocs area_repository.get_areas_by_name_and_coords(global.is_player_but_not_space_or_shuttle_area)
+#define stationlocs area_repository.get_areas_by_name(global.is_player_but_not_space_or_shuttle_area)
+#define wizteleportlocs area_repository.get_areas_by_name(global.is_station_area)
+#define maintlocs area_repository.get_areas_by_name(global.is_station_and_maint_area)
+#define wizportallocs area_repository.get_areas_by_name(global.is_station_but_not_space_or_shuttle_area)
diff --git a/code/_helpers/atom_movables.dm b/code/_helpers/atom_movables.dm
index 8a8518502af0..0d6cdf5a6278 100644
--- a/code/_helpers/atom_movables.dm
+++ b/code/_helpers/atom_movables.dm
@@ -27,30 +27,20 @@
if(final_x || final_y)
return locate(final_x, final_y, T.z)
-// Walks up the loc tree until it finds a holder of the given holder_type
-/proc/get_holder_of_type(atom/A, holder_type)
- if(!istype(A)) return
- for(A, A && !istype(A, holder_type), A=A.loc);
- return A
-
/atom/movable/proc/throw_at_random(var/include_own_turf, var/maxrange, var/speed)
- var/list/turfs = RANGE_TURFS(src, maxrange)
+ var/turf/own_turf = get_turf(src)
+ var/list/turfs = RANGE_TURFS(own_turf, maxrange)
if(!maxrange)
maxrange = 1
if(!include_own_turf)
- turfs -= get_turf(src)
+ turfs -= own_turf
src.throw_at(pick(turfs), maxrange, speed)
/atom/movable/proc/do_simple_ranged_interaction(var/mob/user)
return FALSE
-/atom/movable/hitby(var/atom/movable/AM)
- ..()
- if(density && prob(50))
- do_simple_ranged_interaction()
-
-/atom/movable/proc/can_be_injected_by(var/atom/injector)
+/atom/movable/can_be_injected_by(var/atom/injector)
if(!Adjacent(get_turf(injector)))
return FALSE
if(!reagents)
diff --git a/code/_helpers/auxtools.dm b/code/_helpers/auxtools.dm
new file mode 100644
index 000000000000..89b922001a68
--- /dev/null
+++ b/code/_helpers/auxtools.dm
@@ -0,0 +1,29 @@
+var/global/auxtools_debug_server = world.GetConfig("env", "AUXTOOLS_DEBUG_DLL")
+
+/proc/auxtools_stack_trace(msg)
+ CRASH(msg)
+
+/proc/auxtools_expr_stub()
+ CRASH("auxtools not loaded")
+
+/proc/enable_debugging(mode, port)
+ CRASH("auxtools not loaded")
+
+/world/New()
+ auxtools_init()
+ return ..()
+
+/world/proc/auxtools_init()
+ if (global.auxtools_debug_server)
+ call_ext(global.auxtools_debug_server, "auxtools_init")()
+ enable_debugging()
+ return TRUE
+
+/world/Del()
+ auxtools_shutdown()
+ return ..()
+
+/world/proc/auxtools_shutdown()
+ if (global.auxtools_debug_server)
+ call_ext(global.auxtools_debug_server, "auxtools_shutdown")()
+ return TRUE
diff --git a/code/_helpers/cmp.dm b/code/_helpers/cmp.dm
index 2cf60a86e3b6..70bb6dc061fa 100644
--- a/code/_helpers/cmp.dm
+++ b/code/_helpers/cmp.dm
@@ -17,7 +17,7 @@
return a.sort_order - b.sort_order
/proc/cmp_name_or_type_asc(atom/a, atom/b)
- return sorttext(istype(b) || ("name" in b.vars) ? b.name : b.type, istype(a) || ("name" in a.vars) ? a.name : a.type)
+ return sorttext("[b]", "[a]")
/proc/cmp_name_asc(atom/a, atom/b)
return sorttext(b.name, a.name)
@@ -49,8 +49,16 @@
/proc/cmp_text_dsc(a,b)
return sorttext(a, b)
+/proc/cmp_list_name_key_asc(var/list/a, var/list/b)
+ return sorttext(b["name"], a["name"])
+
+/proc/cmp_list_name_key_dsc(var/list/a, var/list/b)
+ return sorttext(a["name"], b["name"])
+
/proc/cmp_qdel_item_time(datum/qdel_item/A, datum/qdel_item/B)
. = B.hard_delete_time - A.hard_delete_time
+ if (!. && B.qdels && A.qdels) // sort by time per call
+ . = (B.destroy_time / B.qdels) - (A.destroy_time / A.qdels)
if (!.)
. = B.destroy_time - A.destroy_time
if (!.)
@@ -58,8 +66,10 @@
if (!.)
. = B.qdels - A.qdels
-/proc/cmp_ruincost_priority(datum/map_template/ruin/A, datum/map_template/ruin/B)
- return initial(A.cost) - initial(B.cost)
+/proc/cmp_unit_test_priority(datum/unit_test/A, datum/unit_test/B)
+ . = A.priority - B.priority
+ if (!.)
+ . = sorttext(B, A)
/proc/cmp_timer(datum/timedevent/a, datum/timedevent/b)
return a.timeToRun - b.timeToRun
@@ -76,11 +86,14 @@
/proc/cmp_fusion_reaction_des(var/decl/fusion_reaction/A, var/decl/fusion_reaction/B)
return B.priority - A.priority
+/proc/cmp_human_examine_priority(decl/human_examination/a, decl/human_examination/b)
+ return a.priority - b.priority
+
/proc/cmp_program(var/datum/computer_file/program/A, var/datum/computer_file/program/B)
return cmp_text_asc(A.filedesc, B.filedesc)
-/proc/cmp_emails_asc(var/datum/computer_file/data/email_account/A, var/datum/computer_file/data/email_account/B)
- return cmp_text_asc(A.login,B.login)
+/proc/cmp_accounts_asc(var/datum/computer_file/data/account/A, var/datum/computer_file/data/account/B)
+ return cmp_text_asc(A.login, B.login)
/proc/cmp_planelayer(atom/A, atom/B)
return (B.plane - A.plane) || (B.layer - A.layer)
@@ -89,4 +102,67 @@
. = B.marked_value - A.marked_value
/proc/cmp_cocktail_des(var/decl/cocktail/A, var/decl/cocktail/B)
- . = B.mix_priority() - A.mix_priority()
\ No newline at end of file
+ . = B.mix_priority() - A.mix_priority()
+
+/proc/cmp_mob_sortvalue_asc(mob/a, mob/b)
+ . = a.mob_sort_value - b.mob_sort_value
+
+/proc/cmp_mob_sortvalue_des(mob/a, mob/b)
+ . = b.mob_sort_value - a.mob_sort_value
+
+/proc/cmp_rcon_tag_asc(var/obj/machinery/power/smes/buildable/a, var/obj/machinery/power/smes/buildable/b)
+ return sorttext(b.RCon_tag, a.RCon_tag)
+
+/proc/cmp_category_groups(var/datum/category_group/A, var/datum/category_group/B)
+ return A.sort_order - B.sort_order
+
+/proc/cmp_job_asc(var/datum/job/A, var/datum/job/B)
+ return A.get_occupations_tab_sort_score() - B.get_occupations_tab_sort_score()
+
+/proc/cmp_job_desc(var/datum/job/A, var/datum/job/B)
+ return B.get_occupations_tab_sort_score() - A.get_occupations_tab_sort_score()
+
+/proc/cmp_lobby_option_asc(var/datum/lobby_option/A, var/datum/lobby_option/B)
+ return A.sort_priority - B.sort_priority
+
+/proc/cmp_files_sort(datum/computer_file/a, datum/computer_file/b)
+ . = istype(b, /datum/computer_file/directory) - istype(a, /datum/computer_file/directory) // Prioritize directories over other files.
+ if(!.)
+ return sorttext(b.filename, a.filename)
+
+/proc/cmp_submap_archetype_asc(var/decl/submap_archetype/A, var/decl/submap_archetype/B)
+ return A.sort_priority - B.sort_priority
+
+/proc/cmp_submap_asc(var/datum/submap/A, var/datum/submap/B)
+ return A.archetype.sort_priority - B.archetype.sort_priority
+
+/proc/cmp_gripper_asc(datum/inventory_slot/gripper/a, datum/inventory_slot/gripper/b)
+ return a.hand_sort_priority - b.hand_sort_priority
+
+/proc/cmp_decl_uid_asc(decl/a, decl/b)
+ return sorttext(b.uid, a.uid)
+
+/proc/cmp_decl_sort_value_asc(decl/a, decl/b)
+ return a.sort_order - b.sort_order
+
+/proc/cmp_inventory_slot_desc(datum/inventory_slot/a, datum/inventory_slot/b)
+ return b.quick_equip_priority - a.quick_equip_priority
+
+/proc/cmp_skill_category_asc(decl/skill_category/a, decl/skill_category/b)
+ return a.sort_priority - b.sort_priority
+
+/proc/cmp_skill_asc(decl/skill/a, decl/skill/b)
+ if(length(a.prerequisites))
+ var/decl/skill/prerequisite = GET_DECL(a.prerequisites[1])
+ if(b == prerequisite)
+ return 1 // goes before
+ return cmp_skill_asc(GET_DECL(a.prerequisites[1]), b)
+ if(length(b.prerequisites))
+ var/decl/skill/prerequisite = GET_DECL(b.prerequisites[1])
+ if(a == prerequisite)
+ return -1 // goes after
+ return cmp_skill_asc(a, GET_DECL(b.prerequisites[1]))
+ return cmp_name_or_type_asc(a, b)
+
+/proc/cmp_priority_list(list/A, list/B)
+ return A["priority"] - B["priority"]
diff --git a/code/_helpers/datastructures/priority_queue.dm b/code/_helpers/datastructures/priority_queue.dm
new file mode 100644
index 000000000000..f75f71dabbb7
--- /dev/null
+++ b/code/_helpers/datastructures/priority_queue.dm
@@ -0,0 +1,70 @@
+/// An automatically ordered list, using the cmp proc to weight the list items
+/datum/priority_queue
+ /// The actual queue
+ VAR_PRIVATE/list/my_queue = list()
+ /// The weight function used to order the queue
+ VAR_PRIVATE/cmp
+
+/// Takes a proc `comparer` that will be used to compare the items inserted
+/// * Param `comparer` take two arguments and return the difference in their weight
+/// * For example: /proc/CompareItems(atom/A, atom/B) return A.size - B.size
+/datum/priority_queue/New(comparer)
+ cmp = comparer
+
+/// * Returns: `TRUE` if the queue is empty, otherwise `FALSE`
+/datum/priority_queue/proc/IsEmpty()
+ return !my_queue.len
+
+/// Add an `item` to the list, immediatly ordering it to its position using dichotomic search
+/datum/priority_queue/proc/Enqueue(item)
+ ADD_SORTED(my_queue, item, cmp)
+
+/// Removes and returns the first item in the queue
+/// * Returns: The first `item` in the queue, otherwise `FALSE`
+/datum/priority_queue/proc/Dequeue()
+ if(!my_queue.len)
+ return FALSE
+ . = my_queue[1]
+
+ Remove(.)
+
+/// Removes an `item` from the list
+/// * Returns: `TRUE` if succesfully removed, otherwise `FALSE`
+/datum/priority_queue/proc/Remove(item)
+ . = my_queue.Remove(item)
+
+/// * Returns: A copy of the item list
+/datum/priority_queue/proc/List()
+ . = my_queue.Copy()
+
+/// Finds an `item` in the list
+/// * Returns: The position of the `item`, or `0` if not found
+/datum/priority_queue/proc/Seek(item)
+ . = my_queue.Find(item)
+
+/// Gets the item at the positon `index`
+/// * Returns: The `item` at the index, or `0` if outside the range of the queue
+/datum/priority_queue/proc/Get(index)
+ if(index > my_queue.len || index < 1)
+ return 0
+ return my_queue[index]
+
+/// * Returns: The length of the queue
+/datum/priority_queue/proc/Length()
+ . = my_queue.len
+
+/datum/priority_queue/proc/GetQueue()
+ return my_queue
+
+/// Resorts the `item` to its correct position in the queue.
+/// * For example: The queue is sorted based on weight and atom A changes weight after being added
+/datum/priority_queue/proc/ReSort(item)
+ var/i = Seek(item)
+ if(i == 0)
+ return
+ while(i < my_queue.len && call(cmp)(my_queue[i],my_queue[i+1]) > 0)
+ my_queue.Swap(i,i+1)
+ i++
+ while(i > 1 && call(cmp)(my_queue[i],my_queue[i-1]) <= 0) // Last inserted element being first in case of ties (optimization)
+ my_queue.Swap(i,i-1)
+ i--
diff --git a/code/__datastructures/stack.dm b/code/_helpers/datastructures/stack.dm
similarity index 100%
rename from code/__datastructures/stack.dm
rename to code/_helpers/datastructures/stack.dm
diff --git a/code/_helpers/dview.dm b/code/_helpers/dview.dm
deleted file mode 100644
index 266d4f51acc9..000000000000
--- a/code/_helpers/dview.dm
+++ /dev/null
@@ -1,32 +0,0 @@
-GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
-
-//Version of view() which ignores darkness, because BYOND doesn't have it.
-/proc/dview(var/range = world.view, var/center, var/invis_flags = 0)
- if(!center)
- return
-
- GLOB.dview_mob.loc = center
- GLOB.dview_mob.see_invisible = invis_flags
- . = view(range, GLOB.dview_mob)
- GLOB.dview_mob.loc = null
-
-/mob/dview
- invisibility = 101
- density = 0
-
- anchored = 1
- simulated = 0
-
- see_in_dark = 1e6
-
- virtual_mob = null
-
-/mob/dview/Destroy()
- SHOULD_CALL_PARENT(FALSE)
- crash_with("Prevented attempt to delete dview mob: [log_info_line(src)]")
- return QDEL_HINT_LETMELIVE // Prevents destruction
-
-/mob/dview/Initialize()
- . = ..()
- // We don't want to be in any mob lists; we're a dummy not a mob.
- STOP_PROCESSING(SSmobs, src)
\ No newline at end of file
diff --git a/code/_helpers/emissive.dm b/code/_helpers/emissive.dm
new file mode 100644
index 000000000000..98cde2aadb31
--- /dev/null
+++ b/code/_helpers/emissive.dm
@@ -0,0 +1,6 @@
+/proc/emissive_overlay(icon, icon_state, loc, dir, color, flags)
+ var/image/I = image(icon, loc, icon_state, EMISSIVE_LAYER, dir)
+ I.plane = EMISSIVE_PLANE
+ I.color = color
+ I.appearance_flags |= flags
+ return I
diff --git a/code/_helpers/files.dm b/code/_helpers/files.dm
index 94d51d2bad97..c6d4b7ea49ff 100644
--- a/code/_helpers/files.dm
+++ b/code/_helpers/files.dm
@@ -1,27 +1,13 @@
-//checks if a file exists and contains text
-//returns text as a string if these conditions are met
-/proc/return_file_text(filename)
- if(fexists(filename) == 0)
- error("File not found ([filename])")
- return
-
- var/text = file2text(filename)
- if(!text)
- error("File empty ([filename])")
- return
-
- return text
-
//Sends resource files to client cache
/client/proc/getFiles()
for(var/file in args)
- src << browse_rsc(file)
+ send_rsc(src, file, null)
/client/proc/browse_files(root="data/logs/", max_iterations=10, list/valid_extensions=list(".txt",".log",".htm"))
var/path = root
for(var/i=0, iError: browse_files(): File not found/Invalid file([path]).")
+ to_chat(src, SPAN_WARNING("Error: browse_files(): File not found/Invalid file([path])."))
return
return path
@@ -53,7 +39,7 @@
/client/proc/file_spam_check()
var/time_to_wait = fileaccess_timer - world.time
if(time_to_wait > 0)
- to_chat(src, "Error: file_spam_check(): Spam. Please wait [round(time_to_wait/10)] seconds.")
+ to_chat(src, SPAN_WARNING("Error: file_spam_check(): Spam. Please wait [round(time_to_wait/10)] seconds."))
return 1
fileaccess_timer = world.time + FTPDELAY
return 0
diff --git a/code/_helpers/functional.dm b/code/_helpers/functional.dm
index 23f8c46321f6..a63056951c4d 100644
--- a/code/_helpers/functional.dm
+++ b/code/_helpers/functional.dm
@@ -48,7 +48,7 @@ if(LAZYLEN(extra_arguments)) {\
to_chat(feedback_receiver, "Value must be a text.")
/proc/is_dir_predicate(var/value, var/feedback_receiver)
- . = (value in GLOB.alldirs)
+ . = (value in global.alldirs)
if(!. && feedback_receiver)
to_chat(feedback_receiver, "Value must be a direction.")
diff --git a/code/_helpers/game.dm b/code/_helpers/game.dm
index 6eedf5cabca1..f084ad999bbb 100644
--- a/code/_helpers/game.dm
+++ b/code/_helpers/game.dm
@@ -3,46 +3,29 @@
/proc/is_on_same_plane_or_station(var/z1, var/z2)
if(z1 == z2)
return 1
- if((z1 in GLOB.using_map.station_levels) && (z2 in GLOB.using_map.station_levels))
+ if(isStationLevel(z1) && isStationLevel(z2))
return 1
return 0
-/proc/max_default_z_level()
- var/max_z = 0
- for(var/z in GLOB.using_map.station_levels)
- max_z = max(z, max_z)
- for(var/z in GLOB.using_map.admin_levels)
- max_z = max(z, max_z)
- for(var/z in GLOB.using_map.player_levels)
- max_z = max(z, max_z)
- return max_z
-
/proc/living_observers_present(var/list/zlevels)
if(LAZYLEN(zlevels))
- for(var/mob/M in GLOB.player_list) //if a tree ticks on the empty zlevel does it really tick
+ for(var/mob/M in global.player_list) //if a tree ticks on the empty zlevel does it really tick
if(M.stat != DEAD) //(no it doesn't)
var/turf/T = get_turf(M)
if(T && (T.z in zlevels))
return TRUE
return FALSE
-/proc/get_area(O)
- var/turf/loc = get_turf(O)
- if(loc)
- var/area/res = loc.loc
- .= res
+/proc/get_area_name(O) //get area's proper name
+ var/area/A = get_area(O)
+ return A?.proper_name
-/proc/get_area_name(N) //get area by its name
- for(var/area/A in world)
- if(A.name == N)
+/proc/get_area_by_name(N) //get area by its name
+ for(var/area/A in global.areas)
+ if(A.proper_name == N)
return A
return 0
-/proc/get_area_master(const/O)
- var/area/A = get_area(O)
- if (isarea(A))
- return A
-
/proc/in_range(atom/source, mob/user)
if(get_dist(source, user) <= 1)
return TRUE
@@ -61,23 +44,30 @@
return heard
+// These are procs rather than macros so they can be used as predicates, I think(?)
+/proc/isSealedLevel(var/level)
+ return level in SSmapping.sealed_levels
+
+/proc/isMapLevel(var/level)
+ return level in SSmapping.map_levels
+
/proc/isStationLevel(var/level)
- return level in GLOB.using_map.station_levels
+ return level in SSmapping.station_levels
/proc/isNotStationLevel(var/level)
return !isStationLevel(level)
/proc/isPlayerLevel(var/level)
- return level in GLOB.using_map.player_levels
+ return level in SSmapping.player_levels
/proc/isAdminLevel(var/level)
- return level in GLOB.using_map.admin_levels
+ return level in SSmapping.admin_levels
/proc/isNotAdminLevel(var/level)
return !isAdminLevel(level)
/proc/isContactLevel(var/level)
- return level in GLOB.using_map.contact_levels
+ return level in SSmapping.contact_levels
/proc/circlerange(center=usr,radius=3)
@@ -109,6 +99,11 @@
//turfs += centerturf
return atoms
+/// Despite what the ref says, get_dist does not factor in the Z axis.
+/// This is just get_dist() but Z-aware.
+/proc/get_dist_3d(atom/Loc1, atom/Loc2)
+ return max(abs(Loc1.x-Loc2.x), abs(Loc1.y-Loc2.y), abs(Loc1.z-Loc2.z))
+
/proc/get_dist_euclidian(atom/Loc1, atom/Loc2)
var/dx = Loc1.x - Loc2.x
var/dy = Loc1.y - Loc2.y
@@ -118,7 +113,7 @@
return dist
/proc/get_dist_bounds(var/target, var/source) // Alternative to get_dist for multi-turf objects
- return Ceiling(bounds_dist(target, source)/world.icon_size) + 1
+ return ceil(bounds_dist(target, source)/world.icon_size) + 1
/proc/circlerangeturfs(center=usr,radius=3)
var/turf/centerturf = get_turf(center)
@@ -134,7 +129,7 @@
if(dx*dx + dy*dy <= rsq)
. += T
-/proc/circleviewturfs(center=usr,radius=3) //Is there even a diffrence between this proc and circlerangeturfs()?
+/proc/circleviewturfs(center=usr,radius=3)
var/turf/centerturf = get_turf(center)
var/list/turfs = new/list()
@@ -181,9 +176,8 @@
return L
-// Returns a list of mobs and/or objects in range of R from source. Used in radio and say code.
-
-/proc/get_mobs_or_objects_in_view(var/R, var/atom/source, var/include_mobs = 1, var/include_objects = 1)
+// Returns a list of mobs and/or objects in range of get_range from source. Used in radio and say code.
+/proc/get_mobs_or_objects_in_view(var/get_range, var/atom/source, var/include_mobs = 1, var/include_objects = 1)
var/turf/T = get_turf(source)
var/list/hear = list()
@@ -191,8 +185,7 @@
if(!T)
return hear
- var/list/range = hear(R, T)
-
+ var/list/range = hear(get_range, T)
for(var/I in range)
if(ismob(I))
hear |= recursive_content_check(I, hear, 3, 1, 0, include_mobs, include_objects)
@@ -204,105 +197,62 @@
hear |= recursive_content_check(I, hear, 3, 1, 0, include_mobs, include_objects)
if(include_objects)
hear += I
-
return hear
-
-/proc/get_mobs_in_radio_ranges(var/list/obj/item/radio/radios)
-
- set background = 1
-
- . = list()
- // Returns a list of mobs who can hear any of the radios given in @radios
- var/list/speaker_coverage = list()
- for(var/obj/item/radio/R in radios)
- if(R)
- //Cyborg checks. Receiving message uses a bit of cyborg's charge.
- var/obj/item/radio/borg/BR = R
- if(istype(BR) && BR.myborg)
- var/mob/living/silicon/robot/borg = BR.myborg
- var/datum/robot_component/CO = borg.get_component("radio")
- if(!CO)
- continue //No radio component (Shouldn't happen)
- if(!borg.is_component_functioning("radio") || !borg.cell_use_power(CO.active_usage))
- continue //No power.
-
- var/turf/speaker = get_turf(R)
- if(speaker)
- for(var/turf/T in hear(R.canhear_range,speaker))
- speaker_coverage[T] = T
-
-
- // Try to find all the players who can hear the message
- for(var/i = 1; i <= GLOB.player_list.len; i++)
- var/mob/M = GLOB.player_list[i]
- if(M)
- var/turf/ear = get_turf(M)
- if(ear)
- // Ghostship is magic: Ghosts can hear radio chatter from anywhere
- if(speaker_coverage[ear] || (isghost(M) && M.get_preference_value(/datum/client_preference/ghost_radio) == GLOB.PREF_ALL_CHATTER))
- . |= M // Since we're already looping through mobs, why bother using |= ? This only slows things down.
- return .
-
-/proc/get_mobs_and_objs_in_view_fast(var/turf/T, var/range, var/list/mobs, var/list/objs, var/checkghosts = null)
-
- var/list/hear = dview(range,T,INVISIBILITY_MAXIMUM)
+// Alternative to get_mobs_or_objects_in_view which only considers mobs and "listening" objects.
+/proc/get_listeners_in_range(turf/center, range, list/mobs, list/objs, check_ghosts=FALSE)
var/list/hearturfs = list()
-
- for(var/atom/movable/AM in hear)
- if(ismob(AM))
- mobs += AM
- hearturfs += get_turf(AM)
- else if(isobj(AM))
- objs += AM
- hearturfs += get_turf(AM)
-
- for(var/mob/M in GLOB.player_list)
- if(checkghosts && M.stat == DEAD && M.get_preference_value(checkghosts) != GLOB.PREF_NEARBY)
+ FOR_DVIEW(var/turf/T, range, center, INVISIBILITY_MAXIMUM)
+ hearturfs[T] = TRUE
+ for(var/mob/M in T)
+ mobs += M
+ END_FOR_DVIEW
+
+ for(var/mob/M in global.player_list)
+ if(check_ghosts && M.stat == DEAD && M.get_preference_value(check_ghosts) != PREF_NEARBY)
mobs |= M
- else if(get_turf(M) in hearturfs)
+ else if(hearturfs[get_turf(M)])
mobs |= M
- for(var/obj/O in GLOB.listening_objects)
- if(get_turf(O) in hearturfs)
- objs |= O
+ for(var/obj/O in global.listening_objects)
+ if(hearturfs[get_turf(O)])
+ objs += O
-proc
- inLineOfSight(X1,Y1,X2,Y2,Z=1,PX1=16.5,PY1=16.5,PX2=16.5,PY2=16.5)
- var/turf/T
- if(X1==X2)
- if(Y1==Y2)
- return 1 //Light cannot be blocked on same tile
- else
- var/s = SIMPLE_SIGN(Y2-Y1)
- Y1+=s
- while(Y1!=Y2)
- T=locate(X1,Y1,Z)
- if(T.opacity)
- return 0
- Y1+=s
+/proc/inLineOfSight(X1,Y1,X2,Y2,Z=1,PX1=16.5,PY1=16.5,PX2=16.5,PY2=16.5)
+ var/turf/T
+ if(X1==X2)
+ if(Y1==Y2)
+ return 1 //Light cannot be blocked on same tile
else
- var/m=(32*(Y2-Y1)+(PY2-PY1))/(32*(X2-X1)+(PX2-PX1))
- var/b=(Y1+PY1/32-0.015625)-m*(X1+PX1/32-0.015625) //In tiles
- var/signX = SIMPLE_SIGN(X2-X1)
- var/signY = SIMPLE_SIGN(Y2-Y1)
- if(X1 abs (dx)) //slope is above 1:1 (move horizontally in a tie)
- if(dy > 0)
- return get_step(start, SOUTH)
- else
- return get_step(start, NORTH)
- else
- if(dx > 0)
- return get_step(start, WEST)
- else
- return get_step(start, EAST)
-
/proc/get_mob_by_key(var/key)
for(var/mob/M in SSmobs.mob_list)
if(M.ckey == lowertext(key))
return M
return null
-
-// Will return a list of active candidates. It increases the buffer 5 times until it finds a candidate which is active within the buffer.
-/proc/get_active_candidates(var/buffer = 1)
-
- var/list/candidates = list() //List of candidate KEYS to assume control of the new larva ~Carn
- var/i = 0
- while(candidates.len <= 0 && i < 5)
- for(var/mob/observer/ghost/G in GLOB.player_list)
- if(((G.client.inactivity/10)/60) <= buffer + i) // the most active players are more likely to become an alien
- if(!(G.mind && G.mind.current && G.mind.current.stat != DEAD))
- candidates += G.key
- i++
- return candidates
-
-/proc/ScreenText(obj/O, maptext="", screen_loc="CENTER-7,CENTER-7", maptext_height=480, maptext_width=480)
- if(!isobj(O)) O = new /obj/screen/text()
- O.maptext = maptext
- O.maptext_height = maptext_height
- O.maptext_width = maptext_width
- O.screen_loc = screen_loc
- return O
-
-/proc/Show2Group4Delay(obj/O, list/group, delay=0)
- if(!isobj(O)) return
- if(!group) group = GLOB.clients
- for(var/client/C in group)
- C.screen += O
- if(delay)
- spawn(delay)
- for(var/client/C in group)
- C.screen -= O
-
-/proc/flick_overlay(image/I, list/show_to, duration)
- for(var/client/C in show_to)
- C.images += I
- spawn(duration)
- for(var/client/C in show_to)
- C.images -= I
-
-datum/projectile_data
+/datum/projectile_data
var/src_x
var/src_y
var/time
@@ -396,24 +292,12 @@ datum/projectile_data
src.dest_x = dest_x
src.dest_y = dest_y
-/proc/projectile_trajectory(var/src_x, var/src_y, var/rotation, var/angle, var/power)
-
- // returns the destination (Vx,y) that a projectile shot at [src_x], [src_y], with an angle of [angle],
- // rotated at [rotation] and with the power of [power]
- // Thanks to VistaPOWA for this function
-
- var/power_x = power * cos(angle)
- var/power_y = power * sin(angle)
- var/time = 2* power_y / 10 //10 = g
-
- var/distance = time * power_x
-
- var/dest_x = src_x + distance*sin(rotation);
- var/dest_y = src_y + distance*cos(rotation);
-
- return new /datum/projectile_data(src_x, src_y, time, distance, power_x, power_y, dest_x, dest_y)
-
/proc/MixColors(const/list/colors)
+ switch(length(colors))
+ if(1)
+ return colors[1]
+ if(2)
+ return BlendHSV(colors[1], colors[2], 0.5)
var/list/reds = list()
var/list/blues = list()
var/list/greens = list()
@@ -462,31 +346,39 @@ datum/projectile_data
* Gets the highest and lowest pressures from the tiles in cardinal directions
* around us, then checks the difference.
*/
-/proc/getOPressureDifferential(var/turf/loc)
- var/minp=16777216;
- var/maxp=0;
- for(var/dir in GLOB.cardinal)
- var/turf/simulated/T=get_turf(get_step(loc,dir))
- var/cp=0
- if(T && istype(T) && T.zone)
- var/datum/gas_mixture/environment = T.return_air()
- cp = environment.return_pressure()
- else
- if(istype(T,/turf/simulated))
+/proc/get_surrounding_pressure_differential(var/turf/loc, atom/originator)
+ var/minp = INFINITY
+ var/maxp = 0
+ var/has_neighbour = FALSE
+ var/airblock // zeroed by ATMOS_CANPASS_TURF, declared early as microopt
+ for(var/dir in global.cardinal)
+ var/turf/neighbour = get_step(loc,dir)
+ if(!neighbour)
+ continue
+ for(var/obj/O in loc)
+ if(originator && O == originator)
continue
- if(cpmaxp)maxp=cp
- return abs(minp-maxp)
+ ATMOS_CANPASS_MOVABLE(airblock, O, neighbour)
+ . |= airblock
+ if(airblock & AIR_BLOCKED)
+ continue
+ ATMOS_CANPASS_TURF(airblock, neighbour, loc)
+ if(airblock & AIR_BLOCKED)
+ continue
+ var/datum/gas_mixture/environment = neighbour.return_air()
+ var/cp = environment ? environment.return_pressure() : 0
+ has_neighbour = TRUE
+ minp = min(minp, cp)
+ maxp = max(maxp, cp)
+ return has_neighbour ? abs(minp-maxp) : 0
/proc/convert_k2c(var/temp)
return ((temp - T0C))
-/proc/convert_c2k(var/temp)
- return ((temp + T0C))
-
/proc/getCardinalAirInfo(var/turf/loc, var/list/stats=list("temperature"))
var/list/temps = new/list(4)
- for(var/dir in GLOB.cardinal)
+ var/statslen = length(stats)
+ for(var/dir in global.cardinal)
var/direction
switch(dir)
if(NORTH)
@@ -497,21 +389,11 @@ datum/projectile_data
direction = 3
if(WEST)
direction = 4
- var/turf/simulated/T=get_turf(get_step(loc,dir))
- var/list/rstats = new /list(stats.len)
- if(T && istype(T) && T.zone)
- var/datum/gas_mixture/environment = T.return_air()
- for(var/i=1;i<=stats.len;i++)
- if(stats[i] == "pressure")
- rstats[i] = environment.return_pressure()
- else
- rstats[i] = environment.vars[stats[i]]
- else if(istype(T, /turf/simulated))
- rstats = null // Exclude zone (wall, door, etc).
- else if(istype(T, /turf))
- // Should still work. (/turf/return_air())
- var/datum/gas_mixture/environment = T.return_air()
- for(var/i=1;i<=stats.len;i++)
+ var/turf/T = get_step(loc,dir)
+ var/list/rstats = new /list(statslen)
+ var/datum/gas_mixture/environment = T?.return_air()
+ if(environment)
+ for(var/i= 1 to statslen)
if(stats[i] == "pressure")
rstats[i] = environment.return_pressure()
else
@@ -525,9 +407,6 @@ datum/projectile_data
/proc/SecondsToTicks(var/seconds)
return seconds * 10
-/proc/round_is_spooky(var/spookiness_threshold = config.cult_ghostwriter_req_cultists)
- return (GLOB.cult.current_antagonists.len > spookiness_threshold)
-
/proc/window_flash(var/client_or_usr)
if (!client_or_usr)
return
diff --git a/code/_helpers/gauss.dm b/code/_helpers/gauss.dm
new file mode 100644
index 000000000000..6b3d5899d5f2
--- /dev/null
+++ b/code/_helpers/gauss.dm
@@ -0,0 +1,33 @@
+#define ACCURACY 10000
+
+/**
+ * Converts a uniform distributed random number into a normal distributed one
+ * since this method produces two random numbers, one is saved for subsequent calls
+ * (making the cost negligble for every second call).
+ * * This will return +/- decimals, situated about mean with standard deviation stddev
+ * * 68% chance that the number is within 1stddev
+ * * 95% chance that the number is within 2stddev
+ * * 98% chance that the number is within 3stddev...etc
+ */
+/proc/gaussian(mean, stddev)
+ var/static/gaussian_next
+ var/R1
+ var/R2
+ var/working
+ if(gaussian_next != null)
+ R1 = gaussian_next
+ gaussian_next = null
+ else
+ do
+ R1 = (rand(-ACCURACY, ACCURACY) / ACCURACY)
+ R2 = (rand(-ACCURACY, ACCURACY) / ACCURACY)
+ working = (R1 * R1) + (R2 * R2)
+
+ while(working >= 1 || working == 0)
+ working = sqrt(((-2 * log(working)) / working))
+ R1 *= working
+ gaussian_next = (R2 * working)
+
+ return (mean + (stddev * R1))
+
+#undef ACCURACY
diff --git a/code/_helpers/global_lists.dm b/code/_helpers/global_lists.dm
index fcd35ed989c4..daeb63811418 100644
--- a/code/_helpers/global_lists.dm
+++ b/code/_helpers/global_lists.dm
@@ -1,124 +1,75 @@
-//Since it didn't really belong in any other category, I'm putting this here
-//This is for procs to replace all the goddamn 'in world's that are chilling around the code
+// I really don't like having miscellaneous 'collection of definitions' files floating around in the codebase.
+// I've already found a lot of the lists that used to be here a new forever home (or taken them out back and shot them),
+// but hopefully we can do the same for the rest eventually.
+// Either find a better spot for them that's related to their uses/function/etc., or delete them.
-var/global/list/cable_list = list() //Index for all cables, so that powernets don't have to look through the entire world all the time
-var/global/list/landmarks_list = list() //list of all landmarks created
-var/global/list/side_effects = list() //list of all medical sideeffects types by thier names |BS12
-var/list/mannequins_
-
-// Uplinks
-var/list/obj/item/uplink/world_uplinks = list()
-
-//Preferences stuff
-//Hairstyles
-GLOBAL_LIST_EMPTY(hair_styles_list) //stores /datum/sprite_accessory/hair indexed by name
-GLOBAL_LIST_EMPTY(facial_hair_styles_list) //stores /datum/sprite_accessory/facial_hair indexed by name
-
-var/global/list/skin_styles_female_list = list() //unused
-GLOBAL_LIST_EMPTY(body_marking_styles_list) //stores /datum/sprite_accessory/marking indexed by name
-
-GLOBAL_DATUM_INIT(underwear, /datum/category_collection/underwear, new())
-
-// Visual nets
-var/list/datum/visualnet/visual_nets = list()
-var/datum/visualnet/camera/cameranet = new()
-
-// Runes
-var/global/list/rune_list = new()
-var/global/list/endgame_exits = list()
-var/global/list/endgame_safespawns = list()
-
-var/global/list/syndicate_access = list(access_maint_tunnels, access_syndicate, access_external_airlocks)
-
-// Strings which corraspond to bodypart covering flags, useful for outputting what something covers.
+// Strings which correspond to bodypart covering flags, useful for outputting what something covers.
var/global/list/string_part_flags = list(
- "head" = HEAD,
- "face" = FACE,
- "eyes" = EYES,
- "upper body" = UPPER_TORSO,
- "lower body" = LOWER_TORSO,
- "legs" = LEGS,
- "feet" = FEET,
- "arms" = ARMS,
- "hands" = HANDS
+ "head" = SLOT_HEAD,
+ "face" = SLOT_FACE,
+ "eyes" = SLOT_EYES,
+ "ears" = SLOT_EARS,
+ "upper body" = SLOT_UPPER_BODY,
+ "lower body" = SLOT_LOWER_BODY,
+ "tail" = SLOT_TAIL,
+ "legs" = SLOT_LEGS,
+ "feet" = SLOT_FEET,
+ "arms" = SLOT_ARMS,
+ "hands" = SLOT_HANDS
)
-// Strings which corraspond to slot flags, useful for outputting what slot something is.
+// TODO: These should probably be able to be generated automatically from inventory slot subtype definitions, maybe?
+/// Strings which correspond to slot flags, useful for outputting what slot something is.
var/global/list/string_slot_flags = list(
- "back" = SLOT_BACK,
- "face" = SLOT_MASK,
- "waist" = SLOT_BELT,
- "ID slot" = SLOT_ID,
- "ears" = SLOT_EARS,
- "eyes" = SLOT_EYES,
- "hands" = SLOT_GLOVES,
- "head" = SLOT_HEAD,
- "feet" = SLOT_FEET,
- "exo slot" = SLOT_OCLOTHING,
- "body" = SLOT_ICLOTHING,
- "uniform" = SLOT_TIE,
- "holster" = SLOT_HOLSTER
+ "back" = SLOT_BACK,
+ "face" = SLOT_FACE,
+ "waist" = SLOT_LOWER_BODY,
+ "tail" = SLOT_TAIL,
+ "ID slot" = SLOT_ID,
+ "ears" = SLOT_EARS,
+ "eyes" = SLOT_EYES,
+ "hands" = SLOT_HANDS,
+ "head" = SLOT_HEAD,
+ "feet" = SLOT_FEET,
+ "exo slot" = SLOT_OVER_BODY,
+ "body" = SLOT_UPPER_BODY,
+ "holster" = SLOT_HOLSTER
)
-//////////////////////////
-/////Initial Building/////
-//////////////////////////
-
-/proc/get_mannequin(var/ckey)
- if(!mannequins_)
- mannequins_ = new()
- . = mannequins_[ckey]
- if(!.)
- . = new/mob/living/carbon/human/dummy/mannequin()
- mannequins_[ckey] = .
-
-/hook/global_init/proc/makeDatumRefLists()
- var/list/paths
-
- //Hair - Initialise all /datum/sprite_accessory/hair into an list indexed by hair-style name
- paths = typesof(/datum/sprite_accessory/hair) - /datum/sprite_accessory/hair
- for(var/path in paths)
- var/datum/sprite_accessory/hair/H = new path()
- GLOB.hair_styles_list[H.name] = H
-
- //Facial Hair - Initialise all /datum/sprite_accessory/facial_hair into an list indexed by facialhair-style name
- paths = typesof(/datum/sprite_accessory/facial_hair) - /datum/sprite_accessory/facial_hair
- for(var/path in paths)
- var/datum/sprite_accessory/facial_hair/H = new path()
- GLOB.facial_hair_styles_list[H.name] = H
-
- //Body markings - Initialise all /datum/sprite_accessory/marking into an list indexed by marking name
- paths = typesof(/datum/sprite_accessory/marking) - /datum/sprite_accessory/marking
- for(var/path in paths)
- var/datum/sprite_accessory/marking/M = new path()
- GLOB.body_marking_styles_list[M.name] = M
+// Used to avoid constantly generating new lists during movement.
+var/global/list/all_maniple_limbs = list(
+ (ORGAN_CATEGORY_MANIPLE)
+)
+var/global/list/all_stance_limbs = list(
+ (ORGAN_CATEGORY_STANCE),
+ (ORGAN_CATEGORY_STANCE_ROOT)
+)
+var/global/list/child_stance_limbs = list(
+ (ORGAN_CATEGORY_STANCE)
+)
- return 1
+// TODO: Replace keybinding datums with keybinding decls to make this unnecessary.
+var/global/list/hotkey_keybinding_list_by_key = list() // Replace this with just looping over all keybinding decls (as below) in a 'reset hotkeys' proc.
+var/global/list/keybindings_by_name = list() // Replace this with just decl lookups.
+/proc/makeDatumRefLists()
+ // Keybindings
+ for(var/KB in subtypesof(/datum/keybinding))
+ var/datum/keybinding/keybinding = KB
+ if(TYPE_IS_ABSTRACT(keybinding))
+ continue
+ ASSERT(keybinding.name)
+ var/datum/keybinding/instance = new keybinding
+ global.keybindings_by_name[instance.name] = instance
+ if(length(instance.hotkey_keys))
+ for(var/bound_key in instance.hotkey_keys)
+ global.hotkey_keybinding_list_by_key[bound_key] += list(instance.name)
-// This is all placeholder procs for an eventual PR to change them to use decls.
-var/list/all_species
-var/list/playable_species // A list of ALL playable species, whitelisted, latejoin or otherwise.
-/proc/build_species_lists()
- if(global.all_species && global.playable_species)
- return
- global.playable_species = list()
- global.all_species = list()
- for(var/species_type in typesof(/datum/species))
- var/datum/species/species = species_type
- var/species_name = initial(species.name)
- if(species_name)
- global.all_species[species_name] = new species
- species = get_species_by_key(species_name)
- if(!(species.spawn_flags & SPECIES_IS_RESTRICTED))
- global.playable_species += species.name
- if(GLOB.using_map.default_species)
- global.playable_species |= GLOB.using_map.default_species
-/proc/get_species_by_key(var/species_key)
- build_species_lists()
- . = global.all_species[species_key]
-/proc/get_all_species()
- build_species_lists()
- . = global.all_species
/proc/get_playable_species()
- build_species_lists()
- . = global.playable_species
+ var/static/list/_playable_species // A list of ALL playable species, whitelisted, latejoin or otherwise. (read: non-restricted)
+ if(!_playable_species)
+ _playable_species = list()
+ for(var/decl/species/species in decls_repository.get_decls_of_subtype_unassociated(/decl/species))
+ if(species.spawn_flags & SPECIES_IS_RESTRICTED)
+ continue
+ _playable_species += species.uid
+ return _playable_species
diff --git a/code/_helpers/icons.dm b/code/_helpers/icons.dm
index b60872d08571..38aaf7af68be 100644
--- a/code/_helpers/icons.dm
+++ b/code/_helpers/icons.dm
@@ -15,7 +15,7 @@ CHANGING ICONS
Several new procs have been added to the /icon datum to simplify working with icons. To use them,
remember you first need to setup an /icon var like so:
-var/icon/my_icon = new('iconfile.dmi')
+var/global/icon/my_icon = new('iconfile.dmi')
icon/ChangeOpacity(amount = 1)
A very common operation in DM is to try to make an icon more or less transparent. Making an icon more
@@ -77,40 +77,24 @@ More than one HSV color can match the same RGB color.
Here are some procs you can use for color management:
-ReadRGB(rgb)
- Takes an RGB string like "#ffaa55" and converts it to a list such as list(255,170,85). If an RGBA format is used
- that includes alpha, the list will have a fourth item for the alpha value.
-hsv(hue, sat, val, apha)
+hsv(hue, sat, val)
Counterpart to rgb(), this takes the values you input and converts them to a string in "#hhhssvv" or "#hhhssvvaa"
format. Alpha is not included in the result if null.
-ReadHSV(rgb)
- Takes an HSV string like "#100ff80" and converts it to a list such as list(256,255,128). If an HSVA format is used that
- includes alpha, the list will have a fourth item for the alpha value.
-RGBtoHSV(rgb)
- Takes an RGB or RGBA string like "#ffaa55" and converts it into an HSV or HSVA color such as "#080aaff".
-HSVtoRGB(hsv)
- Takes an HSV or HSVA string like "#080aaff" and converts it into an RGB or RGBA color such as "#ff55aa".
BlendRGB(rgb1, rgb2, amount)
Blends between two RGB or RGBA colors using regular RGB blending. If amount is 0, the first color is the result;
if 1, the second color is the result. 0.5 produces an average of the two. Values outside the 0 to 1 range are allowed as well.
The returned value is an RGB or RGBA color.
BlendHSV(hsv1, hsv2, amount)
- Blends between two HSV or HSVA colors using HSV blending, which tends to produce nicer results than regular RGB
+ Blends between two RGB or RGBA colors using HSV blending, which tends to produce nicer results than regular RGB
blending because the brightness of the color is left intact. If amount is 0, the first color is the result; if 1,
the second color is the result. 0.5 produces an average of the two. Values outside the 0 to 1 range are allowed as well.
- The returned value is an HSV or HSVA color.
-BlendRGBasHSV(rgb1, rgb2, amount)
- Like BlendHSV(), but the colors used and the return value are RGB or RGBA colors. The blending is done in HSV form.
-HueToAngle(hue)
- Converts a hue to an angle range of 0 to 360. Angle 0 is red, 120 is green, and 240 is blue.
-AngleToHue(hue)
- Converts an angle to a hue in the valid range.
+ The returned value is an RGB or RGBA color.
RotateHue(hsv, angle)
Takes an HSV or HSVA value and rotates the hue forward through red, green, and blue by an angle from 0 to 360.
(Rotating red by 60 degrees produces yellow.) The result is another HSV or HSVA color with the same saturation and value
as the original, but a different hue.
GrayScale(rgb)
- Takes an RGB or RGBA color and converts it to grayscale. Returns an RGB or RGBA string.
+ Takes an RGB or RGBA color and converts it to grayscale, preserving perceptual lightness. Returns an RGB or RGBA string.
ColorTone(rgb, tone)
Similar to GrayScale(), this proc converts an RGB or RGBA color to a range of black -> tone -> white instead of
using strict shades of gray. The tone value is an RGB color; any alpha value is ignored.
@@ -154,7 +138,7 @@ mob
// Testing object types (and layers)
overlays+=/obj/effect/overlayTest
- loc = locate (10,10,1)
+ forceMove(locate(10,10,1))
verb
Browse_Icon()
set name = "1. Browse Icon"
@@ -163,11 +147,11 @@ mob
// Send the icon to src's local cache
send_rsc(src, getFlatIcon(src), iconName)
// Display the icon in their browser
- src<
